FD.io VPP  v17.07-30-g839fa73
Vector Packet Processing
flowprobe.c
Go to the documentation of this file.
1 /*
2  * flowprobe.c - ipfix probe plugin
3  *
4  * Copyright (c) 2016 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /**
19  * @file
20  * @brief Per-packet IPFIX flow record generator plugin
21  *
22  * This file implements vpp plugin registration mechanics,
23  * debug CLI, and binary API handling.
24  */
25 
26 #include <vnet/vnet.h>
27 #include <vpp/app/version.h>
28 #include <vnet/plugin/plugin.h>
29 #include <flowprobe/flowprobe.h>
30 
31 #include <vlibapi/api.h>
32 #include <vlibmemory/api.h>
33 #include <vlibsocket/api.h>
34 
35 /* define message IDs */
37 
38 /* define message structures */
39 #define vl_typedefs
41 #undef vl_typedefs
42 
43 /* define generated endian-swappers */
44 #define vl_endianfun
46 #undef vl_endianfun
47 
48 /* instantiate all the print functions we know about */
49 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
50 #define vl_printfun
52 #undef vl_printfun
53 
58  vlib_frame_t * f);
59 
60 /* Get the API version number */
61 #define vl_api_version(n,v) static u32 api_version=(v);
63 #undef vl_api_version
64 
65 #define REPLY_MSG_ID_BASE fm->msg_id_base
67 
68 /* Define the per-interface configurable features */
69 /* *INDENT-OFF* */
70 VNET_FEATURE_INIT (flow_perpacket_ip4, static) =
71 {
72  .arc_name = "ip4-output",
73  .node_name = "flowprobe-ip4",
74  .runs_before = VNET_FEATURES ("interface-output"),
75 };
76 
77 VNET_FEATURE_INIT (flow_perpacket_ip6, static) =
78 {
79  .arc_name = "ip6-output",
80  .node_name = "flowprobe-ip6",
81  .runs_before = VNET_FEATURES ("interface-output"),
82 };
83 
84 VNET_FEATURE_INIT (flow_perpacket_l2, static) =
85 {
86  .arc_name = "interface-output",
87  .node_name = "flowprobe-l2",
88  .runs_before = VNET_FEATURES ("interface-tx"),
89 };
90 /* *INDENT-ON* */
91 
92 /* Macro to finish up custom dump fns */
93 #define FINISH \
94  vec_add1 (s, 0); \
95  vl_print (handle, (char *)s); \
96  vec_free (s); \
97  return handle;
98 
99 static inline ipfix_field_specifier_t *
101 {
102 #define flowprobe_template_ip4_field_count() 4
103  /* sourceIpv4Address, TLV type 8, u32 */
104  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
105  sourceIPv4Address, 4);
106  f++;
107  /* destinationIPv4Address, TLV type 12, u32 */
108  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
109  destinationIPv4Address, 4);
110  f++;
111  /* protocolIdentifier, TLV type 4, u8 */
112  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
113  protocolIdentifier, 1);
114  f++;
115  /* octetDeltaCount, TLV type 1, u64 */
116  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
117  octetDeltaCount, 8);
118  f++;
119  return f;
120 }
121 
122 static inline ipfix_field_specifier_t *
124 {
125 #define flowprobe_template_ip6_field_count() 4
126  /* sourceIpv6Address, TLV type 27, 16 octets */
127  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
128  sourceIPv6Address, 16);
129  f++;
130  /* destinationIPv6Address, TLV type 28, 16 octets */
131  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
132  destinationIPv6Address, 16);
133  f++;
134  /* protocolIdentifier, TLV type 4, u8 */
135  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
136  protocolIdentifier, 1);
137  f++;
138  /* octetDeltaCount, TLV type 1, u64 */
139  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
140  octetDeltaCount, 8);
141  f++;
142  return f;
143 }
144 
145 static inline ipfix_field_specifier_t *
147 {
148 #define flowprobe_template_l2_field_count() 3
149  /* sourceMacAddress, TLV type 56, u8[6] we hope */
150  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
151  sourceMacAddress, 6);
152  f++;
153  /* destinationMacAddress, TLV type 80, u8[6] we hope */
154  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
155  destinationMacAddress, 6);
156  f++;
157  /* ethernetType, TLV type 256, u16 */
158  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
159  ethernetType, 2);
160  f++;
161  return f;
162 }
163 
164 static inline ipfix_field_specifier_t *
166 {
167 #define flowprobe_template_common_field_count() 3
168  /* ingressInterface, TLV type 10, u32 */
169  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
170  ingressInterface, 4);
171  f++;
172 
173  /* egressInterface, TLV type 14, u32 */
174  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
175  egressInterface, 4);
176  f++;
177 
178  /* packetDeltaCount, TLV type 2, u64 */
179  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
180  packetDeltaCount, 8);
181  f++;
182 
183  return f;
184 }
185 
186 static inline ipfix_field_specifier_t *
188 {
189 #define flowprobe_template_l4_field_count() 2
190  /* sourceTransportPort, TLV type 7, u16 */
191  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
192  sourceTransportPort, 2);
193  f++;
194  /* destinationTransportPort, TLV type 11, u16 */
195  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
196  destinationTransportPort, 2);
197  f++;
198  return f;
199 }
200 
201 /**
202  * @brief Create an IPFIX template packet rewrite string
203  * @param frm flow_report_main_t *
204  * @param fr flow_report_t *
205  * @param collector_address ip4_address_t * the IPFIX collector address
206  * @param src_address ip4_address_t * the source address we should use
207  * @param collector_port u16 the collector port we should use, host byte order
208  * @returns u8 * vector containing the indicated IPFIX template packet
209  */
210 static inline u8 *
212  flow_report_t * fr,
213  ip4_address_t * collector_address,
214  ip4_address_t * src_address,
215  u16 collector_port,
216  flowprobe_variant_t which)
217 {
218  ip4_header_t *ip;
219  udp_header_t *udp;
224  ipfix_field_specifier_t *first_field;
225  u8 *rewrite = 0;
227  u32 field_count = 0;
228  flow_report_stream_t *stream;
231  bool collect_ip4 = false, collect_ip6 = false;
232 
233  stream = &frm->streams[fr->stream_index];
234 
235  if (flags & FLOW_RECORD_L3)
236  {
237  collect_ip4 = which == FLOW_VARIANT_L2_IP4 || which == FLOW_VARIANT_IP4;
238  collect_ip6 = which == FLOW_VARIANT_L2_IP6 || which == FLOW_VARIANT_IP6;
239  if (which == FLOW_VARIANT_L2_IP4)
240  flags |= FLOW_RECORD_L2_IP4;
241  if (which == FLOW_VARIANT_L2_IP6)
242  flags |= FLOW_RECORD_L2_IP6;
243  }
244 
245  field_count += flowprobe_template_common_field_count ();
246  if (flags & FLOW_RECORD_L2)
247  field_count += flowprobe_template_l2_field_count ();
248  if (collect_ip4)
249  field_count += flowprobe_template_ip4_field_count ();
250  if (collect_ip6)
251  field_count += flowprobe_template_ip6_field_count ();
252  if (flags & FLOW_RECORD_L4)
253  field_count += flowprobe_template_l4_field_count ();
254 
255  /* allocate rewrite space */
257  (rewrite, sizeof (ip4_ipfix_template_packet_t)
258  + field_count * sizeof (ipfix_field_specifier_t) - 1,
260 
261  tp = (ip4_ipfix_template_packet_t *) rewrite;
262  ip = (ip4_header_t *) & tp->ip4;
263  udp = (udp_header_t *) (ip + 1);
264  h = (ipfix_message_header_t *) (udp + 1);
265  s = (ipfix_set_header_t *) (h + 1);
266  t = (ipfix_template_header_t *) (s + 1);
267  first_field = f = (ipfix_field_specifier_t *) (t + 1);
268 
269  ip->ip_version_and_header_length = 0x45;
270  ip->ttl = 254;
271  ip->protocol = IP_PROTOCOL_UDP;
272  ip->src_address.as_u32 = src_address->as_u32;
273  ip->dst_address.as_u32 = collector_address->as_u32;
274  udp->src_port = clib_host_to_net_u16 (stream->src_port);
275  udp->dst_port = clib_host_to_net_u16 (collector_port);
276  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
277 
278  /* FIXUP: message header export_time */
279  /* FIXUP: message header sequence_number */
280  h->domain_id = clib_host_to_net_u32 (stream->domain_id);
281 
282  /* Add TLVs to the template */
284 
285  if (flags & FLOW_RECORD_L2)
287  if (collect_ip4)
289  if (collect_ip6)
291  if (flags & FLOW_RECORD_L4)
293 
294  /* Back to the template packet... */
295  ip = (ip4_header_t *) & tp->ip4;
296  udp = (udp_header_t *) (ip + 1);
297 
298  ASSERT (f - first_field);
299  /* Field count in this template */
300  t->id_count = ipfix_id_count (fr->template_id, f - first_field);
301 
302  fm->template_size[flags] = (u8 *) f - (u8 *) s;
303 
304  /* set length in octets */
305  s->set_id_length =
306  ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
307 
308  /* message length in octets */
309  h->version_length = version_length ((u8 *) f - (u8 *) h);
310 
311  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
312  ip->checksum = ip4_header_checksum (ip);
313 
314  return rewrite;
315 }
316 
317 static u8 *
319  flow_report_t * fr,
320  ip4_address_t * collector_address,
321  ip4_address_t * src_address,
322  u16 collector_port)
323 {
325  (frm, fr, collector_address, src_address, collector_port,
327 }
328 
329 static u8 *
331  flow_report_t * fr,
332  ip4_address_t * collector_address,
333  ip4_address_t * src_address,
334  u16 collector_port)
335 {
337  (frm, fr, collector_address, src_address, collector_port,
339 }
340 
341 static u8 *
343  flow_report_t * fr,
344  ip4_address_t * collector_address,
345  ip4_address_t * src_address,
346  u16 collector_port)
347 {
349  (frm, fr, collector_address, src_address, collector_port,
351 }
352 
353 static u8 *
355  flow_report_t * fr,
356  ip4_address_t * collector_address,
357  ip4_address_t * src_address,
358  u16 collector_port)
359 {
361  (frm, fr, collector_address, src_address, collector_port,
363 }
364 
365 static u8 *
367  flow_report_t * fr,
368  ip4_address_t * collector_address,
369  ip4_address_t * src_address,
370  u16 collector_port)
371 {
373  (frm, fr, collector_address, src_address, collector_port,
375 }
376 
377 /**
378  * @brief Flush accumulated data
379  * @param frm flow_report_main_t *
380  * @param fr flow_report_t *
381  * @param f vlib_frame_t *
382  *
383  * <em>Notes:</em>
384  * This function must simply return the incoming frame, or no template packets
385  * will be sent.
386  */
387 vlib_frame_t *
389  flow_report_t * fr,
390  vlib_frame_t * f, u32 * to_next, u32 node_index)
391 {
393  return f;
394 }
395 
396 vlib_frame_t *
398  flow_report_t * fr,
399  vlib_frame_t * f, u32 * to_next, u32 node_index)
400 {
402  return f;
403 }
404 
405 vlib_frame_t *
407  flow_report_t * fr,
408  vlib_frame_t * f, u32 * to_next, u32 node_index)
409 {
411  return f;
412 }
413 
414 static int
415 flowprobe_template_add_del (u32 domain_id, u16 src_port,
417  vnet_flow_data_callback_t * flow_data_callback,
418  vnet_flow_rewrite_callback_t * rewrite_callback,
419  bool is_add, u16 * template_id)
420 {
423  .rewrite_callback = rewrite_callback,
424  .flow_data_callback = flow_data_callback,
425  .is_add = is_add,
426  .domain_id = domain_id,
427  .src_port = src_port,
428  .opaque.as_uword = flags,
429  };
430  return vnet_flow_report_add_del (frm, &a, template_id);
431 }
432 
433 static void
435 {
436  vlib_main_t *vm = vlib_get_main ();
438  u32 my_cpu_number = vm->thread_index;
439  int i;
440  u32 poolindex;
441 
442  for (i = 0; i < vec_len (expired_timers); i++)
443  {
444  poolindex = expired_timers[i] & 0x7FFFFFFF;
445  vec_add1 (fm->expired_passive_per_worker[my_cpu_number], poolindex);
446  }
447 }
448 
449 static clib_error_t *
451 {
454  vlib_main_t *vm = vlib_get_main ();
455  clib_error_t *error = 0;
456  u32 num_threads;
457  int i;
458 
459  /* Decide how many worker threads we have */
460  num_threads = 1 /* main thread */ + tm->n_threads;
461 
462  /* Hash table per worker */
464 
465  /* Init per worker flow state and timer wheels */
466  if (active_timer)
467  {
468  vec_validate (fm->timers_per_worker, num_threads - 1);
469  vec_validate (fm->expired_passive_per_worker, num_threads - 1);
470  vec_validate (fm->hash_per_worker, num_threads - 1);
471  vec_validate (fm->pool_per_worker, num_threads - 1);
472 
473  for (i = 0; i < num_threads; i++)
474  {
475  int j;
476  pool_alloc (fm->pool_per_worker[i], 1 << fm->ht_log2len);
477  vec_resize (fm->hash_per_worker[i], 1 << fm->ht_log2len);
478  for (j = 0; j < (1 << fm->ht_log2len); j++)
479  fm->hash_per_worker[i][j] = ~0;
480  fm->timers_per_worker[i] =
481  clib_mem_alloc (sizeof (TWT (tw_timer_wheel)));
482  tw_timer_wheel_init_2t_1w_2048sl (fm->timers_per_worker[i],
484  1.0, 1024);
485  }
486  fm->disabled = true;
487  }
488  else
489  {
490  f64 now = vlib_time_now (vm);
491  vec_validate (fm->stateless_entry, num_threads - 1);
492  for (i = 0; i < num_threads; i++)
493  fm->stateless_entry[i].last_exported = now;
494  fm->disabled = false;
495  }
496  fm->initialized = true;
497  return error;
498 }
499 
500 static int
502  u8 which)
503 {
504  vec_validate_init_empty (fm->flow_per_interface, sw_if_index, ~0);
505 
506  if (fm->flow_per_interface[sw_if_index] == (u8) ~ 0)
507  return -1;
508  else if (fm->flow_per_interface[sw_if_index] != which)
509  return 0;
510  else
511  return 1;
512 }
513 
514 /**
515  * @brief configure / deconfigure the IPFIX flow-per-packet
516  * @param fm flowprobe_main_t * fm
517  * @param sw_if_index u32 the desired interface
518  * @param is_add int 1 to enable the feature, 0 to disable it
519  * @returns 0 if successful, non-zero otherwise
520  */
521 
522 static int
524  u32 sw_if_index, u8 which, int is_add)
525 {
526  vlib_main_t *vm = vlib_get_main ();
527  int rv = 0;
528  u16 template_id = 0;
530 
531  fm->flow_per_interface[sw_if_index] = (is_add) ? which : (u8) ~ 0;
532  fm->template_per_flow[which] += (is_add) ? 1 : -1;
533  if (is_add && fm->template_per_flow[which] > 1)
534  template_id = fm->template_reports[flags];
535 
536  if ((is_add && fm->template_per_flow[which] == 1) ||
537  (!is_add && fm->template_per_flow[which] == 0))
538  {
539  if (which == FLOW_VARIANT_L2)
540  {
541  if (fm->record & FLOW_RECORD_L2)
542  {
543  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
546  is_add, &template_id);
547  }
548  if (fm->record & FLOW_RECORD_L3 || fm->record & FLOW_RECORD_L4)
549  {
550  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
553  is_add, &template_id);
554  fm->template_reports[flags | FLOW_RECORD_L2_IP4] =
555  (is_add) ? template_id : 0;
556  rv =
557  flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
560  is_add, &template_id);
561  fm->template_reports[flags | FLOW_RECORD_L2_IP6] =
562  (is_add) ? template_id : 0;
563 
564  /* Special case L2 */
566  flags | FLOW_RECORD_L2_IP4;
568  flags | FLOW_RECORD_L2_IP6;
569 
570  fm->template_reports[flags] = template_id;
571  }
572  }
573  else if (which == FLOW_VARIANT_IP4)
574  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
577  is_add, &template_id);
578  else if (which == FLOW_VARIANT_IP6)
579  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
582  is_add, &template_id);
583  }
584  if (rv && rv != VNET_API_ERROR_VALUE_EXIST)
585  {
586  clib_warning ("vnet_flow_report_add_del returned %d", rv);
587  return -1;
588  }
589 
590  if (which != (u8) ~ 0)
591  {
592  fm->context[which].flags = fm->record;
593  fm->template_reports[flags] = (is_add) ? template_id : 0;
594  }
595 
596  if (which == FLOW_VARIANT_IP4)
597  vnet_feature_enable_disable ("ip4-output", "flowprobe-ip4",
598  sw_if_index, is_add, 0, 0);
599  else if (which == FLOW_VARIANT_IP6)
600  vnet_feature_enable_disable ("ip6-output", "flowprobe-ip6",
601  sw_if_index, is_add, 0, 0);
602  else if (which == FLOW_VARIANT_L2)
603  vnet_feature_enable_disable ("interface-output", "flowprobe-l2",
604  sw_if_index, is_add, 0, 0);
605 
606  /* Stateful flow collection */
607  if (is_add && !fm->initialized)
608  {
610  if (fm->active_timer)
611  vlib_process_signal_event (vm, flowprobe_timer_node.index, 1, 0);
612  }
613 
614  return 0;
615 }
616 
617 /**
618  * @brief API message handler
619  * @param mp vl_api_flowprobe_tx_interface_add_del_t * mp the api message
620  */
623 {
625  vl_api_flowprobe_tx_interface_add_del_reply_t *rmp;
626  u32 sw_if_index = ntohl (mp->sw_if_index);
627  int rv = 0;
628 
630 
631  if (mp->which != FLOW_VARIANT_IP4 && mp->which != FLOW_VARIANT_L2
632  && mp->which != FLOW_VARIANT_IP6)
633  {
634  rv = VNET_API_ERROR_UNIMPLEMENTED;
635  goto out;
636  }
637 
638  if (fm->record == 0)
639  {
640  clib_warning ("Please specify flowprobe params record first...");
641  rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
642  goto out;
643  }
644 
645  rv = validate_feature_on_interface (fm, sw_if_index, mp->which);
646  if ((rv == 1 && mp->is_add == 1) || rv == 0)
647  {
648  rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
649  goto out;
650  }
651 
653  (fm, sw_if_index, mp->which, mp->is_add);
654 
655 out:
657 
658  REPLY_MACRO (VL_API_FLOWPROBE_TX_INTERFACE_ADD_DEL_REPLY);
659 }
660 
661 /**
662  * @brief API message custom-dump function
663  * @param mp vl_api_flowprobe_tx_interface_add_del_t * mp the api message
664  * @param handle void * print function handle
665  * @returns u8 * output string
666  */
669 {
670  u8 *s;
671 
672  s = format (0, "SCRIPT: flowprobe_tx_interface_add_del ");
673  s = format (s, "sw_if_index %d is_add %d which %d ",
674  clib_host_to_net_u32 (mp->sw_if_index),
675  (int) mp->is_add, (int) mp->which);
676  FINISH;
677 }
678 
679 #define vec_neg_search(v,E) \
680 ({ \
681  word _v(i) = 0; \
682  while (_v(i) < vec_len(v) && v[_v(i)] == E) \
683  { \
684  _v(i)++; \
685  } \
686  if (_v(i) == vec_len(v)) \
687  _v(i) = ~0; \
688  _v(i); \
689 })
690 
691 static int
693  u8 record_l3, u8 record_l4,
694  u32 active_timer, u32 passive_timer)
695 {
697 
698  if (vec_neg_search (fm->flow_per_interface, (u8) ~ 0) != ~0)
699  return ~0;
700 
701  if (record_l2)
702  flags |= FLOW_RECORD_L2;
703  if (record_l3)
704  flags |= FLOW_RECORD_L3;
705  if (record_l4)
706  flags |= FLOW_RECORD_L4;
707 
708  fm->record = flags;
709 
710  /*
711  * Timers: ~0 is default, 0 is off
712  */
713  fm->active_timer =
714  (active_timer == (u32) ~ 0 ? FLOWPROBE_TIMER_ACTIVE : active_timer);
715  fm->passive_timer =
716  (passive_timer == (u32) ~ 0 ? FLOWPROBE_TIMER_PASSIVE : passive_timer);
717 
718  return 0;
719 }
720 
721 void
723 {
725  vl_api_flowprobe_params_reply_t *rmp;
726  int rv = 0;
727 
728  rv = flowprobe_params
729  (fm, mp->record_l2, mp->record_l3, mp->record_l4,
730  clib_net_to_host_u32 (mp->active_timer),
731  clib_net_to_host_u32 (mp->passive_timer));
732 
733  REPLY_MACRO (VL_API_FLOWPROBE_PARAMS_REPLY);
734 }
735 
736 /* List of message types that this plugin understands */
737 #define foreach_flowprobe_plugin_api_msg \
738 _(FLOWPROBE_TX_INTERFACE_ADD_DEL, flowprobe_tx_interface_add_del) \
739 _(FLOWPROBE_PARAMS, flowprobe_params)
740 
741 /* *INDENT-OFF* */
743  .version = VPP_BUILD_VER,
744  .description = "Flow per Packet",
745 };
746 /* *INDENT-ON* */
747 
748 u8 *
749 format_flowprobe_entry (u8 * s, va_list * args)
750 {
751  flowprobe_entry_t *e = va_arg (*args, flowprobe_entry_t *);
752  s = format (s, " %d/%d", e->key.rx_sw_if_index, e->key.tx_sw_if_index);
753 
754  s = format (s, " %U %U", format_ethernet_address, &e->key.src_mac,
755  format_ethernet_address, &e->key.dst_mac);
756  s = format (s, " %U -> %U",
757  format_ip46_address, &e->key.src_address, IP46_TYPE_ANY,
758  format_ip46_address, &e->key.dst_address, IP46_TYPE_ANY);
759  s = format (s, " %d", e->key.protocol);
760  s = format (s, " %d %d\n", clib_net_to_host_u16 (e->key.src_port),
761  clib_net_to_host_u16 (e->key.dst_port));
762 
763  return s;
764 }
765 
766 static clib_error_t *
768  unformat_input_t * input, vlib_cli_command_t * cm)
769 {
771  int i;
773 
774  vlib_cli_output (vm, "Dumping IPFIX table");
775 
776  for (i = 0; i < vec_len (fm->pool_per_worker); i++)
777  {
778  /* *INDENT-OFF* */
779  pool_foreach (e, fm->pool_per_worker[i], (
780  {
781  vlib_cli_output (vm, "%U",
782  format_flowprobe_entry,
783  e);
784  }));
785  /* *INDENT-ON* */
786 
787  }
788  return 0;
789 }
790 
791 static clib_error_t *
793  unformat_input_t * input, vlib_cli_command_t * cm)
794 {
796  int i;
797 
798  vlib_cli_output (vm, "IPFIX table statistics");
799  vlib_cli_output (vm, "Flow entry size: %d\n", sizeof (flowprobe_entry_t));
800  vlib_cli_output (vm, "Flow pool size per thread: %d\n",
801  0x1 << FLOWPROBE_LOG2_HASHSIZE);
802 
803  for (i = 0; i < vec_len (fm->pool_per_worker); i++)
804  vlib_cli_output (vm, "Pool utilisation thread %d is %d%%\n", i,
805  (100 * pool_elts (fm->pool_per_worker[i])) /
806  (0x1 << FLOWPROBE_LOG2_HASHSIZE));
807  return 0;
808 }
809 
810 static clib_error_t *
812  unformat_input_t * input,
813  vlib_cli_command_t * cmd)
814 {
816  u32 sw_if_index = ~0;
817  int is_add = 1;
818  u8 which = FLOW_VARIANT_IP4;
819  int rv;
820 
822  {
823  if (unformat (input, "disable"))
824  is_add = 0;
825  else if (unformat (input, "%U", unformat_vnet_sw_interface,
826  fm->vnet_main, &sw_if_index));
827  else if (unformat (input, "ip4"))
828  which = FLOW_VARIANT_IP4;
829  else if (unformat (input, "ip6"))
830  which = FLOW_VARIANT_IP6;
831  else if (unformat (input, "l2"))
832  which = FLOW_VARIANT_L2;
833  else
834  break;
835  }
836 
837  if (fm->record == 0)
838  return clib_error_return (0,
839  "Please specify flowprobe params record first...");
840 
841  if (sw_if_index == ~0)
842  return clib_error_return (0, "Please specify an interface...");
843 
844  rv = validate_feature_on_interface (fm, sw_if_index, which);
845  if (rv == 1)
846  {
847  if (is_add)
848  return clib_error_return (0,
849  "Datapath is already enabled for given interface...");
850  }
851  else if (rv == 0)
852  return clib_error_return (0,
853  "Interface has enable different datapath ...");
854 
855  rv =
856  flowprobe_tx_interface_add_del_feature (fm, sw_if_index, which, is_add);
857  switch (rv)
858  {
859  case 0:
860  break;
861 
862  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
863  return clib_error_return
864  (0, "Invalid interface, only works on physical ports");
865  break;
866 
867  case VNET_API_ERROR_UNIMPLEMENTED:
868  return clib_error_return (0, "ip6 not supported");
869  break;
870 
871  default:
872  return clib_error_return (0, "flowprobe_enable_disable returned %d",
873  rv);
874  }
875  return 0;
876 }
877 
878 static clib_error_t *
880  unformat_input_t * input,
881  vlib_cli_command_t * cmd)
882 {
884  bool record_l2 = false, record_l3 = false, record_l4 = false;
885  u32 active_timer = ~0;
886  u32 passive_timer = ~0;
887 
889  {
890  if (unformat (input, "active %d", &active_timer))
891  ;
892  else if (unformat (input, "passive %d", &passive_timer))
893  ;
894  else if (unformat (input, "record"))
896  {
897  if (unformat (input, "l2"))
898  record_l2 = true;
899  else if (unformat (input, "l3"))
900  record_l3 = true;
901  else if (unformat (input, "l4"))
902  record_l4 = true;
903  else
904  break;
905  }
906  else
907  break;
908  }
909 
910  if (passive_timer > 0 && active_timer > passive_timer)
911  return clib_error_return (0,
912  "Passive timer has to be greater than active one...");
913 
914  if (flowprobe_params (fm, record_l2, record_l3, record_l4,
915  active_timer, passive_timer))
916  return clib_error_return (0,
917  "Couldn't change flowperpacket params when feature is enabled on some interface ...");
918  return 0;
919 }
920 
921 /*?
922  * '<em>flowprobe feature add-del</em>' commands to enable/disable
923  * per-packet IPFIX flow record generation on an interface
924  *
925  * @cliexpar
926  * @parblock
927  * To enable per-packet IPFIX flow-record generation on an interface:
928  * @cliexcmd{flowprobe feature add-del GigabitEthernet2/0/0}
929  *
930  * To disable per-packet IPFIX flow-record generation on an interface:
931  * @cliexcmd{flowprobe feature add-del GigabitEthernet2/0/0 disable}
932  * @cliexend
933  * @endparblock
934 ?*/
935 /* *INDENT-OFF* */
936 VLIB_CLI_COMMAND (flowprobe_enable_disable_command, static) = {
937  .path = "flowprobe feature add-del",
938  .short_help =
939  "flowprobe feature add-del <interface-name> <l2|ip4|ip6> disable",
941 };
942 VLIB_CLI_COMMAND (flowprobe_params_command, static) = {
943  .path = "flowprobe params",
944  .short_help =
945  "flowprobe params record <[l2] [l3] [l4]> [active <timer> passive <timer>]",
946  .function = flowprobe_params_command_fn,
947 };
948 VLIB_CLI_COMMAND (flowprobe_show_table_command, static) = {
949  .path = "show flowprobe table",
950  .short_help = "show flowprobe table",
951  .function = flowprobe_show_table_fn,
952 };
953 VLIB_CLI_COMMAND (flowprobe_show_stats_command, static) = {
954  .path = "show flowprobe statistics",
955  .short_help = "show flowprobe statistics",
956  .function = flowprobe_show_stats_fn,
957 };
958 /* *INDENT-ON* */
959 
960 /**
961  * @brief Set up the API message handling tables
962  * @param vm vlib_main_t * vlib main data structure pointer
963  * @returns 0 to indicate all is well
964  */
965 static clib_error_t *
967 {
969 #define _(N,n) \
970  vl_msg_api_set_handlers((VL_API_##N + fm->msg_id_base), \
971  #n, \
972  vl_api_##n##_t_handler, \
973  vl_noop_handler, \
974  vl_api_##n##_t_endian, \
975  vl_api_##n##_t_print, \
976  sizeof(vl_api_##n##_t), 1);
978 #undef _
979 
980  return 0;
981 }
982 
983 #define vl_msg_name_crc_list
985 #undef vl_msg_name_crc_list
986 
987 static void
989 {
990 #define _(id,n,crc) \
991  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base);
992  foreach_vl_msg_name_crc_flowprobe;
993 #undef _
994 }
995 
996 /*
997  * Main-core process, sending an interrupt to the per worker input
998  * process that spins the per worker timer wheel.
999  */
1000 static uword
1002 {
1003  uword *event_data = 0;
1004  vlib_main_t **worker_vms = 0, *worker_vm;
1006 
1007  /* Wait for Godot... */
1009  uword event_type = vlib_process_get_events (vm, &event_data);
1010  if (event_type != 1)
1011  clib_warning ("bogus kickoff event received, %d", event_type);
1012  vec_reset_length (event_data);
1013 
1014  int i;
1015  if (vec_len (vlib_mains) == 0)
1016  vec_add1 (worker_vms, vm);
1017  else
1018  {
1019  for (i = 0; i < vec_len (vlib_mains); i++)
1020  {
1021  worker_vm = vlib_mains[i];
1022  if (worker_vm)
1023  vec_add1 (worker_vms, worker_vm);
1024  }
1025  }
1026  f64 sleep_duration = 0.1;
1027 
1028  while (1)
1029  {
1030  /* Send an interrupt to each timer input node */
1031  sleep_duration = 0.1;
1032  for (i = 0; i < vec_len (worker_vms); i++)
1033  {
1034  worker_vm = worker_vms[i];
1035  if (worker_vm)
1036  {
1038  flowprobe_walker_node.index);
1039  sleep_duration =
1040  (fm->expired_passive_per_worker[i] > 0) ? 1e-4 : 0.1;
1041  }
1042  }
1043  vlib_process_suspend (vm, sleep_duration);
1044  }
1045  return 0; /* or not */
1046 }
1047 
1048 /* *INDENT-OFF* */
1049 VLIB_REGISTER_NODE (flowprobe_timer_node,static) = {
1050  .function = timer_process,
1051  .name = "flowprobe-timer-process",
1052  .type = VLIB_NODE_TYPE_PROCESS,
1053 };
1054 /* *INDENT-ON* */
1055 
1056 /**
1057  * @brief Set up the API message handling tables
1058  * @param vm vlib_main_t * vlib main data structure pointer
1059  * @returns 0 to indicate all is well, or a clib_error_t
1060  */
1061 static clib_error_t *
1063 {
1066  clib_error_t *error = 0;
1067  u8 *name;
1068  u32 num_threads;
1069  int i;
1070 
1071  fm->vnet_main = vnet_get_main ();
1072 
1073  /* Construct the API name */
1074  name = format (0, "flowprobe_%08x%c", api_version, 0);
1075 
1076  /* Ask for a correctly-sized block of API message decode slots */
1078  ((char *) name, VL_MSG_FIRST_AVAILABLE);
1079 
1080  /* Hook up message handlers */
1081  error = flowprobe_plugin_api_hookup (vm);
1082 
1083  /* Add our API messages to the global name_crc hash table */
1085 
1086  vec_free (name);
1087 
1088  /* Set up time reference pair */
1089  fm->vlib_time_0 = vlib_time_now (vm);
1091 
1092  memset (fm->template_reports, 0, sizeof (fm->template_reports));
1093  memset (fm->template_size, 0, sizeof (fm->template_size));
1094  memset (fm->template_per_flow, 0, sizeof (fm->template_per_flow));
1095 
1096  /* Decide how many worker threads we have */
1097  num_threads = 1 /* main thread */ + tm->n_threads;
1098 
1099  /* Allocate per worker thread vectors per flavour */
1100  for (i = 0; i < FLOW_N_VARIANTS; i++)
1101  {
1102  vec_validate (fm->context[i].buffers_per_worker, num_threads - 1);
1103  vec_validate (fm->context[i].frames_per_worker, num_threads - 1);
1105  num_threads - 1);
1106  }
1107 
1110 
1111  return error;
1112 }
1113 
1115 
1116 /*
1117  * fd.io coding-style-patch-verification: ON
1118  *
1119  * Local Variables:
1120  * eval: (c-set-style "gnu")
1121  * End:
1122  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
uword flowprobe_walker_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
flowprobe_protocol_context_t context[FLOW_N_VARIANTS]
Definition: flowprobe.h:118
flowprobe_variant_t
Definition: flowprobe.h:46
vlib_frame_t * flowprobe_data_callback_ip4(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
Flush accumulated data.
Definition: flowprobe.c:388
u16 vl_msg_api_get_msg_ids(const char *name, int n)
Definition: api_shared.c:837
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
u32 ** expired_passive_per_worker
Definition: flowprobe.h:133
#define FLOWPROBE_LOG2_HASHSIZE
Definition: flowprobe.h:33
void flowprobe_flush_callback_ip6(void)
Definition: node.c:844
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
Definition: node_funcs.h:699
a
Definition: bitmap.h:516
#define FLOWPROBE_TIMER_PASSIVE
Definition: flowprobe.h:32
static u8 * flowprobe_template_rewrite_l2_ip6(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port)
Definition: flowprobe.c:366
static void setup_message_id_table(flowprobe_main_t *fm, api_main_t *am)
Definition: flowprobe.c:988
ip4_address_t src_address
Definition: ip4_packet.h:164
static clib_error_t * flowprobe_plugin_api_hookup(vlib_main_t *vm)
Set up the API message handling tables.
Definition: flowprobe.c:966
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
uword as_uword
Definition: flow_report.h:57
#define pool_alloc(P, N)
Allocate N more free elements to pool (unspecified alignment).
Definition: pool.h:274
static void vlib_node_set_interrupt_pending(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:195
static u32 ipfix_e_id_length(int e, u16 id, u16 length)
Definition: ipfix_packet.h:72
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:192
flowprobe_key_t key
Definition: flowprobe.h:101
u32 stream_index
Definition: flow_report.h:72
int vnet_flow_report_add_del(flow_report_main_t *frm, vnet_flow_report_add_del_args_t *a, u16 *template_id)
Definition: flow_report.c:239
flowprobe_record_t record
Definition: flowprobe.h:135
u32 thread_index
Definition: main.h:159
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:522
struct _vlib_node_registration vlib_node_registration_t
opaque_t opaque
Definition: flow_report.h:80
#define flowprobe_template_l2_field_count()
format_function_t format_ip46_address
Definition: format.h:61
flowprobe_entry_t * stateless_entry
Definition: flowprobe.h:138
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u16 template_reports[FLOW_N_RECORDS]
Definition: flowprobe.h:119
unformat_function_t unformat_vnet_sw_interface
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:447
u8 *( vnet_flow_rewrite_callback_t)(struct flow_report_main *, struct flow_report *, ip4_address_t *, ip4_address_t *, u16)
Definition: flow_report.h:44
static u8 * flowprobe_template_rewrite_ip4(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port)
Definition: flowprobe.c:330
static ipfix_field_specifier_t * flowprobe_template_common_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:165
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
u8 * flow_per_interface
Definition: flowprobe.h:144
flowprobe_entry_t ** pool_per_worker
Definition: flowprobe.h:129
Enable / disable per-packet IPFIX recording on an interface.
Definition: flowprobe.api:15
flow_report_stream_t * streams
Definition: flow_report.h:91
static uword vlib_process_suspend(vlib_main_t *vm, f64 dt)
Suspend a vlib cooperative multi-tasking thread for a period of time.
Definition: node_funcs.h:448
static ipfix_field_specifier_t * flowprobe_template_ip4_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:100
flow-per-packet plugin header file
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:376
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
Definition: node_funcs.h:542
static u8 * flowprobe_template_rewrite_ip6(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port)
Definition: flowprobe.c:318
ip4_address_t dst_address
Definition: ip4_packet.h:164
vlib_frame_t ** frames_per_worker
frames containing ipfix buffers, per-worker thread
Definition: flowprobe.h:70
u32 ** hash_per_worker
Definition: flowprobe.h:128
#define flowprobe_template_l4_field_count()
#define clib_error_return(e, args...)
Definition: error.h:99
#define vec_resize(V, N)
Resize a vector (no header, unspecified alignment) Add N elements to end of given vector V...
Definition: vec.h:241
vlib_frame_t *( vnet_flow_data_callback_t)(struct flow_report_main *, struct flow_report *, vlib_frame_t *, u32 *, u32)
Definition: flow_report.h:50
void flowprobe_flush_callback_ip4(void)
Definition: node.c:838
#define foreach_flowprobe_plugin_api_msg
Definition: flowprobe.c:737
u64 nanosecond_time_0
Time reference pair.
Definition: flowprobe.h:123
static int flowprobe_params(flowprobe_main_t *fm, u8 record_l2, u8 record_l3, u8 record_l4, u32 active_timer, u32 passive_timer)
Definition: flowprobe.c:692
u8 ht_log2len
Per CPU flow-state.
Definition: flowprobe.h:127
flow_report_main_t flow_report_main
Definition: flow_report.c:21
static int flowprobe_tx_interface_add_del_feature(flowprobe_main_t *fm, u32 sw_if_index, u8 which, int is_add)
configure / deconfigure the IPFIX flow-per-packet
Definition: flowprobe.c:523
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:946
VNET_FEATURE_INIT(flow_perpacket_ip4, static)
struct _unformat_input_t unformat_input_t
#define flowprobe_template_ip4_field_count()
u16 template_per_flow[FLOW_N_VARIANTS]
Definition: flowprobe.h:143
#define REPLY_MACRO(t)
VLIB_PLUGIN_REGISTER()
static void flowprobe_expired_timer_callback(u32 *expired_timers)
Definition: flowprobe.c:434
static u32 version_length(u16 length)
Definition: ipfix_packet.h:31
vlib_thread_main_t vlib_thread_main
Definition: threads.c:36
void vl_api_flowprobe_tx_interface_add_del_t_handler(vl_api_flowprobe_tx_interface_add_del_t *mp)
API message handler.
Definition: flowprobe.c:622
#define BAD_SW_IF_INDEX_LABEL
api_main_t api_main
Definition: api_shared.c:35
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define flowprobe_template_ip6_field_count()
static clib_error_t * flowprobe_show_stats_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cm)
Definition: flowprobe.c:792
#define FLOWPROBE_TIMER_ACTIVE
Definition: flowprobe.h:31
static int flowprobe_template_add_del(u32 domain_id, u16 src_port, flowprobe_record_t flags, vnet_flow_data_callback_t *flow_data_callback, vnet_flow_rewrite_callback_t *rewrite_callback, bool is_add, u16 *template_id)
Definition: flowprobe.c:415
f64 last_exported
Definition: flowprobe.h:105
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
vlib_node_registration_t flowprobe_walker_node
Definition: flowprobe.c:55
vnet_main_t * vnet_main
convenience vnet_main_t pointer
Definition: flowprobe.h:149
static u32 ipfix_id_count(u16 id, u16 count)
Definition: ipfix_packet.h:175
#define clib_warning(format, args...)
Definition: error.h:59
#define vec_neg_search(v, E)
Definition: flowprobe.c:679
#define FINISH
Definition: flowprobe.c:93
static u64 unix_time_now_nsec(void)
Definition: time.h:238
static clib_error_t * flowprobe_init(vlib_main_t *vm)
Set up the API message handling tables.
Definition: flowprobe.c:1062
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
flowprobe_record_t
Definition: flowprobe.h:35
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
vlib_frame_t * flowprobe_data_callback_l2(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
Definition: flowprobe.c:406
u16 template_id
Definition: flow_report.h:71
static ipfix_field_specifier_t * flowprobe_template_ip6_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:123
static void * clib_mem_alloc(uword size)
Definition: mem.h:109
#define VNET_FEATURES(...)
Definition: feature.h:368
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
flowprobe_main_t flowprobe_main
Definition: flowprobe.c:54
u64 uword
Definition: types.h:112
static u32 ipfix_set_id_length(u16 set_id, u16 length)
Definition: ipfix_packet.h:114
vlib_buffer_t ** buffers_per_worker
ipfix buffers under construction, per-worker thread
Definition: flowprobe.h:68
unsigned short u16
Definition: types.h:57
#define flowprobe_template_common_field_count()
void flowprobe_flush_callback_l2(void)
Definition: node.c:850
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
static u8 * flowprobe_template_rewrite_l2(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port)
Definition: flowprobe.c:342
u16 template_size[FLOW_N_RECORDS]
Definition: flowprobe.h:120
vlib_main_t ** vlib_mains
static ipfix_field_specifier_t * flowprobe_template_l4_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:187
u16 msg_id_base
API message ID base.
Definition: flowprobe.h:116
void vl_api_flowprobe_params_t_handler(vl_api_flowprobe_params_t *mp)
Definition: flowprobe.c:722
u8 * format_flowprobe_entry(u8 *s, va_list *args)
Definition: flowprobe.c:749
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:144
static ipfix_field_specifier_t * flowprobe_template_l2_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:146
static int validate_feature_on_interface(flowprobe_main_t *fm, u32 sw_if_index, u8 which)
Definition: flowprobe.c:501
static u8 * flowprobe_template_rewrite_l2_ip4(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port)
Definition: flowprobe.c:354
vlib_frame_t * flowprobe_data_callback_ip6(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
Definition: flowprobe.c:397
u8 ip_version_and_header_length
Definition: ip4_packet.h:132
u16 * next_record_offset_per_worker
next record offset, per worker thread
Definition: flowprobe.h:72
static void * vl_api_flowprobe_tx_interface_add_del_t_print(vl_api_flowprobe_tx_interface_add_del_t *mp, void *handle)
API message custom-dump function.
Definition: flowprobe.c:668
static uword timer_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: flowprobe.c:1001
u32 flags
Definition: vhost-user.h:76
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:485
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
static clib_error_t * flowprobe_show_table_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cm)
Definition: flowprobe.c:767
static clib_error_t * flowprobe_tx_interface_add_del_feature_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: flowprobe.c:811
flowprobe_record_t flags
Definition: flowprobe.h:66
static clib_error_t * flowprobe_params_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: flowprobe.c:879
static u8 * flowprobe_template_rewrite_inline(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port, flowprobe_variant_t which)
Create an IPFIX template packet rewrite string.
Definition: flowprobe.c:211
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
static vlib_node_registration_t flowprobe_timer_node
(constructor) VLIB_REGISTER_NODE (flowprobe_timer_node)
Definition: flowprobe.c:56
static clib_error_t * flowprobe_create_state_tables(u32 active_timer)
Definition: flowprobe.c:450
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:239
Definition: flowprobe.h:99
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:225
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#define VALIDATE_SW_IF_INDEX(mp)
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109