123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- Subject: Add bidirectional flow (RFC5103) support in IPFIX. Fix the compile warnings
- Origin: softflowd-0.9.9-8-gd53e821 <https://github.com/irino/softflowd/commit/softflowd-0.9.9-8-gd53e821>
- Upstream-Author: Hitoshi Irino <hitoshi.irino@gmail.com>
- Date: Sun Oct 5 15:24:17 2014 +0900
- --- a/freelist.c
- +++ b/freelist.c
- @@ -44,8 +44,9 @@
- void
- freelist_init(struct freelist *fl, size_t allocsz)
- {
- + size_t sizeof_fl = sizeof(fl);
- FLOGIT((LOG_DEBUG, "%s: %s(%p, %zu)", __func__, __func__, fl, allocsz));
- - bzero(fl, sizeof(fl));
- + bzero(fl, sizeof_fl);
- fl->allocsz = roundup(allocsz, FREELIST_ALLOC_ALIGN);
- fl->free_entries = NULL;
- }
- --- a/ipfix.c
- +++ b/ipfix.c
- @@ -57,6 +57,11 @@
- struct IPFIX_FIELD_SPECIFIER {
- u_int16_t ie, length;
- } __packed;
- +struct IPFIX_VENDOR_FIELD_SPECIFIER {
- + u_int16_t ie, length;
- + u_int32_t pen;
- +} __packed;
- +#define REVERSE_PEN 29305
-
- #define IPFIX_TEMPLATE_SET_ID 2
- #define IPFIX_OPTION_TEMPLATE_SET_ID 3
- @@ -114,12 +119,31 @@
- #define PSAMP_selectorAlgorithm_count 1
-
- /* Stuff pertaining to the templates that softflowd uses */
- -#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS 16
- +#define IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS 14
- +#define IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS 2
- +#define IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS 5
- +
- +#define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS \
- + IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \
- + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS
- +
- +#define IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS \
- + IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \
- + IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS + \
- + IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS
- +
- struct IPFIX_SOFTFLOWD_TEMPLATE {
- struct IPFIX_TEMPLATE_SET_HEADER h;
- struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS];
- } __packed;
-
- +struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE {
- + struct IPFIX_TEMPLATE_SET_HEADER h;
- + struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS];
- + struct IPFIX_VENDOR_FIELD_SPECIFIER v[IPFIX_SOFTFLOWD_TEMPLATE_VENDORRECORDS];
- + struct IPFIX_FIELD_SPECIFIER t[IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS];
- +} __packed;
- +
- #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS 1
- #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS 4
- struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE {
- @@ -135,7 +159,12 @@
- u_int16_t sourceTransportPort, destinationTransportPort;
- u_int8_t protocolIdentifier, tcpControlBits, ipVersion, ipClassOfService;
- u_int16_t icmpTypeCode, vlanId;
- - //u_int32_t flowEndSysUpTime, flowStartSysUpTime;
- +} __packed;
- +
- +struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION {
- + u_int32_t octetDeltaCount, packetDeltaCount;
- + u_int8_t tcpControlBits, ipClassOfService;
- + u_int16_t icmpTypeCode;
- } __packed;
-
- union IPFIX_SOFTFLOWD_DATA_TIME {
- @@ -155,13 +184,26 @@
- union IPFIX_SOFTFLOWD_DATA_TIME t;
- } __packed;
-
- +struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4 {
- + u_int32_t sourceIPv4Address, destinationIPv4Address;
- + struct IPFIX_SOFTFLOWD_DATA_COMMON c;
- + struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION b;
- + union IPFIX_SOFTFLOWD_DATA_TIME t;
- +} __packed;
- +
- struct IPFIX_SOFTFLOWD_DATA_V6 {
- - //u_int8_t src_addr[16], dst_addr[16];
- struct in6_addr sourceIPv6Address, destinationIPv6Address;
- struct IPFIX_SOFTFLOWD_DATA_COMMON c;
- union IPFIX_SOFTFLOWD_DATA_TIME t;
- } __packed;
-
- +struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6 {
- + struct in6_addr sourceIPv6Address, destinationIPv6Address;
- + struct IPFIX_SOFTFLOWD_DATA_COMMON c;
- + struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION b;
- + union IPFIX_SOFTFLOWD_DATA_TIME t;
- +} __packed;
- +
- struct IPFIX_SOFTFLOWD_OPTION_DATA {
- struct IPFIX_SET_HEADER c;
- u_int32_t scope_pid;
- @@ -192,6 +234,8 @@
-
- static struct IPFIX_SOFTFLOWD_TEMPLATE v4_template;
- static struct IPFIX_SOFTFLOWD_TEMPLATE v6_template;
- +static struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE v4_bidirection_template;
- +static struct IPFIX_SOFTFLOWD_BIDIRECTION_TEMPLATE v6_bidirection_template;
- static struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE option_template;
- static struct IPFIX_SOFTFLOWD_OPTION_DATA option_data;
- static int ipfix_pkts_until_template = -1;
- @@ -321,6 +365,161 @@
- }
-
- static void
- +ipfix_init_template_bidirection(struct FLOWTRACKPARAMETERS *param)
- +{
- + bzero(&v4_bidirection_template, sizeof(v4_bidirection_template));
- + v4_bidirection_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID);
- + v4_bidirection_template.h.c.length = htons(sizeof(v4_bidirection_template));
- + v4_bidirection_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V4_TEMPLATE_ID);
- + v4_bidirection_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS);
- + v4_bidirection_template.r[0].ie = htons(IPFIX_sourceIPv4Address);
- + v4_bidirection_template.r[0].length = htons(4);
- + v4_bidirection_template.r[1].ie = htons(IPFIX_destinationIPv4Address);
- + v4_bidirection_template.r[1].length = htons(4);
- + v4_bidirection_template.r[2].ie = htons(IPFIX_octetDeltaCount);
- + v4_bidirection_template.r[2].length = htons(4);
- + v4_bidirection_template.r[3].ie = htons(IPFIX_packetDeltaCount);
- + v4_bidirection_template.r[3].length = htons(4);
- + v4_bidirection_template.r[4].ie = htons(IPFIX_ingressInterface);
- + v4_bidirection_template.r[4].length = htons(4);
- + v4_bidirection_template.r[5].ie = htons(IPFIX_egressInterface);
- + v4_bidirection_template.r[5].length = htons(4);
- + v4_bidirection_template.r[6].ie = htons(IPFIX_sourceTransportPort);
- + v4_bidirection_template.r[6].length = htons(2);
- + v4_bidirection_template.r[7].ie = htons(IPFIX_destinationTransportPort);
- + v4_bidirection_template.r[7].length = htons(2);
- + v4_bidirection_template.r[8].ie = htons(IPFIX_protocolIdentifier);
- + v4_bidirection_template.r[8].length = htons(1);
- + v4_bidirection_template.r[9].ie = htons(IPFIX_tcpControlBits);
- + v4_bidirection_template.r[9].length = htons(1);
- + v4_bidirection_template.r[10].ie = htons(IPFIX_ipVersion);
- + v4_bidirection_template.r[10].length = htons(1);
- + v4_bidirection_template.r[11].ie = htons(IPFIX_ipClassOfService);
- + v4_bidirection_template.r[11].length = htons(1);
- + v4_bidirection_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv4);
- + v4_bidirection_template.r[12].length = htons(2);
- + v4_bidirection_template.r[13].ie = htons(IPFIX_vlanId);
- + v4_bidirection_template.r[13].length = htons(2);
- + v4_bidirection_template.v[0].ie = htons(IPFIX_octetDeltaCount | 0x8000);
- + v4_bidirection_template.v[0].length = htons(4);
- + v4_bidirection_template.v[0].pen = htonl(REVERSE_PEN);
- + v4_bidirection_template.v[1].ie = htons(IPFIX_packetDeltaCount | 0x8000);
- + v4_bidirection_template.v[1].length = htons(4);
- + v4_bidirection_template.v[1].pen = htonl(REVERSE_PEN);
- + v4_bidirection_template.v[2].ie = htons(IPFIX_tcpControlBits | 0x8000);
- + v4_bidirection_template.v[2].length = htons(1);
- + v4_bidirection_template.v[2].pen = htonl(REVERSE_PEN);
- + v4_bidirection_template.v[3].ie = htons(IPFIX_ipClassOfService | 0x8000);
- + v4_bidirection_template.v[3].length = htons(1);
- + v4_bidirection_template.v[3].pen = htonl(REVERSE_PEN);
- + v4_bidirection_template.v[4].ie = htons(IPFIX_icmpTypeCodeIPv4 | 0x8000);
- + v4_bidirection_template.v[4].length = htons(2);
- + v4_bidirection_template.v[4].pen = htonl(REVERSE_PEN);
- + if (param->time_format == 's') {
- + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartSeconds);
- + v4_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
- + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndSeconds);
- + v4_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
- + } else if (param->time_format == 'm') {
- + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartMilliSeconds);
- + v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
- + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndMilliSeconds);
- + v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
- + } else if (param->time_format == 'M') {
- + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartMicroSeconds);
- + v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
- + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndMicroSeconds);
- + v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
- + } else if (param->time_format == 'n') {
- + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartNanoSeconds);
- + v4_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
- + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndNanoSeconds);
- + v4_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
- + } else {
- + v4_bidirection_template.t[0].ie = htons(IPFIX_flowStartSysUpTime);
- + v4_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
- + v4_bidirection_template.t[1].ie = htons(IPFIX_flowEndSysUpTime);
- + v4_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
- + }
- +
- + bzero(&v6_bidirection_template, sizeof(v6_bidirection_template));
- + v6_bidirection_template.h.c.set_id = htons(IPFIX_TEMPLATE_SET_ID);
- + v6_bidirection_template.h.c.length = htons(sizeof(v6_bidirection_template));
- + v6_bidirection_template.h.r.template_id = htons(IPFIX_SOFTFLOWD_V6_TEMPLATE_ID);
- + v6_bidirection_template.h.r.count = htons(IPFIX_SOFTFLOWD_TEMPLATE_BIDIRECTION_NRECORDS);
- + v6_bidirection_template.r[0].ie = htons(IPFIX_sourceIPv6Address);
- + v6_bidirection_template.r[0].length = htons(16);
- + v6_bidirection_template.r[1].ie = htons(IPFIX_destinationIPv6Address);
- + v6_bidirection_template.r[1].length = htons(16);
- + v6_bidirection_template.r[2].ie = htons(IPFIX_octetDeltaCount);
- + v6_bidirection_template.r[2].length = htons(4);
- + v6_bidirection_template.r[3].ie = htons(IPFIX_packetDeltaCount);
- + v6_bidirection_template.r[3].length = htons(4);
- + v6_bidirection_template.r[4].ie = htons(IPFIX_ingressInterface);
- + v6_bidirection_template.r[4].length = htons(4);
- + v6_bidirection_template.r[5].ie = htons(IPFIX_egressInterface);
- + v6_bidirection_template.r[5].length = htons(4);
- + v6_bidirection_template.r[6].ie = htons(IPFIX_sourceTransportPort);
- + v6_bidirection_template.r[6].length = htons(2);
- + v6_bidirection_template.r[7].ie = htons(IPFIX_destinationTransportPort);
- + v6_bidirection_template.r[7].length = htons(2);
- + v6_bidirection_template.r[8].ie = htons(IPFIX_protocolIdentifier);
- + v6_bidirection_template.r[8].length = htons(1);
- + v6_bidirection_template.r[9].ie = htons(IPFIX_tcpControlBits);
- + v6_bidirection_template.r[9].length = htons(1);
- + v6_bidirection_template.r[10].ie = htons(IPFIX_ipVersion);
- + v6_bidirection_template.r[10].length = htons(1);
- + v6_bidirection_template.r[11].ie = htons(IPFIX_ipClassOfService);
- + v6_bidirection_template.r[11].length = htons(1);
- + v6_bidirection_template.r[12].ie = htons(IPFIX_icmpTypeCodeIPv6);
- + v6_bidirection_template.r[12].length = htons(2);
- + v6_bidirection_template.r[13].ie = htons(IPFIX_vlanId);
- + v6_bidirection_template.r[13].length = htons(2);
- + v6_bidirection_template.v[0].ie = htons(IPFIX_octetDeltaCount | 0x8000);
- + v6_bidirection_template.v[0].length = htons(4);
- + v6_bidirection_template.v[0].pen = htonl(REVERSE_PEN);
- + v6_bidirection_template.v[1].ie = htons(IPFIX_packetDeltaCount | 0x8000);
- + v6_bidirection_template.v[1].length = htons(4);
- + v6_bidirection_template.v[1].pen = htonl(REVERSE_PEN);
- + v6_bidirection_template.v[2].ie = htons(IPFIX_tcpControlBits | 0x8000);
- + v6_bidirection_template.v[2].length = htons(1);
- + v6_bidirection_template.v[2].pen = htonl(REVERSE_PEN);
- + v6_bidirection_template.v[3].ie = htons(IPFIX_ipClassOfService | 0x8000);
- + v6_bidirection_template.v[3].length = htons(1);
- + v6_bidirection_template.v[3].pen = htonl(REVERSE_PEN);
- + v6_bidirection_template.v[4].ie = htons(IPFIX_icmpTypeCodeIPv6 | 0x8000);
- + v6_bidirection_template.v[4].length = htons(2);
- + v6_bidirection_template.v[4].pen = htonl(REVERSE_PEN);
- + if (param->time_format == 's') {
- + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartSeconds);
- + v6_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
- + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndSeconds);
- + v6_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
- + } else if (param->time_format == 'm') {
- + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartMilliSeconds);
- + v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
- + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndMilliSeconds);
- + v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
- + } else if (param->time_format == 'M') {
- + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartMicroSeconds);
- + v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
- + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndMicroSeconds);
- + v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
- + } else if (param->time_format == 'n') {
- + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartNanoSeconds);
- + v6_bidirection_template.t[0].length = htons(sizeof(u_int64_t));
- + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndNanoSeconds);
- + v6_bidirection_template.t[1].length = htons(sizeof(u_int64_t));
- + } else {
- + v6_bidirection_template.t[0].ie = htons(IPFIX_flowStartSysUpTime);
- + v6_bidirection_template.t[0].length = htons(sizeof(u_int32_t));
- + v6_bidirection_template.t[1].ie = htons(IPFIX_flowEndSysUpTime);
- + v6_bidirection_template.t[1].length = htons(sizeof(u_int32_t));
- + }
- +}
- +
- +
- +static void
- ipfix_init_option(struct timeval *system_boot_time, struct OPTION *option) {
- bzero(&option_template, sizeof(option_template));
- option_template.h.c.set_id = htons(IPFIX_OPTION_TEMPLATE_SET_ID);
- @@ -350,6 +549,7 @@
- option_data.samplingInterval = htons(1);
- option_data.samplingSpace = htonl(option->sample > 0 ? option->sample - 1 : 0);
- }
- +
- static int
- ipfix_flow_to_flowset(const struct FLOW *flow, u_char *packet, u_int len,
- u_int16_t ifidx, const struct timeval *system_boot_time, u_int *len_used,
- @@ -468,6 +668,112 @@
- return (nflows);
- }
-
- +static int
- +ipfix_flow_to_bidirection_flowset(const struct FLOW *flow, u_char *packet,
- + u_int len, u_int16_t ifidx,
- + const struct timeval *system_boot_time,
- + u_int *len_used,
- + struct FLOWTRACKPARAMETERS *param)
- +{
- + union {
- + struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4 d4;
- + struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6 d6;
- + } d;
- + struct IPFIX_SOFTFLOWD_DATA_COMMON *dc;
- + struct IPFIX_SOFTFLOWD_DATA_BIDIRECTION *db;
- + union IPFIX_SOFTFLOWD_DATA_TIME *dt;
- + u_int freclen, ret_len, nflows;
- +
- + bzero(&d, sizeof(d));
- + *len_used = nflows = ret_len = 0;
- + switch (flow->af) {
- + case AF_INET:
- + freclen = sizeof(struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V4);
- + if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) {
- + freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2;
- + }
- + memcpy(&d.d4.sourceIPv4Address, &flow->addr[0].v4, 4);
- + memcpy(&d.d4.destinationIPv4Address, &flow->addr[1].v4, 4);
- + dc = &d.d4.c;
- + db = &d.d4.b;
- + dt = &d.d4.t;
- + dc->ipVersion = 4;
- + break;
- + case AF_INET6:
- + freclen = sizeof(struct IPFIX_SOFTFLOWD_BIDIRECTION_DATA_V6);
- + if (!(param->time_format == 'm' || param->time_format == 'M' || param->time_format == 'n')) {
- + freclen -= (sizeof(u_int64_t) - sizeof(u_int32_t)) * 2;
- + }
- + memcpy(&d.d6.sourceIPv6Address, &flow->addr[0].v6, 16);
- + memcpy(&d.d6.destinationIPv6Address, &flow->addr[1].v6, 16);
- + dc = &d.d6.c;
- + db = &d.d6.b;
- + dt = &d.d6.t;
- + dc->ipVersion = 6;
- + break;
- + default:
- + return (-1);
- + }
- +
- + if (param->time_format == 's') {
- + dt->u32.start = htonl(flow->flow_start.tv_sec);
- + dt->u32.end = htonl(flow->flow_last.tv_sec);
- + }
- +#if defined(htobe64) || defined(HAVE_DECL_HTOBE64)
- + else if (param->time_format == 'm') { /* milliseconds */
- + dt->u64.start =
- + htobe64((u_int64_t)flow->flow_start.tv_sec * 1000 + (u_int64_t)flow->flow_start.tv_usec / 1000);
- + dt->u64.end =
- + htobe64((u_int64_t)flow->flow_last.tv_sec * 1000 + (u_int64_t)flow->flow_last.tv_usec / 1000);
- + } else if (param->time_format == 'M') { /* microseconds */
- + dt->u64.start =
- + 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));
- + dt->u64.end =
- + 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));
- + } else if (param->time_format == 'n') { /* nanoseconds */
- + dt->u64.start =
- + 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));
- + dt->u64.end =
- + 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));
- + }
- +#endif
- + else {
- + dt->u32.start =
- + htonl(timeval_sub_ms(&flow->flow_start, system_boot_time));
- + dt->u32.end =
- + htonl(timeval_sub_ms(&flow->flow_last, system_boot_time));
- + }
- + dc->octetDeltaCount = htonl(flow->octets[0]);
- + db->octetDeltaCount = htonl(flow->octets[1]);
- + dc->packetDeltaCount = htonl(flow->packets[0]);
- + db->packetDeltaCount = htonl(flow->packets[1]);
- + dc->ingressInterface = dc->egressInterface = htonl(ifidx);
- + dc->sourceTransportPort = flow->port[0];
- + dc->destinationTransportPort = flow->port[1];
- + dc->protocolIdentifier = flow->protocol;
- + dc->tcpControlBits = flow->tcp_flags[0];
- + db->tcpControlBits = flow->tcp_flags[1];
- + dc->ipClassOfService = flow->tos[0];
- + db->ipClassOfService = flow->tos[1];
- + if (flow->protocol == IPPROTO_ICMP || flow->protocol == IPPROTO_ICMPV6) {
- + dc->icmpTypeCode = flow->port[1];
- + db->icmpTypeCode = flow->port[0];
- + }
- + dc->vlanId = htons(flow->vlanid);
- +
- + if (flow->octets[0] > 0 || flow->octets[1] > 0) {
- + if (ret_len + freclen > len)
- + return (-1);
- + memcpy(packet + ret_len, &d, freclen);
- + ret_len += freclen;
- + nflows++;
- + }
- +
- + *len_used = ret_len;
- + return (nflows);
- +}
- +
- +
- /*
- * Given an array of expired flows, send netflow v9 report packets
- * Returns number of packets sent or -1 on error
- @@ -487,7 +793,6 @@
- u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
- struct timeval *system_boot_time = ¶m->system_boot_time;
- u_int64_t *flows_exported = ¶m->flows_exported;
- - u_int64_t *packets_sent = ¶m->packets_sent;
- u_int64_t *records_sent = ¶m->records_sent;
- struct OPTION *option = ¶m->option;
-
- @@ -620,3 +925,152 @@
- if (ipfix_pkts_until_template > 0)
- ipfix_pkts_until_template = 0;
- }
- +
- +/*
- + * Given an array of expired flows, send netflow v9 report packets
- + * Returns number of packets sent or -1 on error
- + */
- +int
- +send_ipfix_bidirection(struct FLOW **flows, int num_flows, int nfsock,
- + u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
- + int verbose_flag)
- +{
- + struct IPFIX_HEADER *ipfix;
- + struct IPFIX_SET_HEADER *dh;
- + struct timeval now;
- + u_int offset, last_af, i, j, num_packets, inc, last_valid;
- + socklen_t errsz;
- + int err, r;
- + u_int records;
- + u_char packet[IPFIX_SOFTFLOWD_MAX_PACKET_SIZE];
- + struct timeval *system_boot_time = ¶m->system_boot_time;
- + u_int64_t *flows_exported = ¶m->flows_exported;
- + u_int64_t *records_sent = ¶m->records_sent;
- + struct OPTION *option = ¶m->option;
- +
- + gettimeofday(&now, NULL);
- +
- + if (ipfix_pkts_until_template == -1) {
- + ipfix_init_template_bidirection(param);
- + ipfix_pkts_until_template = 0;
- + if (option != NULL){
- + ipfix_init_option(system_boot_time, option);
- + }
- + }
- +
- + last_valid = num_packets = 0;
- + for (j = 0; j < num_flows;) {
- + bzero(packet, sizeof(packet));
- + ipfix = (struct IPFIX_HEADER *)packet;
- +
- + ipfix->version = htons(10);
- + ipfix->length = 0; /* Filled as we go, htons at end */
- + ipfix->export_time = htonl(time(NULL));
- + ipfix->od_id = 0;
- + offset = sizeof(*ipfix);
- +
- + /* Refresh template headers if we need to */
- + if (ipfix_pkts_until_template <= 0) {
- + memcpy(packet + offset, &v4_bidirection_template,
- + sizeof(v4_bidirection_template));
- + offset += sizeof(v4_bidirection_template);
- + memcpy(packet + offset, &v6_bidirection_template,
- + sizeof(v6_bidirection_template));
- + offset += sizeof(v6_bidirection_template);
- + if (option != NULL){
- + memcpy(packet + offset, &option_template,
- + sizeof(option_template));
- + offset += sizeof(option_template);
- + memcpy(packet + offset, &option_data,
- + sizeof(option_data));
- + offset += sizeof(option_data);
- + }
- +
- + ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL;
- + }
- +
- + dh = NULL;
- + last_af = 0;
- + records = 0;
- + for (i = 0; i + j < num_flows; i++) {
- + if (dh == NULL || flows[i + j]->af != last_af) {
- + if (dh != NULL) {
- + if (offset % 4 != 0) {
- + /* Pad to multiple of 4 */
- + dh->length += 4 - (offset % 4);
- + offset += 4 - (offset % 4);
- + }
- + /* Finalise last header */
- + dh->length = htons(dh->length);
- + }
- + if (offset + sizeof(*dh) > sizeof(packet)) {
- + /* Mark header is finished */
- + dh = NULL;
- + break;
- + }
- + dh = (struct IPFIX_SET_HEADER *)
- + (packet + offset);
- + dh->set_id =
- + (flows[i + j]->af == AF_INET) ?
- + v4_bidirection_template.h.r.template_id :
- + v6_bidirection_template.h.r.template_id;
- + last_af = flows[i + j]->af;
- + last_valid = offset;
- + dh->length = sizeof(*dh); /* Filled as we go */
- + offset += sizeof(*dh);
- + }
- +
- + r = ipfix_flow_to_bidirection_flowset(flows[i + j],
- + packet + offset,
- + sizeof(packet) - offset,
- + ifidx,
- + system_boot_time,
- + &inc, param);
- + if (r <= 0) {
- + /* yank off data header, if we had to go back */
- + if (last_valid)
- + offset = last_valid;
- + break;
- + }
- + records += (u_int)r;
- + offset += inc;
- + dh->length += inc;
- + last_valid = 0; /* Don't clobber this header now */
- + if (verbose_flag) {
- + logit(LOG_DEBUG, "Flow %d/%d: "
- + "r %d offset %d ie %04x len %d(0x%04x)",
- + r, i, j, offset,
- + dh->set_id, dh->length,
- + dh->length);
- + }
- + }
- + /* Don't finish header if it has already been done */
- + if (dh != NULL) {
- + if (offset % 4 != 0) {
- + /* Pad to multiple of 4 */
- + dh->length += 4 - (offset % 4);
- + offset += 4 - (offset % 4);
- + }
- + /* Finalise last header */
- + dh->length = htons(dh->length);
- + }
- + ipfix->length = htons(offset);
- + *records_sent += records;
- + ipfix->sequence = htonl((u_int32_t)(*records_sent & 0x00000000ffffffff));
- +
- + if (verbose_flag)
- + logit(LOG_DEBUG, "Sending flow packet len = %d", offset);
- + errsz = sizeof(err);
- + /* Clear ICMP errors */
- + getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz);
- + if (send(nfsock, packet, (size_t)offset, 0) == -1)
- + return (-1);
- + num_packets++;
- + ipfix_pkts_until_template--;
- +
- + j += i;
- + }
- +
- + *flows_exported += j;
- + return (num_packets);
- +}
- --- a/softflowd.c
- +++ b/softflowd.c
- @@ -99,16 +99,17 @@
- struct NETFLOW_SENDER {
- int version;
- netflow_send_func_t *func;
- + netflow_send_func_t *bidir_func;
- int v6_capable;
- };
-
- /* Array of NetFlow export function that we know of. NB. nf[0] is default */
- static const struct NETFLOW_SENDER nf[] = {
- - { 5, send_netflow_v5, 0 },
- - { 1, send_netflow_v1, 0 },
- - { 9, send_netflow_v9, 1 },
- - { 10, send_ipfix, 1 },
- - { -1, NULL, 0 },
- + { 5, send_netflow_v5, NULL, 0 },
- + { 1, send_netflow_v1, NULL, 0 },
- + { 9, send_netflow_v9, NULL, 1 },
- + { 10, send_ipfix, send_ipfix_bidirection, 1 },
- + { -1, NULL, NULL, 0 },
- };
-
- /* Describes a location where we send NetFlow packets to */
- @@ -854,8 +855,15 @@
- /* Processing for expired flows */
- if (num_expired > 0) {
- if (target != NULL && target->fd != -1) {
- - r = target->dialect->func(expired_flows, num_expired,
- - target->fd, if_index, &ft->param, verbose_flag);
- + netflow_send_func_t *func =
- + ft->param.bidirection == 1 ?
- + target->dialect->bidir_func :
- + target->dialect->func;
- + if (func == NULL) {
- + func = target->dialect->func;
- + }
- + r = func(expired_flows, num_expired,
- + target->fd, if_index, &ft->param, verbose_flag);
- if (verbose_flag)
- logit(LOG_DEBUG, "sent %d netflow packets", r);
- if (r > 0) {
- @@ -1085,7 +1093,7 @@
- {
- int i, j;
- u_int32_t frametype;
- - int add_offset = 0;
- + int vlan_size = 0;
-
- static const struct DATALINK *dl = NULL;
-
- @@ -1104,22 +1112,31 @@
- frametype = 0;
-
- /* Processing 802.1Q vlan in ethernet */
- - if (linktype == DLT_EN10MB && ntohs(*(u_int16_t *)(pkt + dl->ft_off)) == 0x8100) {
- - add_offset = 4;
- - if (caplen <= dl->skiplen + add_offset)
- - return (-1);
- - *vlanid = ntohs(*(u_int16_t *)(pkt + dl->ft_off + 2)) & 0x0fff;
- + if (linktype == DLT_EN10MB) {
- + for (j = 0; j < dl->ft_len; j++) {
- + frametype <<= 8;
- + frametype |= pkt[j + dl->ft_off];
- + }
- + frametype &= dl->ft_mask;
- + if (frametype == 0x8100) {
- + for (j = 0; j < 2; j++) {
- + *vlanid <<= 8;
- + *vlanid |= pkt[j + dl->skiplen];
- + }
- + vlan_size = 4;
- + }
- }
- + frametype = 0;
-
- if (dl->ft_is_be) {
- for (j = 0; j < dl->ft_len; j++) {
- frametype <<= 8;
- - frametype |= pkt[j + dl->ft_off + add_offset];
- + frametype |= pkt[j + dl->ft_off + vlan_size];
- }
- } else {
- for (j = dl->ft_len - 1; j >= 0 ; j--) {
- frametype <<= 8;
- - frametype |= pkt[j + dl->ft_off + add_offset];
- + frametype |= pkt[j + dl->ft_off + vlan_size];
- }
- }
- frametype &= dl->ft_mask;
- @@ -1131,7 +1148,7 @@
- else
- return (-1);
-
- - return (dl->skiplen + add_offset);
- + return (dl->skiplen + vlan_size);
- }
-
- /*
- @@ -1739,7 +1756,7 @@
- dontfork_flag = 0;
- always_v6 = 0;
-
- - while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:")) != -1) {
- + while ((ch = getopt(argc, argv, "6hdDL:T:i:r:f:t:n:m:p:c:v:s:P:A:b")) != -1) {
- switch (ch) {
- case '6':
- always_v6 = 1;
- @@ -1885,6 +1902,9 @@
- exit(1);
- }
- break;
- + case 'b':
- + flowtrack.param.bidirection = 1;
- + break;
- default:
- fprintf(stderr, "Invalid commandline option.\n");
- usage();
- --- a/softflowd.h
- +++ b/softflowd.h
- @@ -140,6 +140,7 @@
- /* Optional information */
- struct OPTION option;
- char time_format;
- + u_int8_t bidirection;
- };
- /*
- * This structure is the root of the flow tracking system.
- @@ -234,6 +235,10 @@
- int send_ipfix(struct FLOW **flows, int num_flows, int nfsock,
- u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
- int verbose_flag);
- +int send_ipfix_bidirection(struct FLOW **flows, int num_flows, int nfsock,
- + u_int16_t ifidx,
- + struct FLOWTRACKPARAMETERS *param,
- + int verbose_flag);
-
- /* Force a resend of the flow template */
- void netflow9_resend_template(void);
|