FD.io VPP  v17.10-9-gd594711
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() 5
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  /* flowStartNanoseconds, TLV type 156, u64 */
184  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
185  flowStartNanoseconds, 8);
186  f++;
187 
188  /* flowEndNanoseconds, TLV type 157, u64 */
189  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
190  flowEndNanoseconds, 8);
191  f++;
192 
193  return f;
194 }
195 
196 static inline ipfix_field_specifier_t *
198 {
199 #define flowprobe_template_l4_field_count() 3
200  /* sourceTransportPort, TLV type 7, u16 */
201  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
202  sourceTransportPort, 2);
203  f++;
204  /* destinationTransportPort, TLV type 11, u16 */
205  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
206  destinationTransportPort, 2);
207  f++;
208  /* tcpControlBits, TLV type 6, u16 */
209  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
210  tcpControlBits, 2);
211  f++;
212 
213  return f;
214 }
215 
216 /**
217  * @brief Create an IPFIX template packet rewrite string
218  * @param frm flow_report_main_t *
219  * @param fr flow_report_t *
220  * @param collector_address ip4_address_t * the IPFIX collector address
221  * @param src_address ip4_address_t * the source address we should use
222  * @param collector_port u16 the collector port we should use, host byte order
223  * @returns u8 * vector containing the indicated IPFIX template packet
224  */
225 static inline u8 *
227  flow_report_t * fr,
228  ip4_address_t * collector_address,
229  ip4_address_t * src_address,
230  u16 collector_port,
231  flowprobe_variant_t which)
232 {
233  ip4_header_t *ip;
234  udp_header_t *udp;
239  ipfix_field_specifier_t *first_field;
240  u8 *rewrite = 0;
242  u32 field_count = 0;
243  flow_report_stream_t *stream;
246  bool collect_ip4 = false, collect_ip6 = false;
247 
248  stream = &frm->streams[fr->stream_index];
249 
250  if (flags & FLOW_RECORD_L3)
251  {
252  collect_ip4 = which == FLOW_VARIANT_L2_IP4 || which == FLOW_VARIANT_IP4;
253  collect_ip6 = which == FLOW_VARIANT_L2_IP6 || which == FLOW_VARIANT_IP6;
254  if (which == FLOW_VARIANT_L2_IP4)
255  flags |= FLOW_RECORD_L2_IP4;
256  if (which == FLOW_VARIANT_L2_IP6)
257  flags |= FLOW_RECORD_L2_IP6;
258  }
259 
260  field_count += flowprobe_template_common_field_count ();
261  if (flags & FLOW_RECORD_L2)
262  field_count += flowprobe_template_l2_field_count ();
263  if (collect_ip4)
264  field_count += flowprobe_template_ip4_field_count ();
265  if (collect_ip6)
266  field_count += flowprobe_template_ip6_field_count ();
267  if (flags & FLOW_RECORD_L4)
268  field_count += flowprobe_template_l4_field_count ();
269 
270  /* allocate rewrite space */
272  (rewrite, sizeof (ip4_ipfix_template_packet_t)
273  + field_count * sizeof (ipfix_field_specifier_t) - 1,
275 
276  tp = (ip4_ipfix_template_packet_t *) rewrite;
277  ip = (ip4_header_t *) & tp->ip4;
278  udp = (udp_header_t *) (ip + 1);
279  h = (ipfix_message_header_t *) (udp + 1);
280  s = (ipfix_set_header_t *) (h + 1);
281  t = (ipfix_template_header_t *) (s + 1);
282  first_field = f = (ipfix_field_specifier_t *) (t + 1);
283 
284  ip->ip_version_and_header_length = 0x45;
285  ip->ttl = 254;
286  ip->protocol = IP_PROTOCOL_UDP;
287  ip->src_address.as_u32 = src_address->as_u32;
288  ip->dst_address.as_u32 = collector_address->as_u32;
289  udp->src_port = clib_host_to_net_u16 (stream->src_port);
290  udp->dst_port = clib_host_to_net_u16 (collector_port);
291  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
292 
293  /* FIXUP: message header export_time */
294  /* FIXUP: message header sequence_number */
295  h->domain_id = clib_host_to_net_u32 (stream->domain_id);
296 
297  /* Add TLVs to the template */
299 
300  if (flags & FLOW_RECORD_L2)
302  if (collect_ip4)
304  if (collect_ip6)
306  if (flags & FLOW_RECORD_L4)
308 
309  /* Back to the template packet... */
310  ip = (ip4_header_t *) & tp->ip4;
311  udp = (udp_header_t *) (ip + 1);
312 
313  ASSERT (f - first_field);
314  /* Field count in this template */
315  t->id_count = ipfix_id_count (fr->template_id, f - first_field);
316 
317  fm->template_size[flags] = (u8 *) f - (u8 *) s;
318 
319  /* set length in octets */
320  s->set_id_length =
321  ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
322 
323  /* message length in octets */
324  h->version_length = version_length ((u8 *) f - (u8 *) h);
325 
326  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
327  ip->checksum = ip4_header_checksum (ip);
328 
329  return rewrite;
330 }
331 
332 static u8 *
334  flow_report_t * fr,
335  ip4_address_t * collector_address,
336  ip4_address_t * src_address,
337  u16 collector_port)
338 {
340  (frm, fr, collector_address, src_address, collector_port,
342 }
343 
344 static u8 *
346  flow_report_t * fr,
347  ip4_address_t * collector_address,
348  ip4_address_t * src_address,
349  u16 collector_port)
350 {
352  (frm, fr, collector_address, src_address, collector_port,
354 }
355 
356 static u8 *
358  flow_report_t * fr,
359  ip4_address_t * collector_address,
360  ip4_address_t * src_address,
361  u16 collector_port)
362 {
364  (frm, fr, collector_address, src_address, collector_port,
366 }
367 
368 static u8 *
370  flow_report_t * fr,
371  ip4_address_t * collector_address,
372  ip4_address_t * src_address,
373  u16 collector_port)
374 {
376  (frm, fr, collector_address, src_address, collector_port,
378 }
379 
380 static u8 *
382  flow_report_t * fr,
383  ip4_address_t * collector_address,
384  ip4_address_t * src_address,
385  u16 collector_port)
386 {
388  (frm, fr, collector_address, src_address, collector_port,
390 }
391 
392 /**
393  * @brief Flush accumulated data
394  * @param frm flow_report_main_t *
395  * @param fr flow_report_t *
396  * @param f vlib_frame_t *
397  *
398  * <em>Notes:</em>
399  * This function must simply return the incoming frame, or no template packets
400  * will be sent.
401  */
402 vlib_frame_t *
404  flow_report_t * fr,
405  vlib_frame_t * f, u32 * to_next, u32 node_index)
406 {
408  return f;
409 }
410 
411 vlib_frame_t *
413  flow_report_t * fr,
414  vlib_frame_t * f, u32 * to_next, u32 node_index)
415 {
417  return f;
418 }
419 
420 vlib_frame_t *
422  flow_report_t * fr,
423  vlib_frame_t * f, u32 * to_next, u32 node_index)
424 {
426  return f;
427 }
428 
429 static int
430 flowprobe_template_add_del (u32 domain_id, u16 src_port,
432  vnet_flow_data_callback_t * flow_data_callback,
433  vnet_flow_rewrite_callback_t * rewrite_callback,
434  bool is_add, u16 * template_id)
435 {
438  .rewrite_callback = rewrite_callback,
439  .flow_data_callback = flow_data_callback,
440  .is_add = is_add,
441  .domain_id = domain_id,
442  .src_port = src_port,
443  .opaque.as_uword = flags,
444  };
445  return vnet_flow_report_add_del (frm, &a, template_id);
446 }
447 
448 static void
450 {
453  u32 my_cpu_number = vm->thread_index;
454  int i;
455  u32 poolindex;
456 
457  for (i = 0; i < vec_len (expired_timers); i++)
458  {
459  poolindex = expired_timers[i] & 0x7FFFFFFF;
460  vec_add1 (fm->expired_passive_per_worker[my_cpu_number], poolindex);
461  }
462 }
463 
464 static clib_error_t *
466 {
470  clib_error_t *error = 0;
471  u32 num_threads;
472  int i;
473 
474  /* Decide how many worker threads we have */
475  num_threads = 1 /* main thread */ + tm->n_threads;
476 
477  /* Hash table per worker */
479 
480  /* Init per worker flow state and timer wheels */
481  if (active_timer)
482  {
483  vec_validate (fm->timers_per_worker, num_threads - 1);
484  vec_validate (fm->expired_passive_per_worker, num_threads - 1);
485  vec_validate (fm->hash_per_worker, num_threads - 1);
486  vec_validate (fm->pool_per_worker, num_threads - 1);
487 
488  for (i = 0; i < num_threads; i++)
489  {
490  int j;
491  pool_alloc (fm->pool_per_worker[i], 1 << fm->ht_log2len);
492  vec_resize (fm->hash_per_worker[i], 1 << fm->ht_log2len);
493  for (j = 0; j < (1 << fm->ht_log2len); j++)
494  fm->hash_per_worker[i][j] = ~0;
495  fm->timers_per_worker[i] =
496  clib_mem_alloc (sizeof (TWT (tw_timer_wheel)));
497  tw_timer_wheel_init_2t_1w_2048sl (fm->timers_per_worker[i],
499  1.0, 1024);
500  }
501  fm->disabled = true;
502  }
503  else
504  {
505  f64 now = vlib_time_now (vm);
506  vec_validate (fm->stateless_entry, num_threads - 1);
507  for (i = 0; i < num_threads; i++)
508  fm->stateless_entry[i].last_exported = now;
509  fm->disabled = false;
510  }
511  fm->initialized = true;
512  return error;
513 }
514 
515 static int
517  u8 which)
518 {
519  vec_validate_init_empty (fm->flow_per_interface, sw_if_index, ~0);
520 
521  if (fm->flow_per_interface[sw_if_index] == (u8) ~ 0)
522  return -1;
523  else if (fm->flow_per_interface[sw_if_index] != which)
524  return 0;
525  else
526  return 1;
527 }
528 
529 /**
530  * @brief configure / deconfigure the IPFIX flow-per-packet
531  * @param fm flowprobe_main_t * fm
532  * @param sw_if_index u32 the desired interface
533  * @param is_add int 1 to enable the feature, 0 to disable it
534  * @returns 0 if successful, non-zero otherwise
535  */
536 
537 static int
539  u32 sw_if_index, u8 which, int is_add)
540 {
542  int rv = 0;
543  u16 template_id = 0;
545 
546  fm->flow_per_interface[sw_if_index] = (is_add) ? which : (u8) ~ 0;
547  fm->template_per_flow[which] += (is_add) ? 1 : -1;
548  if (is_add && fm->template_per_flow[which] > 1)
549  template_id = fm->template_reports[flags];
550 
551  if ((is_add && fm->template_per_flow[which] == 1) ||
552  (!is_add && fm->template_per_flow[which] == 0))
553  {
554  if (which == FLOW_VARIANT_L2)
555  {
556  if (fm->record & FLOW_RECORD_L2)
557  {
558  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
561  is_add, &template_id);
562  }
563  if (fm->record & FLOW_RECORD_L3 || fm->record & FLOW_RECORD_L4)
564  {
565  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
568  is_add, &template_id);
569  fm->template_reports[flags | FLOW_RECORD_L2_IP4] =
570  (is_add) ? template_id : 0;
571  rv =
572  flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
575  is_add, &template_id);
576  fm->template_reports[flags | FLOW_RECORD_L2_IP6] =
577  (is_add) ? template_id : 0;
578 
579  /* Special case L2 */
581  flags | FLOW_RECORD_L2_IP4;
583  flags | FLOW_RECORD_L2_IP6;
584 
585  fm->template_reports[flags] = template_id;
586  }
587  }
588  else if (which == FLOW_VARIANT_IP4)
589  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
592  is_add, &template_id);
593  else if (which == FLOW_VARIANT_IP6)
594  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
597  is_add, &template_id);
598  }
599  if (rv && rv != VNET_API_ERROR_VALUE_EXIST)
600  {
601  clib_warning ("vnet_flow_report_add_del returned %d", rv);
602  return -1;
603  }
604 
605  if (which != (u8) ~ 0)
606  {
607  fm->context[which].flags = fm->record;
608  fm->template_reports[flags] = (is_add) ? template_id : 0;
609  }
610 
611  if (which == FLOW_VARIANT_IP4)
612  vnet_feature_enable_disable ("ip4-output", "flowprobe-ip4",
613  sw_if_index, is_add, 0, 0);
614  else if (which == FLOW_VARIANT_IP6)
615  vnet_feature_enable_disable ("ip6-output", "flowprobe-ip6",
616  sw_if_index, is_add, 0, 0);
617  else if (which == FLOW_VARIANT_L2)
618  vnet_feature_enable_disable ("interface-output", "flowprobe-l2",
619  sw_if_index, is_add, 0, 0);
620 
621  /* Stateful flow collection */
622  if (is_add && !fm->initialized)
623  {
625  if (fm->active_timer)
626  vlib_process_signal_event (vm, flowprobe_timer_node.index, 1, 0);
627  }
628 
629  return 0;
630 }
631 
632 /**
633  * @brief API message handler
634  * @param mp vl_api_flowprobe_tx_interface_add_del_t * mp the api message
635  */
638 {
640  vl_api_flowprobe_tx_interface_add_del_reply_t *rmp;
641  u32 sw_if_index = ntohl (mp->sw_if_index);
642  int rv = 0;
643 
645 
646  if (mp->which != FLOW_VARIANT_IP4 && mp->which != FLOW_VARIANT_L2
647  && mp->which != FLOW_VARIANT_IP6)
648  {
649  rv = VNET_API_ERROR_UNIMPLEMENTED;
650  goto out;
651  }
652 
653  if (fm->record == 0)
654  {
655  clib_warning ("Please specify flowprobe params record first...");
656  rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
657  goto out;
658  }
659 
660  rv = validate_feature_on_interface (fm, sw_if_index, mp->which);
661  if ((rv == 1 && mp->is_add == 1) || rv == 0)
662  {
663  rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
664  goto out;
665  }
666 
668  (fm, sw_if_index, mp->which, mp->is_add);
669 
670 out:
672 
673  REPLY_MACRO (VL_API_FLOWPROBE_TX_INTERFACE_ADD_DEL_REPLY);
674 }
675 
676 /**
677  * @brief API message custom-dump function
678  * @param mp vl_api_flowprobe_tx_interface_add_del_t * mp the api message
679  * @param handle void * print function handle
680  * @returns u8 * output string
681  */
684 {
685  u8 *s;
686 
687  s = format (0, "SCRIPT: flowprobe_tx_interface_add_del ");
688  s = format (s, "sw_if_index %d is_add %d which %d ",
689  clib_host_to_net_u32 (mp->sw_if_index),
690  (int) mp->is_add, (int) mp->which);
691  FINISH;
692 }
693 
694 #define vec_neg_search(v,E) \
695 ({ \
696  word _v(i) = 0; \
697  while (_v(i) < vec_len(v) && v[_v(i)] == E) \
698  { \
699  _v(i)++; \
700  } \
701  if (_v(i) == vec_len(v)) \
702  _v(i) = ~0; \
703  _v(i); \
704 })
705 
706 static int
708  u8 record_l3, u8 record_l4,
709  u32 active_timer, u32 passive_timer)
710 {
712 
713  if (vec_neg_search (fm->flow_per_interface, (u8) ~ 0) != ~0)
714  return ~0;
715 
716  if (record_l2)
717  flags |= FLOW_RECORD_L2;
718  if (record_l3)
719  flags |= FLOW_RECORD_L3;
720  if (record_l4)
721  flags |= FLOW_RECORD_L4;
722 
723  fm->record = flags;
724 
725  /*
726  * Timers: ~0 is default, 0 is off
727  */
728  fm->active_timer =
729  (active_timer == (u32) ~ 0 ? FLOWPROBE_TIMER_ACTIVE : active_timer);
730  fm->passive_timer =
731  (passive_timer == (u32) ~ 0 ? FLOWPROBE_TIMER_PASSIVE : passive_timer);
732 
733  return 0;
734 }
735 
736 void
738 {
740  vl_api_flowprobe_params_reply_t *rmp;
741  int rv = 0;
742 
743  rv = flowprobe_params
744  (fm, mp->record_l2, mp->record_l3, mp->record_l4,
745  clib_net_to_host_u32 (mp->active_timer),
746  clib_net_to_host_u32 (mp->passive_timer));
747 
748  REPLY_MACRO (VL_API_FLOWPROBE_PARAMS_REPLY);
749 }
750 
751 /* List of message types that this plugin understands */
752 #define foreach_flowprobe_plugin_api_msg \
753 _(FLOWPROBE_TX_INTERFACE_ADD_DEL, flowprobe_tx_interface_add_del) \
754 _(FLOWPROBE_PARAMS, flowprobe_params)
755 
756 /* *INDENT-OFF* */
758  .version = VPP_BUILD_VER,
759  .description = "Flow per Packet",
760 };
761 /* *INDENT-ON* */
762 
763 u8 *
764 format_flowprobe_entry (u8 * s, va_list * args)
765 {
766  flowprobe_entry_t *e = va_arg (*args, flowprobe_entry_t *);
767  s = format (s, " %d/%d", e->key.rx_sw_if_index, e->key.tx_sw_if_index);
768 
769  s = format (s, " %U %U", format_ethernet_address, &e->key.src_mac,
771  s = format (s, " %U -> %U",
774  s = format (s, " %d", e->key.protocol);
775  s = format (s, " %d %d\n", clib_net_to_host_u16 (e->key.src_port),
776  clib_net_to_host_u16 (e->key.dst_port));
777 
778  return s;
779 }
780 
781 static clib_error_t *
783  unformat_input_t * input, vlib_cli_command_t * cm)
784 {
786  int i;
788 
789  vlib_cli_output (vm, "Dumping IPFIX table");
790 
791  for (i = 0; i < vec_len (fm->pool_per_worker); i++)
792  {
793  /* *INDENT-OFF* */
794  pool_foreach (e, fm->pool_per_worker[i], (
795  {
796  vlib_cli_output (vm, "%U",
797  format_flowprobe_entry,
798  e);
799  }));
800  /* *INDENT-ON* */
801 
802  }
803  return 0;
804 }
805 
806 static clib_error_t *
808  unformat_input_t * input, vlib_cli_command_t * cm)
809 {
811  int i;
812 
813  vlib_cli_output (vm, "IPFIX table statistics");
814  vlib_cli_output (vm, "Flow entry size: %d\n", sizeof (flowprobe_entry_t));
815  vlib_cli_output (vm, "Flow pool size per thread: %d\n",
816  0x1 << FLOWPROBE_LOG2_HASHSIZE);
817 
818  for (i = 0; i < vec_len (fm->pool_per_worker); i++)
819  vlib_cli_output (vm, "Pool utilisation thread %d is %d%%\n", i,
820  (100 * pool_elts (fm->pool_per_worker[i])) /
821  (0x1 << FLOWPROBE_LOG2_HASHSIZE));
822  return 0;
823 }
824 
825 static clib_error_t *
827  unformat_input_t * input,
828  vlib_cli_command_t * cmd)
829 {
831  u32 sw_if_index = ~0;
832  int is_add = 1;
833  u8 which = FLOW_VARIANT_IP4;
834  int rv;
835 
837  {
838  if (unformat (input, "disable"))
839  is_add = 0;
840  else if (unformat (input, "%U", unformat_vnet_sw_interface,
841  fm->vnet_main, &sw_if_index));
842  else if (unformat (input, "ip4"))
843  which = FLOW_VARIANT_IP4;
844  else if (unformat (input, "ip6"))
845  which = FLOW_VARIANT_IP6;
846  else if (unformat (input, "l2"))
847  which = FLOW_VARIANT_L2;
848  else
849  break;
850  }
851 
852  if (fm->record == 0)
853  return clib_error_return (0,
854  "Please specify flowprobe params record first...");
855 
856  if (sw_if_index == ~0)
857  return clib_error_return (0, "Please specify an interface...");
858 
859  rv = validate_feature_on_interface (fm, sw_if_index, which);
860  if (rv == 1)
861  {
862  if (is_add)
863  return clib_error_return (0,
864  "Datapath is already enabled for given interface...");
865  }
866  else if (rv == 0)
867  return clib_error_return (0,
868  "Interface has enable different datapath ...");
869 
870  rv =
871  flowprobe_tx_interface_add_del_feature (fm, sw_if_index, which, is_add);
872  switch (rv)
873  {
874  case 0:
875  break;
876 
877  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
878  return clib_error_return
879  (0, "Invalid interface, only works on physical ports");
880  break;
881 
882  case VNET_API_ERROR_UNIMPLEMENTED:
883  return clib_error_return (0, "ip6 not supported");
884  break;
885 
886  default:
887  return clib_error_return (0, "flowprobe_enable_disable returned %d",
888  rv);
889  }
890  return 0;
891 }
892 
893 static clib_error_t *
895  unformat_input_t * input,
896  vlib_cli_command_t * cmd)
897 {
899  bool record_l2 = false, record_l3 = false, record_l4 = false;
900  u32 active_timer = ~0;
901  u32 passive_timer = ~0;
902 
904  {
905  if (unformat (input, "active %d", &active_timer))
906  ;
907  else if (unformat (input, "passive %d", &passive_timer))
908  ;
909  else if (unformat (input, "record"))
911  {
912  if (unformat (input, "l2"))
913  record_l2 = true;
914  else if (unformat (input, "l3"))
915  record_l3 = true;
916  else if (unformat (input, "l4"))
917  record_l4 = true;
918  else
919  break;
920  }
921  else
922  break;
923  }
924 
925  if (passive_timer > 0 && active_timer > passive_timer)
926  return clib_error_return (0,
927  "Passive timer has to be greater than active one...");
928 
929  if (flowprobe_params (fm, record_l2, record_l3, record_l4,
930  active_timer, passive_timer))
931  return clib_error_return (0,
932  "Couldn't change flowperpacket params when feature is enabled on some interface ...");
933  return 0;
934 }
935 
936 /*?
937  * '<em>flowprobe feature add-del</em>' commands to enable/disable
938  * per-packet IPFIX flow record generation on an interface
939  *
940  * @cliexpar
941  * @parblock
942  * To enable per-packet IPFIX flow-record generation on an interface:
943  * @cliexcmd{flowprobe feature add-del GigabitEthernet2/0/0}
944  *
945  * To disable per-packet IPFIX flow-record generation on an interface:
946  * @cliexcmd{flowprobe feature add-del GigabitEthernet2/0/0 disable}
947  * @cliexend
948  * @endparblock
949 ?*/
950 /* *INDENT-OFF* */
951 VLIB_CLI_COMMAND (flowprobe_enable_disable_command, static) = {
952  .path = "flowprobe feature add-del",
953  .short_help =
954  "flowprobe feature add-del <interface-name> <l2|ip4|ip6> disable",
956 };
957 VLIB_CLI_COMMAND (flowprobe_params_command, static) = {
958  .path = "flowprobe params",
959  .short_help =
960  "flowprobe params record <[l2] [l3] [l4]> [active <timer> passive <timer>]",
961  .function = flowprobe_params_command_fn,
962 };
963 VLIB_CLI_COMMAND (flowprobe_show_table_command, static) = {
964  .path = "show flowprobe table",
965  .short_help = "show flowprobe table",
966  .function = flowprobe_show_table_fn,
967 };
968 VLIB_CLI_COMMAND (flowprobe_show_stats_command, static) = {
969  .path = "show flowprobe statistics",
970  .short_help = "show flowprobe statistics",
971  .function = flowprobe_show_stats_fn,
972 };
973 /* *INDENT-ON* */
974 
975 /**
976  * @brief Set up the API message handling tables
977  * @param vm vlib_main_t * vlib main data structure pointer
978  * @returns 0 to indicate all is well
979  */
980 static clib_error_t *
982 {
984 #define _(N,n) \
985  vl_msg_api_set_handlers((VL_API_##N + fm->msg_id_base), \
986  #n, \
987  vl_api_##n##_t_handler, \
988  vl_noop_handler, \
989  vl_api_##n##_t_endian, \
990  vl_api_##n##_t_print, \
991  sizeof(vl_api_##n##_t), 1);
993 #undef _
994 
995  return 0;
996 }
997 
998 #define vl_msg_name_crc_list
1000 #undef vl_msg_name_crc_list
1001 
1002 static void
1004 {
1005 #define _(id,n,crc) \
1006  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base);
1007  foreach_vl_msg_name_crc_flowprobe;
1008 #undef _
1009 }
1010 
1011 /*
1012  * Main-core process, sending an interrupt to the per worker input
1013  * process that spins the per worker timer wheel.
1014  */
1015 static uword
1017 {
1018  uword *event_data = 0;
1019  vlib_main_t **worker_vms = 0, *worker_vm;
1021 
1022  /* Wait for Godot... */
1024  uword event_type = vlib_process_get_events (vm, &event_data);
1025  if (event_type != 1)
1026  clib_warning ("bogus kickoff event received, %d", event_type);
1027  vec_reset_length (event_data);
1028 
1029  int i;
1030  if (vec_len (vlib_mains) == 0)
1031  vec_add1 (worker_vms, vm);
1032  else
1033  {
1034  for (i = 0; i < vec_len (vlib_mains); i++)
1035  {
1036  worker_vm = vlib_mains[i];
1037  if (worker_vm)
1038  vec_add1 (worker_vms, worker_vm);
1039  }
1040  }
1041  f64 sleep_duration = 0.1;
1042 
1043  while (1)
1044  {
1045  /* Send an interrupt to each timer input node */
1046  sleep_duration = 0.1;
1047  for (i = 0; i < vec_len (worker_vms); i++)
1048  {
1049  worker_vm = worker_vms[i];
1050  if (worker_vm)
1051  {
1053  flowprobe_walker_node.index);
1054  sleep_duration =
1055  (fm->expired_passive_per_worker[i] > 0) ? 1e-4 : 0.1;
1056  }
1057  }
1058  vlib_process_suspend (vm, sleep_duration);
1059  }
1060  return 0; /* or not */
1061 }
1062 
1063 /* *INDENT-OFF* */
1064 VLIB_REGISTER_NODE (flowprobe_timer_node,static) = {
1065  .function = timer_process,
1066  .name = "flowprobe-timer-process",
1067  .type = VLIB_NODE_TYPE_PROCESS,
1068 };
1069 /* *INDENT-ON* */
1070 
1071 /**
1072  * @brief Set up the API message handling tables
1073  * @param vm vlib_main_t * vlib main data structure pointer
1074  * @returns 0 to indicate all is well, or a clib_error_t
1075  */
1076 static clib_error_t *
1078 {
1081  clib_error_t *error = 0;
1082  u8 *name;
1083  u32 num_threads;
1084  int i;
1085 
1086  fm->vnet_main = vnet_get_main ();
1087 
1088  /* Construct the API name */
1089  name = format (0, "flowprobe_%08x%c", api_version, 0);
1090 
1091  /* Ask for a correctly-sized block of API message decode slots */
1093  ((char *) name, VL_MSG_FIRST_AVAILABLE);
1094 
1095  /* Hook up message handlers */
1096  error = flowprobe_plugin_api_hookup (vm);
1097 
1098  /* Add our API messages to the global name_crc hash table */
1100 
1101  vec_free (name);
1102 
1103  /* Set up time reference pair */
1104  fm->vlib_time_0 = vlib_time_now (vm);
1106 
1107  memset (fm->template_reports, 0, sizeof (fm->template_reports));
1108  memset (fm->template_size, 0, sizeof (fm->template_size));
1109  memset (fm->template_per_flow, 0, sizeof (fm->template_per_flow));
1110 
1111  /* Decide how many worker threads we have */
1112  num_threads = 1 /* main thread */ + tm->n_threads;
1113 
1114  /* Allocate per worker thread vectors per flavour */
1115  for (i = 0; i < FLOW_N_VARIANTS; i++)
1116  {
1117  vec_validate (fm->context[i].buffers_per_worker, num_threads - 1);
1118  vec_validate (fm->context[i].frames_per_worker, num_threads - 1);
1120  num_threads - 1);
1121  }
1122 
1125 
1126  return error;
1127 }
1128 
1130 
1131 /*
1132  * fd.io coding-style-patch-verification: ON
1133  *
1134  * Local Variables:
1135  * eval: (c-set-style "gnu")
1136  * End:
1137  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
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:125
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:403
u16 vl_msg_api_get_msg_ids(const char *name, int n)
Definition: api_shared.c:857
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
u32 ** expired_passive_per_worker
Definition: flowprobe.h:140
#define FLOWPROBE_LOG2_HASHSIZE
Definition: flowprobe.h:33
void flowprobe_flush_callback_ip6(void)
Definition: node.c:892
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
ip46_address_t src_address
Definition: flowprobe.h:82
#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:381
static void setup_message_id_table(flowprobe_main_t *fm, api_main_t *am)
Definition: flowprobe.c:1003
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:981
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:323
static void vlib_node_set_interrupt_pending(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:196
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:221
flowprobe_key_t key
Definition: flowprobe.h:99
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:142
u32 thread_index
Definition: main.h:173
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
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:145
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u16 template_reports[FLOW_N_RECORDS]
Definition: flowprobe.h:126
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:443
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:345
u32 tx_sw_if_index
Definition: flowprobe.h:78
vlib_main_t ** vlib_mains
Definition: buffer.c:292
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:151
flowprobe_entry_t ** pool_per_worker
Definition: flowprobe.h:136
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:437
#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:333
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:135
#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:237
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:886
#define foreach_flowprobe_plugin_api_msg
Definition: flowprobe.c:752
u64 nanosecond_time_0
Time reference pair.
Definition: flowprobe.h:130
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:707
u8 ht_log2len
Per CPU flow-state.
Definition: flowprobe.h:134
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:538
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:950
VNET_FEATURE_INIT(flow_perpacket_ip4, static)
struct _unformat_input_t unformat_input_t
#define flowprobe_template_ip4_field_count()
u32 rx_sw_if_index
Definition: flowprobe.h:77
u16 template_per_flow[FLOW_N_VARIANTS]
Definition: flowprobe.h:150
#define REPLY_MACRO(t)
VLIB_PLUGIN_REGISTER()
static void flowprobe_expired_timer_callback(u32 *expired_timers)
Definition: flowprobe.c:449
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:637
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:182
#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()
vlib_main_t * vm
Definition: buffer.c:283
static clib_error_t * flowprobe_show_stats_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cm)
Definition: flowprobe.c:807
vec_header_t h
Definition: buffer.c:282
#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:430
f64 last_exported
Definition: flowprobe.h:105
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
vlib_node_registration_t flowprobe_walker_node
Definition: flowprobe.c:55
vnet_main_t * vnet_main
convenience vnet_main_t pointer
Definition: flowprobe.h:156
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:694
#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:1077
#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:421
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:112
#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:898
#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:357
u16 template_size[FLOW_N_RECORDS]
Definition: flowprobe.h:127
static ipfix_field_specifier_t * flowprobe_template_l4_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:197
u16 msg_id_base
API message ID base.
Definition: flowprobe.h:123
void vl_api_flowprobe_params_t_handler(vl_api_flowprobe_params_t *mp)
Definition: flowprobe.c:737
u8 * format_flowprobe_entry(u8 *s, va_list *args)
Definition: flowprobe.c:764
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
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:516
ip46_address_t dst_address
Definition: flowprobe.h:83
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:369
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:412
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:683
static uword timer_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: flowprobe.c:1016
u32 flags
Definition: vhost-user.h:77
#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:481
#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:782
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:826
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:894
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:226
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:465
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:239
Definition: flowprobe.h:97
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:229
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:128