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