cherry-pick.softflowd-0.9.9-8-gd53e821.add-bidirectional-flow-rfc5103-support-in-ipfix.patch 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. Subject: Add bidirectional flow (RFC5103) support in IPFIX. Fix the compile warnings
  2. Origin: softflowd-0.9.9-8-gd53e821 <https://github.com/irino/softflowd/commit/softflowd-0.9.9-8-gd53e821>
  3. Upstream-Author: Hitoshi Irino <hitoshi.irino@gmail.com>
  4. Date: Sun Oct 5 15:24:17 2014 +0900
  5. --- a/freelist.c
  6. +++ b/freelist.c
  7. @@ -44,8 +44,9 @@
  8. void
  9. freelist_init(struct freelist *fl, size_t allocsz)
  10. {
  11. + size_t sizeof_fl = sizeof(fl);
  12. FLOGIT((LOG_DEBUG, "%s: %s(%p, %zu)", __func__, __func__, fl, allocsz));
  13. - bzero(fl, sizeof(fl));
  14. + bzero(fl, sizeof_fl);
  15. fl->allocsz = roundup(allocsz, FREELIST_ALLOC_ALIGN);
  16. fl->free_entries = NULL;
  17. }
  18. --- a/ipfix.c
  19. +++ b/ipfix.c
  20. @@ -57,6 +57,11 @@
  21. struct IPFIX_FIELD_SPECIFIER {
  22. u_int16_t ie, length;
  23. } __packed;
  24. +struct IPFIX_VENDOR_FIELD_SPECIFIER {
  25. + u_int16_t ie, length;
  26. + u_int32_t pen;
  27. +} __packed;
  28. +#define REVERSE_PEN 29305
  29. #define IPFIX_TEMPLATE_SET_ID 2
  30. #define IPFIX_OPTION_TEMPLATE_SET_ID 3
  31. @@ -114,12 +119,31 @@
  32. #define PSAMP_selectorAlgorithm_count 1
  33. /* Stuff pertaining to the templates that softflowd uses */
  34. -#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS 16
  35. +#define IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS 14
  36. +#define IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS 2
  37. +#define IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS 5
  38. +
  39. +#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS \
  40. + IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \
  41. + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS
  42. +
  43. +#define IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS \
  44. + IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \
  45. + IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS + \
  46. + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS
  47. +
  48. struct IPFIX_SOFTFLOWD_TEMPLATE {
  49. struct IPFIX_TEMPLATE_SET_HEADER h;
  50. struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS];
  51. } __packed;
  52. +struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE {
  53. + struct IPFIX_TEMPLATE_SET_HEADER h;
  54. + struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS];
  55. + struct IPFIX_VENDOR_FIELD_SPECIFIER v[IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS];
  56. + struct IPFIX_FIELD_SPECIFIER t[IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS];
  57. +} __packed;
  58. +
  59. #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS 1
  60. #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS 4
  61. struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE {
  62. @@ -135,7 +159,12 @@
  63. u_int16_t sourceTransportPort, destinationTransportPort;
  64. u_int8_t protocolIdentifier, tcpControlBits, ipVersion, ipClassOfService;
  65. u_int16_t icmpTypeCode, vlanId;
  66. - //u_int32_t flowEndSysUpTime, flowStartSysUpTime;
  67. +} __packed;
  68. +
  69. +struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION {
  70. + u_int32_t octetDeltaCount, packetDeltaCount;
  71. + u_int8_t tcpControlBits, ipClassOfService;
  72. + u_int16_t icmpTypeCode;
  73. } __packed;
  74. union IPFIX_SOFTFLOWD_DATA_TIME {
  75. @@ -155,13 +184,26 @@
  76. union IPFIX_SOFTFLOWD_DATA_TIME t;
  77. } __packed;
  78. +struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4 {
  79. + u_int32_t sourceIPv4Address, destinationIPv4Address;
  80. + struct IPFIX_SOFTFLOWD_DATA_COMMON c;
  81. + struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION b;
  82. + union IPFIX_SOFTFLOWD_DATA_TIME t;
  83. +} __packed;
  84. +
  85. struct IPFIX_SOFTFLOWD_DATA_V6 {
  86. - //u_int8_t src_addr[16], dst_addr[16];
  87. struct in6_addr sourceIPv6Address, destinationIPv6Address;
  88. struct IPFIX_SOFTFLOWD_DATA_COMMON c;
  89. union IPFIX_SOFTFLOWD_DATA_TIME t;
  90. } __packed;
  91. +struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6 {
  92. + struct in6_addr sourceIPv6Address, destinationIPv6Address;
  93. + struct IPFIX_SOFTFLOWD_DATA_COMMON c;
  94. + struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION b;
  95. + union IPFIX_SOFTFLOWD_DATA_TIME t;
  96. +} __packed;
  97. +
  98. struct IPFIX_SOFTFLOWD_OPTION_DATA {
  99. struct IPFIX_SET_HEADER c;
  100. u_int32_t scope_pid;
  101. @@ -192,6 +234,8 @@
  102. static struct IPFIX_SOFTFLOWD_TEMPLATE v4_template;
  103. static struct IPFIX_SOFTFLOWD_TEMPLATE v6_template;
  104. +static struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE v4_bidirection_template;
  105. +static struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE v6_bidirection_template;
  106. static struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE option_template;
  107. static struct IPFIX_SOFTFLOWD_OPTION_DATA option_data;
  108. static int ipfix_pkts_until_template = -1;
  109. @@ -321,6 +365,161 @@
  110. }
  111. static void
  112. +ipfix_init_template_bidirection(struct FLOWTRACKPARAMETERS *param)
  113. +{
  114. + bzero(&v4_bidirection_template, sizeof(v4_bidirection_template));
  115. + v4_bidirection_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID);
  116. + v4_bidirection_template.h.c.length = htons(sizeof(v4_bidirection_template));
  117. + v4_bidirection_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V4_TEMPLATE_ID);
  118. + v4_bidirection_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS);
  119. + v4_bidirection_template.r[0].ie = htons(IPFIX_sourceIPv4Address);
  120. + v4_bidirection_template.r[0].length = htons(4);
  121. + v4_bidirection_template.r[1].ie = htons(IPFIX_destinationIPv4Address);
  122. + v4_bidirection_template.r[1].length = htons(4);
  123. + v4_bidirection_template.r[2].ie = htons(IPFIX_octetDeltaCount);
  124. + v4_bidirection_template.r[2].length = htons(4);
  125. + v4_bidirection_template.r[3].ie = htons(IPFIX_packetDeltaCount);
  126. + v4_bidirection_template.r[3].length = htons(4);
  127. + v4_bidirection_template.r[4].ie = htons(IPFIX_ingressInterface);
  128. + v4_bidirection_template.r[4].length = htons(4);
  129. + v4_bidirection_template.r[5].ie = htons(IPFIX_egressInterface);
  130. + v4_bidirection_template.r[5].length = htons(4);
  131. + v4_bidirection_template.r[6].ie = htons(IPFIX_sourceTransportPort);
  132. + v4_bidirection_template.r[6].length = htons(2);
  133. + v4_bidirection_template.r[7].ie = htons(IPFIX_destinationTransportPort);
  134. + v4_bidirection_template.r[7].length = htons(2);
  135. + v4_bidirection_template.r[8].ie = htons(IPFIX_protocolIdentifier);
  136. + v4_bidirection_template.r[8].length = htons(1);
  137. + v4_bidirection_template.r[9].ie = htons(IPFIX_tcpControlBits);
  138. + v4_bidirection_template.r[9].length = htons(1);
  139. + v4_bidirection_template.r[10].ie = htons(IPFIX_ipVersion);
  140. + v4_bidirection_template.r[10].length = htons(1);
  141. + v4_bidirection_template.r[11].ie = htons(IPFIX_ipClassOfService);
  142. + v4_bidirection_template.r[11].length = htons(1);
  143. + v4_bidirection_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv4);
  144. + v4_bidirection_template.r[12].length = htons(2);
  145. + v4_bidirection_template.r[13].ie = htons(IPFIX_vlanId);
  146. + v4_bidirection_template.r[13].length = htons(2);
  147. + v4_bidirection_template.v[0].ie = htons(IPFIX_octetDeltaCount | 0x8000);
  148. + v4_bidirection_template.v[0].length = htons(4);
  149. + v4_bidirection_template.v[0].pen = htonl(REVERSE_PEN);
  150. + v4_bidirection_template.v[1].ie = htons(IPFIX_packetDeltaCount | 0x8000);
  151. + v4_bidirection_template.v[1].length = htons(4);
  152. + v4_bidirection_template.v[1].pen = htonl(REVERSE_PEN);
  153. + v4_bidirection_template.v[2].ie = htons(IPFIX_tcpControlBits | 0x8000);
  154. + v4_bidirection_template.v[2].length = htons(1);
  155. + v4_bidirection_template.v[2].pen = htonl(REVERSE_PEN);
  156. + v4_bidirection_template.v[3].ie = htons(IPFIX_ipClassOfService | 0x8000);
  157. + v4_bidirection_template.v[3].length = htons(1);
  158. + v4_bidirection_template.v[3].pen = htonl(REVERSE_PEN);
  159. + v4_bidirection_template.v[4].ie = htons(IPFIX_icmpTypeCodeIPv4 | 0x8000);
  160. + v4_bidirection_template.v[4].length = htons(2);
  161. + v4_bidirection_template.v[4].pen = htonl(REVERSE_PEN);
  162. + if (param->time_format == 's') {
  163. + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartSeconds);
  164. + v4_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
  165. + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndSeconds);
  166. + v4_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
  167. + } else if (param->time_format == 'm') {
  168. + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartMilliSeconds);
  169. + v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
  170. + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndMilliSeconds);
  171. + v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
  172. + } else if (param->time_format == 'M') {
  173. + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartMicroSeconds);
  174. + v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
  175. + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndMicroSeconds);
  176. + v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
  177. + } else if (param->time_format == 'n') {
  178. + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartNanoSeconds);
  179. + v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
  180. + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndNanoSeconds);
  181. + v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
  182. + } else {
  183. + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartSysUpTime);
  184. + v4_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
  185. + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndSysUpTime);
  186. + v4_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
  187. + }
  188. +
  189. + bzero(&v6_bidirection_template, sizeof(v6_bidirection_template));
  190. + v6_bidirection_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID);
  191. + v6_bidirection_template.h.c.length = htons(sizeof(v6_bidirection_template));
  192. + v6_bidirection_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V6_TEMPLATE_ID);
  193. + v6_bidirection_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS);
  194. + v6_bidirection_template.r[0].ie = htons(IPFIX_sourceIPv6Address);
  195. + v6_bidirection_template.r[0].length = htons(16);
  196. + v6_bidirection_template.r[1].ie = htons(IPFIX_destinationIPv6Address);
  197. + v6_bidirection_template.r[1].length = htons(16);
  198. + v6_bidirection_template.r[2].ie = htons(IPFIX_octetDeltaCount);
  199. + v6_bidirection_template.r[2].length = htons(4);
  200. + v6_bidirection_template.r[3].ie = htons(IPFIX_packetDeltaCount);
  201. + v6_bidirection_template.r[3].length = htons(4);
  202. + v6_bidirection_template.r[4].ie = htons(IPFIX_ingressInterface);
  203. + v6_bidirection_template.r[4].length = htons(4);
  204. + v6_bidirection_template.r[5].ie = htons(IPFIX_egressInterface);
  205. + v6_bidirection_template.r[5].length = htons(4);
  206. + v6_bidirection_template.r[6].ie = htons(IPFIX_sourceTransportPort);
  207. + v6_bidirection_template.r[6].length = htons(2);
  208. + v6_bidirection_template.r[7].ie = htons(IPFIX_destinationTransportPort);
  209. + v6_bidirection_template.r[7].length = htons(2);
  210. + v6_bidirection_template.r[8].ie = htons(IPFIX_protocolIdentifier);
  211. + v6_bidirection_template.r[8].length = htons(1);
  212. + v6_bidirection_template.r[9].ie = htons(IPFIX_tcpControlBits);
  213. + v6_bidirection_template.r[9].length = htons(1);
  214. + v6_bidirection_template.r[10].ie = htons(IPFIX_ipVersion);
  215. + v6_bidirection_template.r[10].length = htons(1);
  216. + v6_bidirection_template.r[11].ie = htons(IPFIX_ipClassOfService);
  217. + v6_bidirection_template.r[11].length = htons(1);
  218. + v6_bidirection_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv6);
  219. + v6_bidirection_template.r[12].length = htons(2);
  220. + v6_bidirection_template.r[13].ie = htons(IPFIX_vlanId);
  221. + v6_bidirection_template.r[13].length = htons(2);
  222. + v6_bidirection_template.v[0].ie = htons(IPFIX_octetDeltaCount | 0x8000);
  223. + v6_bidirection_template.v[0].length = htons(4);
  224. + v6_bidirection_template.v[0].pen = htonl(REVERSE_PEN);
  225. + v6_bidirection_template.v[1].ie = htons(IPFIX_packetDeltaCount | 0x8000);
  226. + v6_bidirection_template.v[1].length = htons(4);
  227. + v6_bidirection_template.v[1].pen = htonl(REVERSE_PEN);
  228. + v6_bidirection_template.v[2].ie = htons(IPFIX_tcpControlBits | 0x8000);
  229. + v6_bidirection_template.v[2].length = htons(1);
  230. + v6_bidirection_template.v[2].pen = htonl(REVERSE_PEN);
  231. + v6_bidirection_template.v[3].ie = htons(IPFIX_ipClassOfService | 0x8000);
  232. + v6_bidirection_template.v[3].length = htons(1);
  233. + v6_bidirection_template.v[3].pen = htonl(REVERSE_PEN);
  234. + v6_bidirection_template.v[4].ie = htons(IPFIX_icmpTypeCodeIPv6 | 0x8000);
  235. + v6_bidirection_template.v[4].length = htons(2);
  236. + v6_bidirection_template.v[4].pen = htonl(REVERSE_PEN);
  237. + if (param->time_format == 's') {
  238. + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartSeconds);
  239. + v6_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
  240. + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndSeconds);
  241. + v6_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
  242. + } else if (param->time_format == 'm') {
  243. + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartMilliSeconds);
  244. + v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
  245. + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndMilliSeconds);
  246. + v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
  247. + } else if (param->time_format == 'M') {
  248. + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartMicroSeconds);
  249. + v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
  250. + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndMicroSeconds);
  251. + v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
  252. + } else if (param->time_format == 'n') {
  253. + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartNanoSeconds);
  254. + v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
  255. + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndNanoSeconds);
  256. + v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
  257. + } else {
  258. + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartSysUpTime);
  259. + v6_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
  260. + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndSysUpTime);
  261. + v6_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
  262. + }
  263. +}
  264. +
  265. +
  266. +static void
  267. ipfix_init_option(struct timeval *system_boot_time, struct OPTION *option) {
  268. bzero(&option_template, sizeof(option_template));
  269. option_template.h.c.set_id = htons(IPFIX_OPTION_TEMPLATE_SET_ID);
  270. @@ -350,6 +549,7 @@
  271. option_data.samplingInterval = htons(1);
  272. option_data.samplingSpace = htonl(option->sample > 0 ? option->sample - 1 : 0);
  273. }
  274. +
  275. static int
  276. ipfix_flow_to_flowset(const struct FLOW *flow, u_char *packet, u_int len,
  277. u_int16_t ifidx, const struct timeval *system_boot_time, u_int *len_used,
  278. @@ -468,6 +668,112 @@
  279. return (nflows);
  280. }
  281. +static int
  282. +ipfix_flow_to_bidirection_flowset(const struct FLOW *flow, u_char *packet,
  283. + u_int len, u_int16_t ifidx,
  284. + const struct timeval *system_boot_time,
  285. + u_int *len_used,
  286. + struct FLOWTRACKPARAMETERS *param)
  287. +{
  288. + union {
  289. + struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4 d4;
  290. + struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6 d6;
  291. + } d;
  292. + struct IPFIX_SOFTFLOWD_DATA_COMMON *dc;
  293. + struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION *db;
  294. + union IPFIX_SOFTFLOWD_DATA_TIME *dt;
  295. + u_int freclen, ret_len, nflows;
  296. +
  297. + bzero(&d, sizeof(d));
  298. + *len_used = nflows = ret_len = 0;
  299. + switch (flow->af) {
  300. + case AF_INET:
  301. + freclen = sizeof(struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4);
  302. + if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) {
  303. + freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2;
  304. + }
  305. + memcpy(&d.d4.sourceIPv4Address, &flow->addr[0].v4, 4);
  306. + memcpy(&d.d4.destinationIPv4Address, &flow->addr[1].v4, 4);
  307. + dc = &d.d4.c;
  308. + db = &d.d4.b;
  309. + dt = &d.d4.t;
  310. + dc->ipVersion = 4;
  311. + break;
  312. + case AF_INET6:
  313. + freclen = sizeof(struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6);
  314. + if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) {
  315. + freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2;
  316. + }
  317. + memcpy(&d.d6.sourceIPv6Address, &flow->addr[0].v6, 16);
  318. + memcpy(&d.d6.destinationIPv6Address, &flow->addr[1].v6, 16);
  319. + dc = &d.d6.c;
  320. + db = &d.d6.b;
  321. + dt = &d.d6.t;
  322. + dc->ipVersion = 6;
  323. + break;
  324. + default:
  325. + return (-1);
  326. + }
  327. +
  328. + if (param->time_format == 's') {
  329. + dt->u32.start = htonl(flow->flow_start.tv_sec);
  330. + dt->u32.end = htonl(flow->flow_last.tv_sec);
  331. + }
  332. +#if defined(htobe64) || defined(HAVE_DECL_HTOBE64)
  333. + else if (param->time_format == 'm') { /* milliseconds */
  334. + dt->u64.start =
  335. + htobe64((u_int64_t)flow->flow_start.tv_sec * 1000 + (u_int64_t)flow->flow_start.tv_usec / 1000);
  336. + dt->u64.end =
  337. + htobe64((u_int64_t)flow->flow_last.tv_sec * 1000 + (u_int64_t)flow->flow_last.tv_usec / 1000);
  338. + } else if (param->time_format == 'M') { /* microseconds */
  339. + dt->u64.start =
  340. + htobe64(((u_int64_t)flow->flow_start.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_start.tv_usec << 32) / 1e6));
  341. + dt->u64.end =
  342. + htobe64(((u_int64_t)flow->flow_last.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_last.tv_usec << 32) / 1e6));
  343. + } else if (param->time_format == 'n') { /* nanoseconds */
  344. + dt->u64.start =
  345. + htobe64(((u_int64_t)flow->flow_start.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_start.tv_usec << 32) / 1e9));
  346. + dt->u64.end =
  347. + htobe64(((u_int64_t)flow->flow_last.tv_sec + JAN_1970) << 32 | (u_int32_t)(((u_int64_t)flow->flow_last.tv_usec << 32) / 1e9));
  348. + }
  349. +#endif
  350. + else {
  351. + dt->u32.start =
  352. + htonl(timeval_sub_ms(&flow->flow_start, system_boot_time));
  353. + dt->u32.end =
  354. + htonl(timeval_sub_ms(&flow->flow_last, system_boot_time));
  355. + }
  356. + dc->octetDeltaCount = htonl(flow->octets[0]);
  357. + db->octetDeltaCount = htonl(flow->octets[1]);
  358. + dc->packetDeltaCount = htonl(flow->packets[0]);
  359. + db->packetDeltaCount = htonl(flow->packets[1]);
  360. + dc->ingressInterface = dc->egressInterface = htonl(ifidx);
  361. + dc->sourceTransportPort = flow->port[0];
  362. + dc->destinationTransportPort = flow->port[1];
  363. + dc->protocolIdentifier = flow->protocol;
  364. + dc->tcpControlBits = flow->tcp_flags[0];
  365. + db->tcpControlBits = flow->tcp_flags[1];
  366. + dc->ipClassOfService = flow->tos[0];
  367. + db->ipClassOfService = flow->tos[1];
  368. + if (flow->protocol == IPPROTO_ICMP || flow->protocol == IPPROTO_ICMPV6) {
  369. + dc->icmpTypeCode = flow->port[1];
  370. + db->icmpTypeCode = flow->port[0];
  371. + }
  372. + dc->vlanId = htons(flow->vlanid);
  373. +
  374. + if (flow->octets[0] > 0 || flow->octets[1] > 0) {
  375. + if (ret_len + freclen > len)
  376. + return (-1);
  377. + memcpy(packet + ret_len, &d, freclen);
  378. + ret_len += freclen;
  379. + nflows++;
  380. + }
  381. +
  382. + *len_used = ret_len;
  383. + return (nflows);
  384. +}
  385. +
  386. +
  387. /*
  388. * Given an array of expired flows, send netflow v9 report packets
  389. * Returns number of packets sent or -1 on error
  390. @@ -487,7 +793,6 @@
  391. u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
  392. struct timeval *system_boot_time = &param->system_boot_time;
  393. u_int64_t *flows_exported = &param->flows_exported;
  394. - u_int64_t *packets_sent = &param->packets_sent;
  395. u_int64_t *records_sent = &param->records_sent;
  396. struct OPTION *option = &param->option;
  397. @@ -620,3 +925,152 @@
  398. if (ipfix_pkts_until_template > 0)
  399. ipfix_pkts_until_template = 0;
  400. }
  401. +
  402. +/*
  403. + * Given an array of expired flows, send netflow v9 report packets
  404. + * Returns number of packets sent or -1 on error
  405. + */
  406. +int
  407. +send_ipfix_bidirection(struct FLOW **flows, int num_flows, int nfsock,
  408. + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
  409. + int verbose_flag)
  410. +{
  411. + struct IPFIX_HEADER *ipfix;
  412. + struct IPFIX_SET_HEADER *dh;
  413. + struct timeval now;
  414. + u_int offset, last_af, i, j, num_packets, inc, last_valid;
  415. + socklen_t errsz;
  416. + int err, r;
  417. + u_int records;
  418. + u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
  419. + struct timeval *system_boot_time = &param->system_boot_time;
  420. + u_int64_t *flows_exported = &param->flows_exported;
  421. + u_int64_t *records_sent = &param->records_sent;
  422. + struct OPTION *option = &param->option;
  423. +
  424. + gettimeofday(&now, NULL);
  425. +
  426. + if (ipfix_pkts_until_template == -1) {
  427. + ipfix_init_template_bidirection(param);
  428. + ipfix_pkts_until_template = 0;
  429. + if (option != NULL){
  430. + ipfix_init_option(system_boot_time, option);
  431. + }
  432. + }
  433. +
  434. + last_valid = num_packets = 0;
  435. + for (j = 0; j < num_flows;) {
  436. + bzero(packet, sizeof(packet));
  437. + ipfix = (struct IPFIX_HEADER *)packet;
  438. +
  439. + ipfix->version = htons(10);
  440. + ipfix->length = 0; /* Filled as we go, htons at end */
  441. + ipfix->export_time = htonl(time(NULL));
  442. + ipfix->od_id = 0;
  443. + offset = sizeof(*ipfix);
  444. +
  445. + /* Refresh template headers if we need to */
  446. + if (ipfix_pkts_until_template <= 0) {
  447. + memcpy(packet + offset, &v4_bidirection_template,
  448. + sizeof(v4_bidirection_template));
  449. + offset += sizeof(v4_bidirection_template);
  450. + memcpy(packet + offset, &v6_bidirection_template,
  451. + sizeof(v6_bidirection_template));
  452. + offset += sizeof(v6_bidirection_template);
  453. + if (option != NULL){
  454. + memcpy(packet + offset, &option_template,
  455. + sizeof(option_template));
  456. + offset += sizeof(option_template);
  457. + memcpy(packet + offset, &option_data,
  458. + sizeof(option_data));
  459. + offset += sizeof(option_data);
  460. + }
  461. +
  462. + ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL;
  463. + }
  464. +
  465. + dh = NULL;
  466. + last_af = 0;
  467. + records = 0;
  468. + for (i = 0; i + j < num_flows; i++) {
  469. + if (dh == NULL || flows[i + j]->af != last_af) {
  470. + if (dh != NULL) {
  471. + if (offset % 4 != 0) {
  472. + /* Pad to multiple of 4 */
  473. + dh->length += 4 - (offset % 4);
  474. + offset += 4 - (offset % 4);
  475. + }
  476. + /* Finalise last header */
  477. + dh->length = htons(dh->length);
  478. + }
  479. + if (offset + sizeof(*dh) > sizeof(packet)) {
  480. + /* Mark header is finished */
  481. + dh = NULL;
  482. + break;
  483. + }
  484. + dh = (struct IPFIX_SET_HEADER *)
  485. + (packet + offset);
  486. + dh->set_id =
  487. + (flows[i + j]->af == AF_INET) ?
  488. + v4_bidirection_template.h.r.template_id :
  489. + v6_bidirection_template.h.r.template_id;
  490. + last_af = flows[i + j]->af;
  491. + last_valid = offset;
  492. + dh->length = sizeof(*dh); /* Filled as we go */
  493. + offset += sizeof(*dh);
  494. + }
  495. +
  496. + r = ipfix_flow_to_bidirection_flowset(flows[i + j],
  497. + packet + offset,
  498. + sizeof(packet) - offset,
  499. + ifidx,
  500. + system_boot_time,
  501. + &inc, param);
  502. + if (r <= 0) {
  503. + /* yank off data header, if we had to go back */
  504. + if (last_valid)
  505. + offset = last_valid;
  506. + break;
  507. + }
  508. + records += (u_int)r;
  509. + offset += inc;
  510. + dh->length += inc;
  511. + last_valid = 0; /* Don't clobber this header now */
  512. + if (verbose_flag) {
  513. + logit(LOG_DEBUG, "Flow %d/%d: "
  514. + "r %d offset %d ie %04x len %d(0x%04x)",
  515. + r, i, j, offset,
  516. + dh->set_id, dh->length,
  517. + dh->length);
  518. + }
  519. + }
  520. + /* Don't finish header if it has already been done */
  521. + if (dh != NULL) {
  522. + if (offset % 4 != 0) {
  523. + /* Pad to multiple of 4 */
  524. + dh->length += 4 - (offset % 4);
  525. + offset += 4 - (offset % 4);
  526. + }
  527. + /* Finalise last header */
  528. + dh->length = htons(dh->length);
  529. + }
  530. + ipfix->length = htons(offset);
  531. + *records_sent += records;
  532. + ipfix->sequence = htonl((u_int32_t)(*records_sent & 0x00000000ffffffff));
  533. +
  534. + if (verbose_flag)
  535. + logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
  536. + errsz = sizeof(err);
  537. + /* Clear ICMP errors */
  538. + getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz);
  539. + if (send(nfsock, packet, (size_t)offset, 0) == -1)
  540. + return (-1);
  541. + num_packets++;
  542. + ipfix_pkts_until_template--;
  543. +
  544. + j += i;
  545. + }
  546. +
  547. + *flows_exported += j;
  548. + return (num_packets);
  549. +}
  550. --- a/softflowd.c
  551. +++ b/softflowd.c
  552. @@ -99,16 +99,17 @@
  553. struct NETFLOW_SENDER {
  554. int version;
  555. netflow_send_func_t *func;
  556. + netflow_send_func_t *bidir_func;
  557. int v6_capable;
  558. };
  559. /* Array of NetFlow export function that we know of. NB. nf[0] is default */
  560. static const struct NETFLOW_SENDER nf[] = {
  561. - { 5, send_netflow_v5, 0 },
  562. - { 1, send_netflow_v1, 0 },
  563. - { 9, send_netflow_v9, 1 },
  564. - { 10, send_ipfix, 1 },
  565. - { -1, NULL, 0 },
  566. + { 5, send_netflow_v5, NULL, 0 },
  567. + { 1, send_netflow_v1, NULL, 0 },
  568. + { 9, send_netflow_v9, NULL, 1 },
  569. + { 10, send_ipfix, send_ipfix_bidirection, 1 },
  570. + { -1, NULL, NULL, 0 },
  571. };
  572. /* Describes a location where we send NetFlow packets to */
  573. @@ -854,8 +855,15 @@
  574. /* Processing for expired flows */
  575. if (num_expired > 0) {
  576. if (target != NULL && target->fd != -1) {
  577. - r = target->dialect->func(expired_flows, num_expired,
  578. - target->fd, if_index, &ft->param, verbose_flag);
  579. + netflow_send_func_t *func =
  580. + ft->param.bidirection == 1 ?
  581. + target->dialect->bidir_func :
  582. + target->dialect->func;
  583. + if (func == NULL) {
  584. + func = target->dialect->func;
  585. + }
  586. + r = func(expired_flows, num_expired,
  587. + target->fd, if_index, &ft->param, verbose_flag);
  588. if (verbose_flag)
  589. logit(LOG_DEBUG, "sent %d netflow packets", r);
  590. if (r > 0) {
  591. @@ -1085,7 +1093,7 @@
  592. {
  593. int i, j;
  594. u_int32_t frametype;
  595. - int add_offset = 0;
  596. + int vlan_size = 0;
  597. static const struct DATALINK *dl = NULL;
  598. @@ -1104,22 +1112,31 @@
  599. frametype = 0;
  600. /* Processing 802.1Q vlan in ethernet */
  601. - if (linktype == DLT_EN10MB && ntohs(*(u_int16_t *)(pkt + dl->ft_off)) == 0x8100) {
  602. - add_offset = 4;
  603. - if (caplen <= dl->skiplen + add_offset)
  604. - return (-1);
  605. - *vlanid = ntohs(*(u_int16_t *)(pkt + dl->ft_off + 2)) & 0x0fff;
  606. + if (linktype == DLT_EN10MB) {
  607. + for (j = 0; j < dl->ft_len; j++) {
  608. + frametype <<= 8;
  609. + frametype |= pkt[j + dl->ft_off];
  610. + }
  611. + frametype &= dl->ft_mask;
  612. + if (frametype == 0x8100) {
  613. + for (j = 0; j < 2; j++) {
  614. + *vlanid <<= 8;
  615. + *vlanid |= pkt[j + dl->skiplen];
  616. + }
  617. + vlan_size = 4;
  618. + }
  619. }
  620. + frametype = 0;
  621. if (dl->ft_is_be) {
  622. for (j = 0; j < dl->ft_len; j++) {
  623. frametype <<= 8;
  624. - frametype |= pkt[j + dl->ft_off + add_offset];
  625. + frametype |= pkt[j + dl->ft_off + vlan_size];
  626. }
  627. } else {
  628. for (j = dl->ft_len - 1; j >= 0 ; j--) {
  629. frametype <<= 8;
  630. - frametype |= pkt[j + dl->ft_off + add_offset];
  631. + frametype |= pkt[j + dl->ft_off + vlan_size];
  632. }
  633. }
  634. frametype &= dl->ft_mask;
  635. @@ -1131,7 +1148,7 @@
  636. else
  637. return (-1);
  638. - return (dl->skiplen + add_offset);
  639. + return (dl->skiplen + vlan_size);
  640. }
  641. /*
  642. @@ -1739,7 +1756,7 @@
  643. dontfork_flag = 0;
  644. always_v6 = 0;
  645. - while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:")) != -1) {
  646. + while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:b")) != -1) {
  647. switch (ch) {
  648. case '6':
  649. always_v6 = 1;
  650. @@ -1885,6 +1902,9 @@
  651. exit(1);
  652. }
  653. break;
  654. + case 'b':
  655. + flowtrack.param.bidirection = 1;
  656. + break;
  657. default:
  658. fprintf(stderr, "Invalid commandline option.\n");
  659. usage();
  660. --- a/softflowd.h
  661. +++ b/softflowd.h
  662. @@ -140,6 +140,7 @@
  663. /* Optional information */
  664. struct OPTION option;
  665. char time_format;
  666. + u_int8_t bidirection;
  667. };
  668. /*
  669. * This structure is the root of the flow tracking system.
  670. @@ -234,6 +235,10 @@
  671. int send_ipfix(struct FLOW **flows, int num_flows, int nfsock,
  672. u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
  673. int verbose_flag);
  674. +int send_ipfix_bidirection(struct FLOW **flows, int num_flows, int nfsock,
  675. + u_int16_t ifidx,
  676. + struct FLOWTRACKPARAMETERS *param,
  677. + int verbose_flag);
  678. /* Force a resend of the flow template */
  679. void netflow9_resend_template(void);