123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035 |
- /*
- * Copyright 2002 Damien Miller <djm@mindrot.org> All rights reserved.
- * Copyright 2012 Hitoshi Irino <irino@sfc.wide.ad.jp> All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "common.h"
- #include "log.h"
- #include "treetype.h"
- #include "softflowd.h"
- #include "netflow9.h"
- #include "ipfix.h"
- #include "psamp.h"
- const struct IPFIX_FIELD_SPECIFIER field_v4[] = {
- {IPFIX_sourceIPv4Address, 4},
- {IPFIX_destinationIPv4Address, 4}
- };
- const struct IPFIX_FIELD_SPECIFIER field_v6[] = {
- {IPFIX_sourceIPv6Address, 16},
- {IPFIX_destinationIPv6Address, 16}
- };
- const struct IPFIX_FIELD_SPECIFIER field_common[] = {
- {IPFIX_octetDeltaCount, 4},
- {IPFIX_packetDeltaCount, 4},
- {IPFIX_ingressInterface, 4},
- {IPFIX_egressInterface, 4},
- {IPFIX_flowDirection, 1},
- {IPFIX_flowEndReason, 1},
- #ifdef ENABLE_IFNAME
- {IPFIX_interfaceName, IFNAMSIZ}
- #endif
- };
- const struct IPFIX_FIELD_SPECIFIER field_transport[] = {
- {IPFIX_sourceTransportPort, 2},
- {IPFIX_destinationTransportPort, 2},
- {IPFIX_protocolIdentifier, 1},
- {IPFIX_tcpControlBits, 1},
- {IPFIX_ipVersion, 1},
- {IPFIX_ipClassOfService, 1}
- };
- const struct IPFIX_FIELD_SPECIFIER field_icmp4[] = {
- {IPFIX_icmpTypeCodeIPv4, 2},
- {IPFIX_protocolIdentifier, 1},
- {IPFIX_ipVersion, 1},
- {IPFIX_ipClassOfService, 1}
- };
- const struct IPFIX_FIELD_SPECIFIER field_icmp6[] = {
- {IPFIX_icmpTypeCodeIPv6, 2},
- {IPFIX_protocolIdentifier, 1},
- {IPFIX_ipVersion, 1},
- {IPFIX_ipClassOfService, 1}
- };
- const struct IPFIX_FIELD_SPECIFIER field_vlan[] = {
- {IPFIX_vlanId, 2},
- {IPFIX_postVlanId, 2}
- };
- const struct IPFIX_FIELD_SPECIFIER field_ether[] = {
- {IPFIX_sourceMacAddress, 6},
- {IPFIX_postDestinationMacAddress, 6}
- };
- const struct IPFIX_FIELD_SPECIFIER field_timesec[] = {
- {IPFIX_flowStartSeconds, 4},
- {IPFIX_flowEndSeconds, 4}
- };
- const struct IPFIX_FIELD_SPECIFIER field_timemsec[] = {
- {IPFIX_flowStartMilliSeconds, 8},
- {IPFIX_flowEndMilliSeconds, 8}
- };
- const struct IPFIX_FIELD_SPECIFIER field_timeusec[] = {
- {IPFIX_flowStartMicroSeconds, 8},
- {IPFIX_flowEndMicroSeconds, 8}
- };
- const struct IPFIX_FIELD_SPECIFIER field_timensec[] = {
- {IPFIX_flowStartNanoSeconds, 8},
- {IPFIX_flowEndNanoSeconds, 8}
- };
- const struct IPFIX_FIELD_SPECIFIER field_timesysup[] = {
- {IPFIX_flowStartSysUpTime, 4},
- {IPFIX_flowEndSysUpTime, 4}
- };
- const struct IPFIX_FIELD_SPECIFIER field_bicommon[] = {
- {IPFIX_octetDeltaCount, 4},
- {IPFIX_packetDeltaCount, 4},
- {IPFIX_ipClassOfService, 1}
- };
- const struct IPFIX_FIELD_SPECIFIER field_bitransport[] =
- { {IPFIX_tcpControlBits, 1} };
- const struct IPFIX_FIELD_SPECIFIER field_biicmp4[] =
- { {IPFIX_icmpTypeCodeIPv4, 2} };
- const struct IPFIX_FIELD_SPECIFIER field_biicmp6[] =
- { {IPFIX_icmpTypeCodeIPv6, 2} };
- const struct IPFIX_FIELD_SPECIFIER field_scope[] =
- { {IPFIX_meteringProcessId, 4} };
- const struct IPFIX_FIELD_SPECIFIER field_option[] = {
- {IPFIX_systemInitTimeMilliseconds, 8},
- {PSAMP_samplingPacketInterval, 4},
- {PSAMP_samplingPacketSpace, 4},
- {PSAMP_selectorAlgorithm, 2},
- {IPFIX_interfaceName, IFNAMSIZ}
- };
- const struct IPFIX_FIELD_SPECIFIER field_nf9scope[] =
- { {NFLOW9_OPTION_SCOPE_INTERFACE, 4} };
- const struct IPFIX_FIELD_SPECIFIER field_nf9option[] = {
- {NFLOW9_SAMPLING_INTERVAL, 4},
- {NFLOW9_SAMPLING_ALGORITHM, 1},
- {IPFIX_interfaceName, IFNAMSIZ}
- };
- /* Stuff pertaining to the templates that softflowd uses */
- #define IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS \
- sizeof(field_v4) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS \
- sizeof(field_timesysup) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS \
- sizeof(field_common) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS \
- sizeof(field_transport) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS \
- sizeof(field_icmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS \
- sizeof(field_vlan) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS \
- sizeof(field_ether) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS \
- sizeof(field_bicommon) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS \
- sizeof(field_bitransport) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS \
- sizeof(field_biicmp4) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS \
- IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS + \
- IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS + \
- IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS + \
- IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS + \
- IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS + \
- IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS
- #define IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS \
- IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS + \
- IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS
- struct IPFIX_SOFTFLOWD_TEMPLATE {
- struct IPFIX_TEMPLATE_SET_HEADER h;
- struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_TEMPLATE_NRECORDS];
- struct IPFIX_VENDOR_FIELD_SPECIFIER
- v[IPFIX_SOFTFLOWD_TEMPLATE_BI_NRECORDS];
- u_int16_t data_len, bi_count;
- } __packed;
- #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS \
- sizeof(field_scope) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS \
- sizeof(field_option) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS \
- sizeof(field_nf9scope) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- #define NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS \
- sizeof(field_nf9option) / sizeof(struct IPFIX_FIELD_SPECIFIER)
- struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE {
- struct IPFIX_OPTION_TEMPLATE_SET_HEADER h;
- struct IPFIX_FIELD_SPECIFIER
- s[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS];
- struct IPFIX_FIELD_SPECIFIER r[IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS];
- } __packed;
- /* softflowd data set */
- struct IPFIX_SOFTFLOWD_DATA_COMMON {
- u_int32_t octetDeltaCount, packetDeltaCount;
- u_int32_t ingressInterface, egressInterface;
- u_int8_t flowDirection, flowEndReason;
- #ifdef ENABLE_IFNAME
- char interfaceName[IFNAMSIZ];
- #endif
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_TRANSPORT {
- u_int16_t sourceTransportPort, destinationTransportPort;
- u_int8_t protocolIdentifier, tcpControlBits, ipVersion, ipClassOfService;
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_ICMP {
- u_int16_t icmpTypeCode;
- u_int8_t protocolIdentifier, ipVersion, ipClassOfService;
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_VLAN {
- u_int16_t vlanId, postVlanId;
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_ETHER {
- u_int8_t sourceMacAddress[6], destinationMacAddress[6];
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_BICOMMON {
- u_int32_t octetDeltaCount, packetDeltaCount;
- u_int8_t ipClassOfService;
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT {
- u_int8_t tcpControlBits;
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_BIICMP {
- u_int16_t icmpTypeCode;
- } __packed;
- union IPFIX_SOFTFLOWD_DATA_TIME {
- struct {
- u_int32_t start;
- u_int32_t end;
- } u32;
- struct {
- u_int64_t start;
- u_int64_t end;
- } u64;
- };
- struct IPFIX_SOFTFLOWD_DATA_V4ADDR {
- u_int32_t sourceIPv4Address, destinationIPv4Address;
- } __packed;
- struct IPFIX_SOFTFLOWD_DATA_V6ADDR {
- struct in6_addr sourceIPv6Address, destinationIPv6Address;
- } __packed;
- struct IPFIX_SOFTFLOWD_OPTION_DATA {
- struct IPFIX_SET_HEADER c;
- u_int32_t scope_pid;
- u_int64_t systemInitTimeMilliseconds;
- u_int32_t samplingInterval;
- u_int32_t samplingSpace;
- u_int16_t samplingAlgorithm;
- char interfaceName[IFNAMSIZ];
- } __packed;
- struct NFLOW9_SOFTFLOWD_OPTION_DATA {
- struct IPFIX_SET_HEADER c;
- u_int32_t scope_ifidx;
- u_int32_t samplingInterval;
- u_int8_t samplingAlgorithm;
- char interfaceName[IFNAMSIZ];
- } __packed;
- /* Local data: templates and counters */
- #define IPFIX_SOFTFLOWD_MAX_PACKET_SIZE 1428
- #define IPFIX_SOFTFLOWD_V4_TEMPLATE_ID 1024
- #define IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID 1025
- #define IPFIX_SOFTFLOWD_V6_TEMPLATE_ID 2048
- #define IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID 2049
- #define IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID 256
- #define IPFIX_DEFAULT_TEMPLATE_INTERVAL 16
- /* ... */
- #define IPFIX_OPTION_SCOPE_SYSTEM 1
- #define IPFIX_OPTION_SCOPE_INTERFACE 2
- #define IPFIX_OPTION_SCOPE_LINECARD 3
- #define IPFIX_OPTION_SCOPE_CACHE 4
- #define IPFIX_OPTION_SCOPE_TEMPLATE 5
- /* ... */
- #define IPFIX_SAMPLING_ALGORITHM_DETERMINISTIC 1
- #define IPFIX_SAMPLING_ALGORITHM_RANDOM 2
- /* ... */
- // prototype
- void memcpy_template (u_char * packet, u_int * offset,
- struct IPFIX_SOFTFLOWD_TEMPLATE *template,
- u_int8_t bi_flag, u_int8_t max_num_label);
- // variables
- enum { TMPLV4, TMPLICMPV4, TMPLV6, TMPLICMPV6, TMPLMAX };
- static struct IPFIX_SOFTFLOWD_TEMPLATE templates[TMPLMAX];
- static struct IPFIX_SOFTFLOWD_OPTION_TEMPLATE option_template;
- static struct IPFIX_SOFTFLOWD_OPTION_DATA option_data;
- static struct NFLOW9_SOFTFLOWD_OPTION_DATA nf9opt_data;
- static int ipfix_pkts_until_template = -1;
- int
- ipfix_init_fields (struct IPFIX_FIELD_SPECIFIER *dst,
- u_int * index,
- const struct IPFIX_FIELD_SPECIFIER *src,
- u_int field_number) {
- int i, length = 0;
- for (i = 0; i < field_number; i++) {
- dst[*index + i].ie = htons (src[i].ie);
- dst[*index + i].length = htons (src[i].length);
- length += src[i].length;
- }
- *index += field_number;
- return length;
- }
- void
- conv_unix_to_ntp (struct timeval tv, struct ntp_time_t *ntp) {
- if (ntp != NULL) {
- ntp->second = tv.tv_sec + 0x83AA7E80;
- ntp->fraction =
- (uint32_t) ((double) (tv.tv_usec + 1) * (double) (1LL << 32) * 1.0e-6);
- }
- }
- struct timeval
- conv_ntp_to_unix (struct ntp_time_t ntp) {
- struct timeval tv = {
- ntp.second - 0x83AA7E80, // the seconds from Jan 1, 1900 to Jan 1, 1970
- (uint32_t) ((double) ntp.fraction * 1.0e6 / (double) (1LL << 32))
- };
- return tv;
- }
- static int
- ipfix_init_bifields (struct IPFIX_SOFTFLOWD_TEMPLATE *template,
- u_int * index,
- const struct IPFIX_FIELD_SPECIFIER *fields,
- u_int field_number) {
- int i, length = 0;
- for (i = 0; i < field_number; i++) {
- template->v[*index + i].ie = htons (fields[i].ie | 0x8000);
- template->v[*index + i].length = htons (fields[i].length);
- template->v[*index + i].pen = htonl (REVERSE_PEN);
- length += fields[i].length;
- }
- *index += field_number;
- return length;
- }
- static int
- ipfix_init_template_time (struct FLOWTRACKPARAMETERS *param,
- struct IPFIX_SOFTFLOWD_TEMPLATE *template,
- u_int * index) {
- int length = 0;
- if (param->time_format == 's') {
- length = ipfix_init_fields (template->r, index,
- field_timesec,
- IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
- } else if (param->time_format == 'm') {
- length = ipfix_init_fields (template->r, index,
- field_timemsec,
- IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
- } else if (param->time_format == 'M') {
- length = ipfix_init_fields (template->r, index,
- field_timeusec,
- IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
- } else if (param->time_format == 'n') {
- length = ipfix_init_fields (template->r, index,
- field_timensec,
- IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
- } else {
- length = ipfix_init_fields (template->r, index,
- field_timesysup,
- IPFIX_SOFTFLOWD_TEMPLATE_TIMERECORDS);
- }
- return length;
- }
- static void
- ipfix_init_template_unity (struct FLOWTRACKPARAMETERS *param,
- struct IPFIX_SOFTFLOWD_TEMPLATE *template,
- u_int template_id, u_int8_t v6_flag,
- u_int8_t icmp_flag, u_int8_t bi_flag,
- u_int16_t version) {
- u_int index = 0, bi_index = 0, length = 0;
- memset (template, 0, sizeof (*template));
- template->h.c.set_id = htons (version == 10 ?
- IPFIX_TEMPLATE_SET_ID :
- NFLOW9_TEMPLATE_SET_ID);
- template->h.r.template_id = htons (template_id);
- if (v6_flag) {
- length += ipfix_init_fields (template->r, &index,
- field_v6,
- IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS);
- } else {
- length += ipfix_init_fields (template->r, &index,
- field_v4,
- IPFIX_SOFTFLOWD_TEMPLATE_IPRECORDS);
- }
- length += ipfix_init_template_time (param, template, &index);
- length += ipfix_init_fields (template->r, &index,
- field_common,
- IPFIX_SOFTFLOWD_TEMPLATE_COMMONRECORDS);
- if (icmp_flag) {
- if (v6_flag) {
- length += ipfix_init_fields (template->r, &index,
- field_icmp6,
- IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS);
- } else {
- length += ipfix_init_fields (template->r, &index,
- field_icmp4,
- IPFIX_SOFTFLOWD_TEMPLATE_ICMPRECORDS);
- }
- } else {
- length += ipfix_init_fields (template->r, &index,
- field_transport,
- IPFIX_SOFTFLOWD_TEMPLATE_TRANSPORTRECORDS);
- }
- if (param->track_level >= TRACK_FULL_VLAN) {
- length += ipfix_init_fields (template->r, &index,
- field_vlan,
- IPFIX_SOFTFLOWD_TEMPLATE_VLANRECORDS);
- }
- if (param->track_level >= TRACK_FULL_VLAN_ETHER) {
- length += ipfix_init_fields (template->r, &index,
- field_ether,
- IPFIX_SOFTFLOWD_TEMPLATE_ETHERRECORDS);
- }
- if (bi_flag) {
- length +=
- ipfix_init_bifields (template, &bi_index,
- field_bicommon,
- IPFIX_SOFTFLOWD_TEMPLATE_BICOMMONRECORDS);
- if (icmp_flag) {
- if (v6_flag) {
- length +=
- ipfix_init_bifields (template, &bi_index,
- field_biicmp6,
- IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS);
- } else {
- length +=
- ipfix_init_bifields (template, &bi_index,
- field_biicmp4,
- IPFIX_SOFTFLOWD_TEMPLATE_BIICMPRECORDS);
- }
- } else {
- length +=
- ipfix_init_bifields (template, &bi_index,
- field_bitransport,
- IPFIX_SOFTFLOWD_TEMPLATE_BITRANSPORTRECORDS);
- }
- }
- template->bi_count = bi_index;
- template->h.r.count = htons (index + bi_index + param->max_num_label); // mpls
- template->h.c.length =
- htons (sizeof (struct IPFIX_TEMPLATE_SET_HEADER) +
- index * sizeof (struct IPFIX_FIELD_SPECIFIER) +
- bi_index * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER) +
- param->max_num_label * sizeof (struct IPFIX_FIELD_SPECIFIER));
- template->data_len =
- length + param->max_num_label * IPFIX_mplsLabelStackSection_SIZE;
- }
- static void
- ipfix_init_template (struct FLOWTRACKPARAMETERS *param,
- u_int8_t bi_flag, u_int16_t version) {
- u_int8_t v6_flag = 0, icmp_flag = 0;
- u_int16_t template_id = 0;
- int i = 0;
- for (i = 0; i < TMPLMAX; i++) {
- switch (i) {
- case TMPLV4:
- v6_flag = 0;
- icmp_flag = 0;
- template_id = IPFIX_SOFTFLOWD_V4_TEMPLATE_ID;
- break;
- case TMPLICMPV4:
- v6_flag = 0;
- icmp_flag = 1;
- template_id = IPFIX_SOFTFLOWD_ICMPV4_TEMPLATE_ID;
- break;
- case TMPLV6:
- v6_flag = 1;
- icmp_flag = 0;
- template_id = IPFIX_SOFTFLOWD_V6_TEMPLATE_ID;
- break;
- case TMPLICMPV6:
- v6_flag = 1;
- icmp_flag = 1;
- template_id = IPFIX_SOFTFLOWD_ICMPV6_TEMPLATE_ID;
- break;
- }
- ipfix_init_template_unity (param, &templates[i],
- template_id, v6_flag,
- icmp_flag, bi_flag, version);
- }
- }
- static void
- nflow9_init_option (u_int16_t ifidx, struct OPTION *option) {
- u_int scope_index = 0, option_index = 0;
- u_int16_t scope_len =
- NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS *
- sizeof (struct IPFIX_FIELD_SPECIFIER);
- u_int16_t opt_len =
- NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS *
- sizeof (struct IPFIX_FIELD_SPECIFIER);
- memset (&option_template, 0, sizeof (option_template));
- option_template.h.c.set_id = htons (NFLOW9_OPTION_TEMPLATE_SET_ID);
- option_template.h.c.length =
- htons (sizeof (option_template.h) + scope_len + opt_len);
- option_template.h.u.n.template_id =
- htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
- option_template.h.u.n.scope_length = htons (scope_len);
- option_template.h.u.n.option_length = htons (opt_len);
- ipfix_init_fields (option_template.s, &scope_index,
- field_nf9scope,
- NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS);
- ipfix_init_fields (option_template.r, &option_index,
- field_nf9option,
- NFLOW9_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
- memset (&nf9opt_data, 0, sizeof (nf9opt_data));
- nf9opt_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
- nf9opt_data.c.length = htons (sizeof (nf9opt_data));
- nf9opt_data.scope_ifidx = htonl (ifidx);
- nf9opt_data.samplingInterval =
- htonl (option->sample > 1 ? option->sample : 1);
- nf9opt_data.samplingAlgorithm = NFLOW9_SAMPLING_ALGORITHM_DETERMINISTIC;
- strncpy (nf9opt_data.interfaceName, option->interfaceName,
- strlen (option->interfaceName) <
- sizeof (nf9opt_data.interfaceName) ?
- strlen (option->interfaceName) :
- sizeof (nf9opt_data.interfaceName));
- }
- static void
- ipfix_init_option (struct timeval *system_boot_time, struct OPTION *option) {
- u_int scope_index = 0, option_index = 0;
- memset (&option_template, 0, sizeof (option_template));
- option_template.h.c.set_id = htons (IPFIX_OPTION_TEMPLATE_SET_ID);
- option_template.h.c.length = htons (sizeof (option_template));
- option_template.h.u.i.r.template_id =
- htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
- option_template.h.u.i.r.count =
- htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS +
- IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
- option_template.h.u.i.scope_count =
- htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS);
- ipfix_init_fields (option_template.s, &scope_index,
- field_scope,
- IPFIX_SOFTFLOWD_OPTION_TEMPLATE_SCOPE_RECORDS);
- ipfix_init_fields (option_template.r, &option_index, field_option,
- IPFIX_SOFTFLOWD_OPTION_TEMPLATE_NRECORDS);
- memset (&option_data, 0, sizeof (option_data));
- option_data.c.set_id = htons (IPFIX_SOFTFLOWD_OPTION_TEMPLATE_ID);
- option_data.c.length = htons (sizeof (option_data));
- option_data.scope_pid = htonl ((u_int32_t) option->meteringProcessId);
- #if defined(htobe64) || defined(HAVE_DECL_HTOBE64)
- option_data.systemInitTimeMilliseconds =
- htobe64 ((u_int64_t) system_boot_time->tv_sec * 1000 +
- (u_int64_t) system_boot_time->tv_usec / 1000);
- #endif
- option_data.samplingAlgorithm = htons (PSAMP_selectorAlgorithm_count);
- option_data.samplingInterval = htonl (1);
- option_data.samplingSpace =
- htonl (option->sample > 0 ? option->sample - 1 : 0);
- strncpy (option_data.interfaceName, option->interfaceName,
- strlen (option->interfaceName) <
- sizeof (option_data.interfaceName) ?
- strlen (option->interfaceName) :
- sizeof (option_data.interfaceName));
- }
- static int
- copy_data_time (union IPFIX_SOFTFLOWD_DATA_TIME *dt,
- const struct FLOW *flow,
- const struct timeval *system_boot_time,
- struct FLOWTRACKPARAMETERS *param) {
- int length = (param->time_format == 'm' || param->time_format == 'M'
- || param->time_format == 'n') ? 16 : 8;
- if (dt == NULL)
- return -1;
- switch (param->time_format) {
- struct ntp_time_t ntptime;
- case 's':
- dt->u32.start = htonl (flow->flow_start.tv_sec);
- dt->u32.end = htonl (flow->flow_last.tv_sec);
- break;
- #if defined(htobe64) || defined(HAVE_DECL_HTOBE64)
- case 'm':
- 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);
- break;
- case 'M':
- case 'n':
- conv_unix_to_ntp ((struct timeval) flow->flow_start, &ntptime);
- dt->u64.start =
- htobe64 ((u_int64_t) ntptime.second << 32 | ntptime.fraction);
- conv_unix_to_ntp ((struct timeval) flow->flow_last, &ntptime);
- dt->u64.end =
- htobe64 ((u_int64_t) ntptime.second << 32 | ntptime.fraction);
- break;
- #endif
- default:
- 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));
- break;
- }
- return length;
- }
- static u_int
- ipfix_flow_to_template_index (const struct FLOW *flow) {
- u_int index = 0;
- if (flow->af == AF_INET) {
- index = (flow->protocol == IPPROTO_ICMP) ? TMPLICMPV4 : TMPLV4;
- } else if (flow->af == AF_INET6) {
- index = (flow->protocol == IPPROTO_ICMPV6) ? TMPLICMPV6 : TMPLV6;
- }
- return index;
- }
- 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,
- struct FLOWTRACKPARAMETERS *param, u_int8_t bi_flag) {
- struct IPFIX_SOFTFLOWD_DATA_V4ADDR *d4[2] = { NULL, NULL };
- struct IPFIX_SOFTFLOWD_DATA_V6ADDR *d6[2] = { NULL, NULL };
- union IPFIX_SOFTFLOWD_DATA_TIME *dt[2] = { NULL, NULL };
- struct IPFIX_SOFTFLOWD_DATA_COMMON *dc[2] = { NULL, NULL };
- struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *dtr[2] = { NULL, NULL };
- struct IPFIX_SOFTFLOWD_DATA_ICMP *di[2] = { NULL, NULL };
- struct IPFIX_SOFTFLOWD_DATA_VLAN *dv[2] = { NULL, NULL };
- struct IPFIX_SOFTFLOWD_DATA_ETHER *de[2] = { NULL, NULL };
- struct IPFIX_SOFTFLOWD_DATA_BICOMMON *dbc = NULL;
- struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *dbtr = NULL;
- struct IPFIX_SOFTFLOWD_DATA_BIICMP *dbi = NULL;
- struct OPTION *option = ¶m->option;
- u_int freclen = 0, nflows = 0, offset = 0;
- u_int frecnum = bi_flag ? 1 : 2;
- u_int tmplindex = ipfix_flow_to_template_index (flow);
- int i = 0, k = 0;
- freclen = templates[tmplindex].data_len;
- if (len < freclen * frecnum)
- return (-1);
- for (i = 0; i < frecnum; i++) {
- if (bi_flag == 0 && flow->octets[i] == 0)
- continue;
- nflows++;
- if (flow->af == AF_INET) {
- d4[i] = (struct IPFIX_SOFTFLOWD_DATA_V4ADDR *) &packet[offset];
- memcpy (&d4[i]->sourceIPv4Address, &flow->addr[i].v4, 4);
- memcpy (&d4[i]->destinationIPv4Address, &flow->addr[i ^ 1].v4, 4);
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V4ADDR);
- } else if (flow->af == AF_INET6) {
- d6[i] = (struct IPFIX_SOFTFLOWD_DATA_V6ADDR *) &packet[offset];
- memcpy (&d6[i]->sourceIPv6Address, &flow->addr[i].v6, 16);
- memcpy (&d6[i]->destinationIPv6Address, &flow->addr[i ^ 1].v6, 16);
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_V6ADDR);
- }
- dt[i] = (union IPFIX_SOFTFLOWD_DATA_TIME *) &packet[offset];
- offset += copy_data_time (dt[i], flow, system_boot_time, param);
- dc[i] = (struct IPFIX_SOFTFLOWD_DATA_COMMON *) &packet[offset];
- dc[i]->octetDeltaCount = htonl (flow->octets[i]);
- dc[i]->packetDeltaCount = htonl (flow->packets[i]);
- dc[i]->ingressInterface = dc[i]->egressInterface = htonl (ifidx);
- dc[i]->flowDirection = i;
- dc[i]->flowEndReason = flow->flowEndReason;
- #ifdef ENABLE_IFNAME
- strncpy (dc[i]->interfaceName, option->interfaceName,
- strlen (option->interfaceName) <
- sizeof (dc[i]->interfaceName) ?
- strlen (option->interfaceName) : sizeof (dc[i]->interfaceName));
- #endif
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_COMMON);
- if (flow->protocol != IPPROTO_ICMP && flow->protocol != IPPROTO_ICMPV6) {
- dtr[i] = (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT *) &packet[offset];
- dtr[i]->sourceTransportPort = flow->port[i];
- dtr[i]->destinationTransportPort = flow->port[i ^ 1];
- dtr[i]->protocolIdentifier = flow->protocol;
- dtr[i]->tcpControlBits = flow->tcp_flags[i];
- dtr[i]->ipClassOfService = flow->tos[i];
- dtr[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6;
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_TRANSPORT);
- } else {
- di[i] = (struct IPFIX_SOFTFLOWD_DATA_ICMP *) &packet[offset];
- di[i]->icmpTypeCode = flow->port[i ^ 1];
- di[i]->protocolIdentifier = flow->protocol;
- di[i]->ipClassOfService = flow->tos[i];
- di[i]->ipVersion = (flow->af == AF_INET) ? 4 : 6;
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ICMP);
- }
- if (param->track_level >= TRACK_FULL_VLAN) {
- dv[i] = (struct IPFIX_SOFTFLOWD_DATA_VLAN *) &packet[offset];
- dv[i]->vlanId = htons (flow->vlanid[i]);
- dv[i]->postVlanId = htons (flow->vlanid[i ^ 1]);
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_VLAN);
- }
- if (param->track_level >= TRACK_FULL_VLAN_ETHER) {
- de[i] = (struct IPFIX_SOFTFLOWD_DATA_ETHER *) &packet[offset];
- memcpy (&de[i]->sourceMacAddress, &flow->ethermac[i], 6);
- memcpy (&de[i]->destinationMacAddress, &flow->ethermac[i ^ 1], 6);
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_ETHER);
- }
- if (bi_flag && i == 0) {
- dbc = (struct IPFIX_SOFTFLOWD_DATA_BICOMMON *) &packet[offset];
- dbc->octetDeltaCount = htonl (flow->octets[1]);
- dbc->packetDeltaCount = htonl (flow->packets[1]);
- dbc->ipClassOfService = flow->tos[1];
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BICOMMON);
- if (flow->protocol != IPPROTO_ICMP && flow->protocol != IPPROTO_ICMPV6) {
- dbtr = (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT *)
- &packet[offset];
- dbtr->tcpControlBits = flow->tcp_flags[1];
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BITRANSPORT);
- } else {
- dbi = (struct IPFIX_SOFTFLOWD_DATA_BIICMP *)
- &packet[offset];
- dbi->icmpTypeCode = flow->port[1];
- offset += sizeof (struct IPFIX_SOFTFLOWD_DATA_BIICMP);
- }
- }
- for (k = 0; k < param->max_num_label; k++) {
- memcpy (&packet[offset], &flow->mplsLabels[k],
- IPFIX_mplsLabelStackSection_SIZE);
- offset += IPFIX_mplsLabelStackSection_SIZE;
- }
- }
- *len_used = offset;
- return (nflows);
- }
- static int
- valuate_icmp (struct FLOW *flow) {
- if (flow == NULL)
- return -1;
- if (flow->af == AF_INET)
- if (flow->protocol == IPPROTO_ICMP)
- return 1;
- else
- return 0;
- else if (flow->af == AF_INET6)
- if (flow->protocol == IPPROTO_ICMPV6)
- return 1;
- else
- return 0;
- else
- return -1;
- return -1;
- }
- void
- ipfix_resend_template (void) {
- if (ipfix_pkts_until_template > 0)
- ipfix_pkts_until_template = 0;
- }
- void
- memcpy_template (u_char * packet, u_int * offset,
- struct IPFIX_SOFTFLOWD_TEMPLATE *template, u_int8_t bi_flag,
- u_int8_t max_num_label) {
- int i = 0;
- int size = ntohs (template->h.c.length) -
- template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER) -
- max_num_label * sizeof (struct IPFIX_FIELD_SPECIFIER);
- memcpy (packet + *offset, template, size);
- *offset += size;
- if (bi_flag) {
- size = template->bi_count * sizeof (struct IPFIX_VENDOR_FIELD_SPECIFIER);
- memcpy (packet + *offset, template->v, size);
- *offset += size;
- }
- // mpls
- for (i = 0; i < max_num_label; i++) {
- struct IPFIX_FIELD_SPECIFIER *mpls_fs =
- (struct IPFIX_FIELD_SPECIFIER *) &packet[*offset];
- mpls_fs->ie = htons (IPFIX_mplsTopLabelStackSection + i);
- mpls_fs->length = htons (IPFIX_mplsLabelStackSection_SIZE);
- *offset += sizeof (struct IPFIX_FIELD_SPECIFIER);
- }
- }
- /*
- * Given an array of expired flows, send ipfix report packets
- * Returns number of packets sent or -1 on error
- */
- static int
- send_ipfix_common (struct FLOW **flows, int num_flows,
- struct NETFLOW_TARGET *target,
- u_int16_t ifidx, struct FLOWTRACKPARAMETERS *param,
- int verbose_flag, u_int8_t bi_flag, u_int16_t version) {
- struct IPFIX_HEADER *ipfix;
- struct NFLOW9_HEADER *nf9;
- struct IPFIX_SET_HEADER *dh;
- struct timeval now;
- u_int offset, last_af, i, j, num_packets, inc, last_valid, tmplindex;
- int8_t icmp_flag, last_icmp_flag;
- int 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;
- static u_int sequence = 1;
- if (version != 9 && version != 10)
- return (-1);
- if (param->adjust_time)
- now = param->last_packet_time;
- else
- gettimeofday (&now, NULL);
- if (ipfix_pkts_until_template == -1) {
- ipfix_init_template (param, bi_flag, version);
- ipfix_pkts_until_template = 0;
- if (option != NULL) {
- if (version == 10) {
- ipfix_init_option (system_boot_time, option);
- } else {
- nflow9_init_option (ifidx, option);
- }
- }
- }
- last_valid = num_packets = 0;
- for (j = 0; j < num_flows;) {
- memset (packet, 0, sizeof (packet));
- if (version == 10) {
- ipfix = (struct IPFIX_HEADER *) packet;
- ipfix->version = htons (version);
- ipfix->length = 0; /* Filled as we go, htons at end */
- if (param->adjust_time)
- ipfix->export_time = htonl (now.tv_sec);
- else
- ipfix->export_time = htonl (time (NULL));
- ipfix->od_id = 0;
- offset = sizeof (*ipfix);
- } else if (version == 9) {
- nf9 = (struct NFLOW9_HEADER *) packet;
- nf9->version = htons (version);
- nf9->flows = 0; /* Filled as we go, htons at end */
- nf9->uptime_ms = htonl (timeval_sub_ms (&now, system_boot_time));
- if (param->adjust_time)
- nf9->export_time = htonl (now.tv_sec);
- else
- nf9->export_time = htonl (time (NULL));
- nf9->od_id = 0;
- offset = sizeof (*nf9);
- }
- /* Refresh template headers if we need to */
- if (ipfix_pkts_until_template <= 0) {
- for (i = 0; i < TMPLMAX; i++) {
- memcpy_template (packet, &offset, &templates[i], bi_flag,
- param->max_num_label);
- }
- if (option != NULL) {
- u_int16_t opt_tmpl_len = ntohs (option_template.h.c.length);
- memcpy (packet + offset, &option_template, opt_tmpl_len);
- offset += opt_tmpl_len;
- if (version == 10) {
- memcpy (packet + offset, &option_data, sizeof (option_data));
- offset += sizeof (option_data);
- } else if (version == 9) {
- memcpy (packet + offset, &nf9opt_data, sizeof (nf9opt_data));
- offset += sizeof (nf9opt_data);
- }
- }
- ipfix_pkts_until_template = IPFIX_DEFAULT_TEMPLATE_INTERVAL;
- if (target->is_loadbalance && target->num_destinations > 1) {
- if (version == 10) {
- ipfix->length = htons (offset);
- ipfix->sequence =
- htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
- } else if (version == 9) {
- nf9->flows = htons (records);
- nf9->sequence = htonl (sequence++);
- }
- if (send_multi_destinations
- (target->num_destinations, target->destinations, 0, packet,
- offset) < 0)
- return (-1);
- offset = version == 10 ? sizeof (*ipfix) : sizeof (*nf9); // resest offset
- }
- }
- dh = NULL;
- last_af = 0;
- last_icmp_flag = -1;
- records = 0;
- for (i = 0; i + j < num_flows; i++) {
- icmp_flag = valuate_icmp (flows[i + j]);
- if (dh == NULL || flows[i + j]->af != last_af ||
- icmp_flag != last_icmp_flag) {
- 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);
- tmplindex = ipfix_flow_to_template_index (flows[i + j]);
- dh->set_id = templates[tmplindex].h.r.template_id;
- last_af = flows[i + j]->af;
- last_icmp_flag = icmp_flag;
- last_valid = offset;
- dh->length = sizeof (*dh); /* Filled as we go */
- offset += sizeof (*dh);
- }
- r = ipfix_flow_to_flowset (flows[i + j],
- packet + offset,
- sizeof (packet) - offset,
- ifidx, system_boot_time,
- &inc, param, bi_flag);
- 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);
- }
- *records_sent += records;
- if (version == 10) {
- ipfix->length = htons (offset);
- ipfix->sequence =
- htonl ((u_int32_t) (*records_sent & 0x00000000ffffffff));
- } else if (version == 9) {
- nf9->flows = htons (records);
- nf9->sequence = htonl (sequence++);
- }
- if (verbose_flag)
- logit (LOG_DEBUG, "Sending flow packet len = %d", offset);
- if (send_multi_destinations
- (target->num_destinations, target->destinations,
- target->is_loadbalance, packet, offset) < 0)
- return (-1);
- num_packets++;
- ipfix_pkts_until_template--;
- j += i;
- }
- *flows_exported += j;
- param->packets_sent += num_packets;
- #ifdef ENABLE_PTHREAD
- if (use_thread)
- free (flows);
- #endif /* ENABLE_PTHREAD */
- return (num_packets);
- }
- int
- send_nflow9 (struct SENDPARAMETER sp) {
- return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx,
- sp.param, sp.verbose_flag, 0, 9);
- }
- int
- send_ipfix (struct SENDPARAMETER sp) {
- return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx,
- sp.param, sp.verbose_flag, 0, 10);
- }
- int
- send_ipfix_bi (struct SENDPARAMETER sp) {
- return send_ipfix_common (sp.flows, sp.num_flows, sp.target, sp.ifidx,
- sp.param, sp.verbose_flag, 1, 10);
- }
|