ipfix-export: refactor fields in flow_report_main 11/34011/3
authorPaul Atkins <patkins@graphiant.com>
Tue, 21 Sep 2021 19:49:12 +0000 (20:49 +0100)
committerNeale Ranns <neale@graphiant.com>
Mon, 22 Nov 2021 09:30:09 +0000 (09:30 +0000)
Pull out the fields in flow_report_main_t that are specific to a single
exporter and move them into a new structure that represents an exporter.
Add a pool of exporters to flow_report_main_t and do a pool_get() to get
the entry at index 0, so that the existing users of the code need only
change the path at which they access the old fields and have no need to
make further code changes.  In functions that were accessing the fields
that now make up the ipfix_exporter create a local var that points to the
first (always valid) exporter and use this as the base for the fields
rather than finding them from flow_report_main.

This is in preparation for supporting multiple flow_exporters.

Note that at the moment the code supports multiple 'streams' for a given
exporter, where each stream has its own source port, domain id and template
space. But all streams within an exporter have the same destination address,
so this is not the same as multiple exporters.

Type: refactor
Signed-off-by: Paul Atkins <patkins@graphiant.com>
Change-Id: I49f5c7fb9e901773351d31dc8a59178c37e99301

src/plugins/flowprobe/flowprobe.c
src/plugins/flowprobe/node.c
src/plugins/ioam/analyse/ioam_summary_export.c
src/plugins/ioam/udp-ping/udp_ping_export.c
src/plugins/nat/lib/ipfix_logging.c
src/vnet/ipfix-export/flow_api.c
src/vnet/ipfix-export/flow_report.c
src/vnet/ipfix-export/flow_report.h
src/vnet/ipfix-export/flow_report_classify.c

index ffc43bc..ff49b0b 100644 (file)
@@ -223,8 +223,9 @@ flowprobe_template_rewrite_inline (flow_report_main_t * frm,
   flowprobe_main_t *fm = &flowprobe_main;
   flowprobe_record_t flags = fr->opaque.as_uword;
   bool collect_ip4 = false, collect_ip6 = false;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
 
   if (flags & FLOW_RECORD_L3)
     {
index fd5d60f..611ce62 100644 (file)
@@ -533,6 +533,7 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
 {
   flowprobe_main_t *fm = &flowprobe_main;
   flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
   vlib_frame_t *f;
   ip4_ipfix_template_packet_t *tp;
   ipfix_set_header_t *s;
@@ -550,19 +551,19 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
       flowprobe_get_headersize ())
     return;
 
-  u32 i, index = vec_len (frm->streams);
+  u32 i, index = vec_len (exp->streams);
   for (i = 0; i < index; i++)
-    if (frm->streams[i].domain_id == 1)
+    if (exp->streams[i].domain_id == 1)
       {
        index = i;
        break;
       }
-  if (i == vec_len (frm->streams))
+  if (i == vec_len (exp->streams))
     {
-      vec_validate (frm->streams, index);
-      frm->streams[index].domain_id = 1;
+      vec_validate (exp->streams, index);
+      exp->streams[index].domain_id = 1;
     }
-  stream = &frm->streams[index];
+  stream = &exp->streams[index];
 
   tp = vlib_buffer_get_current (b0);
   ip = (ip4_header_t *) & tp->ip4;
@@ -574,10 +575,10 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
   ip->ttl = 254;
   ip->protocol = IP_PROTOCOL_UDP;
   ip->flags_and_fragment_offset = 0;
-  ip->src_address.as_u32 = frm->src_address.as_u32;
-  ip->dst_address.as_u32 = frm->ipfix_collector.as_u32;
+  ip->src_address.as_u32 = exp->src_address.as_u32;
+  ip->dst_address.as_u32 = exp->ipfix_collector.as_u32;
   udp->src_port = clib_host_to_net_u16 (stream->src_port);
-  udp->dst_port = clib_host_to_net_u16 (frm->collector_port);
+  udp->dst_port = clib_host_to_net_u16 (exp->collector_port);
   udp->checksum = 0;
 
   /* FIXUP: message header export_time */
@@ -603,7 +604,7 @@ flowprobe_export_send (vlib_main_t * vm, vlib_buffer_t * b0,
   ip->checksum = ip4_header_checksum (ip);
   udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
 
-  if (frm->udp_checksum)
+  if (exp->udp_checksum)
     {
       /* RFC 7011 section 10.3.2. */
       udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
@@ -642,7 +643,7 @@ static vlib_buffer_t *
 flowprobe_get_buffer (vlib_main_t * vm, flowprobe_variant_t which)
 {
   flowprobe_main_t *fm = &flowprobe_main;
-  flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
   vlib_buffer_t *b0;
   u32 bi0;
   u32 my_cpu_number = vm->thread_index;
@@ -669,7 +670,7 @@ flowprobe_get_buffer (vlib_main_t * vm, flowprobe_variant_t which)
       b0->flags |=
        (VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_FLOW_REPORT);
       vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
-      vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index;
+      vnet_buffer (b0)->sw_if_index[VLIB_TX] = exp->fib_index;
       fm->context[which].next_record_offset_per_worker[my_cpu_number] =
        b0->current_length;
     }
@@ -682,7 +683,7 @@ flowprobe_export_entry (vlib_main_t * vm, flowprobe_entry_t * e)
 {
   u32 my_cpu_number = vm->thread_index;
   flowprobe_main_t *fm = &flowprobe_main;
-  flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
   vlib_buffer_t *b0;
   bool collect_ip4 = false, collect_ip6 = false;
   flowprobe_variant_t which = e->key.which;
@@ -724,7 +725,7 @@ flowprobe_export_entry (vlib_main_t * vm, flowprobe_entry_t * e)
 
   fm->context[which].next_record_offset_per_worker[my_cpu_number] = offset;
   /* Time to flush the buffer? */
-  if (offset + fm->template_size[flags] > frm->path_mtu)
+  if (offset + fm->template_size[flags] > exp->path_mtu)
     flowprobe_export_send (vm, b0, which);
 }
 
@@ -935,14 +936,14 @@ flowprobe_walker_process (vlib_main_t * vm,
                          vlib_node_runtime_t * rt, vlib_frame_t * f)
 {
   flowprobe_main_t *fm = &flowprobe_main;
-  flow_report_main_t *frm = &flow_report_main;
   flowprobe_entry_t *e;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
 
   /*
    * $$$$ Remove this check from here and track FRM status and disable
    * this process if required.
    */
-  if (frm->ipfix_collector.as_u32 == 0 || frm->src_address.as_u32 == 0)
+  if (exp->ipfix_collector.as_u32 == 0 || exp->src_address.as_u32 == 0)
     {
       fm->disabled = true;
       return 0;
index 032272f..141c03a 100644 (file)
@@ -38,8 +38,9 @@ ioam_template_rewrite (flow_report_main_t * frm, flow_report_t * fr,
   u32 field_count = 0;
   u32 field_index = 0;
   flow_report_stream_t *stream;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
 
   /* Determine field count */
 #define _(field,mask,item,length)                                   \
@@ -285,8 +286,9 @@ ioam_send_flows (flow_report_main_t * frm, flow_report_t * fr,
   flow_report_stream_t *stream;
   ioam_analyser_data_t *aggregated_data;
   u16 data_len;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
 
   clib_memset (&temp, 0, sizeof (ip6_address_t));
 
@@ -339,7 +341,7 @@ ioam_send_flows (flow_report_main_t * frm, flow_report_t * fr,
        records_this_buffer++;
 
        /* Flush data if packet len is about to reach path mtu */
-       if (next_offset > (frm->path_mtu - 250))
+       if (next_offset > (exp->path_mtu - 250))
          flush = 1;
       }
 
@@ -366,7 +368,7 @@ ioam_send_flows (flow_report_main_t * frm, flow_report_t * fr,
        udp->length =
          clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
 
-       if (frm->udp_checksum)
+       if (exp->udp_checksum)
          {
            /* RFC 7011 section 10.3.2. */
            udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
index 3e83598..84d8ddf 100644 (file)
@@ -56,8 +56,9 @@ udp_ping_send_flows (flow_report_main_t * frm, flow_report_t * fr,
   ip46_udp_ping_flow *ip46_flow;
   u16 src_port, dst_port;
   u16 data_len;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
   data_len = vec_len (udp_ping_main.ip46_flow);
 
   for (i = 0; i < data_len; i++)
@@ -120,7 +121,7 @@ udp_ping_send_flows (flow_report_main_t * frm, flow_report_t * fr,
              records_this_buffer++;
 
              /* Flush data if packet len is about to reach path mtu */
-             if (next_offset > (frm->path_mtu - UDP_PING_EXPORT_RECORD_SIZE))
+             if (next_offset > (exp->path_mtu - UDP_PING_EXPORT_RECORD_SIZE))
                {
                  b0->current_length = next_offset;
                  b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
index 27a0b92..9bdb50d 100644 (file)
@@ -163,8 +163,9 @@ nat_template_rewrite (flow_report_main_t * frm,
   u32 field_count = 0;
   flow_report_stream_t *stream;
   u32 stream_index;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
 
   stream_index = clib_atomic_fetch_or(&silm->stream_index, 0);
   clib_atomic_cmp_and_swap (&silm->stream_index,
@@ -497,16 +498,17 @@ nat_ipfix_header_create (flow_report_main_t * frm,
   ip4_header_t *ip;
   udp_header_t *udp;
   vlib_main_t *vm = vlib_get_main ();
-  
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
+
   stream_index = clib_atomic_fetch_or(&silm->stream_index, 0);
-  stream = &frm->streams[stream_index];
+  stream = &exp->streams[stream_index];
 
   b0->current_data = 0;
   b0->current_length = sizeof (*ip) + sizeof (*udp) + sizeof (*h) +
     sizeof (*s);
   b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_FLOW_REPORT);
   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
-  vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index;
+  vnet_buffer (b0)->sw_if_index[VLIB_TX] = exp->fib_index;
   tp = vlib_buffer_get_current (b0);
   ip = (ip4_header_t *) & tp->ip4;
   udp = (udp_header_t *) (ip + 1);
@@ -517,10 +519,10 @@ nat_ipfix_header_create (flow_report_main_t * frm,
   ip->ttl = 254;
   ip->protocol = IP_PROTOCOL_UDP;
   ip->flags_and_fragment_offset = 0;
-  ip->src_address.as_u32 = frm->src_address.as_u32;
-  ip->dst_address.as_u32 = frm->ipfix_collector.as_u32;
+  ip->src_address.as_u32 = exp->src_address.as_u32;
+  ip->dst_address.as_u32 = exp->ipfix_collector.as_u32;
   udp->src_port = clib_host_to_net_u16 (stream->src_port);
-  udp->dst_port = clib_host_to_net_u16 (frm->collector_port);
+  udp->dst_port = clib_host_to_net_u16 (exp->collector_port);
   udp->checksum = 0;
 
   h->export_time = clib_host_to_net_u32 ((u32)
@@ -545,6 +547,7 @@ nat_ipfix_send (flow_report_main_t *frm, vlib_frame_t *f, vlib_buffer_t *b0,
   ip4_header_t *ip;
   udp_header_t *udp;
   vlib_main_t *vm = vlib_get_main ();
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   tp = vlib_buffer_get_current (b0);
   ip = (ip4_header_t *) & tp->ip4;
@@ -563,7 +566,7 @@ nat_ipfix_send (flow_report_main_t *frm, vlib_frame_t *f, vlib_buffer_t *b0,
   ip->checksum = ip4_header_checksum (ip);
   udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
 
-  if (frm->udp_checksum)
+  if (exp->udp_checksum)
     {
       udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
       if (udp->checksum == 0)
@@ -591,6 +594,7 @@ nat_ipfix_logging_nat44_ses (u32 thread_index, u8 nat_event, u32 src_ip,
   u64 now;
   u16 template_id;
   u32 vrf_id;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
   now += silm->milisecond_time_0;
@@ -663,8 +667,8 @@ nat_ipfix_logging_nat44_ses (u32 thread_index, u8 nat_event, u32 src_ip,
       b0->current_length += NAT44_SESSION_CREATE_LEN;
     }
 
-  if (PREDICT_FALSE
-      (do_flush || (offset + NAT44_SESSION_CREATE_LEN) > frm->path_mtu))
+  if (PREDICT_FALSE (do_flush ||
+                    (offset + NAT44_SESSION_CREATE_LEN) > exp->path_mtu))
     {
       template_id = clib_atomic_fetch_or (
         &silm->nat44_session_template_id,
@@ -691,6 +695,7 @@ nat_ipfix_logging_addr_exhausted (u32 thread_index, u32 pool_id, int do_flush)
   u64 now;
   u8 nat_event = NAT_ADDRESSES_EXHAUTED;
   u16 template_id;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
   now += silm->milisecond_time_0;
@@ -746,8 +751,8 @@ nat_ipfix_logging_addr_exhausted (u32 thread_index, u32 pool_id, int do_flush)
       b0->current_length += NAT_ADDRESSES_EXHAUTED_LEN;
     }
 
-  if (PREDICT_FALSE
-      (do_flush || (offset + NAT_ADDRESSES_EXHAUTED_LEN) > frm->path_mtu))
+  if (PREDICT_FALSE (do_flush ||
+                    (offset + NAT_ADDRESSES_EXHAUTED_LEN) > exp->path_mtu))
     {
       template_id = clib_atomic_fetch_or (
           &silm->addr_exhausted_template_id,
@@ -776,6 +781,7 @@ nat_ipfix_logging_max_entries_per_usr (u32 thread_index,
   u8 nat_event = QUOTA_EXCEEDED;
   u32 quota_event = clib_host_to_net_u32 (MAX_ENTRIES_PER_USER);
   u16 template_id;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
   now += silm->milisecond_time_0;
@@ -838,8 +844,8 @@ nat_ipfix_logging_max_entries_per_usr (u32 thread_index,
       b0->current_length += MAX_ENTRIES_PER_USER_LEN;
     }
 
-  if (PREDICT_FALSE
-      (do_flush || (offset + MAX_ENTRIES_PER_USER_LEN) > frm->path_mtu))
+  if (PREDICT_FALSE (do_flush ||
+                    (offset + MAX_ENTRIES_PER_USER_LEN) > exp->path_mtu))
     {
       template_id = clib_atomic_fetch_or (
           &silm->max_entries_per_user_template_id,
@@ -867,6 +873,7 @@ nat_ipfix_logging_max_ses (u32 thread_index, u32 limit, int do_flush)
   u8 nat_event = QUOTA_EXCEEDED;
   u32 quota_event = clib_host_to_net_u32 (MAX_SESSION_ENTRIES);
   u16 template_id;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
   now += silm->milisecond_time_0;
@@ -926,8 +933,7 @@ nat_ipfix_logging_max_ses (u32 thread_index, u32 limit, int do_flush)
       b0->current_length += MAX_SESSIONS_LEN;
     }
 
-  if (PREDICT_FALSE
-      (do_flush || (offset + MAX_SESSIONS_LEN) > frm->path_mtu))
+  if (PREDICT_FALSE (do_flush || (offset + MAX_SESSIONS_LEN) > exp->path_mtu))
     {
       template_id = clib_atomic_fetch_or (
         &silm->max_sessions_template_id,
@@ -955,6 +961,7 @@ nat_ipfix_logging_max_bib (u32 thread_index, u32 limit, int do_flush)
   u8 nat_event = QUOTA_EXCEEDED;
   u32 quota_event = clib_host_to_net_u32 (MAX_BIB_ENTRIES);
   u16 template_id;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
   now += silm->milisecond_time_0;
@@ -1014,8 +1021,7 @@ nat_ipfix_logging_max_bib (u32 thread_index, u32 limit, int do_flush)
       b0->current_length += MAX_BIBS_LEN;
     }
 
-  if (PREDICT_FALSE
-      (do_flush || (offset + MAX_BIBS_LEN) > frm->path_mtu))
+  if (PREDICT_FALSE (do_flush || (offset + MAX_BIBS_LEN) > exp->path_mtu))
     {
       template_id = clib_atomic_fetch_or (
         &silm->max_bibs_template_id,
@@ -1044,6 +1050,7 @@ nat_ipfix_logging_nat64_bibe (u32 thread_index, u8 nat_event,
   vlib_main_t *vm = vlib_get_main ();
   u64 now;
   u16 template_id;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
   now += silm->milisecond_time_0;
@@ -1115,8 +1122,7 @@ nat_ipfix_logging_nat64_bibe (u32 thread_index, u8 nat_event,
       b0->current_length += NAT64_BIB_LEN;
     }
 
-  if (PREDICT_FALSE
-      (do_flush || (offset + NAT64_BIB_LEN) > frm->path_mtu))
+  if (PREDICT_FALSE (do_flush || (offset + NAT64_BIB_LEN) > exp->path_mtu))
     {
       template_id = clib_atomic_fetch_or (
         &silm->nat64_bib_template_id,
@@ -1147,6 +1153,7 @@ nat_ipfix_logging_nat64_ses (u32 thread_index, u8 nat_event,
   vlib_main_t *vm = vlib_get_main ();
   u64 now;
   u16 template_id;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   now = (u64) ((vlib_time_now (vm) - silm->vlib_time_0) * 1e3);
   now += silm->milisecond_time_0;
@@ -1230,8 +1237,7 @@ nat_ipfix_logging_nat64_ses (u32 thread_index, u8 nat_event,
       b0->current_length += NAT64_SES_LEN;
     }
 
-  if (PREDICT_FALSE
-      (do_flush || (offset + NAT64_SES_LEN) > frm->path_mtu))
+  if (PREDICT_FALSE (do_flush || (offset + NAT64_SES_LEN) > exp->path_mtu))
     {
       template_id = clib_atomic_fetch_or (
         &silm->nat64_ses_template_id,
@@ -1477,8 +1483,9 @@ data_callback (flow_report_main_t * frm, flow_report_t * fr,
                vlib_frame_t * f, u32 * to_next, u32 node_index)
 {
   nat_ipfix_logging_main_t *silm = &nat_ipfix_logging_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  if (PREDICT_FALSE (++silm->call_counter >= vec_len (frm->reports)))
+  if (PREDICT_FALSE (++silm->call_counter >= vec_len (exp->reports)))
     {
       nat_ipfix_flush_from_main();
       silm->call_counter = 0;
index deee9d6..7e4f1fe 100644 (file)
@@ -41,6 +41,7 @@ vl_api_set_ipfix_exporter_t_handler (vl_api_set_ipfix_exporter_t * mp)
 {
   vlib_main_t *vm = vlib_get_main ();
   flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
   vl_api_registration_t *reg;
   vl_api_set_ipfix_exporter_reply_t *rmp;
   ip4_address_t collector, src;
@@ -113,18 +114,18 @@ vl_api_set_ipfix_exporter_t_handler (vl_api_set_ipfix_exporter_t * mp)
     }
 
   /* Reset report streams if we are reconfiguring IP addresses */
-  if (frm->ipfix_collector.as_u32 != collector.as_u32 ||
-      frm->src_address.as_u32 != src.as_u32 ||
-      frm->collector_port != collector_port)
+  if (exp->ipfix_collector.as_u32 != collector.as_u32 ||
+      exp->src_address.as_u32 != src.as_u32 ||
+      exp->collector_port != collector_port)
     vnet_flow_reports_reset (frm);
 
-  frm->ipfix_collector.as_u32 = collector.as_u32;
-  frm->collector_port = collector_port;
-  frm->src_address.as_u32 = src.as_u32;
-  frm->fib_index = fib_index;
-  frm->path_mtu = path_mtu;
-  frm->template_interval = template_interval;
-  frm->udp_checksum = udp_checksum;
+  exp->ipfix_collector.as_u32 = collector.as_u32;
+  exp->collector_port = collector_port;
+  exp->src_address.as_u32 = src.as_u32;
+  exp->fib_index = fib_index;
+  exp->path_mtu = path_mtu;
+  exp->template_interval = template_interval;
+  exp->udp_checksum = udp_checksum;
 
   /* Turn on the flow reporting process */
   vlib_process_signal_event (vm, flow_report_process_node.index, 1, 0);
@@ -137,6 +138,7 @@ static void
 vl_api_ipfix_exporter_dump_t_handler (vl_api_ipfix_exporter_dump_t * mp)
 {
   flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
   vl_api_registration_t *reg;
   vl_api_ipfix_exporter_details_t *rmp;
   ip4_main_t *im = &ip4_main;
@@ -154,22 +156,22 @@ vl_api_ipfix_exporter_dump_t_handler (vl_api_ipfix_exporter_dump_t * mp)
     ntohs ((REPLY_MSG_ID_BASE) + VL_API_IPFIX_EXPORTER_DETAILS);
   rmp->context = mp->context;
 
-  memcpy (&collector.ip4, &frm->ipfix_collector, sizeof (ip4_address_t));
+  memcpy (&collector.ip4, &exp->ipfix_collector, sizeof (ip4_address_t));
   ip_address_encode (&collector, IP46_TYPE_IP4, &rmp->collector_address);
 
-  rmp->collector_port = htons (frm->collector_port);
+  rmp->collector_port = htons (exp->collector_port);
 
-  memcpy (&src.ip4, &frm->src_address, sizeof (ip4_address_t));
+  memcpy (&src.ip4, &exp->src_address, sizeof (ip4_address_t));
   ip_address_encode (&src, IP46_TYPE_IP4, &rmp->src_address);
 
-  if (frm->fib_index == ~0)
+  if (exp->fib_index == ~0)
     vrf_id = ~0;
   else
-    vrf_id = im->fibs[frm->fib_index].ft_table_id;
+    vrf_id = im->fibs[exp->fib_index].ft_table_id;
   rmp->vrf_id = htonl (vrf_id);
-  rmp->path_mtu = htonl (frm->path_mtu);
-  rmp->template_interval = htonl (frm->template_interval);
-  rmp->udp_checksum = (frm->udp_checksum != 0);
+  rmp->path_mtu = htonl (exp->path_mtu);
+  rmp->template_interval = htonl (exp->template_interval);
+  rmp->udp_checksum = (exp->udp_checksum != 0);
 
   vl_api_send_msg (reg, (u8 *) rmp);
 }
index 8583932..a28f783 100644 (file)
@@ -24,43 +24,45 @@ flow_report_main_t flow_report_main;
 static_always_inline u8
 stream_index_valid (u32 index)
 {
-  flow_report_main_t *frm = &flow_report_main;
-  return index < vec_len (frm->streams) &&
-    frm->streams[index].domain_id != ~0;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
+
+  return index < vec_len (exp->streams) && exp->streams[index].domain_id != ~0;
 }
 
 static_always_inline flow_report_stream_t *
 add_stream (void)
 {
-  flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
+
   u32 i;
-  for (i = 0; i < vec_len (frm->streams); i++)
+  for (i = 0; i < vec_len (exp->streams); i++)
     if (!stream_index_valid (i))
-      return &frm->streams[i];
-  u32 index = vec_len (frm->streams);
-  vec_validate (frm->streams, index);
-  return &frm->streams[index];
+      return &exp->streams[i];
+  u32 index = vec_len (exp->streams);
+  vec_validate (exp->streams, index);
+  return &exp->streams[index];
 }
 
 static_always_inline void
 delete_stream (u32 index)
 {
-  flow_report_main_t *frm = &flow_report_main;
-  ASSERT (index < vec_len (frm->streams));
-  ASSERT (frm->streams[index].domain_id != ~0);
-  frm->streams[index].domain_id = ~0;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
+
+  ASSERT (index < vec_len (exp->streams));
+  ASSERT (exp->streams[index].domain_id != ~0);
+  exp->streams[index].domain_id = ~0;
 }
 
 static i32
 find_stream (u32 domain_id, u16 src_port)
 {
-  flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp = pool_elt_at_index (flow_report_main.exporters, 0);
   flow_report_stream_t *stream;
   u32 i;
-  for (i = 0; i < vec_len (frm->streams); i++)
+  for (i = 0; i < vec_len (exp->streams); i++)
     if (stream_index_valid (i))
       {
-       stream = &frm->streams[i];
+       stream = &exp->streams[i];
        if (domain_id == stream->domain_id)
          {
            if (src_port != stream->src_port)
@@ -87,12 +89,13 @@ send_template_packet (flow_report_main_t * frm,
   udp_header_t *udp;
   vlib_main_t *vm = frm->vlib_main;
   flow_report_stream_t *stream;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   ASSERT (buffer_indexp);
 
   if (fr->update_rewrite || fr->rewrite == 0)
     {
-      if (frm->ipfix_collector.as_u32 == 0 || frm->src_address.as_u32 == 0)
+      if (exp->ipfix_collector.as_u32 == 0 || exp->src_address.as_u32 == 0)
        {
          vlib_node_set_state (frm->vlib_main, flow_report_process_node.index,
                               VLIB_NODE_STATE_DISABLED);
@@ -104,13 +107,9 @@ send_template_packet (flow_report_main_t * frm,
 
   if (fr->update_rewrite)
     {
-      fr->rewrite = fr->rewrite_callback (frm, fr,
-                                         &frm->ipfix_collector,
-                                         &frm->src_address,
-                                         frm->collector_port,
-                                         fr->report_elements,
-                                         fr->n_report_elements,
-                                         fr->stream_indexp);
+      fr->rewrite = fr->rewrite_callback (
+       frm, fr, &exp->ipfix_collector, &exp->src_address, exp->collector_port,
+       fr->report_elements, fr->n_report_elements, fr->stream_indexp);
       fr->update_rewrite = 0;
     }
 
@@ -126,7 +125,7 @@ send_template_packet (flow_report_main_t * frm,
   b0->current_length = vec_len (fr->rewrite);
   b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_FLOW_REPORT);
   vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
-  vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index;
+  vnet_buffer (b0)->sw_if_index[VLIB_TX] = exp->fib_index;
 
   tp = vlib_buffer_get_current (b0);
   ip = (ip4_header_t *) & tp->ip4;
@@ -139,7 +138,7 @@ send_template_packet (flow_report_main_t * frm,
      (vlib_time_now (frm->vlib_main) - frm->vlib_time_0));
   h->export_time = clib_host_to_net_u32 (h->export_time);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
 
   /* FIXUP: message header sequence_number. Templates do not increase it */
   h->sequence_number = clib_host_to_net_u32 (stream->sequence_number);
@@ -147,7 +146,7 @@ send_template_packet (flow_report_main_t * frm,
   /* FIXUP: udp length */
   udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
 
-  if (frm->udp_checksum)
+  if (exp->udp_checksum)
     {
       /* RFC 7011 section 10.3.2. */
       udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);
@@ -183,12 +182,13 @@ vnet_flow_rewrite_generic_callback (flow_report_main_t * frm,
   flow_report_stream_t *stream;
   int i;
   ipfix_report_element_t *ep;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   ASSERT (stream_indexp);
   ASSERT (n_elts);
   ASSERT (report_elts);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
   *stream_indexp = fr->stream_index;
 
   /* allocate rewrite space */
@@ -284,18 +284,19 @@ flow_report_process (vlib_main_t * vm,
       vlib_process_wait_for_event_or_clock (vm, wait_time);
       event_type = vlib_process_get_events (vm, &event_data);
       vec_reset_length (event_data);
+      ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
       /* 5s delay by default, possibly reduced by template intervals */
       wait_time = def_wait_time;
 
-      vec_foreach (fr, frm->reports)
+      vec_foreach (fr, exp->reports)
        {
          f64 next_template;
          now = vlib_time_now (vm);
 
          /* Need to send a template packet? */
          send_template =
-           now > (fr->last_template_sent + frm->template_interval);
+           now > (fr->last_template_sent + exp->template_interval);
          send_template += fr->last_template_sent == 0;
          template_bi = ~0;
          rv = 0;
@@ -308,7 +309,7 @@ flow_report_process (vlib_main_t * vm,
 
          /* decide if template should be sent sooner than current wait time */
          next_template =
-           (fr->last_template_sent + frm->template_interval) - now;
+           (fr->last_template_sent + exp->template_interval) - now;
          wait_time = clib_min (wait_time, next_template);
 
          nf = vlib_get_frame_to_node (vm, ip4_lookup_node_index);
@@ -350,6 +351,7 @@ vnet_flow_report_add_del (flow_report_main_t * frm,
   flow_report_t *fr;
   flow_report_stream_t *stream;
   u32 si;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   si = find_stream (a->domain_id, a->src_port);
   if (si == -2)
@@ -357,9 +359,9 @@ vnet_flow_report_add_del (flow_report_main_t * frm,
   if (si == -1 && a->is_add == 0)
     return VNET_API_ERROR_NO_SUCH_ENTRY;
 
-  for (i = 0; i < vec_len (frm->reports); i++)
+  for (i = 0; i < vec_len (exp->reports); i++)
     {
-      fr = vec_elt_at_index (frm->reports, i);
+      fr = vec_elt_at_index (exp->reports, i);
       if (fr->opaque.as_uword == a->opaque.as_uword
          && fr->rewrite_callback == a->rewrite_callback
          && fr->flow_data_callback == a->flow_data_callback)
@@ -375,8 +377,8 @@ vnet_flow_report_add_del (flow_report_main_t * frm,
     {
       if (found_index != ~0)
        {
-         vec_delete (frm->reports, 1, found_index);
-         stream = &frm->streams[si];
+         vec_delete (exp->reports, 1, found_index);
+         stream = &exp->streams[si];
          stream->n_reports--;
          if (stream->n_reports == 0)
            delete_stream (si);
@@ -395,14 +397,14 @@ vnet_flow_report_add_del (flow_report_main_t * frm,
       stream->src_port = a->src_port;
       stream->sequence_number = 0;
       stream->n_reports = 0;
-      si = stream - frm->streams;
+      si = stream - exp->streams;
     }
   else
-    stream = &frm->streams[si];
+    stream = &exp->streams[si];
 
   stream->n_reports++;
 
-  vec_add2 (frm->reports, fr, 1);
+  vec_add2 (exp->reports, fr, 1);
 
   fr->stream_index = si;
   fr->template_id = 256 + stream->next_template_no;
@@ -446,12 +448,13 @@ vnet_flow_reports_reset (flow_report_main_t * frm)
 {
   flow_report_t *fr;
   u32 i;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  for (i = 0; i < vec_len (frm->streams); i++)
+  for (i = 0; i < vec_len (exp->streams); i++)
     if (stream_index_valid (i))
-      frm->streams[i].sequence_number = 0;
+      exp->streams[i].sequence_number = 0;
 
-  vec_foreach (fr, frm->reports)
+  vec_foreach (fr, exp->reports)
     {
       fr->update_rewrite = 1;
       fr->last_template_sent = 0;
@@ -462,11 +465,12 @@ void
 vnet_stream_reset (flow_report_main_t * frm, u32 stream_index)
 {
   flow_report_t *fr;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  frm->streams[stream_index].sequence_number = 0;
+  exp->streams[stream_index].sequence_number = 0;
 
-  vec_foreach (fr, frm->reports)
-    if (frm->reports->stream_index == stream_index)
+  vec_foreach (fr, exp->reports)
+    if (exp->reports->stream_index == stream_index)
       {
        fr->update_rewrite = 1;
        fr->last_template_sent = 0;
@@ -478,10 +482,12 @@ vnet_stream_change (flow_report_main_t * frm,
                    u32 old_domain_id, u16 old_src_port,
                    u32 new_domain_id, u16 new_src_port)
 {
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
+
   i32 stream_index = find_stream (old_domain_id, old_src_port);
   if (stream_index < 0)
     return 1;
-  flow_report_stream_t *stream = &frm->streams[stream_index];
+  flow_report_stream_t *stream = &exp->streams[stream_index];
   stream->domain_id = new_domain_id;
   stream->src_port = new_src_port;
   if (old_domain_id != new_domain_id || old_src_port != new_src_port)
@@ -505,6 +511,7 @@ set_ipfix_exporter_command_fn (vlib_main_t * vm,
   u32 path_mtu = 512;          // RFC 7011 section 10.3.3.
   u32 template_interval = 20;
   u8 udp_checksum = 0;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -543,28 +550,28 @@ set_ipfix_exporter_command_fn (vlib_main_t * vm,
     return clib_error_return (0, "too small path-mtu value, minimum is 68");
 
   /* Reset report streams if we are reconfiguring IP addresses */
-  if (frm->ipfix_collector.as_u32 != collector.as_u32 ||
-      frm->src_address.as_u32 != src.as_u32 ||
-      frm->collector_port != collector_port)
+  if (exp->ipfix_collector.as_u32 != collector.as_u32 ||
+      exp->src_address.as_u32 != src.as_u32 ||
+      exp->collector_port != collector_port)
     vnet_flow_reports_reset (frm);
 
-  frm->ipfix_collector.as_u32 = collector.as_u32;
-  frm->collector_port = collector_port;
-  frm->src_address.as_u32 = src.as_u32;
-  frm->fib_index = fib_index;
-  frm->path_mtu = path_mtu;
-  frm->template_interval = template_interval;
-  frm->udp_checksum = udp_checksum;
+  exp->ipfix_collector.as_u32 = collector.as_u32;
+  exp->collector_port = collector_port;
+  exp->src_address.as_u32 = src.as_u32;
+  exp->fib_index = fib_index;
+  exp->path_mtu = path_mtu;
+  exp->template_interval = template_interval;
+  exp->udp_checksum = udp_checksum;
 
   if (collector.as_u32)
-    vlib_cli_output (vm, "Collector %U, src address %U, "
+    vlib_cli_output (vm,
+                    "Collector %U, src address %U, "
                     "fib index %d, path MTU %u, "
                     "template resend interval %us, "
                     "udp checksum %s",
-                    format_ip4_address, &frm->ipfix_collector,
-                    format_ip4_address, &frm->src_address,
-                    fib_index, path_mtu, template_interval,
-                    udp_checksum ? "enabled" : "disabled");
+                    format_ip4_address, exp->ipfix_collector,
+                    format_ip4_address, exp->src_address, fib_index, path_mtu,
+                    template_interval, udp_checksum ? "enabled" : "disabled");
   else
     vlib_cli_output (vm, "IPFIX Collector is disabled");
 
@@ -608,13 +615,21 @@ static clib_error_t *
 flow_report_init (vlib_main_t * vm)
 {
   flow_report_main_t *frm = &flow_report_main;
+  ipfix_exporter_t *exp;
 
   frm->vlib_main = vm;
   frm->vnet_main = vnet_get_main ();
   frm->unix_time_0 = time (0);
   frm->vlib_time_0 = vlib_time_now (frm->vlib_main);
-  frm->fib_index = ~0;
-
+  /*
+   * Make sure that we can always access the first exporter for
+   * backwards compatibility reasons.
+   */
+  pool_alloc (frm->exporters, IPFIX_EXPORTERS_MAX);
+  pool_get (frm->exporters, exp);
+  /* Verify that this is at index 0 */
+  ASSERT (frm->exporters == exp);
+  exp->fib_index = ~0;
   return 0;
 }
 
index 30df8a9..d1f3080 100644 (file)
@@ -107,7 +107,16 @@ typedef struct flow_report
   vnet_flow_data_callback_t *flow_data_callback;
 } flow_report_t;
 
-typedef struct flow_report_main
+/*
+ * The maximum number of ipfix exporters we can have at once
+ */
+#define IPFIX_EXPORTERS_MAX 5
+
+/*
+ * We support multiple exporters. Each one has its own configured
+ * destination, and its own set of reports and streams.
+ */
+typedef struct ipfix_exporter
 {
   flow_report_t *reports;
   flow_report_stream_t *streams;
@@ -126,6 +135,16 @@ typedef struct flow_report_main
 
   /* UDP checksum calculation enable flag */
   u8 udp_checksum;
+} ipfix_exporter_t;
+
+typedef struct flow_report_main
+{
+  /*
+   * A pool of the exporters. Entry 0 is always there for backwards
+   * compatability reasons. Entries 1 and above have to be created by
+   * the users.
+   */
+  ipfix_exporter_t *exporters;
 
   /* time scale transform. Joy. */
   u32 unix_time_0;
index 21b6411..35abf97 100644 (file)
@@ -60,8 +60,9 @@ ipfix_classify_template_rewrite (flow_report_main_t * frm,
   u8 transport_protocol;
   u8 *virt_mask;
   u8 *real_mask;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
 
   ipfix_classify_table_t *table = &fcm->tables[flow_table_index];
 
@@ -190,8 +191,9 @@ ipfix_classify_send_flows (flow_report_main_t * frm,
   u8 ip_version;
   u8 transport_protocol;
   u8 *virt_key;
+  ipfix_exporter_t *exp = pool_elt_at_index (frm->exporters, 0);
 
-  stream = &frm->streams[fr->stream_index];
+  stream = &exp->streams[fr->stream_index];
 
   ipfix_classify_table_t *table = &fcm->tables[flow_table_index];
 
@@ -233,7 +235,7 @@ ipfix_classify_send_flows (flow_report_main_t * frm,
                  b0->current_length = copy_len;
                  b0->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
                  vnet_buffer (b0)->sw_if_index[VLIB_RX] = 0;
-                 vnet_buffer (b0)->sw_if_index[VLIB_TX] = frm->fib_index;
+                 vnet_buffer (b0)->sw_if_index[VLIB_TX] = exp->fib_index;
 
                  tp = vlib_buffer_get_current (b0);
                  ip = (ip4_header_t *) & tp->ip4;
@@ -285,7 +287,7 @@ ipfix_classify_send_flows (flow_report_main_t * frm,
              u32 next_record_size = next_offset - record_offset;
              record_offset = next_offset;
 
-             if (next_offset + next_record_size > frm->path_mtu)
+             if (next_offset + next_record_size > exp->path_mtu)
                {
                  s->set_id_length = ipfix_set_id_length (fr->template_id,
                                                          next_offset -
@@ -314,7 +316,7 @@ ipfix_classify_send_flows (flow_report_main_t * frm,
                  udp->length =
                    clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
 
-                 if (frm->udp_checksum)
+                 if (exp->udp_checksum)
                    {
                      /* RFC 7011 section 10.3.2. */
                      udp->checksum =
@@ -370,7 +372,7 @@ flush:
       ip->length = new_l0;
       udp->length = clib_host_to_net_u16 (b0->current_length - sizeof (*ip));
 
-      if (frm->udp_checksum)
+      if (exp->udp_checksum)
        {
          /* RFC 7011 section 10.3.2. */
          udp->checksum = ip4_tcp_udp_compute_checksum (vm, b0, ip);