FD.io VPP  v17.04.2-2-ga8f93f8
Vector Packet Processing
flowperpkt.c
Go to the documentation of this file.
1 /*
2  * flowperpkt.c - per-packet data capture flow report plugin
3  *
4  * Copyright (c) <current-year> <your-organization>
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 <flowperpkt/flowperpkt.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 
55 
56 /* Get the API version number */
57 #define vl_api_version(n,v) static u32 api_version=(v);
59 #undef vl_api_version
60 
61 #define REPLY_MSG_ID_BASE fm->msg_id_base
63 
64 /* Define the per-interface configurable features */
65 /* *INDENT-OFF* */
66 VNET_FEATURE_INIT (flow_perpacket_ipv4, static) =
67 {
68  .arc_name = "ip4-output",
69  .node_name = "flowperpkt-ipv4",
70  .runs_before = VNET_FEATURES ("interface-output"),
71 };
72 
73 VNET_FEATURE_INIT (flow_perpacket_l2, static) =
74 {
75  .arc_name = "interface-output",
76  .node_name = "flowperpkt-l2",
77  .runs_before = VNET_FEATURES ("interface-tx"),
78 };
79 /* *INDENT-ON* */
80 
81 /* Macro to finish up custom dump fns */
82 #define FINISH \
83  vec_add1 (s, 0); \
84  vl_print (handle, (char *)s); \
85  vec_free (s); \
86  return handle;
87 
88 /**
89  * @brief Create an IPFIX template packet rewrite string
90  * @param frm flow_report_main_t *
91  * @param fr flow_report_t *
92  * @param collector_address ip4_address_t * the IPFIX collector address
93  * @param src_address ip4_address_t * the source address we should use
94  * @param collector_port u16 the collector port we should use, host byte order
95  * @returns u8 * vector containing the indicated IPFIX template packet
96  */
97 static inline u8 *
99  flow_report_t * fr,
100  ip4_address_t * collector_address,
101  ip4_address_t * src_address,
102  u16 collector_port, int variant)
103 {
104  ip4_header_t *ip;
105  udp_header_t *udp;
110  ipfix_field_specifier_t *first_field;
111  u8 *rewrite = 0;
113  u32 field_count = 0;
114  flow_report_stream_t *stream;
116 
117  stream = &frm->streams[fr->stream_index];
118 
119  if (variant == FLOW_VARIANT_IPV4)
120  {
121  /*
122  * ip4 Supported Fields:
123  *
124  * ingressInterface, TLV type 10, u32
125  * egressInterface, TLV type 14, u32
126  * sourceIpv4Address, TLV type 8, u32
127  * destinationIPv4Address, TLV type 12, u32
128  * ipClassOfService, TLV type 5, u8
129  * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64)
130  * Implementation: f64 nanoseconds since VPP started
131  * warning: wireshark doesn't really understand this TLV
132  * dataLinkFrameSize, TLV type 312, u16
133  * warning: wireshark doesn't understand this TLV at all
134  */
135 
136  /* Currently 7 fields */
137  field_count += 7;
138 
139  /* allocate rewrite space */
141  (rewrite,
143  + field_count * sizeof (ipfix_field_specifier_t) - 1,
145  }
146  else if (variant == FLOW_VARIANT_L2)
147  {
148  /*
149  * L2 Supported Fields:
150  *
151  * ingressInterface, TLV type 10, u32
152  * egressInterface, TLV type 14, u32
153  * sourceMacAddress, TLV type 56, u8[6] we hope
154  * destinationMacAddress, TLV type 57, u8[6] we hope
155  * ethernetType, TLV type 256, u16
156  * flowStartNanoseconds, TLV type 156, dateTimeNanoseconds (f64)
157  * Implementation: f64 nanoseconds since VPP started
158  * warning: wireshark doesn't really understand this TLV
159  * dataLinkFrameSize, TLV type 312, u16
160  * warning: wireshark doesn't understand this TLV at all
161  */
162 
163  /* Currently 7 fields */
164  field_count += 7;
165 
166  /* allocate rewrite space */
168  (rewrite,
170  + field_count * sizeof (ipfix_field_specifier_t) - 1,
172  }
173 
174  tp = (ip4_ipfix_template_packet_t *) rewrite;
175  ip = (ip4_header_t *) & tp->ip4;
176  udp = (udp_header_t *) (ip + 1);
177  h = (ipfix_message_header_t *) (udp + 1);
178  s = (ipfix_set_header_t *) (h + 1);
179  t = (ipfix_template_header_t *) (s + 1);
180  first_field = f = (ipfix_field_specifier_t *) (t + 1);
181 
182  ip->ip_version_and_header_length = 0x45;
183  ip->ttl = 254;
184  ip->protocol = IP_PROTOCOL_UDP;
185  ip->src_address.as_u32 = src_address->as_u32;
186  ip->dst_address.as_u32 = collector_address->as_u32;
187  udp->src_port = clib_host_to_net_u16 (stream->src_port);
188  udp->dst_port = clib_host_to_net_u16 (collector_port);
189  udp->length = clib_host_to_net_u16 (vec_len (rewrite) - sizeof (*ip));
190 
191  /* FIXUP: message header export_time */
192  /* FIXUP: message header sequence_number */
193  h->domain_id = clib_host_to_net_u32 (stream->domain_id);
194 
195  /* Add TLVs to the template */
196  if (variant == FLOW_VARIANT_IPV4)
197  {
198  f->e_id_length =
199  ipfix_e_id_length (0 /* enterprise */ , ingressInterface,
200  4);
201  f++;
202  f->e_id_length =
203  ipfix_e_id_length (0 /* enterprise */ , egressInterface,
204  4);
205  f++;
206  f->e_id_length =
207  ipfix_e_id_length (0 /* enterprise */ , sourceIPv4Address,
208  4);
209  f++;
210  f->e_id_length =
211  ipfix_e_id_length (0 /* enterprise */ , destinationIPv4Address, 4);
212  f++;
213  f->e_id_length =
214  ipfix_e_id_length (0 /* enterprise */ , ipClassOfService,
215  1);
216  f++;
217  f->e_id_length =
218  ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds,
219  8);
220  f++;
221  f->e_id_length =
222  ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize,
223  2);
224  f++;
225  }
226  else if (variant == FLOW_VARIANT_L2)
227  {
228  f->e_id_length =
229  ipfix_e_id_length (0 /* enterprise */ , ingressInterface,
230  4);
231  f++;
232  f->e_id_length =
233  ipfix_e_id_length (0 /* enterprise */ , egressInterface,
234  4);
235  f++;
236  f->e_id_length =
237  ipfix_e_id_length (0 /* enterprise */ , sourceMacAddress,
238  6);
239  f++;
240  f->e_id_length =
241  ipfix_e_id_length (0 /* enterprise */ , destinationMacAddress, 6);
242  f++;
243  f->e_id_length = ipfix_e_id_length (0 /* enterprise */ , ethernetType,
244  2);
245  f++;
246  f->e_id_length =
247  ipfix_e_id_length (0 /* enterprise */ , flowStartNanoseconds,
248  8);
249  f++;
250  f->e_id_length =
251  ipfix_e_id_length (0 /* enterprise */ , dataLinkFrameSize,
252  2);
253  f++;
254  }
255 
256  /* Extend in the obvious way, right here... */
257 
258  /* Back to the template packet... */
259  ip = (ip4_header_t *) & tp->ip4;
260  udp = (udp_header_t *) (ip + 1);
261 
262  ASSERT (f - first_field);
263  /* Field count in this template */
264  t->id_count = ipfix_id_count (fr->template_id, f - first_field);
265 
266  if (variant == FLOW_VARIANT_IPV4)
267  fm->ipv4_report_id = fr->template_id;
268  else if (variant == FLOW_VARIANT_L2)
269  fm->l2_report_id = fr->template_id;
270 
271  /* set length in octets */
272  s->set_id_length =
273  ipfix_set_id_length (2 /* set_id */ , (u8 *) f - (u8 *) s);
274 
275  /* message length in octets */
276  h->version_length = version_length ((u8 *) f - (u8 *) h);
277 
278  ip->length = clib_host_to_net_u16 ((u8 *) f - (u8 *) ip);
279  ip->checksum = ip4_header_checksum (ip);
280 
281  return rewrite;
282 }
283 
284 u8 *
286  flow_report_t * fr,
287  ip4_address_t * collector_address,
288  ip4_address_t * src_address,
289  u16 collector_port)
290 {
292  (frm, fr, collector_address, src_address, collector_port,
294 }
295 
296 u8 *
298  flow_report_t * fr,
299  ip4_address_t * collector_address,
300  ip4_address_t * src_address,
301  u16 collector_port)
302 {
304  (frm, fr, collector_address, src_address, collector_port,
306 }
307 
308 
309 /**
310  * @brief Flush accumulated data
311  * @param frm flow_report_main_t *
312  * @param fr flow_report_t *
313  * @param f vlib_frame_t *
314  *
315  * <em>Notes:</em>
316  * This function must simply return the incoming frame, or no template packets
317  * will be sent.
318  */
319 vlib_frame_t *
321  flow_report_t * fr,
322  vlib_frame_t * f, u32 * to_next,
323  u32 node_index)
324 {
326  return f;
327 }
328 
329 vlib_frame_t *
331  flow_report_t * fr,
332  vlib_frame_t * f, u32 * to_next, u32 node_index)
333 {
335  return f;
336 }
337 
338 /**
339  * @brief configure / deconfigure the IPFIX flow-per-packet
340  * @param fm flowperpkt_main_t * fm
341  * @param sw_if_index u32 the desired interface
342  * @param is_add int 1 to enable the feature, 0 to disable it
343  * @returns 0 if successful, non-zero otherwise
344  */
345 
347  (flowperpkt_main_t * fm, u32 sw_if_index, int which, int is_add)
348 {
351  int rv;
352 
353  if (which == FLOW_VARIANT_IPV4 && !fm->ipv4_report_created)
354  {
355  memset (a, 0, sizeof (*a));
358  a->is_add = 1;
359  a->domain_id = 1; /*$$$$ config parameter */
360  a->src_port = 4739; /*$$$$ config parameter */
361  fm->ipv4_report_created = 1;
362 
363  rv = vnet_flow_report_add_del (frm, a);
364  if (rv)
365  {
366  clib_warning ("vnet_flow_report_add_del returned %d", rv);
367  return -1;
368  }
369  }
370  else if (which == FLOW_VARIANT_L2 && !fm->l2_report_created)
371  {
372  memset (a, 0, sizeof (*a));
375  a->is_add = 1;
376  a->domain_id = 1; /*$$$$ config parameter */
377  a->src_port = 4739; /*$$$$ config parameter */
378  fm->l2_report_created = 1;
379 
380  rv = vnet_flow_report_add_del (frm, a);
381  if (rv)
382  {
383  clib_warning ("vnet_flow_report_add_del returned %d", rv);
384  return -1;
385  }
386  }
387 
388  if (which == FLOW_VARIANT_IPV4)
389  vnet_feature_enable_disable ("ip4-output", "flowperpkt-ipv4",
390  sw_if_index, is_add, 0, 0);
391  else if (which == FLOW_VARIANT_L2)
392  vnet_feature_enable_disable ("interface-output", "flowperpkt-l2",
393  sw_if_index, is_add, 0, 0);
394 
395  return 0;
396 }
397 
398 /**
399  * @brief API message handler
400  * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message
401  */
404 {
407  u32 sw_if_index = ntohl (mp->sw_if_index);
408  int rv = 0;
409 
411 
412  if (mp->which != FLOW_VARIANT_IPV4 && mp->which != FLOW_VARIANT_L2)
413  {
414  rv = VNET_API_ERROR_UNIMPLEMENTED;
415  goto out;
416  }
417 
418  rv = flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, mp->which,
419  mp->is_add);
420 out:
422 
423  REPLY_MACRO (VL_API_FLOWPERPKT_TX_INTERFACE_ADD_DEL_REPLY);
424 }
425 
426 /**
427  * @brief API message custom-dump function
428  * @param mp vl_api_flowperpkt_tx_interface_add_del_t * mp the api message
429  * @param handle void * print function handle
430  * @returns u8 * output string
431  */
434 {
435  u8 *s;
436 
437  s = format (0, "SCRIPT: flowperpkt_tx_interface_add_del ");
438  s = format (s, "sw_if_index %d is_add %d which %d ",
439  clib_host_to_net_u32 (mp->sw_if_index),
440  (int) mp->is_add, (int) mp->which);
441  FINISH;
442 }
443 
444 /* List of message types that this plugin understands */
445 #define foreach_flowperpkt_plugin_api_msg \
446 _(FLOWPERPKT_TX_INTERFACE_ADD_DEL, flowperpkt_tx_interface_add_del)
447 
448 /* *INDENT-OFF* */
450  .version = VPP_BUILD_VER,
451  .description = "Flow per Packet",
452 };
453 /* *INDENT-ON* */
454 
455 static clib_error_t *
457  unformat_input_t * input,
458  vlib_cli_command_t * cmd)
459 {
461  u32 sw_if_index = ~0;
462  int is_add = 1;
463  u8 which = FLOW_VARIANT_IPV4;
464 
465  int rv;
466 
468  {
469  if (unformat (input, "disable"))
470  is_add = 0;
471  else if (unformat (input, "%U", unformat_vnet_sw_interface,
472  fm->vnet_main, &sw_if_index));
473  else if (unformat (input, "l2"))
474  which = FLOW_VARIANT_L2;
475  else
476  break;
477  }
478 
479  if (sw_if_index == ~0)
480  return clib_error_return (0, "Please specify an interface...");
481 
482  rv =
483  flowperpkt_tx_interface_add_del_feature (fm, sw_if_index, which, is_add);
484  switch (rv)
485  {
486  case 0:
487  break;
488 
489  case VNET_API_ERROR_INVALID_SW_IF_INDEX:
490  return clib_error_return
491  (0, "Invalid interface, only works on physical ports");
492  break;
493 
494  case VNET_API_ERROR_UNIMPLEMENTED:
495  return clib_error_return (0, "ip6 not supported");
496  break;
497 
498  default:
499  return clib_error_return (0, "flowperpkt_enable_disable returned %d",
500  rv);
501  }
502  return 0;
503 }
504 
505 /*?
506  * '<em>flowperpkt feature add-del</em>' commands to enable/disable
507  * per-packet IPFIX flow record generation on an interface
508  *
509  * @cliexpar
510  * @parblock
511  * To enable per-packet IPFIX flow-record generation on an interface:
512  * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0}
513  *
514  * To disable per-packet IPFIX flow-record generation on an interface:
515  * @cliexcmd{flowperpkt feature add-del GigabitEthernet2/0/0 disable}
516  * @cliexend
517  * @endparblock
518 ?*/
519 /* *INDENT-OFF* */
520 VLIB_CLI_COMMAND (flowperpkt_enable_disable_command, static) = {
521  .path = "flowperpkt feature add-del",
522  .short_help =
523  "flowperpkt feature add-del <interface-name> [disable]",
525 };
526 /* *INDENT-ON* */
527 
528 /**
529  * @brief Set up the API message handling tables
530  * @param vm vlib_main_t * vlib main data structure pointer
531  * @returns 0 to indicate all is well
532  */
533 static clib_error_t *
535 {
537 #define _(N,n) \
538  vl_msg_api_set_handlers((VL_API_##N + fm->msg_id_base), \
539  #n, \
540  vl_api_##n##_t_handler, \
541  vl_noop_handler, \
542  vl_api_##n##_t_endian, \
543  vl_api_##n##_t_print, \
544  sizeof(vl_api_##n##_t), 1);
546 #undef _
547 
548  return 0;
549 }
550 
551 #define vl_msg_name_crc_list
553 #undef vl_msg_name_crc_list
554 
555 static void
557 {
558 #define _(id,n,crc) \
559  vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id + fm->msg_id_base);
560  foreach_vl_msg_name_crc_flowperpkt;
561 #undef _
562 }
563 
564 /**
565  * @brief Set up the API message handling tables
566  * @param vm vlib_main_t * vlib main data structure pointer
567  * @returns 0 to indicate all is well, or a clib_error_t
568  */
569 static clib_error_t *
571 {
574  clib_error_t *error = 0;
575  u32 num_threads;
576  u8 *name;
577 
578  fm->vnet_main = vnet_get_main ();
579 
580  /* Construct the API name */
581  name = format (0, "flowperpkt_%08x%c", api_version, 0);
582 
583  /* Ask for a correctly-sized block of API message decode slots */
585  ((char *) name, VL_MSG_FIRST_AVAILABLE);
586 
587  /* Hook up message handlers */
588  error = flowperpkt_plugin_api_hookup (vm);
589 
590  /* Add our API messages to the global name_crc hash table */
592 
593  vec_free (name);
594 
595  /* Decide how many worker threads we have */
596  num_threads = 1 /* main thread */ + tm->n_threads;
597 
598  /* Allocate per worker thread vectors */
599  vec_validate (fm->ipv4_buffers_per_worker, num_threads - 1);
600  vec_validate (fm->l2_buffers_per_worker, num_threads - 1);
601  vec_validate (fm->ipv4_frames_per_worker, num_threads - 1);
602  vec_validate (fm->l2_frames_per_worker, num_threads - 1);
603  vec_validate (fm->ipv4_next_record_offset_per_worker, num_threads - 1);
604  vec_validate (fm->l2_next_record_offset_per_worker, num_threads - 1);
605 
606  /* Set up time reference pair */
607  fm->vlib_time_0 = vlib_time_now (vm);
609 
610  return error;
611 }
612 
614 
615 /*
616  * fd.io coding-style-patch-verification: ON
617  *
618  * Local Variables:
619  * eval: (c-set-style "gnu")
620  * End:
621  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:436
static clib_error_t * flowperpkt_tx_interface_add_del_feature_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: flowperpkt.c:456
vlib_frame_t ** l2_frames_per_worker
Definition: flowperpkt.h:52
a
Definition: bitmap.h:516
ip4_address_t src_address
Definition: ip4_packet.h:163
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
u16 * ipv4_next_record_offset_per_worker
next record offset, per worker thread
Definition: flowperpkt.h:55
u64 nanosecond_time_0
Time reference pair.
Definition: flowperpkt.h:59
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:185
u32 stream_index
Definition: flow_report.h:72
VLIB_PLUGIN_REGISTER()
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
unformat_function_t unformat_vnet_sw_interface
u16 msg_id_base
API message ID base.
Definition: flowperpkt.h:36
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:447
vlib_buffer_t ** ipv4_buffers_per_worker
ipfix buffers under construction, per-worker thread
Definition: flowperpkt.h:47
vlib_frame_t * flowperpkt_data_callback_ipv4(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
Flush accumulated data.
Definition: flowperpkt.c:320
void vl_api_flowperpkt_tx_interface_add_del_t_handler(vl_api_flowperpkt_tx_interface_add_del_t *mp)
API message handler.
Definition: flowperpkt.c:403
static clib_error_t * flowperpkt_plugin_api_hookup(vlib_main_t *vm)
Set up the API message handling tables.
Definition: flowperpkt.c:534
api_main_t api_main
Definition: api_shared.c:35
flow_report_stream_t * streams
Definition: flow_report.h:91
flow-per-packet plugin header file
static int flowperpkt_tx_interface_add_del_feature(flowperpkt_main_t *fm, u32 sw_if_index, int which, int is_add)
configure / deconfigure the IPFIX flow-per-packet
Definition: flowperpkt.c:347
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
int ipv4_report_created
Have the reports [templates] been created?
Definition: flowperpkt.h:39
Enable / disable per-packet IPFIX recording on an interface.
Definition: flowperpkt.api:15
ip4_address_t dst_address
Definition: ip4_packet.h:163
vlib_frame_t ** ipv4_frames_per_worker
frames containing ipfix buffers, per-worker thread
Definition: flowperpkt.h:51
vnet_flow_rewrite_callback_t * rewrite_callback
Definition: flow_report.h:125
#define clib_error_return(e, args...)
Definition: error.h:111
flow_report_main_t flow_report_main
Definition: flow_report.c:21
vlib_frame_t * flowperpkt_data_callback_l2(flow_report_main_t *frm, flow_report_t *fr, vlib_frame_t *f, u32 *to_next, u32 node_index)
Definition: flowperpkt.c:330
vnet_main_t * vnet_main
convenience vnet_main_t pointer
Definition: flowperpkt.h:65
struct _unformat_input_t unformat_input_t
#define REPLY_MACRO(t)
static u8 * flowperpkt_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, int variant)
Create an IPFIX template packet rewrite string.
Definition: flowperpkt.c:98
static u32 version_length(u16 length)
Definition: ipfix_packet.h:31
vlib_thread_main_t vlib_thread_main
Definition: threads.c:36
u16 ipv4_report_id
stream/template IDs
Definition: flowperpkt.h:43
vlib_buffer_t ** l2_buffers_per_worker
Definition: flowperpkt.h:48
#define BAD_SW_IF_INDEX_LABEL
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define foreach_flowperpkt_plugin_api_msg
Definition: flowperpkt.c:445
vlib_main_t * vm
Definition: buffer.c:276
vec_header_t h
Definition: buffer.c:275
VNET_FEATURE_INIT(flow_perpacket_ipv4, static)
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
static u32 ipfix_id_count(u16 id, u16 count)
Definition: ipfix_packet.h:175
#define clib_warning(format, args...)
Definition: error.h:59
void flowperpkt_flush_callback_ipv4(void)
Definition: node.c:313
static u64 unix_time_now_nsec(void)
Definition: time.h:238
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * flowperpkt_template_rewrite_ipv4(flow_report_main_t *frm, flow_report_t *fr, ip4_address_t *collector_address, ip4_address_t *src_address, u16 collector_port)
Definition: flowperpkt.c:285
flowperpkt_main_t flowperpkt_main
Definition: flowperpkt.c:54
u16 * l2_next_record_offset_per_worker
Definition: flowperpkt.h:56
u16 template_id
Definition: flow_report.h:71
u8 * flowperpkt_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: flowperpkt.c:297
#define VNET_FEATURES(...)
Definition: feature.h:368
void flowperpkt_flush_callback_l2(void)
Definition: l2_node.c:312
static u32 ipfix_set_id_length(u16 set_id, u16 length)
Definition: ipfix_packet.h:114
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static clib_error_t * flowperpkt_init(vlib_main_t *vm)
Set up the API message handling tables.
Definition: flowperpkt.c:570
static void * vl_api_flowperpkt_tx_interface_add_del_t_print(vl_api_flowperpkt_tx_interface_add_del_t *mp, void *handle)
API message custom-dump function.
Definition: flowperpkt.c:433
vnet_flow_data_callback_t * flow_data_callback
Definition: flow_report.h:124
#define FINISH
Definition: flowperpkt.c:82
static void setup_message_id_table(flowperpkt_main_t *fm, api_main_t *am)
Definition: flowperpkt.c:556
u16 vl_msg_api_get_msg_ids(char *name, int n)
Definition: api_shared.c:831
u8 ip_version_and_header_length
Definition: ip4_packet.h:131
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
Reply to enable/disable per-packet IPFIX recording messages.
Definition: flowperpkt.api:35
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:238
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:971
int vnet_feature_enable_disable(const char *arc_name, const char *node_name, u32 sw_if_index, int enable_disable, void *feature_config, u32 n_feature_config_bytes)
Definition: feature.c:225
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#define VALIDATE_SW_IF_INDEX(mp)
int vnet_flow_report_add_del(flow_report_main_t *frm, vnet_flow_report_add_del_args_t *a)
Definition: flow_report.c:240