misc: ipfix process node wait time adjustment
[vpp.git] / src / vnet / ipfix-export / flow_report.c
index 793eeda..760de5f 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include <vnet/ipfix-export/flow_report.h>
 #include <vnet/api_errno.h>
+#include <vnet/udp/udp.h>
 
 flow_report_main_t flow_report_main;
 
@@ -86,7 +87,6 @@ send_template_packet (flow_report_main_t * frm,
   udp_header_t *udp;
   vlib_main_t *vm = frm->vlib_main;
   flow_report_stream_t *stream;
-  vlib_buffer_free_list_t *fl;
 
   ASSERT (buffer_indexp);
 
@@ -107,7 +107,10 @@ send_template_packet (flow_report_main_t * frm,
       fr->rewrite = fr->rewrite_callback (frm, fr,
                                          &frm->ipfix_collector,
                                          &frm->src_address,
-                                         frm->collector_port);
+                                         frm->collector_port,
+                                         fr->report_elements,
+                                         fr->n_report_elements,
+                                         fr->stream_indexp);
       fr->update_rewrite = 0;
     }
 
@@ -116,14 +119,9 @@ send_template_packet (flow_report_main_t * frm,
 
   b0 = vlib_get_buffer (vm, bi0);
 
-  /* Initialize the buffer */
-  fl = vlib_buffer_get_free_list (vm, VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
-  vlib_buffer_init_for_free_list (b0, fl);
-  VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
+  ASSERT (vec_len (fr->rewrite) < vlib_buffer_get_default_data_size (vm));
 
-  ASSERT (vec_len (fr->rewrite) < VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES);
-
-  clib_memcpy (b0->data, fr->rewrite, vec_len (fr->rewrite));
+  clib_memcpy_fast (b0->data, fr->rewrite, vec_len (fr->rewrite));
   b0->current_data = 0;
   b0->current_length = vec_len (fr->rewrite);
   b0->flags |= (VLIB_BUFFER_TOTAL_LENGTH_VALID | VNET_BUFFER_F_FLOW_REPORT);
@@ -164,6 +162,92 @@ send_template_packet (flow_report_main_t * frm,
   return 0;
 }
 
+u8 *
+vnet_flow_rewrite_generic_callback (flow_report_main_t * frm,
+                                   flow_report_t * fr,
+                                   ip4_address_t * collector_address,
+                                   ip4_address_t * src_address,
+                                   u16 collector_port,
+                                   ipfix_report_element_t * report_elts,
+                                   u32 n_elts, u32 * stream_indexp)
+{
+  ip4_header_t *ip;
+  udp_header_t *udp;
+  ipfix_message_header_t *h;
+  ipfix_set_header_t *s;
+  ipfix_template_header_t *t;
+  ipfix_field_specifier_t *f;
+  ipfix_field_specifier_t *first_field;
+  u8 *rewrite = 0;
+  ip4_ipfix_template_packet_t *tp;
+  flow_report_stream_t *stream;
+  int i;
+  ipfix_report_element_t *ep;
+
+  ASSERT (stream_indexp);
+  ASSERT (n_elts);
+  ASSERT (report_elts);
+
+  stream = &frm->streams[fr->stream_index];
+  *stream_indexp = fr->stream_index;
+
+  /* allocate rewrite space */
+  vec_validate_aligned (rewrite,
+                       sizeof (ip4_ipfix_template_packet_t)
+                       + n_elts * sizeof (ipfix_field_specifier_t) - 1,
+                       CLIB_CACHE_LINE_BYTES);
+
+  /* create the packet rewrite string */
+  tp = (ip4_ipfix_template_packet_t *) rewrite;
+  ip = (ip4_header_t *) & tp->ip4;
+  udp = (udp_header_t *) (ip + 1);
+  h = (ipfix_message_header_t *) (udp + 1);
+  s = (ipfix_set_header_t *) (h + 1);
+  t = (ipfix_template_header_t *) (s + 1);
+  first_field = f = (ipfix_field_specifier_t *) (t + 1);
+
+  ip->ip_version_and_header_length = 0x45;
+  ip->ttl = 254;
+  ip->protocol = IP_PROTOCOL_UDP;
+  ip->src_address.as_u32 = src_address->as_u32;
+  ip->dst_address.as_u32 = collector_address->as_u32;
+  udp->src_port = clib_host_to_net_u16 (stream->src_port);
+  udp->dst_port = clib_host_to_net_u16 (collector_port);
+  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
+
+  /* FIXUP LATER: message header export_time */
+  h->domain_id = clib_host_to_net_u32 (stream->domain_id);
+
+  ep = report_elts;
+
+  for (i = 0; i < n_elts; i++)
+    {
+      f->e_id_length = ipfix_e_id_length (0, ep->info_element, ep->size);
+      f++;
+      ep++;
+    }
+
+  /* Back to the template packet... */
+  ip = (ip4_header_t *) & tp->ip4;
+  udp = (udp_header_t *) (ip + 1);
+
+  ASSERT (f - first_field);
+  /* Field count in this template */
+  t->id_count = ipfix_id_count (fr->template_id, f - first_field);
+
+  /* set length in octets */
+  s->set_id_length =
+    ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
+
+  /* message length in octets */
+  h->version_length = version_length ((u8 *) f - (u8 *) h);
+
+  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
+  ip->checksum = ip4_header_checksum (ip);
+
+  return rewrite;
+}
+
 static uword
 flow_report_process (vlib_main_t * vm,
                     vlib_node_runtime_t * rt, vlib_frame_t * f)
@@ -176,7 +260,8 @@ flow_report_process (vlib_main_t * vm,
   u32 template_bi;
   u32 *to_next;
   int send_template;
-  f64 now;
+  f64 now, wait_time;
+  f64 def_wait_time = 5.0;
   int rv;
   uword event_type;
   uword *event_data = 0;
@@ -192,14 +277,20 @@ flow_report_process (vlib_main_t * vm,
   ip4_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup");
   ip4_lookup_node_index = ip4_lookup_node->index;
 
+  wait_time = def_wait_time;
+
   while (1)
     {
-      vlib_process_wait_for_event_or_clock (vm, 5.0);
+      vlib_process_wait_for_event_or_clock (vm, wait_time);
       event_type = vlib_process_get_events (vm, &event_data);
       vec_reset_length (event_data);
 
+      /* 5s delay by default, possibly reduced by template intervals */
+      wait_time = def_wait_time;
+
       vec_foreach (fr, frm->reports)
       {
+       f64 next_template;
        now = vlib_time_now (vm);
 
        /* Need to send a template packet? */
@@ -215,6 +306,11 @@ flow_report_process (vlib_main_t * vm,
        if (rv < 0)
          continue;
 
+       /* decide if template should be sent sooner than current wait time */
+       next_template =
+         (fr->last_template_sent + frm->template_interval) - now;
+       wait_time = clib_min (wait_time, next_template);
+
        nf = vlib_get_frame_to_node (vm, ip4_lookup_node_index);
        nf->n_vectors = 0;
        to_next = vlib_frame_vector_args (nf);
@@ -315,7 +411,9 @@ vnet_flow_report_add_del (flow_report_main_t * frm,
   fr->opaque = a->opaque;
   fr->rewrite_callback = a->rewrite_callback;
   fr->flow_data_callback = a->flow_data_callback;
-
+  fr->report_elements = a->report_elements;
+  fr->n_report_elements = a->n_report_elements;
+  fr->stream_indexp = a->stream_indexp;
   if (template_id)
     *template_id = fr->template_id;
 
@@ -412,7 +510,8 @@ set_ipfix_exporter_command_fn (vlib_main_t * vm,
     {
       if (unformat (input, "collector %U", unformat_ip4_address, &collector))
        ;
-      else if (unformat (input, "port %u", &collector_port))
+      else if (unformat (input, "port %U", unformat_udp_port,
+                        &collector_port))
        ;
       else if (unformat (input, "src %U", unformat_ip4_address, &src))
        ;
@@ -481,7 +580,7 @@ VLIB_CLI_COMMAND (set_ipfix_exporter_command, static) = {
                   "collector <ip4-address> [port <port>] "
                   "src <ip4-address> [fib-id <fib-id>] "
                   "[path-mtu <path-mtu>] "
-                  "[template-interval <template-interval>]",
+                  "[template-interval <template-interval>] "
                   "[udp-checksum]",
     .function = set_ipfix_exporter_command_fn,
 };
@@ -519,7 +618,7 @@ flow_report_init (vlib_main_t * vm)
   return 0;
 }
 
-VLIB_INIT_FUNCTION (flow_report_init)
+VLIB_INIT_FUNCTION (flow_report_init);
 /*
  * fd.io coding-style-patch-verification: ON
  *