FD.io VPP  v21.01.1
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 <vnet/udp/udp_local.h>
30 #include <flowprobe/flowprobe.h>
31 
32 #include <vlibapi/api.h>
33 #include <vlibmemory/api.h>
34 
35 /* define message IDs */
36 #include <flowprobe/flowprobe.api_enum.h>
37 #include <flowprobe/flowprobe.api_types.h>
38 
42  vlib_frame_t * f);
43 
44 #define REPLY_MSG_ID_BASE fm->msg_id_base
46 
47 /* Define the per-interface configurable features */
48 /* *INDENT-OFF* */
49 VNET_FEATURE_INIT (flow_perpacket_ip4, static) =
50 {
51  .arc_name = "ip4-output",
52  .node_name = "flowprobe-ip4",
53  .runs_before = VNET_FEATURES ("interface-output"),
54 };
55 
56 VNET_FEATURE_INIT (flow_perpacket_ip6, static) =
57 {
58  .arc_name = "ip6-output",
59  .node_name = "flowprobe-ip6",
60  .runs_before = VNET_FEATURES ("interface-output"),
61 };
62 
63 VNET_FEATURE_INIT (flow_perpacket_l2, static) =
64 {
65  .arc_name = "interface-output",
66  .node_name = "flowprobe-l2",
67  .runs_before = VNET_FEATURES ("interface-tx"),
68 };
69 /* *INDENT-ON* */
70 
71 /* Macro to finish up custom dump fns */
72 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
73 #define FINISH \
74  vec_add1 (s, 0); \
75  vl_print (handle, (char *)s); \
76  vec_free (s); \
77  return handle;
78 
79 static inline ipfix_field_specifier_t *
81 {
82 #define flowprobe_template_ip4_field_count() 4
83  /* sourceIpv4Address, TLV type 8, u32 */
84  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
85  sourceIPv4Address, 4);
86  f++;
87  /* destinationIPv4Address, TLV type 12, u32 */
88  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
89  destinationIPv4Address, 4);
90  f++;
91  /* protocolIdentifier, TLV type 4, u8 */
92  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
93  protocolIdentifier, 1);
94  f++;
95  /* octetDeltaCount, TLV type 1, u64 */
96  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
97  octetDeltaCount, 8);
98  f++;
99  return f;
100 }
101 
102 static inline ipfix_field_specifier_t *
104 {
105 #define flowprobe_template_ip6_field_count() 4
106  /* sourceIpv6Address, TLV type 27, 16 octets */
107  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
108  sourceIPv6Address, 16);
109  f++;
110  /* destinationIPv6Address, TLV type 28, 16 octets */
111  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
112  destinationIPv6Address, 16);
113  f++;
114  /* protocolIdentifier, TLV type 4, u8 */
115  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
116  protocolIdentifier, 1);
117  f++;
118  /* octetDeltaCount, TLV type 1, u64 */
119  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
120  octetDeltaCount, 8);
121  f++;
122  return f;
123 }
124 
125 static inline ipfix_field_specifier_t *
127 {
128 #define flowprobe_template_l2_field_count() 3
129  /* sourceMacAddress, TLV type 56, u8[6] we hope */
130  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
131  sourceMacAddress, 6);
132  f++;
133  /* destinationMacAddress, TLV type 80, u8[6] we hope */
134  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
135  destinationMacAddress, 6);
136  f++;
137  /* ethernetType, TLV type 256, u16 */
138  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
139  ethernetType, 2);
140  f++;
141  return f;
142 }
143 
144 static inline ipfix_field_specifier_t *
146 {
147 #define flowprobe_template_common_field_count() 5
148  /* ingressInterface, TLV type 10, u32 */
149  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
150  ingressInterface, 4);
151  f++;
152 
153  /* egressInterface, TLV type 14, u32 */
154  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
155  egressInterface, 4);
156  f++;
157 
158  /* packetDeltaCount, TLV type 2, u64 */
159  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
160  packetDeltaCount, 8);
161  f++;
162 
163  /* flowStartNanoseconds, TLV type 156, u64 */
164  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
165  flowStartNanoseconds, 8);
166  f++;
167 
168  /* flowEndNanoseconds, TLV type 157, u64 */
169  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
170  flowEndNanoseconds, 8);
171  f++;
172 
173  return f;
174 }
175 
176 static inline ipfix_field_specifier_t *
178 {
179 #define flowprobe_template_l4_field_count() 3
180  /* sourceTransportPort, TLV type 7, u16 */
181  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
182  sourceTransportPort, 2);
183  f++;
184  /* destinationTransportPort, TLV type 11, u16 */
185  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
186  destinationTransportPort, 2);
187  f++;
188  /* tcpControlBits, TLV type 6, u16 */
189  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ ,
190  tcpControlBits, 2);
191  f++;
192 
193  return f;
194 }
195 
196 /**
197  * @brief Create an IPFIX template packet rewrite string
198  * @param frm flow_report_main_t *
199  * @param fr flow_report_t *
200  * @param collector_address ip4_address_t * the IPFIX collector address
201  * @param src_address ip4_address_t * the source address we should use
202  * @param collector_port u16 the collector port we should use, host byte order
203  * @returns u8 * vector containing the indicated IPFIX template packet
204  */
205 static inline u8 *
207  flow_report_t * fr,
208  ip4_address_t * collector_address,
210  u16 collector_port,
212 {
213  ip4_header_t *ip;
214  udp_header_t *udp;
219  ipfix_field_specifier_t *first_field;
220  u8 *rewrite = 0;
222  u32 field_count = 0;
223  flow_report_stream_t *stream;
226  bool collect_ip4 = false, collect_ip6 = false;
227 
228  stream = &frm->streams[fr->stream_index];
229 
230  if (flags & FLOW_RECORD_L3)
231  {
232  collect_ip4 = which == FLOW_VARIANT_L2_IP4 || which == FLOW_VARIANT_IP4;
233  collect_ip6 = which == FLOW_VARIANT_L2_IP6 || which == FLOW_VARIANT_IP6;
234  if (which == FLOW_VARIANT_L2_IP4)
235  flags |= FLOW_RECORD_L2_IP4;
236  if (which == FLOW_VARIANT_L2_IP6)
237  flags |= FLOW_RECORD_L2_IP6;
238  }
239 
240  field_count += flowprobe_template_common_field_count ();
241  if (flags & FLOW_RECORD_L2)
242  field_count += flowprobe_template_l2_field_count ();
243  if (collect_ip4)
244  field_count += flowprobe_template_ip4_field_count ();
245  if (collect_ip6)
246  field_count += flowprobe_template_ip6_field_count ();
247  if (flags & FLOW_RECORD_L4)
248  field_count += flowprobe_template_l4_field_count ();
249 
250  /* allocate rewrite space */
252  (rewrite, sizeof (ip4_ipfix_template_packet_t)
253  + field_count * sizeof (ipfix_field_specifier_t) - 1,
255 
256  tp = (ip4_ipfix_template_packet_t *) rewrite;
257  ip = (ip4_header_t *) & tp->ip4;
258  udp = (udp_header_t *) (ip + 1);
259  h = (ipfix_message_header_t *) (udp + 1);
260  s = (ipfix_set_header_t *) (h + 1);
261  t = (ipfix_template_header_t *) (s + 1);
262  first_field = f = (ipfix_field_specifier_t *) (t + 1);
263 
264  ip->ip_version_and_header_length = 0x45;
265  ip->ttl = 254;
266  ip->protocol = IP_PROTOCOL_UDP;
267  ip->src_address.as_u32 = src_address->as_u32;
268  ip->dst_address.as_u32 = collector_address->as_u32;
269  udp->src_port = clib_host_to_net_u16 (stream->src_port);
270  udp->dst_port = clib_host_to_net_u16 (collector_port);
271  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
272 
273  /* FIXUP: message header export_time */
274  /* FIXUP: message header sequence_number */
275  h->domain_id = clib_host_to_net_u32 (stream->domain_id);
276 
277  /* Add TLVs to the template */
279 
280  if (flags & FLOW_RECORD_L2)
282  if (collect_ip4)
284  if (collect_ip6)
286  if (flags & FLOW_RECORD_L4)
288 
289  /* Back to the template packet... */
290  ip = (ip4_header_t *) & tp->ip4;
291  udp = (udp_header_t *) (ip + 1);
292 
293  ASSERT (f - first_field);
294  /* Field count in this template */
295  t->id_count = ipfix_id_count (fr->template_id, f - first_field);
296 
297  fm->template_size[flags] = (u8 *) f - (u8 *) s;
298 
299  /* set length in octets */
300  s->set_id_length =
301  ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
302 
303  /* message length in octets */
304  h->version_length = version_length ((u8 *) f - (u8 *) h);
305 
306  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
307  ip->checksum = ip4_header_checksum (ip);
308 
309  return rewrite;
310 }
311 
312 static u8 *
314  flow_report_t * fr,
315  ip4_address_t * collector_address,
317  u16 collector_port,
318  ipfix_report_element_t * elts,
319  u32 n_elts, u32 * stream_index)
320 {
322  (frm, fr, collector_address, src_address, collector_port,
324 }
325 
326 static u8 *
328  flow_report_t * fr,
329  ip4_address_t * collector_address,
331  u16 collector_port,
332  ipfix_report_element_t * elts,
333  u32 n_elts, u32 * stream_index)
334 {
336  (frm, fr, collector_address, src_address, collector_port,
338 }
339 
340 static u8 *
342  flow_report_t * fr,
343  ip4_address_t * collector_address,
345  u16 collector_port,
346  ipfix_report_element_t * elts,
347  u32 n_elts, u32 * stream_index)
348 {
350  (frm, fr, collector_address, src_address, collector_port,
352 }
353 
354 static u8 *
356  flow_report_t * fr,
357  ip4_address_t * collector_address,
359  u16 collector_port,
360  ipfix_report_element_t * elts,
361  u32 n_elts, u32 * stream_index)
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,
373  u16 collector_port,
374  ipfix_report_element_t * elts,
375  u32 n_elts, u32 * stream_index)
376 {
378  (frm, fr, collector_address, src_address, collector_port,
380 }
381 
382 /**
383  * @brief Flush accumulated data
384  * @param frm flow_report_main_t *
385  * @param fr flow_report_t *
386  * @param f vlib_frame_t *
387  *
388  * <em>Notes:</em>
389  * This function must simply return the incoming frame, or no template packets
390  * will be sent.
391  */
392 vlib_frame_t *
394  flow_report_t * fr,
395  vlib_frame_t * f, u32 * to_next, u32 node_index)
396 {
398  return f;
399 }
400 
401 vlib_frame_t *
403  flow_report_t * fr,
404  vlib_frame_t * f, u32 * to_next, u32 node_index)
405 {
407  return f;
408 }
409 
410 vlib_frame_t *
412  flow_report_t * fr,
413  vlib_frame_t * f, u32 * to_next, u32 node_index)
414 {
416  return f;
417 }
418 
419 static int
422  vnet_flow_data_callback_t * flow_data_callback,
423  vnet_flow_rewrite_callback_t * rewrite_callback,
424  bool is_add, u16 * template_id)
425 {
428  .rewrite_callback = rewrite_callback,
429  .flow_data_callback = flow_data_callback,
430  .is_add = is_add,
431  .domain_id = domain_id,
432  .src_port = src_port,
433  .opaque.as_uword = flags,
434  };
435  return vnet_flow_report_add_del (frm, &a, template_id);
436 }
437 
438 static void
440 {
443  u32 my_cpu_number = vm->thread_index;
444  int i;
445  u32 poolindex;
446 
447  for (i = 0; i < vec_len (expired_timers); i++)
448  {
449  poolindex = expired_timers[i] & 0x7FFFFFFF;
450  vec_add1 (fm->expired_passive_per_worker[my_cpu_number], poolindex);
451  }
452 }
453 
454 static clib_error_t *
456 {
460  clib_error_t *error = 0;
461  u32 num_threads;
462  int i;
463 
464  /* Decide how many worker threads we have */
465  num_threads = 1 /* main thread */ + tm->n_threads;
466 
467  /* Hash table per worker */
469 
470  /* Init per worker flow state and timer wheels */
471  if (active_timer)
472  {
473  vec_validate (fm->timers_per_worker, num_threads - 1);
474  vec_validate (fm->expired_passive_per_worker, num_threads - 1);
475  vec_validate (fm->hash_per_worker, num_threads - 1);
476  vec_validate (fm->pool_per_worker, num_threads - 1);
477 
478  for (i = 0; i < num_threads; i++)
479  {
480  int j;
481  pool_alloc (fm->pool_per_worker[i], 1 << fm->ht_log2len);
482  vec_resize (fm->hash_per_worker[i], 1 << fm->ht_log2len);
483  for (j = 0; j < (1 << fm->ht_log2len); j++)
484  fm->hash_per_worker[i][j] = ~0;
485  fm->timers_per_worker[i] =
486  clib_mem_alloc (sizeof (TWT (tw_timer_wheel)));
487  tw_timer_wheel_init_2t_1w_2048sl (fm->timers_per_worker[i],
489  1.0, 1024);
490  }
491  fm->disabled = true;
492  }
493  else
494  {
495  f64 now = vlib_time_now (vm);
496  vec_validate (fm->stateless_entry, num_threads - 1);
497  for (i = 0; i < num_threads; i++)
498  fm->stateless_entry[i].last_exported = now;
499  fm->disabled = false;
500  }
501  fm->initialized = true;
502  return error;
503 }
504 
505 static int
507  u8 which)
508 {
509  vec_validate_init_empty (fm->flow_per_interface, sw_if_index, ~0);
510 
511  if (fm->flow_per_interface[sw_if_index] == (u8) ~ 0)
512  return -1;
513  else if (fm->flow_per_interface[sw_if_index] != which)
514  return 0;
515  else
516  return 1;
517 }
518 
519 /**
520  * @brief configure / deconfigure the IPFIX flow-per-packet
521  * @param fm flowprobe_main_t * fm
522  * @param sw_if_index u32 the desired interface
523  * @param is_add int 1 to enable the feature, 0 to disable it
524  * @returns 0 if successful, non-zero otherwise
525  */
526 
527 static int
529  u32 sw_if_index, u8 which, int is_add)
530 {
532  int rv = 0;
533  u16 template_id = 0;
535 
536  fm->flow_per_interface[sw_if_index] = (is_add) ? which : (u8) ~ 0;
537  fm->template_per_flow[which] += (is_add) ? 1 : -1;
538  if (is_add && fm->template_per_flow[which] > 1)
539  template_id = fm->template_reports[flags];
540 
541  if ((is_add && fm->template_per_flow[which] == 1) ||
542  (!is_add && fm->template_per_flow[which] == 0))
543  {
544  if (which == FLOW_VARIANT_L2)
545  {
546  if (fm->record & FLOW_RECORD_L2)
547  {
548  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
551  is_add, &template_id);
552  }
553  if (fm->record & FLOW_RECORD_L3 || fm->record & FLOW_RECORD_L4)
554  {
555  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
558  is_add, &template_id);
559  fm->template_reports[flags | FLOW_RECORD_L2_IP4] =
560  (is_add) ? template_id : 0;
561  rv =
562  flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
565  is_add, &template_id);
566  fm->template_reports[flags | FLOW_RECORD_L2_IP6] =
567  (is_add) ? template_id : 0;
568 
569  /* Special case L2 */
571  flags | FLOW_RECORD_L2_IP4;
573  flags | FLOW_RECORD_L2_IP6;
574 
575  fm->template_reports[flags] = template_id;
576  }
577  }
578  else if (which == FLOW_VARIANT_IP4)
579  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
582  is_add, &template_id);
583  else if (which == FLOW_VARIANT_IP6)
584  rv = flowprobe_template_add_del (1, UDP_DST_PORT_ipfix, flags,
587  is_add, &template_id);
588  }
589  if (rv && rv != VNET_API_ERROR_VALUE_EXIST)
590  {
591  clib_warning ("vnet_flow_report_add_del returned %d", rv);
592  return -1;
593  }
594 
595  if (which != (u8) ~ 0)
596  {
597  fm->context[which].flags = fm->record;
598  fm->template_reports[flags] = (is_add) ? template_id : 0;
599  }
600 
601  if (which == FLOW_VARIANT_IP4)
602  vnet_feature_enable_disable ("ip4-output", "flowprobe-ip4",
603  sw_if_index, is_add, 0, 0);
604  else if (which == FLOW_VARIANT_IP6)
605  vnet_feature_enable_disable ("ip6-output", "flowprobe-ip6",
606  sw_if_index, is_add, 0, 0);
607  else if (which == FLOW_VARIANT_L2)
608  vnet_feature_enable_disable ("interface-output", "flowprobe-l2",
609  sw_if_index, is_add, 0, 0);
610 
611  /* Stateful flow collection */
612  if (is_add && !fm->initialized)
613  {
615  if (fm->active_timer)
616  vlib_process_signal_event (vm, flowprobe_timer_node.index, 1, 0);
617  }
618 
619  return 0;
620 }
621 
622 /**
623  * @brief API message handler
624  * @param mp vl_api_flowprobe_tx_interface_add_del_t * mp the api message
625  */
628 {
630  vl_api_flowprobe_tx_interface_add_del_reply_t *rmp;
631  u32 sw_if_index = ntohl (mp->sw_if_index);
632  int rv = 0;
633 
635 
636  if (fm->record == 0)
637  {
638  clib_warning ("Please specify flowprobe params record first...");
639  rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
640  goto out;
641  }
642 
643  rv = validate_feature_on_interface (fm, sw_if_index, mp->which);
644  if ((rv == 1 && mp->is_add == 1) || rv == 0)
645  {
646  rv = VNET_API_ERROR_CANNOT_ENABLE_DISABLE_FEATURE;
647  goto out;
648  }
649 
651  (fm, sw_if_index, mp->which, mp->is_add);
652 
653 out:
655 
656  REPLY_MACRO (VL_API_FLOWPROBE_TX_INTERFACE_ADD_DEL_REPLY);
657 }
658 
659 #define vec_neg_search(v,E) \
660 ({ \
661  word _v(i) = 0; \
662  while (_v(i) < vec_len(v) && v[_v(i)] == E) \
663  { \
664  _v(i)++; \
665  } \
666  if (_v(i) == vec_len(v)) \
667  _v(i) = ~0; \
668  _v(i); \
669 })
670 
671 static int
673  u8 record_l3, u8 record_l4,
674  u32 active_timer, u32 passive_timer)
675 {
677 
678  if (vec_neg_search (fm->flow_per_interface, (u8) ~ 0) != ~0)
679  return ~0;
680 
681  if (record_l2)
682  flags |= FLOW_RECORD_L2;
683  if (record_l3)
684  flags |= FLOW_RECORD_L3;
685  if (record_l4)
686  flags |= FLOW_RECORD_L4;
687 
688  fm->record = flags;
689 
690  /*
691  * Timers: ~0 is default, 0 is off
692  */
693  fm->active_timer =
694  (active_timer == (u32) ~ 0 ? FLOWPROBE_TIMER_ACTIVE : active_timer);
695  fm->passive_timer =
696  (passive_timer == (u32) ~ 0 ? FLOWPROBE_TIMER_PASSIVE : passive_timer);
697 
698  return 0;
699 }
700 
701 void
703 {
705  vl_api_flowprobe_params_reply_t *rmp;
706  int rv = 0;
707 
708  rv = flowprobe_params
709  (fm,
713  clib_net_to_host_u32 (mp->active_timer),
714  clib_net_to_host_u32 (mp->passive_timer));
715 
716  REPLY_MACRO (VL_API_FLOWPROBE_PARAMS_REPLY);
717 }
718 
719 /* *INDENT-OFF* */
721  .version = VPP_BUILD_VER,
722  .description = "Flow per Packet",
723 };
724 /* *INDENT-ON* */
725 
726 u8 *
727 format_flowprobe_entry (u8 * s, va_list * args)
728 {
729  flowprobe_entry_t *e = va_arg (*args, flowprobe_entry_t *);
730  s = format (s, " %d/%d", e->key.rx_sw_if_index, e->key.tx_sw_if_index);
731 
732  s = format (s, " %U %U", format_ethernet_address, &e->key.src_mac,
734  s = format (s, " %U -> %U",
737  s = format (s, " %d", e->key.protocol);
738  s = format (s, " %d %d\n", clib_net_to_host_u16 (e->key.src_port),
739  clib_net_to_host_u16 (e->key.dst_port));
740 
741  return s;
742 }
743 
744 u8 *
745 format_flowprobe_feature (u8 * s, va_list * args)
746 {
747  u8 *which = va_arg (*args, u8 *);
748  if (*which == FLOW_VARIANT_IP4)
749  s = format (s, "ip4");
750  else if (*which == FLOW_VARIANT_IP6)
751  s = format (s, "ip6");
752  else if (*which == FLOW_VARIANT_L2)
753  s = format (s, "l2");
754 
755  return s;
756 }
757 
758 u8 *
759 format_flowprobe_params (u8 * s, va_list * args)
760 {
761  flowprobe_record_t flags = va_arg (*args, flowprobe_record_t);
762  u32 active_timer = va_arg (*args, u32);
763  u32 passive_timer = va_arg (*args, u32);
764 
765  if (flags & FLOW_RECORD_L2)
766  s = format (s, " l2");
767  if (flags & FLOW_RECORD_L3)
768  s = format (s, " l3");
769  if (flags & FLOW_RECORD_L4)
770  s = format (s, " l4");
771 
772  if (active_timer != (u32) ~ 0)
773  s = format (s, " active: %d", active_timer);
774 
775  if (passive_timer != (u32) ~ 0)
776  s = format (s, " passive: %d", passive_timer);
777 
778  return s;
779 }
780 
781 static clib_error_t *
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",
798  e);
799  }
800  /* *INDENT-ON* */
801 
802  }
803  return 0;
804 }
805 
806 static clib_error_t *
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;
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  u8 *which;
901 
902  vec_foreach (which, fm->flow_per_interface)
903  {
904  if (*which == (u8) ~ 0)
905  continue;
906 
907  sw_if_index = which - fm->flow_per_interface;
909  vnet_get_main (), sw_if_index, format_flowprobe_feature,
910  which);
911  }
912  return 0;
913 }
914 
915 static clib_error_t *
917  unformat_input_t * input,
918  vlib_cli_command_t * cmd)
919 {
921  bool record_l2 = false, record_l3 = false, record_l4 = false;
922  u32 active_timer = ~0;
923  u32 passive_timer = ~0;
924 
926  {
927  if (unformat (input, "active %d", &active_timer))
928  ;
929  else if (unformat (input, "passive %d", &passive_timer))
930  ;
931  else if (unformat (input, "record"))
933  {
934  if (unformat (input, "l2"))
935  record_l2 = true;
936  else if (unformat (input, "l3"))
937  record_l3 = true;
938  else if (unformat (input, "l4"))
939  record_l4 = true;
940  else
941  break;
942  }
943  else
944  break;
945  }
946 
947  if (passive_timer > 0 && active_timer > passive_timer)
948  return clib_error_return (0,
949  "Passive timer has to be greater than active one...");
950 
951  if (flowprobe_params (fm, record_l2, record_l3, record_l4,
952  active_timer, passive_timer))
953  return clib_error_return (0,
954  "Couldn't change flowperpacket params when feature is enabled on some interface ...");
955  return 0;
956 }
957 
958 static clib_error_t *
960  unformat_input_t * input,
961  vlib_cli_command_t * cmd)
962 {
965  u32 active_timer = fm->active_timer;
966  u32 passive_timer = fm->passive_timer;
967 
968  vlib_cli_output (vm, "%U", format_flowprobe_params, flags, active_timer,
969  passive_timer);
970  return 0;
971 }
972 
973 /*?
974  * '<em>flowprobe feature add-del</em>' commands to enable/disable
975  * per-packet IPFIX flow record generation on an interface
976  *
977  * @cliexpar
978  * @parblock
979  * To enable per-packet IPFIX flow-record generation on an interface:
980  * @cliexcmd{flowprobe feature add-del GigabitEthernet2/0/0}
981  *
982  * To disable per-packet IPFIX flow-record generation on an interface:
983  * @cliexcmd{flowprobe feature add-del GigabitEthernet2/0/0 disable}
984  * @cliexend
985  * @endparblock
986 ?*/
987 /* *INDENT-OFF* */
988 VLIB_CLI_COMMAND (flowprobe_enable_disable_command, static) = {
989  .path = "flowprobe feature add-del",
990  .short_help =
991  "flowprobe feature add-del <interface-name> <l2|ip4|ip6> disable",
993 };
994 VLIB_CLI_COMMAND (flowprobe_params_command, static) = {
995  .path = "flowprobe params",
996  .short_help =
997  "flowprobe params record <[l2] [l3] [l4]> [active <timer> passive <timer>]",
998  .function = flowprobe_params_command_fn,
999 };
1000 
1001 VLIB_CLI_COMMAND (flowprobe_show_feature_command, static) = {
1002  .path = "show flowprobe feature",
1003  .short_help =
1004  "show flowprobe feature",
1006 };
1007 VLIB_CLI_COMMAND (flowprobe_show_params_command, static) = {
1008  .path = "show flowprobe params",
1009  .short_help =
1010  "show flowprobe params",
1012 };
1013 VLIB_CLI_COMMAND (flowprobe_show_table_command, static) = {
1014  .path = "show flowprobe table",
1015  .short_help = "show flowprobe table",
1016  .function = flowprobe_show_table_fn,
1017 };
1018 VLIB_CLI_COMMAND (flowprobe_show_stats_command, static) = {
1019  .path = "show flowprobe statistics",
1020  .short_help = "show flowprobe statistics",
1021  .function = flowprobe_show_stats_fn,
1022 };
1023 /* *INDENT-ON* */
1024 
1025 /*
1026  * Main-core process, sending an interrupt to the per worker input
1027  * process that spins the per worker timer wheel.
1028  */
1029 static uword
1031 {
1032  uword *event_data = 0;
1033  vlib_main_t **worker_vms = 0, *worker_vm;
1035 
1036  /* Wait for Godot... */
1038  uword event_type = vlib_process_get_events (vm, &event_data);
1039  if (event_type != 1)
1040  clib_warning ("bogus kickoff event received, %d", event_type);
1041  vec_reset_length (event_data);
1042 
1043  int i;
1044  if (vec_len (vlib_mains) == 0)
1045  vec_add1 (worker_vms, vm);
1046  else
1047  {
1048  for (i = 0; i < vec_len (vlib_mains); i++)
1049  {
1050  worker_vm = vlib_mains[i];
1051  if (worker_vm)
1052  vec_add1 (worker_vms, worker_vm);
1053  }
1054  }
1055  f64 sleep_duration = 0.1;
1056 
1057  while (1)
1058  {
1059  /* Send an interrupt to each timer input node */
1060  sleep_duration = 0.1;
1061  for (i = 0; i < vec_len (worker_vms); i++)
1062  {
1063  worker_vm = worker_vms[i];
1064  if (worker_vm)
1065  {
1067  flowprobe_walker_node.index);
1068  sleep_duration =
1069  (fm->expired_passive_per_worker[i] > 0) ? 1e-4 : 0.1;
1070  }
1071  }
1072  vlib_process_suspend (vm, sleep_duration);
1073  }
1074  return 0; /* or not */
1075 }
1076 
1077 /* *INDENT-OFF* */
1078 VLIB_REGISTER_NODE (flowprobe_timer_node,static) = {
1079  .function = timer_process,
1080  .name = "flowprobe-timer-process",
1081  .type = VLIB_NODE_TYPE_PROCESS,
1082 };
1083 /* *INDENT-ON* */
1084 
1085 #include <flowprobe/flowprobe.api.c>
1086 
1087 /**
1088  * @brief Set up the API message handling tables
1089  * @param vm vlib_main_t * vlib main data structure pointer
1090  * @returns 0 to indicate all is well, or a clib_error_t
1091  */
1092 static clib_error_t *
1094 {
1097  clib_error_t *error = 0;
1098  u32 num_threads;
1099  int i;
1100 
1101  fm->vnet_main = vnet_get_main ();
1102 
1103  /* Ask for a correctly-sized block of API message decode slots */
1105 
1106  /* Set up time reference pair */
1107  fm->vlib_time_0 = vlib_time_now (vm);
1109 
1110  clib_memset (fm->template_reports, 0, sizeof (fm->template_reports));
1111  clib_memset (fm->template_size, 0, sizeof (fm->template_size));
1112  clib_memset (fm->template_per_flow, 0, sizeof (fm->template_per_flow));
1113 
1114  /* Decide how many worker threads we have */
1115  num_threads = 1 /* main thread */ + tm->n_threads;
1116 
1117  /* Allocate per worker thread vectors per flavour */
1118  for (i = 0; i < FLOW_N_VARIANTS; i++)
1119  {
1120  vec_validate (fm->context[i].buffers_per_worker, num_threads - 1);
1121  vec_validate (fm->context[i].frames_per_worker, num_threads - 1);
1123  num_threads - 1);
1124  }
1125 
1128 
1129  return error;
1130 }
1131 
1133 
1134 /*
1135  * fd.io coding-style-patch-verification: ON
1136  *
1137  * Local Variables:
1138  * eval: (c-set-style "gnu")
1139  * End:
1140  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
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:393
u32 ** expired_passive_per_worker
Definition: flowprobe.h:140
u8 * format_flowprobe_feature(u8 *s, va_list *args)
Definition: flowprobe.c:745
#define FLOWPROBE_LOG2_HASHSIZE
Definition: flowprobe.h:33
void flowprobe_flush_callback_ip6(void)
Definition: node.c:887
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:751
vl_api_interface_index_t sw_if_index
Definition: flowprobe.api:46
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
a
Definition: bitmap.h:544
ip46_address_t src_address
Definition: flowprobe.h:82
#define FLOWPROBE_TIMER_PASSIVE
Definition: flowprobe.h:32
ip4_address_t src_address
Definition: ip4_packet.h:125
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
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, ipfix_report_element_t *elts, u32 n_elts, u32 *stream_index)
Definition: flowprobe.c:313
uword as_uword
Definition: flow_report.h:74
#define pool_foreach(VAR, POOL)
Iterate through pool.
Definition: pool.h:527
#define pool_alloc(P, N)
Allocate N more free elements to pool (unspecified alignment).
Definition: pool.h:360
static void vlib_node_set_interrupt_pending(vlib_main_t *vm, u32 node_index)
Definition: node_funcs.h:255
static u32 ipfix_e_id_length(int e, u16 id, u16 length)
Definition: ipfix_packet.h:77
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:334
flowprobe_key_t key
Definition: flowprobe.h:99
u32 stream_index
Definition: flow_report.h:91
vl_api_flowprobe_which_flags_t which
Definition: flowprobe.api:43
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:335
flowprobe_record_t record
Definition: flowprobe.h:142
u32 thread_index
Definition: main.h:250
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:592
opaque_t opaque
Definition: flow_report.h:99
#define flowprobe_template_l2_field_count()
vlib_main_t * vm
Definition: in2out_ed.c:1580
flowprobe_entry_t * stateless_entry
Definition: flowprobe.h:145
u16 template_reports[FLOW_N_RECORDS]
Definition: flowprobe.h:126
unformat_function_t unformat_vnet_sw_interface
vlib_frame_t *() vnet_flow_data_callback_t(struct flow_report_main *, struct flow_report *, vlib_frame_t *, u32 *, u32)
Definition: flow_report.h:52
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:520
u32 tx_sw_if_index
Definition: flowprobe.h:78
vlib_main_t ** vlib_mains
Definition: buffer.c:332
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
static ipfix_field_specifier_t * flowprobe_template_common_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:145
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
double f64
Definition: types.h:142
#define fm
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:33
flow_report_stream_t * streams
Definition: flow_report.h:114
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:482
static ipfix_field_specifier_t * flowprobe_template_ip4_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:80
flow-per-packet plugin header file
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:44
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
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:579
int which
Definition: cJSON.h:234
ip4_address_t dst_address
Definition: ip4_packet.h:125
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
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, ipfix_report_element_t *elts, u32 n_elts, u32 *stream_index)
Definition: flowprobe.c:327
description fragment has unexpected format
Definition: map.api:433
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, ipfix_report_element_t *elts, u32 n_elts, u32 *stream_index)
Definition: flowprobe.c:341
u8 * format_flowprobe_params(u8 *s, va_list *args)
Definition: flowprobe.c:759
#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:281
unsigned int u32
Definition: types.h:88
void flowprobe_flush_callback_ip4(void)
Definition: node.c:881
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:672
static clib_error_t * flowprobe_show_params_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: flowprobe.c:959
u8 ht_log2len
Per CPU flow-state.
Definition: flowprobe.h:134
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
Definition: cJSON.c:84
flow_report_main_t flow_report_main
Definition: flow_report.c:22
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:528
static void vlib_process_signal_event(vlib_main_t *vm, uword node_index, uword type_opaque, uword data)
Definition: node_funcs.h:1015
VNET_FEATURE_INIT(flow_perpacket_ip4, static)
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
#define flowprobe_template_ip4_field_count()
vec_header_t h
Definition: buffer.c:322
u32 rx_sw_if_index
Definition: flowprobe.h:77
u16 template_per_flow[FLOW_N_VARIANTS]
Definition: flowprobe.h:150
#define REPLY_MACRO(t)
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, ipfix_report_element_t *elts, u32 n_elts, u32 *stream_index)
Definition: flowprobe.c:369
vl_api_address_union_t src_address
Definition: ip_types.api:122
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, ipfix_report_element_t *elts, u32 n_elts, u32 *stream_index)
Definition: flowprobe.c:355
VLIB_PLUGIN_REGISTER()
u8 *() vnet_flow_rewrite_callback_t(struct flow_report_main *, struct flow_report *, ip4_address_t *, ip4_address_t *, u16, ipfix_report_element_t *elts, u32 n_elts, u32 *stream_index)
Definition: flow_report.h:57
static void flowprobe_expired_timer_callback(u32 *expired_timers)
Definition: flowprobe.c:439
static u32 version_length(u16 length)
Definition: ipfix_packet.h:33
vlib_thread_main_t vlib_thread_main
Definition: threads.c:35
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:627
format_function_t format_ip46_address
Definition: ip46_address.h:50
vl_api_ip_port_and_mask_t src_port
Definition: flow_types.api:91
static void setup_message_id_table(api_main_t *am)
Definition: bfd_api.c:409
#define BAD_SW_IF_INDEX_LABEL
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
#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:807
#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:420
f64 last_exported
Definition: flowprobe.h:105
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
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:184
#define clib_warning(format, args...)
Definition: error.h:59
#define vec_neg_search(v, E)
Definition: flowprobe.c:659
static u64 unix_time_now_nsec(void)
Definition: time.h:270
static clib_error_t * flowprobe_init(vlib_main_t *vm)
Set up the API message handling tables.
Definition: flowprobe.c:1093
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
flowprobe_record_t
Definition: flowprobe.h:35
#define ASSERT(truth)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
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:411
u16 template_id
Definition: flow_report.h:90
static ipfix_field_specifier_t * flowprobe_template_ip6_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:103
static void * clib_mem_alloc(uword size)
Definition: mem.h:253
#define VNET_FEATURES(...)
Definition: feature.h:470
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
flowprobe_main_t flowprobe_main
Definition: flowprobe.c:39
struct _vlib_node_registration vlib_node_registration_t
static u32 ipfix_set_id_length(u16 set_id, u16 length)
Definition: ipfix_packet.h:121
vlib_buffer_t ** buffers_per_worker
ipfix buffers under construction, per-worker thread
Definition: flowprobe.h:68
vl_api_address_t ip
Definition: l2.api:501
#define flowprobe_template_common_field_count()
void flowprobe_flush_callback_l2(void)
Definition: node.c:893
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u64 uword
Definition: types.h:112
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:177
static clib_error_t * flowprobe_show_feature_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: flowprobe.c:894
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:702
u8 * format_flowprobe_entry(u8 *s, va_list *args)
Definition: flowprobe.c:727
static ipfix_field_specifier_t * flowprobe_template_l2_fields(ipfix_field_specifier_t *f)
Definition: flowprobe.c:126
static int validate_feature_on_interface(flowprobe_main_t *fm, u32 sw_if_index, u8 which)
Definition: flowprobe.c:506
ip46_address_t dst_address
Definition: flowprobe.h:83
#define vec_foreach(var, vec)
Vector iterator.
vlib_node_registration_t flowprobe_walker_node
(constructor) VLIB_REGISTER_NODE (flowprobe_walker_node)
Definition: node.c:1034
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:402
u8 ip_version_and_header_length
Definition: ip4_packet.h:93
u16 * next_record_offset_per_worker
next record offset, per worker thread
Definition: flowprobe.h:72
static uword timer_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Definition: flowprobe.c:1030
#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:556
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
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:916
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:206
static vlib_node_registration_t flowprobe_timer_node
(constructor) VLIB_REGISTER_NODE (flowprobe_timer_node)
Definition: flowprobe.c:40
static clib_error_t * flowprobe_create_state_tables(u32 active_timer)
Definition: flowprobe.c:455
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:314
Definition: flowprobe.h:97
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
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:303
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
#define VALIDATE_SW_IF_INDEX(mp)
vl_api_flowprobe_record_flags_t record_flags
Definition: flowprobe.api:54
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:127