cherry-pick.softflowd-0.9.9-4-g417e018.add-ipfix-c-to-support-exporting-ipfix-formatted-flow-records.patch 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. Subject: Add ipfix.c to support exporting IPFIX format[t]ed flow records
  2. Origin: softflowd-0.9.9-4-g417e018 <https://github.com/irino/softflowd/commit/softflowd-0.9.9-4-g417e018>
  3. Upstream-Author: Hitoshi Irino <hitoshi.irino@gmail.com>
  4. Date: Mon Dec 10 22:33:53 2012 +0900
  5. --- a/Makefile.in
  6. +++ b/Makefile.in
  7. @@ -25,7 +25,7 @@
  8. TARGETS=softflowd${EXEEXT} softflowctl${EXEEXT}
  9. COMMON=convtime.o strlcpy.o strlcat.o closefrom.o daemon.o
  10. -SOFTFLOWD=softflowd.o log.o netflow1.o netflow5.o netflow9.o freelist.o
  11. +SOFTFLOWD=softflowd.o log.o netflow1.o netflow5.o netflow9.o ipfix.o freelist.o
  12. all: $(TARGETS)
  13. --- a/common.h
  14. +++ b/common.h
  15. @@ -70,6 +70,12 @@
  16. #include <inttypes.h>
  17. #endif
  18. +#if defined(HAVE_SYS_ENDIAN_H)
  19. +#include <sys/endian.h>
  20. +#elif defined(HAVE_ENDIAN_H)
  21. +#include <endian.h>
  22. +#endif
  23. +
  24. /* The name of the program */
  25. #define PROGNAME "softflowd"
  26. --- a/configure.ac
  27. +++ b/configure.ac
  28. @@ -52,7 +52,7 @@
  29. [ AC_DEFINE_UNQUOTED([PRIVDROP_CHROOT_DIR], ["${withval}"], [privdrop chroot directory]) ]
  30. )
  31. -AC_CHECK_HEADERS(net/bpf.h pcap.h pcap-bpf.h)
  32. +AC_CHECK_HEADERS(net/bpf.h pcap.h pcap-bpf.h sys/endian.h endian.h)
  33. dnl AC_CHECK_HEADERS(netinet/in_systm.h netinet/tcp.h netinet/udp.h)
  34. dnl
  35. @@ -87,7 +87,7 @@
  36. AC_SEARCH_LIBS(socket, socket)
  37. AC_CHECK_LIB(pcap, pcap_open_live)
  38. -AC_CHECK_FUNCS(closefrom daemon setresuid setreuid setresgid setgid strlcpy strlcat strsep)
  39. +AC_CHECK_FUNCS(closefrom daemon setresuid setreuid setresgid setgid strlcpy strlcat strsep htobe64 htonll)
  40. AC_CHECK_TYPES([u_int64_t, int64_t, uint64_t, u_int32_t, int32_t, uint32_t])
  41. AC_CHECK_TYPES([u_int16_t, int16_t, uint16_t, u_int8_t, int8_t, uint8_t])
  42. --- /dev/null
  43. +++ b/ipfix.c
  44. @@ -0,0 +1,480 @@
  45. +/*
  46. + * Copyright 2002 Damien Miller <djm@mindrot.org> All rights reserved.
  47. + * Copyright 2012 Hitoshi Irino <irino@sfc.wide.ad.jp> All rights reserved.
  48. + *
  49. + * Redistribution and use in source and binary forms, with or without
  50. + * modification, are permitted provided that the following conditions
  51. + * are met:
  52. + * 1. Redistributions of source code must retain the above copyright
  53. + * notice, this list of conditions and the following disclaimer.
  54. + * 2. Redistributions in binary form must reproduce the above copyright
  55. + * notice, this list of conditions and the following disclaimer in the
  56. + * documentation and/or other materials provided with the distribution.
  57. + *
  58. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  59. + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  60. + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  61. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  62. + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  63. + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  64. + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  65. + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  66. + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  67. + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  68. + */
  69. +
  70. +#include "common.h"
  71. +#include "log.h"
  72. +#include "treetype.h"
  73. +#include "softflowd.h"
  74. +
  75. +/* IPFIX a.k.a. Netflow v.10 */
  76. +struct IPFIX_HEADER {
  77. + u_int16_t version, length;
  78. + u_int32_t export_time; /* in seconds */
  79. + u_int32_t sequence, od_id;
  80. +} __packed;
  81. +struct IPFIX_SET_HEADER {
  82. + u_int16_t set_id, length;
  83. +} __packed;
  84. +struct IPFIX_TEMPLATE_RECORD_HEADER {
  85. + u_int16_t template_id, count;
  86. +} __packed;
  87. +struct IPFIX_TEMPLATE_SET_HEADER {
  88. + struct IPFIX_SET_HEADER c;
  89. + struct IPFIX_TEMPLATE_RECORD_HEADER r;
  90. +} __packed;
  91. +struct IPFIX_OPTION_TEMPLATE_SET_HEADER {
  92. + struct IPFIX_SET_HEADER c;
  93. + struct IPFIX_TEMPLATE_RECORD_HEADER r;
  94. + u_int16_t scope_count;
  95. +} __packed;
  96. +struct IPFIX_FIELD_SPECIFIER {
  97. + u_int16_t ie, length;
  98. +} __packed;
  99. +
  100. +#define IPFIX_TEMPLATE_SET_ID 2
  101. +#define IPFIX_OPTION_TEMPLATE_SET_ID 3
  102. +#define IPFIX_MIN_RECORD_SET_ID 256
  103. +
  104. +/* Flowset record ies the we care about */
  105. +#define IPFIX_octetDeltaCount 1
  106. +#define IPFIX_packetDeltaCount 2
  107. +/* ... */
  108. +#define IPFIX_protocolIdentifier 4
  109. +/* ... */
  110. +#define IPFIX_tcpControlBits 6
  111. +#define IPFIX_sourceTransportPort 7
  112. +#define IPFIX_sourceIPv4Address 8
  113. +/* ... */
  114. +#define IPFIX_ingressInterface 10
  115. +#define IPFIX_destinationTransportPort 11
  116. +#define IPFIX_destinationIPv4Address 12
  117. +/* ... */
  118. +#define IPFIX_egressInterface 14
  119. +/* ... */
  120. +#define IPFIX_flowEndSysUpTime 21
  121. +#define IPFIX_flowStartSysUpTime 22
  122. +/* ... */
  123. +#define IPFIX_sourceIPv6Address 27
  124. +#define IPFIX_destinationIPv6Address 28
  125. +/* ... */
  126. +#define IPFIX_ipVersion 60
  127. +
  128. +#define IPFIX_meteringProcessId 143
  129. +#define IPFIX_systemInitTimeMilliseconds 160
  130. +#define PSAMP_selectorAlgorithm 304
  131. +#define PSAMP_samplingPacketInterval 305
  132. +#define PSAMP_samplingPacketSpace 306
  133. +
  134. +#define PSAMP_selectorAlgorithm_count 1
  135. +
  136. +/* Stuff pertaining to the templates that softflowd uses */
  137. +#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS 13
  138. +struct IPFIX_SOFTFLOWD_TEMPLATE {
  139. + struct IPFIX_TEMPLATE_SET_HEADER h;
  140. + struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS];
  141. +} __packed;
  142. +
  143. +#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS 1
  144. +#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS 4
  145. +struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE {
  146. + struct IPFIX_OPTION_TEMPLATE_SET_HEADER h;
  147. + struct IPFIX_FIELD_SPECIFIER s[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS];
  148. + struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS];
  149. +} __packed;
  150. +
  151. +/* softflowd data set */
  152. +struct IPFIX_SOFTFLOWD_DATA_COMMON {
  153. + u_int32_t flowEndSysUpTime, flowStartSysUpTime;
  154. + u_int32_t octetDeltaCount, packetDeltaCount;
  155. + u_int32_t ingressInterface, egressInterface;
  156. + u_int16_t sourceTransportPort, destinationTransportPort;
  157. + u_int8_t protocolIdentifier, tcpControlBits, ipVersion;
  158. +} __packed;
  159. +
  160. +struct IPFIX_SOFTFLOWD_DATA_V4 {
  161. + u_int32_t sourceIPv4Address, destinationIPv4Address;
  162. + struct IPFIX_SOFTFLOWD_DATA_COMMON c;
  163. +} __packed;
  164. +
  165. +struct IPFIX_SOFTFLOWD_DATA_V6 {
  166. + //u_int8_t src_addr[16], dst_addr[16];
  167. + struct in6_addr sourceIPv6Address, destinationIPv6Address;
  168. + struct IPFIX_SOFTFLOWD_DATA_COMMON c;
  169. +} __packed;
  170. +
  171. +struct IPFIX_SOFTFLOWD_OPTION_DATA {
  172. + struct IPFIX_SET_HEADER c;
  173. + u_int32_t scope_pid;
  174. + u_int64_t systemInitTimeMilliseconds;
  175. + u_int16_t samplingAlgorithm;
  176. + u_int16_t samplingInterval;
  177. + u_int32_t samplingSpace;
  178. +} __packed;
  179. +
  180. +/* Local data: templates and counters */
  181. +#define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE 512
  182. +#define IPFIX_SOFTFLOWD_V4_TEMPLATE_ID 1024
  183. +#define IPFIX_SOFTFLOWD_V6_TEMPLATE_ID 2048
  184. +#define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID 256
  185. +
  186. +#define IPFIX_DEFAULT_TEMPLATE_INTERVAL 16
  187. +
  188. +/* ... */
  189. +#define IPFIX_OPTION_SCOPE_SYSTEM 1
  190. +#define IPFIX_OPTION_SCOPE_INTERFACE 2
  191. +#define IPFIX_OPTION_SCOPE_LINECARD 3
  192. +#define IPFIX_OPTION_SCOPE_CACHE 4
  193. +#define IPFIX_OPTION_SCOPE_TEMPLATE 5
  194. +/* ... */
  195. +#define IPFIX_SAMPLING_ALGORITHM_DETERMINISTIC 1
  196. +#define IPFIX_SAMPLING_ALGORITHM_RANDOM 2
  197. +/* ... */
  198. +
  199. +static struct IPFIX_SOFTFLOWD_TEMPLATE v4_template;
  200. +static struct IPFIX_SOFTFLOWD_TEMPLATE v6_template;
  201. +static struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE option_template;
  202. +static struct IPFIX_SOFTFLOWD_OPTION_DATA option_data;
  203. +static int ipfix_pkts_until_template = -1;
  204. +
  205. +static void
  206. +ipfix_init_template(void)
  207. +{
  208. + bzero(&v4_template, sizeof(v4_template));
  209. + v4_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID);
  210. + v4_template.h.c.length = htons(sizeof(v4_template));
  211. + v4_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V4_TEMPLATE_ID);
  212. + v4_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS);
  213. + v4_template.r[0].ie = htons(IPFIX_sourceIPv4Address);
  214. + v4_template.r[0].length = htons(4);
  215. + v4_template.r[1].ie = htons(IPFIX_destinationIPv4Address);
  216. + v4_template.r[1].length = htons(4);
  217. + v4_template.r[2].ie = htons(IPFIX_flowEndSysUpTime);
  218. + v4_template.r[2].length = htons(4);
  219. + v4_template.r[3].ie = htons(IPFIX_flowStartSysUpTime);
  220. + v4_template.r[3].length = htons(4);
  221. + v4_template.r[4].ie = htons(IPFIX_octetDeltaCount);
  222. + v4_template.r[4].length = htons(4);
  223. + v4_template.r[5].ie = htons(IPFIX_packetDeltaCount);
  224. + v4_template.r[5].length = htons(4);
  225. + v4_template.r[6].ie = htons(IPFIX_ingressInterface);
  226. + v4_template.r[6].length = htons(4);
  227. + v4_template.r[7].ie = htons(IPFIX_egressInterface);
  228. + v4_template.r[7].length = htons(4);
  229. + v4_template.r[8].ie = htons(IPFIX_sourceTransportPort);
  230. + v4_template.r[8].length = htons(2);
  231. + v4_template.r[9].ie = htons(IPFIX_destinationTransportPort);
  232. + v4_template.r[9].length = htons(2);
  233. + v4_template.r[10].ie = htons(IPFIX_protocolIdentifier);
  234. + v4_template.r[10].length = htons(1);
  235. + v4_template.r[11].ie = htons(IPFIX_tcpControlBits);
  236. + v4_template.r[11].length = htons(1);
  237. + v4_template.r[12].ie = htons(IPFIX_ipVersion);
  238. + v4_template.r[12].length = htons(1);
  239. +
  240. + bzero(&v6_template, sizeof(v6_template));
  241. + v6_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID);
  242. + v6_template.h.c.length = htons(sizeof(v6_template));
  243. + v6_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V6_TEMPLATE_ID);
  244. + v6_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS);
  245. + v6_template.r[0].ie = htons(IPFIX_sourceIPv6Address);
  246. + v6_template.r[0].length = htons(16);
  247. + v6_template.r[1].ie = htons(IPFIX_destinationIPv6Address);
  248. + v6_template.r[1].length = htons(16);
  249. + v6_template.r[2].ie = htons(IPFIX_flowEndSysUpTime);
  250. + v6_template.r[2].length = htons(4);
  251. + v6_template.r[3].ie = htons(IPFIX_flowStartSysUpTime);
  252. + v6_template.r[3].length = htons(4);
  253. + v6_template.r[4].ie = htons(IPFIX_octetDeltaCount);
  254. + v6_template.r[4].length = htons(4);
  255. + v6_template.r[5].ie = htons(IPFIX_packetDeltaCount);
  256. + v6_template.r[5].length = htons(4);
  257. + v6_template.r[6].ie = htons(IPFIX_ingressInterface);
  258. + v6_template.r[6].length = htons(4);
  259. + v6_template.r[7].ie = htons(IPFIX_egressInterface);
  260. + v6_template.r[7].length = htons(4);
  261. + v6_template.r[8].ie = htons(IPFIX_sourceTransportPort);
  262. + v6_template.r[8].length = htons(2);
  263. + v6_template.r[9].ie = htons(IPFIX_destinationTransportPort);
  264. + v6_template.r[9].length = htons(2);
  265. + v6_template.r[10].ie = htons(IPFIX_protocolIdentifier);
  266. + v6_template.r[10].length = htons(1);
  267. + v6_template.r[11].ie = htons(IPFIX_tcpControlBits);
  268. + v6_template.r[11].length = htons(1);
  269. + v6_template.r[12].ie = htons(IPFIX_ipVersion);
  270. + v6_template.r[12].length = htons(1);
  271. +}
  272. +
  273. +static void
  274. +ipfix_init_option(struct timeval *system_boot_time, struct OPTION *option) {
  275. + bzero(&option_template, sizeof(option_template));
  276. + option_template.h.c.set_id = htons(IPFIX_OPTION_TEMPLATE_SET_ID);
  277. + option_template.h.c.length = htons(sizeof(option_template));
  278. + option_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
  279. + option_template.h.r.count = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS + IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
  280. + option_template.h.scope_count = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS);
  281. + option_template.s[0].ie = htons(IPFIX_meteringProcessId);
  282. + option_template.s[0].length = htons(sizeof(option_data.scope_pid));
  283. + option_template.r[0].ie = htons(IPFIX_systemInitTimeMilliseconds);
  284. + option_template.r[0].length = htons(sizeof(option_data.systemInitTimeMilliseconds));
  285. + option_template.r[1].ie = htons(PSAMP_selectorAlgorithm);
  286. + option_template.r[1].length = htons(sizeof(option_data.samplingAlgorithm));
  287. + option_template.r[2].ie = htons(PSAMP_samplingPacketInterval);
  288. + option_template.r[2].length = htons(sizeof(option_data.samplingInterval));
  289. + option_template.r[3].ie = htons(PSAMP_samplingPacketSpace);
  290. + option_template.r[3].length = htons(sizeof(option_data.samplingSpace));
  291. +
  292. + bzero(&option_data, sizeof(option_data));
  293. + option_data.c.set_id = htons(IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
  294. + option_data.c.length = htons(sizeof(option_data));
  295. + option_data.scope_pid = htonl((u_int32_t)option->meteringProcessId);
  296. +#if defined HAVE_HTOBE64
  297. + option_data.systemInitTimeMilliseconds = htobe64((u_int64_t)system_boot_time->tv_sec * 1000 + (u_int64_t)system_boot_time->tv_usec / 1000);
  298. +#elif defined HAVE_HTONLL
  299. + option_data.systemInitTimeMilliseconds = htonll((u_int64_t)system_boot_time->tv_sec * 1000 + (u_int64_t)system_boot_time->tv_usec / 1000);
  300. +#endif
  301. + option_data.samplingAlgorithm = htons(PSAMP_selectorAlgorithm_count);
  302. + option_data.samplingInterval = htons(1);
  303. + option_data.samplingSpace = htonl(option->sample > 0 ? option->sample - 1 : 0);
  304. +}
  305. +static int
  306. +ipfix_flow_to_flowset(const struct FLOW *flow, u_char *packet, u_int len,
  307. + u_int16_t ifidx, const struct timeval *system_boot_time, u_int *len_used)
  308. +{
  309. + union {
  310. + struct IPFIX_SOFTFLOWD_DATA_V4 d4;
  311. + struct IPFIX_SOFTFLOWD_DATA_V6 d6;
  312. + } d[2];
  313. + struct IPFIX_SOFTFLOWD_DATA_COMMON *dc[2];
  314. + u_int freclen, ret_len, nflows;
  315. +
  316. + bzero(d, sizeof(d));
  317. + *len_used = nflows = ret_len = 0;
  318. + switch (flow->af) {
  319. + case AF_INET:
  320. + freclen = sizeof(struct IPFIX_SOFTFLOWD_DATA_V4);
  321. + memcpy(&d[0].d4.sourceIPv4Address, &flow->addr[0].v4, 4);
  322. + memcpy(&d[0].d4.destinationIPv4Address, &flow->addr[1].v4, 4);
  323. + memcpy(&d[1].d4.sourceIPv4Address, &flow->addr[1].v4, 4);
  324. + memcpy(&d[1].d4.destinationIPv4Address, &flow->addr[0].v4, 4);
  325. + dc[0] = &d[0].d4.c;
  326. + dc[1] = &d[1].d4.c;
  327. + dc[0]->ipVersion = dc[1]->ipVersion = 4;
  328. + break;
  329. + case AF_INET6:
  330. + freclen = sizeof(struct IPFIX_SOFTFLOWD_DATA_V6);
  331. + memcpy(&d[0].d6.sourceIPv6Address, &flow->addr[0].v6, 16);
  332. + memcpy(&d[0].d6.destinationIPv6Address, &flow->addr[1].v6, 16);
  333. + memcpy(&d[1].d6.sourceIPv6Address, &flow->addr[1].v6, 16);
  334. + memcpy(&d[1].d6.destinationIPv6Address, &flow->addr[0].v6, 16);
  335. + dc[0] = &d[0].d6.c;
  336. + dc[1] = &d[1].d6.c;
  337. + dc[0]->ipVersion = dc[1]->ipVersion = 6;
  338. + break;
  339. + default:
  340. + return (-1);
  341. + }
  342. +
  343. + dc[0]->flowStartSysUpTime = dc[1]->flowStartSysUpTime =
  344. + htonl(timeval_sub_ms(&flow->flow_start, system_boot_time));
  345. + dc[0]->flowEndSysUpTime = dc[1]->flowEndSysUpTime =
  346. + htonl(timeval_sub_ms(&flow->flow_last, system_boot_time));
  347. + dc[0]->octetDeltaCount = htonl(flow->octets[0]);
  348. + dc[1]->octetDeltaCount = htonl(flow->octets[1]);
  349. + dc[0]->packetDeltaCount = htonl(flow->packets[0]);
  350. + dc[1]->packetDeltaCount = htonl(flow->packets[1]);
  351. + dc[0]->ingressInterface = dc[0]->egressInterface = htonl(ifidx);
  352. + dc[1]->ingressInterface = dc[1]->egressInterface = htonl(ifidx);
  353. + dc[0]->sourceTransportPort = dc[1]->destinationTransportPort = flow->port[0];
  354. + dc[1]->sourceTransportPort = dc[0]->destinationTransportPort = flow->port[1];
  355. + dc[0]->protocolIdentifier = dc[1]->protocolIdentifier = flow->protocol;
  356. + dc[0]->tcpControlBits = flow->tcp_flags[0];
  357. + dc[1]->tcpControlBits = flow->tcp_flags[1];
  358. +
  359. + if (flow->octets[0] > 0) {
  360. + if (ret_len + freclen > len)
  361. + return (-1);
  362. + memcpy(packet + ret_len, &d[0], freclen);
  363. + ret_len += freclen;
  364. + nflows++;
  365. + }
  366. + if (flow->octets[1] > 0) {
  367. + if (ret_len + freclen > len)
  368. + return (-1);
  369. + memcpy(packet + ret_len, &d[1], freclen);
  370. + ret_len += freclen;
  371. + nflows++;
  372. + }
  373. +
  374. + *len_used = ret_len;
  375. + return (nflows);
  376. +}
  377. +
  378. +/*
  379. + * Given an array of expired flows, send netflow v9 report packets
  380. + * Returns number of packets sent or -1 on error
  381. + */
  382. +int
  383. +send_ipfix(struct FLOW **flows, int num_flows, int nfsock,
  384. + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
  385. + int verbose_flag)
  386. +{
  387. + struct IPFIX_HEADER *ipfix;
  388. + struct IPFIX_SET_HEADER *dh;
  389. + struct timeval now;
  390. + u_int offset, last_af, i, j, num_packets, inc, last_valid;
  391. + socklen_t errsz;
  392. + int err, r;
  393. + u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
  394. + struct timeval *system_boot_time = &param->system_boot_time;
  395. + u_int64_t *flows_exported = &param->flows_exported;
  396. + u_int64_t *packets_sent = &param->packets_sent;
  397. + struct OPTION *option = &param->option;
  398. +
  399. + gettimeofday(&now, NULL);
  400. +
  401. + if (ipfix_pkts_until_template == -1) {
  402. + ipfix_init_template();
  403. + ipfix_pkts_until_template = 0;
  404. + if (option != NULL){
  405. + ipfix_init_option(system_boot_time, option);
  406. + }
  407. + }
  408. +
  409. + last_valid = num_packets = 0;
  410. + for (j = 0; j < num_flows;) {
  411. + bzero(packet, sizeof(packet));
  412. + ipfix = (struct IPFIX_HEADER *)packet;
  413. +
  414. + ipfix->version = htons(10);
  415. + ipfix->length = 0; /* Filled as we go, htons at end */
  416. + ipfix->export_time = htonl(time(NULL));
  417. + ipfix->od_id = 0;
  418. + offset = sizeof(*ipfix);
  419. +
  420. + /* Refresh template headers if we need to */
  421. + if (ipfix_pkts_until_template <= 0) {
  422. + memcpy(packet + offset, &v4_template,
  423. + sizeof(v4_template));
  424. + offset += sizeof(v4_template);
  425. + memcpy(packet + offset, &v6_template,
  426. + sizeof(v6_template));
  427. + offset += sizeof(v6_template);
  428. + if (option != NULL){
  429. + memcpy(packet + offset, &option_template,
  430. + sizeof(option_template));
  431. + offset += sizeof(option_template);
  432. + memcpy(packet + offset, &option_data,
  433. + sizeof(option_data));
  434. + offset += sizeof(option_data);
  435. + }
  436. +
  437. + ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL;
  438. + }
  439. +
  440. + dh = NULL;
  441. + last_af = 0;
  442. + for (i = 0; i + j < num_flows; i++) {
  443. + if (dh == NULL || flows[i + j]->af != last_af) {
  444. + if (dh != NULL) {
  445. + if (offset % 4 != 0) {
  446. + /* Pad to multiple of 4 */
  447. + dh->length += 4 - (offset % 4);
  448. + offset += 4 - (offset % 4);
  449. + }
  450. + /* Finalise last header */
  451. + dh->length = htons(dh->length);
  452. + }
  453. + if (offset + sizeof(*dh) > sizeof(packet)) {
  454. + /* Mark header is finished */
  455. + dh = NULL;
  456. + break;
  457. + }
  458. + dh = (struct IPFIX_SET_HEADER *)
  459. + (packet + offset);
  460. + dh->set_id =
  461. + (flows[i + j]->af == AF_INET) ?
  462. + v4_template.h.r.template_id :
  463. + v6_template.h.r.template_id;
  464. + last_af = flows[i + j]->af;
  465. + last_valid = offset;
  466. + dh->length = sizeof(*dh); /* Filled as we go */
  467. + offset += sizeof(*dh);
  468. + }
  469. +
  470. + r = ipfix_flow_to_flowset(flows[i + j], packet + offset,
  471. + sizeof(packet) - offset, ifidx, system_boot_time, &inc);
  472. + if (r <= 0) {
  473. + /* yank off data header, if we had to go back */
  474. + if (last_valid)
  475. + offset = last_valid;
  476. + break;
  477. + }
  478. + offset += inc;
  479. + dh->length += inc;
  480. + last_valid = 0; /* Don't clobber this header now */
  481. + if (verbose_flag) {
  482. + logit(LOG_DEBUG, "Flow %d/%d: "
  483. + "r %d offset %d ie %04x len %d(0x%04x)",
  484. + r, i, j, offset,
  485. + dh->set_id, dh->length,
  486. + dh->length);
  487. + }
  488. + }
  489. + /* Don't finish header if it has already been done */
  490. + if (dh != NULL) {
  491. + if (offset % 4 != 0) {
  492. + /* Pad to multiple of 4 */
  493. + dh->length += 4 - (offset % 4);
  494. + offset += 4 - (offset % 4);
  495. + }
  496. + /* Finalise last header */
  497. + dh->length = htons(dh->length);
  498. + }
  499. + ipfix->length = htons(offset);
  500. + ipfix->sequence = htonl(*packets_sent + num_packets + 1);
  501. +
  502. + if (verbose_flag)
  503. + logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
  504. + errsz = sizeof(err);
  505. + /* Clear ICMP errors */
  506. + getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz);
  507. + if (send(nfsock, packet, (size_t)offset, 0) == -1)
  508. + return (-1);
  509. + num_packets++;
  510. + ipfix_pkts_until_template--;
  511. +
  512. + j += i;
  513. + }
  514. +
  515. + *flows_exported += j;
  516. + return (num_packets);
  517. +}
  518. +
  519. +void
  520. +ipfix_resend_template(void)
  521. +{
  522. + if (ipfix_pkts_until_template > 0)
  523. + ipfix_pkts_until_template = 0;
  524. +}
  525. --- a/softflowd.c
  526. +++ b/softflowd.c
  527. @@ -107,6 +107,7 @@
  528. { 5, send_netflow_v5, 0 },
  529. { 1, send_netflow_v1, 0 },
  530. { 9, send_netflow_v9, 1 },
  531. + { 10, send_ipfix, 1 },
  532. { -1, NULL, 0 },
  533. };
  534. @@ -1494,7 +1495,7 @@
  535. " (default: %s)\n"
  536. " -c pidfile Location of control socket\n"
  537. " (default: %s)\n"
  538. -" -v 1|5|9 NetFlow export packet version\n"
  539. +" -v 1|5|9|10 NetFlow export packet version\n"
  540. " -L hoplimit Set TTL/hoplimit for export datagrams\n"
  541. " -T full|proto|ip Set flow tracking level (default: full)\n"
  542. " -6 Track IPv6 flows, regardless of whether selected \n"
  543. @@ -1888,6 +1889,7 @@
  544. logit(LOG_NOTICE, "Exporting flows to [%s]:%s",
  545. dest_addr, dest_serv);
  546. }
  547. + flowtrack.param.option.meteringProcessId = getpid();
  548. /* Main processing loop */
  549. gettimeofday(&flowtrack.param.system_boot_time, NULL);
  550. --- a/softflowd.h
  551. +++ b/softflowd.h
  552. @@ -79,6 +79,7 @@
  553. */
  554. struct OPTION {
  555. uint32_t sample;
  556. + pid_t meteringProcessId;
  557. };
  558. struct FLOWTRACKPARAMETERS {
  559. @@ -224,6 +225,9 @@
  560. int send_netflow_v9(struct FLOW **flows, int num_flows, int nfsock,
  561. u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
  562. int verbose_flag);
  563. +int send_ipfix(struct FLOW **flows, int num_flows, int nfsock,
  564. + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
  565. + int verbose_flag);
  566. /* Force a resend of the flow template */
  567. void netflow9_resend_template(void);