FD.io VPP  v20.05.1-6-gf53edbc3b
Vector Packet Processing
ip6_hop_by_hop.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <vlib/vlib.h>
16 #include <vnet/vnet.h>
17 #include <vnet/pg/pg.h>
18 #include <vppinfra/error.h>
19 
20 #include <vnet/ip/ip.h>
21 
22 #include <vppinfra/hash.h>
23 #include <vppinfra/error.h>
24 #include <vppinfra/elog.h>
25 
26 #include <vnet/ip/ip6_hop_by_hop.h>
27 #include <vnet/fib/ip6_fib.h>
29 
30 /**
31  * @file
32  * @brief In-band OAM (iOAM).
33  *
34  * In-band OAM (iOAM) is an implementation study to record operational
35  * information in the packet while the packet traverses a path between
36  * two points in the network.
37  *
38  * VPP can function as in-band OAM encapsulating, transit and
39  * decapsulating node. In this version of VPP in-band OAM data is
40  * transported as options in an IPv6 hop-by-hop extension header. Hence
41  * in-band OAM can be enabled for IPv6 traffic.
42  */
43 
44 #ifndef CLIB_MARCH_VARIANT
46 #endif /* CLIB_MARCH_VARIANT */
47 
48 #define foreach_ip6_hbyh_ioam_input_next \
49  _(IP6_REWRITE, "ip6-rewrite") \
50  _(IP6_LOOKUP, "ip6-lookup") \
51  _(DROP, "ip6-drop")
52 
53 typedef enum
54 {
55 #define _(s,n) IP6_HBYH_IOAM_INPUT_NEXT_##s,
57 #undef _
60 
61 #ifndef CLIB_MARCH_VARIANT
62 static uword
63 unformat_opaque_ioam (unformat_input_t * input, va_list * args)
64 {
65  u64 *opaquep = va_arg (*args, u64 *);
66  u8 *flow_name = NULL;
67  uword ret = 0;
68 
69  if (unformat (input, "ioam-encap %s", &flow_name))
70  {
71  *opaquep = ioam_flow_add (1, flow_name);
72  ret = 1;
73  }
74  else if (unformat (input, "ioam-decap %s", &flow_name))
75  {
76  *opaquep = ioam_flow_add (0, flow_name);
77  ret = 1;
78  }
79 
80  vec_free (flow_name);
81  return ret;
82 }
83 
84 u8 *
86 {
87  flow_data_t *flow = NULL;
89  u32 index;
90 
91  index = IOAM_MASK_DECAP_BIT (flow_ctx);
92 
93  if (pool_is_free_index (hm->flows, index))
94  return NULL;
95 
96  flow = pool_elt_at_index (hm->flows, index);
97  return (flow->flow_name);
98 }
99 
100 /* The main h-b-h tracer will be invoked, no need to do much here */
101 int
103  u8 size,
104  int rewrite_options (u8 * rewrite_string,
105  u8 * rewrite_size))
106 {
108 
109  ASSERT ((u32) option < ARRAY_LEN (hm->add_options));
110 
111  /* Already registered */
112  if (hm->add_options[option])
113  return (-1);
114 
115  hm->add_options[option] = rewrite_options;
116  hm->options_size[option] = size;
117 
118  return (0);
119 }
120 
121 int
123 {
125 
126  ASSERT ((u32) option < ARRAY_LEN (hm->add_options));
127 
128  /* Not registered */
129  if (!hm->add_options[option])
130  return (-1);
131 
132  hm->add_options[option] = NULL;
133  hm->options_size[option] = 0;
134  return (0);
135 }
136 
137 /* Config handler registration */
138 int
140  int config_handler (void *data, u8 disable))
141 {
143 
144  ASSERT ((u32) option < ARRAY_LEN (hm->config_handler));
145 
146  /* Already registered */
147  if (hm->config_handler[option])
148  return (VNET_API_ERROR_INVALID_REGISTRATION);
149 
150  hm->config_handler[option] = config_handler;
151 
152  return (0);
153 }
154 
155 int
157 {
159 
160  ASSERT ((u32) option < ARRAY_LEN (hm->config_handler));
161 
162  /* Not registered */
163  if (!hm->config_handler[option])
164  return (VNET_API_ERROR_INVALID_REGISTRATION);
165 
166  hm->config_handler[option] = NULL;
167  return (0);
168 }
169 
170 /* Flow handler registration */
171 int
173  u32 ioam_flow_handler (u32 flow_ctx, u8 add))
174 {
176 
177  ASSERT ((u32) option < ARRAY_LEN (hm->flow_handler));
178 
179  /* Already registered */
180  if (hm->flow_handler[option])
181  return (VNET_API_ERROR_INVALID_REGISTRATION);
182 
183  hm->flow_handler[option] = ioam_flow_handler;
184 
185  return (0);
186 }
187 
188 int
190 {
192 
193  ASSERT ((u32) option < ARRAY_LEN (hm->flow_handler));
194 
195  /* Not registered */
196  if (!hm->flow_handler[option])
197  return (VNET_API_ERROR_INVALID_REGISTRATION);
198 
199  hm->flow_handler[option] = NULL;
200  return (0);
201 }
202 #endif /* CLIB_MARCH_VARIANT */
203 
204 typedef struct
205 {
208 
209 /* packet trace format function */
210 static u8 *
211 format_ip6_add_hop_by_hop_trace (u8 * s, va_list * args)
212 {
213  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
214  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
215  ip6_add_hop_by_hop_trace_t *t = va_arg (*args,
217 
218  s = format (s, "IP6_ADD_HOP_BY_HOP: next index %d", t->next_index);
219  return s;
220 }
221 
223 
224 #define foreach_ip6_add_hop_by_hop_error \
225 _(PROCESSED, "Pkts w/ added ip6 hop-by-hop options")
226 
227 typedef enum
228 {
229 #define _(sym,str) IP6_ADD_HOP_BY_HOP_ERROR_##sym,
231 #undef _
234 
235 static char *ip6_add_hop_by_hop_error_strings[] = {
236 #define _(sym,string) string,
238 #undef _
239 };
240 
241 VLIB_NODE_FN (ip6_add_hop_by_hop_node) (vlib_main_t * vm,
244 {
246  u32 n_left_from, *from, *to_next;
247  ip_lookup_next_t next_index;
248  u32 processed = 0;
249  u8 *rewrite = hm->rewrite;
250  u32 rewrite_length = vec_len (rewrite);
251 
252  from = vlib_frame_vector_args (frame);
253  n_left_from = frame->n_vectors;
254  next_index = node->cached_next_index;
255 
256  while (n_left_from > 0)
257  {
258  u32 n_left_to_next;
259 
260  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
261  while (n_left_from >= 4 && n_left_to_next >= 2)
262  {
263  u32 bi0, bi1;
264  vlib_buffer_t *b0, *b1;
265  u32 next0, next1;
266  ip6_header_t *ip0, *ip1;
267  ip6_hop_by_hop_header_t *hbh0, *hbh1;
268  u64 *copy_src0, *copy_dst0, *copy_src1, *copy_dst1;
269  u16 new_l0, new_l1;
270 
271  /* Prefetch next iteration. */
272  {
273  vlib_buffer_t *p2, *p3;
274 
275  p2 = vlib_get_buffer (vm, from[2]);
276  p3 = vlib_get_buffer (vm, from[3]);
277 
278  vlib_prefetch_buffer_header (p2, LOAD);
279  vlib_prefetch_buffer_header (p3, LOAD);
280 
281  CLIB_PREFETCH (p2->data - rewrite_length,
282  2 * CLIB_CACHE_LINE_BYTES, STORE);
283  CLIB_PREFETCH (p3->data - rewrite_length,
284  2 * CLIB_CACHE_LINE_BYTES, STORE);
285  }
286 
287  /* speculatively enqueue b0 and b1 to the current next frame */
288  to_next[0] = bi0 = from[0];
289  to_next[1] = bi1 = from[1];
290  from += 2;
291  to_next += 2;
292  n_left_from -= 2;
293  n_left_to_next -= 2;
294 
295  b0 = vlib_get_buffer (vm, bi0);
296  b1 = vlib_get_buffer (vm, bi1);
297 
298  /* $$$$$ Dual loop: process 2 x packets here $$$$$ */
299  ip0 = vlib_buffer_get_current (b0);
300  ip1 = vlib_buffer_get_current (b1);
301 
302  /* Copy the ip header left by the required amount */
303  copy_dst0 = (u64 *) (((u8 *) ip0) - rewrite_length);
304  copy_dst1 = (u64 *) (((u8 *) ip1) - rewrite_length);
305  copy_src0 = (u64 *) ip0;
306  copy_src1 = (u64 *) ip1;
307 
308  copy_dst0[0] = copy_src0[0];
309  copy_dst0[1] = copy_src0[1];
310  copy_dst0[2] = copy_src0[2];
311  copy_dst0[3] = copy_src0[3];
312  copy_dst0[4] = copy_src0[4];
313 
314  copy_dst1[0] = copy_src1[0];
315  copy_dst1[1] = copy_src1[1];
316  copy_dst1[2] = copy_src1[2];
317  copy_dst1[3] = copy_src1[3];
318  copy_dst1[4] = copy_src1[4];
319 
320  vlib_buffer_advance (b0, -(word) rewrite_length);
321  vlib_buffer_advance (b1, -(word) rewrite_length);
322  ip0 = vlib_buffer_get_current (b0);
323  ip1 = vlib_buffer_get_current (b1);
324 
325  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
326  hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
327  /* $$$ tune, rewrite_length is a multiple of 8 */
328  clib_memcpy_fast (hbh0, rewrite, rewrite_length);
329  clib_memcpy_fast (hbh1, rewrite, rewrite_length);
330  /* Patch the protocol chain, insert the h-b-h (type 0) header */
331  hbh0->protocol = ip0->protocol;
332  hbh1->protocol = ip1->protocol;
333  ip0->protocol = 0;
334  ip1->protocol = 0;
335  new_l0 =
336  clib_net_to_host_u16 (ip0->payload_length) + rewrite_length;
337  new_l1 =
338  clib_net_to_host_u16 (ip1->payload_length) + rewrite_length;
339  ip0->payload_length = clib_host_to_net_u16 (new_l0);
340  ip1->payload_length = clib_host_to_net_u16 (new_l1);
341 
342  /* Populate the (first) h-b-h list elt */
343  next0 = IP6_HBYH_IOAM_INPUT_NEXT_IP6_LOOKUP;
344  next1 = IP6_HBYH_IOAM_INPUT_NEXT_IP6_LOOKUP;
345 
346 
347  /* $$$$$ End of processing 2 x packets $$$$$ */
348 
349  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
350  {
351  if (b0->flags & VLIB_BUFFER_IS_TRACED)
352  {
354  vlib_add_trace (vm, node, b0, sizeof (*t));
355  t->next_index = next0;
356  }
357  if (b1->flags & VLIB_BUFFER_IS_TRACED)
358  {
360  vlib_add_trace (vm, node, b1, sizeof (*t));
361  t->next_index = next1;
362  }
363  }
364  processed += 2;
365  /* verify speculative enqueues, maybe switch current next frame */
366  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
367  to_next, n_left_to_next,
368  bi0, bi1, next0, next1);
369  }
370  while (n_left_from > 0 && n_left_to_next > 0)
371  {
372  u32 bi0;
373  vlib_buffer_t *b0;
374  u32 next0;
375  ip6_header_t *ip0;
377  u64 *copy_src0, *copy_dst0;
378  u16 new_l0;
379 
380  /* speculatively enqueue b0 to the current next frame */
381  bi0 = from[0];
382  to_next[0] = bi0;
383  from += 1;
384  to_next += 1;
385  n_left_from -= 1;
386  n_left_to_next -= 1;
387 
388  b0 = vlib_get_buffer (vm, bi0);
389 
390  ip0 = vlib_buffer_get_current (b0);
391 
392  /* Copy the ip header left by the required amount */
393  copy_dst0 = (u64 *) (((u8 *) ip0) - rewrite_length);
394  copy_src0 = (u64 *) ip0;
395 
396  copy_dst0[0] = copy_src0[0];
397  copy_dst0[1] = copy_src0[1];
398  copy_dst0[2] = copy_src0[2];
399  copy_dst0[3] = copy_src0[3];
400  copy_dst0[4] = copy_src0[4];
401  vlib_buffer_advance (b0, -(word) rewrite_length);
402  ip0 = vlib_buffer_get_current (b0);
403 
404  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
405  /* $$$ tune, rewrite_length is a multiple of 8 */
406  clib_memcpy_fast (hbh0, rewrite, rewrite_length);
407  /* Patch the protocol chain, insert the h-b-h (type 0) header */
408  hbh0->protocol = ip0->protocol;
409  ip0->protocol = 0;
410  new_l0 =
411  clib_net_to_host_u16 (ip0->payload_length) + rewrite_length;
412  ip0->payload_length = clib_host_to_net_u16 (new_l0);
413 
414  /* Populate the (first) h-b-h list elt */
415  next0 = IP6_HBYH_IOAM_INPUT_NEXT_IP6_LOOKUP;
416 
417  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
418  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
419  {
421  vlib_add_trace (vm, node, b0, sizeof (*t));
422  t->next_index = next0;
423  }
424 
425  processed++;
426 
427  /* verify speculative enqueue, maybe switch current next frame */
428  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
429  to_next, n_left_to_next,
430  bi0, next0);
431  }
432 
433  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
434  }
435 
436  vlib_node_increment_counter (vm, ip6_add_hop_by_hop_node.index,
437  IP6_ADD_HOP_BY_HOP_ERROR_PROCESSED, processed);
438  return frame->n_vectors;
439 }
440 
441 /* *INDENT-OFF* */
442 VLIB_REGISTER_NODE (ip6_add_hop_by_hop_node) = /* *INDENT-OFF* */
443 {
444  .name = "ip6-add-hop-by-hop",
445  .vector_size = sizeof (u32),
446  .format_trace = format_ip6_add_hop_by_hop_trace,
448  .n_errors = ARRAY_LEN (ip6_add_hop_by_hop_error_strings),
449  .error_strings = ip6_add_hop_by_hop_error_strings,
450  /* See ip/lookup.h */
451  .n_next_nodes = IP6_HBYH_IOAM_INPUT_N_NEXT,
452  .next_nodes = {
453 #define _(s,n) [IP6_HBYH_IOAM_INPUT_NEXT_##s] = n,
455 #undef _
456  },
457 };
458 /* *INDENT-ON* */
459 
460 /* The main h-b-h tracer was already invoked, no need to do much here */
461 typedef struct
462 {
465 
466 /* packet trace format function */
467 static u8 *
468 format_ip6_pop_hop_by_hop_trace (u8 * s, va_list * args)
469 {
470  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
471  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
473  va_arg (*args, ip6_pop_hop_by_hop_trace_t *);
474 
475  s = format (s, "IP6_POP_HOP_BY_HOP: next index %d", t->next_index);
476  return s;
477 }
478 
479 #ifndef CLIB_MARCH_VARIANT
480 int
482  int options (vlib_buffer_t * b,
483  ip6_header_t * ip,
485 {
487 
488  ASSERT ((u32) option < ARRAY_LEN (hm->pop_options));
489 
490  /* Already registered */
491  if (hm->pop_options[option])
492  return (-1);
493 
494  hm->pop_options[option] = options;
495 
496  return (0);
497 }
498 
499 int
501 {
503 
504  ASSERT ((u32) option < ARRAY_LEN (hm->pop_options));
505 
506  /* Not registered */
507  if (!hm->pop_options[option])
508  return (-1);
509 
510  hm->pop_options[option] = NULL;
511  return (0);
512 }
513 #endif /* CLIB_MARCH_VARIANT */
514 
516 
517 #define foreach_ip6_pop_hop_by_hop_error \
518 _(PROCESSED, "Pkts w/ removed ip6 hop-by-hop options") \
519 _(NO_HOHO, "Pkts w/ no ip6 hop-by-hop options") \
520 _(OPTION_FAILED, "ip6 pop hop-by-hop failed to process")
521 
522 typedef enum
523 {
524 #define _(sym,str) IP6_POP_HOP_BY_HOP_ERROR_##sym,
526 #undef _
529 
530 static char *ip6_pop_hop_by_hop_error_strings[] = {
531 #define _(sym,string) string,
533 #undef _
534 };
535 
536 static inline void
538  ip6_header_t * ip0,
540  vlib_buffer_t * b)
541 {
543  ip6_hop_by_hop_option_t *opt0, *limit0;
544  u8 type0;
545 
546  if (!hbh0 || !ip0)
547  return;
548 
549  opt0 = (ip6_hop_by_hop_option_t *) (hbh0 + 1);
550  limit0 = (ip6_hop_by_hop_option_t *)
551  ((u8 *) hbh0 + ((hbh0->length + 1) << 3));
552 
553  /* Scan the set of h-b-h options, process ones that we understand */
554  while (opt0 < limit0)
555  {
556  type0 = opt0->type;
557  switch (type0)
558  {
559  case 0: /* Pad1 */
560  opt0 = (ip6_hop_by_hop_option_t *) ((u8 *) opt0) + 1;
561  continue;
562  case 1: /* PadN */
563  break;
564  default:
565  if (hm->pop_options[type0])
566  {
567  if ((*hm->pop_options[type0]) (b, ip0, opt0) < 0)
568  {
570  ip6_pop_hop_by_hop_node.index,
571  IP6_POP_HOP_BY_HOP_ERROR_OPTION_FAILED,
572  1);
573  }
574  }
575  }
576  opt0 =
577  (ip6_hop_by_hop_option_t *) (((u8 *) opt0) + opt0->length +
578  sizeof (ip6_hop_by_hop_option_t));
579  }
580 }
581 
582 VLIB_NODE_FN (ip6_pop_hop_by_hop_node) (vlib_main_t * vm,
585 {
586  u32 n_left_from, *from, *to_next;
587  ip_lookup_next_t next_index;
588  u32 processed = 0;
589  u32 no_header = 0;
590 
591  from = vlib_frame_vector_args (frame);
592  n_left_from = frame->n_vectors;
593  next_index = node->cached_next_index;
594 
595  while (n_left_from > 0)
596  {
597  u32 n_left_to_next;
598 
599  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
600 
601  while (n_left_from >= 4 && n_left_to_next >= 2)
602  {
603  u32 bi0, bi1;
604  vlib_buffer_t *b0, *b1;
605  u32 next0, next1;
606  u32 adj_index0, adj_index1;
607  ip6_header_t *ip0, *ip1;
608  ip_adjacency_t *adj0, *adj1;
609  ip6_hop_by_hop_header_t *hbh0, *hbh1;
610  u64 *copy_dst0, *copy_src0, *copy_dst1, *copy_src1;
611  u16 new_l0, new_l1;
612 
613  /* Prefetch next iteration. */
614  {
615  vlib_buffer_t *p2, *p3;
616 
617  p2 = vlib_get_buffer (vm, from[2]);
618  p3 = vlib_get_buffer (vm, from[3]);
619 
620  vlib_prefetch_buffer_header (p2, LOAD);
621  vlib_prefetch_buffer_header (p3, LOAD);
622 
625  }
626 
627  /* speculatively enqueue b0 and b1 to the current next frame */
628  to_next[0] = bi0 = from[0];
629  to_next[1] = bi1 = from[1];
630  from += 2;
631  to_next += 2;
632  n_left_from -= 2;
633  n_left_to_next -= 2;
634 
635  b0 = vlib_get_buffer (vm, bi0);
636  b1 = vlib_get_buffer (vm, bi1);
637 
638  /* $$$$$ Dual loop: process 2 x packets here $$$$$ */
639  ip0 = vlib_buffer_get_current (b0);
640  ip1 = vlib_buffer_get_current (b1);
641  adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
642  adj_index1 = vnet_buffer (b1)->ip.adj_index[VLIB_TX];
643  adj0 = adj_get (adj_index0);
644  adj1 = adj_get (adj_index1);
645 
646  next0 = adj0->lookup_next_index;
647  next1 = adj1->lookup_next_index;
648 
649  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
650  hbh1 = (ip6_hop_by_hop_header_t *) (ip1 + 1);
651 
652  ioam_pop_hop_by_hop_processing (vm, ip0, hbh0, b0);
653  ioam_pop_hop_by_hop_processing (vm, ip1, hbh1, b1);
654 
655  vlib_buffer_advance (b0, (hbh0->length + 1) << 3);
656  vlib_buffer_advance (b1, (hbh1->length + 1) << 3);
657 
658  new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
659  ((hbh0->length + 1) << 3);
660  new_l1 = clib_net_to_host_u16 (ip1->payload_length) -
661  ((hbh1->length + 1) << 3);
662 
663  ip0->payload_length = clib_host_to_net_u16 (new_l0);
664  ip1->payload_length = clib_host_to_net_u16 (new_l1);
665 
666  ip0->protocol = hbh0->protocol;
667  ip1->protocol = hbh1->protocol;
668 
669  copy_src0 = (u64 *) ip0;
670  copy_src1 = (u64 *) ip1;
671  copy_dst0 = copy_src0 + (hbh0->length + 1);
672  copy_dst0[4] = copy_src0[4];
673  copy_dst0[3] = copy_src0[3];
674  copy_dst0[2] = copy_src0[2];
675  copy_dst0[1] = copy_src0[1];
676  copy_dst0[0] = copy_src0[0];
677  copy_dst1 = copy_src1 + (hbh1->length + 1);
678  copy_dst1[4] = copy_src1[4];
679  copy_dst1[3] = copy_src1[3];
680  copy_dst1[2] = copy_src1[2];
681  copy_dst1[1] = copy_src1[1];
682  copy_dst1[0] = copy_src1[0];
683  processed += 2;
684  /* $$$$$ End of processing 2 x packets $$$$$ */
685 
686  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
687  {
688  if (b0->flags & VLIB_BUFFER_IS_TRACED)
689  {
691  vlib_add_trace (vm, node, b0, sizeof (*t));
692  t->next_index = next0;
693  }
694  if (b1->flags & VLIB_BUFFER_IS_TRACED)
695  {
697  vlib_add_trace (vm, node, b1, sizeof (*t));
698  t->next_index = next1;
699  }
700  }
701 
702  /* verify speculative enqueues, maybe switch current next frame */
703  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
704  to_next, n_left_to_next,
705  bi0, bi1, next0, next1);
706  }
707 
708  while (n_left_from > 0 && n_left_to_next > 0)
709  {
710  u32 bi0;
711  vlib_buffer_t *b0;
712  u32 next0;
713  u32 adj_index0;
714  ip6_header_t *ip0;
715  ip_adjacency_t *adj0;
717  u64 *copy_dst0, *copy_src0;
718  u16 new_l0;
719 
720  /* speculatively enqueue b0 to the current next frame */
721  bi0 = from[0];
722  to_next[0] = bi0;
723  from += 1;
724  to_next += 1;
725  n_left_from -= 1;
726  n_left_to_next -= 1;
727 
728  b0 = vlib_get_buffer (vm, bi0);
729 
730  ip0 = vlib_buffer_get_current (b0);
731  adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
732  adj0 = adj_get (adj_index0);
733 
734  /* Default use the next_index from the adjacency. */
735  next0 = adj0->lookup_next_index;
736 
737  /* Perfectly normal to end up here w/ out h-b-h header */
738  hbh0 = (ip6_hop_by_hop_header_t *) (ip0 + 1);
739 
740  /* TODO:Temporarily doing it here.. do this validation in end_of_path_cb */
741  ioam_pop_hop_by_hop_processing (vm, ip0, hbh0, b0);
742  /* Pop the trace data */
743  vlib_buffer_advance (b0, (hbh0->length + 1) << 3);
744  new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
745  ((hbh0->length + 1) << 3);
746  ip0->payload_length = clib_host_to_net_u16 (new_l0);
747  ip0->protocol = hbh0->protocol;
748  copy_src0 = (u64 *) ip0;
749  copy_dst0 = copy_src0 + (hbh0->length + 1);
750  copy_dst0[4] = copy_src0[4];
751  copy_dst0[3] = copy_src0[3];
752  copy_dst0[2] = copy_src0[2];
753  copy_dst0[1] = copy_src0[1];
754  copy_dst0[0] = copy_src0[0];
755  processed++;
756 
757  if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
758  && (b0->flags & VLIB_BUFFER_IS_TRACED)))
759  {
761  vlib_add_trace (vm, node, b0, sizeof (*t));
762  t->next_index = next0;
763  }
764 
765  /* verify speculative enqueue, maybe switch current next frame */
766  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
767  to_next, n_left_to_next,
768  bi0, next0);
769  }
770 
771  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
772  }
773 
774  vlib_node_increment_counter (vm, ip6_pop_hop_by_hop_node.index,
775  IP6_POP_HOP_BY_HOP_ERROR_PROCESSED, processed);
776  vlib_node_increment_counter (vm, ip6_pop_hop_by_hop_node.index,
777  IP6_POP_HOP_BY_HOP_ERROR_NO_HOHO, no_header);
778  return frame->n_vectors;
779 }
780 
781 /* *INDENT-OFF* */
782 VLIB_REGISTER_NODE (ip6_pop_hop_by_hop_node) =
783 {
784  .name = "ip6-pop-hop-by-hop",
785  .vector_size = sizeof (u32),
786  .format_trace = format_ip6_pop_hop_by_hop_trace,
788  .sibling_of = "ip6-lookup",
789  .n_errors = ARRAY_LEN (ip6_pop_hop_by_hop_error_strings),
790  .error_strings = ip6_pop_hop_by_hop_error_strings,
791  /* See ip/lookup.h */
792  .n_next_nodes = 0,
793 };
794 /* *INDENT-ON* */
795 
796 typedef struct
797 {
801 
802 #ifndef CLIB_MARCH_VARIANT
803 
804 /* packet trace format function */
805 static u8 *
807 {
808  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
809  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
811  va_arg (*args, ip6_local_hop_by_hop_trace_t *);
812 
813  s = format (s, "IP6_LOCAL_HOP_BY_HOP: protocol %d, next index %d\n",
814  t->protocol, t->next_index);
815  return s;
816 }
817 
819 
820 #endif /* CLIB_MARCH_VARIANT */
821 
822 #define foreach_ip6_local_hop_by_hop_error \
823 _(UNKNOWN, "Unknown protocol ip6 local h-b-h packets dropped") \
824 _(OK, "Good ip6 local h-b-h packets")
825 
826 typedef enum
827 {
828 #define _(sym,str) IP6_LOCAL_HOP_BY_HOP_ERROR_##sym,
830 #undef _
833 
834 #ifndef CLIB_MARCH_VARIANT
835 static char *ip6_local_hop_by_hop_error_strings[] = {
836 #define _(sym,string) string,
838 #undef _
839 };
840 #endif /* CLIB_MARCH_VARIANT */
841 
842 typedef enum
843 {
847 
851  int is_trace)
852 {
853  u32 n_left_from, *from;
854  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
855  u16 nexts[VLIB_FRAME_SIZE], *next;
856  u32 ok = 0;
857  u32 unknown_proto_error = node->errors[IP6_LOCAL_HOP_BY_HOP_ERROR_UNKNOWN];
859 
860  /* Note: there is only one of these */
862 
863  from = vlib_frame_vector_args (frame);
864  n_left_from = frame->n_vectors;
865 
866  vlib_get_buffers (vm, from, bufs, n_left_from);
867  b = bufs;
868  next = nexts;
869 
870  while (n_left_from >= 4)
871  {
872  ip6_header_t *ip0, *ip1, *ip2, *ip3;
873  u8 *hbh0, *hbh1, *hbh2, *hbh3;
874 
875  /* Prefetch next iteration. */
876  if (PREDICT_TRUE (n_left_from >= 8))
877  {
878  vlib_prefetch_buffer_header (b[4], STORE);
879  vlib_prefetch_buffer_header (b[5], STORE);
880  vlib_prefetch_buffer_header (b[6], STORE);
881  vlib_prefetch_buffer_header (b[7], STORE);
882  CLIB_PREFETCH (b[4]->data, CLIB_CACHE_LINE_BYTES, STORE);
883  CLIB_PREFETCH (b[5]->data, CLIB_CACHE_LINE_BYTES, STORE);
884  CLIB_PREFETCH (b[6]->data, CLIB_CACHE_LINE_BYTES, STORE);
885  CLIB_PREFETCH (b[7]->data, CLIB_CACHE_LINE_BYTES, STORE);
886  }
887 
888  /*
889  * Leave current_data pointing at the IP header.
890  * It's reasonably likely that any registered handler
891  * will want to know where to find the ip6 header.
892  */
893  ip0 = vlib_buffer_get_current (b[0]);
894  ip1 = vlib_buffer_get_current (b[1]);
895  ip2 = vlib_buffer_get_current (b[2]);
896  ip3 = vlib_buffer_get_current (b[3]);
897 
898  /* Look at hop-by-hop header */
899  hbh0 = ip6_next_header (ip0);
900  hbh1 = ip6_next_header (ip1);
901  hbh2 = ip6_next_header (ip2);
902  hbh3 = ip6_next_header (ip3);
903 
904  /*
905  * ... to find the next header type and see if we
906  * have a handler for it...
907  */
908  next[0] = rt->next_index_by_protocol[*hbh0];
909  next[1] = rt->next_index_by_protocol[*hbh1];
910  next[2] = rt->next_index_by_protocol[*hbh2];
911  next[3] = rt->next_index_by_protocol[*hbh3];
912 
913  b[0]->error = unknown_proto_error;
914  b[1]->error = unknown_proto_error;
915  b[2]->error = unknown_proto_error;
916  b[3]->error = unknown_proto_error;
917 
918  /* Account for non-drop pkts */
919  ok += next[0] != 0;
920  ok += next[1] != 0;
921  ok += next[2] != 0;
922  ok += next[3] != 0;
923 
924  if (is_trace)
925  {
926  if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
927  {
929  vlib_add_trace (vm, node, b[0], sizeof (*t));
930  t->next_index = next[0];
931  t->protocol = *hbh0;
932  }
933  if (b[1]->flags & VLIB_BUFFER_IS_TRACED)
934  {
936  vlib_add_trace (vm, node, b[1], sizeof (*t));
937  t->next_index = next[1];
938  t->protocol = *hbh1;
939  }
940  if (b[2]->flags & VLIB_BUFFER_IS_TRACED)
941  {
943  vlib_add_trace (vm, node, b[2], sizeof (*t));
944  t->next_index = next[2];
945  t->protocol = *hbh2;
946  }
947  if (b[3]->flags & VLIB_BUFFER_IS_TRACED)
948  {
950  vlib_add_trace (vm, node, b[3], sizeof (*t));
951  t->next_index = next[3];
952  t->protocol = *hbh3;
953  }
954  }
955 
956  b += 4;
957  next += 4;
958  n_left_from -= 4;
959  }
960 
961  while (n_left_from > 0)
962  {
963  ip6_header_t *ip0;
964  u8 *hbh0;
965 
966  ip0 = vlib_buffer_get_current (b[0]);
967 
968  hbh0 = ip6_next_header (ip0);
969 
970  next[0] = rt->next_index_by_protocol[*hbh0];
971 
972  b[0]->error = unknown_proto_error;
973  ok += next[0] != 0;
974 
975  if (is_trace)
976  {
977  if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
978  {
980  vlib_add_trace (vm, node, b[0], sizeof (*t));
981  t->next_index = next[0];
982  t->protocol = *hbh0;
983  }
984  }
985 
986  b += 1;
987  next += 1;
988  n_left_from -= 1;
989  }
990 
991  vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
992 
994  IP6_LOCAL_HOP_BY_HOP_ERROR_OK, ok);
995  return frame->n_vectors;
996 }
997 
998 VLIB_NODE_FN (ip6_local_hop_by_hop_node) (vlib_main_t * vm,
1000  vlib_frame_t * frame)
1001 {
1002  if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
1003  return ip6_local_hop_by_hop_inline (vm, node, frame, 1 /* is_trace */ );
1004  else
1005  return ip6_local_hop_by_hop_inline (vm, node, frame, 0 /* is_trace */ );
1006 }
1007 
1008 #ifndef CLIB_MARCH_VARIANT
1009 /* *INDENT-OFF* */
1010 VLIB_REGISTER_NODE (ip6_local_hop_by_hop_node) =
1011 {
1012  .name = "ip6-local-hop-by-hop",
1013  .vector_size = sizeof (u32),
1014  .format_trace = format_ip6_local_hop_by_hop_trace,
1016 
1017  .n_errors = ARRAY_LEN(ip6_local_hop_by_hop_error_strings),
1018  .error_strings = ip6_local_hop_by_hop_error_strings,
1019 
1020  .n_next_nodes = IP6_LOCAL_HOP_BY_HOP_N_NEXT,
1021 
1022  /* edit / add dispositions here */
1023  .next_nodes =
1024  {
1025  [IP6_LOCAL_HOP_BY_HOP_NEXT_DROP] = "error-drop",
1026  },
1027 };
1028 /* *INDENT-ON* */
1029 
1030 clib_error_t *
1032  unformat_input_t * input, vlib_cli_command_t * cmd)
1033 {
1034  int i;
1035  u32 next_index;
1038  vlib_node_t *n = vlib_get_node (vm, ip6_local_hop_by_hop_node.index);
1039 
1040  vlib_cli_output (vm, "%-6s%s", "Proto", "Node Name");
1041 
1042  for (i = 0; i < ARRAY_LEN (rt->next_index_by_protocol); i++)
1043  {
1044  if ((next_index = rt->next_index_by_protocol[i]))
1045  {
1046  u32 next_node_index = n->next_nodes[next_index];
1047  vlib_node_t *next_n = vlib_get_node (vm, next_node_index);
1048  vlib_cli_output (vm, "[%3d] %v", i, next_n->name);
1049  }
1050  }
1051 
1052  return 0;
1053 }
1054 
1055 /*?
1056  * Display the set of ip6 local hop-by-hop next protocol handler nodes
1057  *
1058  * @cliexpar
1059  * Display ip6 local hop-by-hop next protocol handler nodes
1060  * @cliexcmd{show ip6 hbh}
1061 ?*/
1062 /* *INDENT-OFF* */
1063 VLIB_CLI_COMMAND (show_ip6_hbh, static) = {
1064  .path = "show ip6 hbh",
1065  .short_help = "show ip6 hbh",
1066  .function = show_ip6_hbh_command_fn,
1067 };
1068 /* *INDENT-ON* */
1069 
1070 
1071 #endif /* CLIB_MARCH_VARIANT */
1072 
1073 
1074 #ifndef CLIB_MARCH_VARIANT
1075 static clib_error_t *
1077 {
1078  clib_error_t *error;
1080 
1081  if ((error = vlib_call_init_function (vm, ip_main_init)))
1082  return (error);
1083 
1084  if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
1085  return error;
1086 
1087  hm->vlib_main = vm;
1088  hm->vnet_main = vnet_get_main ();
1089  hm->unix_time_0 = (u32) time (0); /* Store starting time */
1090  hm->vlib_time_0 = vlib_time_now (vm);
1091  hm->ioam_flag = IOAM_HBYH_MOD;
1092  clib_memset (hm->add_options, 0, sizeof (hm->add_options));
1093  clib_memset (hm->pop_options, 0, sizeof (hm->pop_options));
1094  clib_memset (hm->options_size, 0, sizeof (hm->options_size));
1095 
1099 
1100  memset (hm->ip6_local_hbh_runtime, 0,
1102 
1103  ip6_register_protocol (IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS,
1104  ip6_local_hop_by_hop_node.index);
1105  return (0);
1106 }
1107 
1108 /* *INDENT-OFF* */
1110 {
1111  .runs_after = VLIB_INITS("ip_main_init", "ip6_lookup_init"),
1112 };
1113 /* *INDENT-ON* */
1114 
1115 void
1117 {
1119  vlib_main_t *vm = hm->vlib_main;
1120  ip6_local_hop_by_hop_runtime_t *local_hbh_runtime
1121  = hm->ip6_local_hbh_runtime;
1122  u32 old_next_index;
1123 
1124  ASSERT (protocol < ARRAY_LEN (local_hbh_runtime->next_index_by_protocol));
1125 
1126  old_next_index = local_hbh_runtime->next_index_by_protocol[protocol];
1127 
1128  local_hbh_runtime->next_index_by_protocol[protocol] =
1129  vlib_node_add_next (vm, ip6_local_hop_by_hop_node.index, node_index);
1130 
1131  /* Someone will eventually do this. Trust me. */
1132  if (old_next_index &&
1133  (old_next_index != local_hbh_runtime->next_index_by_protocol[protocol]))
1134  clib_warning ("WARNING: replaced next index for protocol %d", protocol);
1135 }
1136 
1137 int
1138 ip6_ioam_set_rewrite (u8 ** rwp, int has_trace_option,
1139  int has_pot_option, int has_seqno_option)
1140 {
1142  u8 *rewrite = NULL;
1143  u32 size, rnd_size;
1145  u8 *current;
1146  u8 *trace_data_size = NULL;
1147  u8 *pot_data_size = NULL;
1148 
1149  vec_free (*rwp);
1150 
1151  if (has_trace_option == 0 && has_pot_option == 0)
1152  return -1;
1153 
1154  /* Work out how much space we need */
1155  size = sizeof (ip6_hop_by_hop_header_t);
1156 
1157  //if (has_trace_option && hm->get_sizeof_options[HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST] != 0)
1158  if (has_trace_option
1160  {
1162  }
1163  if (has_pot_option
1165  {
1167  }
1168 
1169  if (has_seqno_option)
1170  {
1172  }
1173 
1174  /* Round to a multiple of 8 octets */
1175  rnd_size = (size + 7) & ~7;
1176 
1177  /* allocate it, zero-fill / pad by construction */
1178  vec_validate (rewrite, rnd_size - 1);
1179 
1180  hbh = (ip6_hop_by_hop_header_t *) rewrite;
1181  /* Length of header in 8 octet units, not incl first 8 octets */
1182  hbh->length = (rnd_size >> 3) - 1;
1183  current = (u8 *) (hbh + 1);
1184 
1185  if (has_trace_option
1187  {
1189  {
1190  trace_data_size =
1192  if (0 ==
1194  trace_data_size))
1195  current += *trace_data_size;
1196  }
1197  }
1198  if (has_pot_option
1200  {
1201  pot_data_size =
1203  if (0 ==
1205  pot_data_size))
1206  current += *pot_data_size;
1207  }
1208 
1209  if (has_seqno_option &&
1211  {
1212  if (0 == hm->add_options[HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE] (current,
1213  &
1214  (hm->options_size
1217  }
1218 
1219  *rwp = rewrite;
1220  return 0;
1221 }
1222 
1223 clib_error_t *
1225 {
1227 
1228  vec_free (hm->rewrite);
1229  hm->rewrite = 0;
1230  hm->has_trace_option = 0;
1231  hm->has_pot_option = 0;
1232  hm->has_seqno_option = 0;
1233  hm->has_analyse_option = 0;
1236 
1239 
1241  {
1243  &hm->has_analyse_option,
1244  1);
1245  }
1246 
1247  return 0;
1248 }
1249 
1250 clib_error_t *
1252  unformat_input_t * input,
1253  vlib_cli_command_t * cmd)
1254 {
1255  return (clear_ioam_rewrite_fn ());
1256 }
1257 
1258 /*?
1259  * This command clears all the In-band OAM (iOAM) features enabled by
1260  * the '<em>set ioam rewrite</em>' command. Use '<em>show ioam summary</em>' to
1261  * verify the configured settings cleared.
1262  *
1263  * @cliexpar
1264  * Example of how to clear iOAM features:
1265  * @cliexcmd{clear ioam rewrite}
1266 ?*/
1267 /* *INDENT-OFF* */
1268 VLIB_CLI_COMMAND (ip6_clear_ioam_rewrite_cmd, static) = {
1269  .path = "clear ioam rewrite",
1270  .short_help = "clear ioam rewrite",
1271  .function = clear_ioam_rewrite_command_fn,
1272 };
1273 /* *INDENT-ON* */
1274 
1275 clib_error_t *
1276 ip6_ioam_enable (int has_trace_option, int has_pot_option,
1277  int has_seqno_option, int has_analyse_option)
1278 {
1279  int rv;
1281  rv = ip6_ioam_set_rewrite (&hm->rewrite, has_trace_option,
1282  has_pot_option, has_seqno_option);
1283 
1284  switch (rv)
1285  {
1286  case 0:
1287  if (has_trace_option)
1288  {
1289  hm->has_trace_option = has_trace_option;
1292  0);
1293  }
1294 
1295  if (has_pot_option)
1296  {
1297  hm->has_pot_option = has_pot_option;
1300  0);
1301  }
1302  hm->has_analyse_option = has_analyse_option;
1303  if (has_seqno_option)
1304  {
1305  hm->has_seqno_option = has_seqno_option;
1307  {
1309  &has_analyse_option,
1310  0);
1311  }
1312  }
1313  break;
1314 
1315  default:
1316  return clib_error_return_code (0, rv, 0,
1317  "ip6_ioam_set_rewrite returned %d", rv);
1318  }
1319 
1320  return 0;
1321 }
1322 
1323 
1324 static clib_error_t *
1326  unformat_input_t * input,
1327  vlib_cli_command_t * cmd)
1328 {
1329  int has_trace_option = 0;
1330  int has_pot_option = 0;
1331  int has_seqno_option = 0;
1332  int has_analyse_option = 0;
1333  clib_error_t *rv = 0;
1334 
1335  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1336  {
1337  if (unformat (input, "trace"))
1338  has_trace_option = 1;
1339  else if (unformat (input, "pot"))
1340  has_pot_option = 1;
1341  else if (unformat (input, "seqno"))
1342  has_seqno_option = 1;
1343  else if (unformat (input, "analyse"))
1344  has_analyse_option = 1;
1345  else
1346  break;
1347  }
1348 
1349 
1350  rv = ip6_ioam_enable (has_trace_option, has_pot_option,
1351  has_seqno_option, has_analyse_option);
1352 
1353  return rv;
1354 }
1355 
1356 /*?
1357  * This command is used to enable In-band OAM (iOAM) features on IPv6.
1358  * '<em>trace</em>' is used to enable iOAM trace feature. '<em>pot</em>' is used to
1359  * enable the Proof Of Transit feature. '<em>ppc</em>' is used to indicate the
1360  * Per Packet Counter feature for Edge to Edge processing. '<em>ppc</em>' is
1361  * used to indicate if this node is an '<em>encap</em>' node (iOAM edge node
1362  * where packet enters iOAM domain), a '<em>decap</em>' node (iOAM edge node
1363  * where packet leaves iOAM domain) or '<em>none</em>' (iOAM node where packet
1364  * is in-transit through the iOAM domain). '<em>ppc</em>' can only be set if
1365  * '<em>trace</em>' or '<em>pot</em>' is enabled.
1366  *
1367  * Use '<em>clear ioam rewrite</em>' to disable all features enabled by this
1368  * command. Use '<em>show ioam summary</em>' to verify the configured settings.
1369  *
1370  * @cliexpar
1371  * Example of how to enable trace and pot with ppc set to encap:
1372  * @cliexcmd{set ioam rewrite trace pot ppc encap}
1373 ?*/
1374 /* *INDENT-OFF* */
1375 VLIB_CLI_COMMAND (ip6_set_ioam_rewrite_cmd, static) = {
1376  .path = "set ioam rewrite",
1377  .short_help = "set ioam [trace] [pot] [seqno] [analyse]",
1378  .function = ip6_set_ioam_rewrite_command_fn,
1379 };
1380 /* *INDENT-ON* */
1381 
1382 static clib_error_t *
1384  unformat_input_t * input,
1385  vlib_cli_command_t * cmd)
1386 {
1388  u8 *s = 0;
1389 
1390 
1391  if (!is_zero_ip6_address (&hm->adj))
1392  {
1393  s = format (s, " REWRITE FLOW CONFIGS - \n");
1394  s = format (s, " Destination Address : %U\n",
1395  format_ip6_address, &hm->adj, sizeof (ip6_address_t));
1396  s =
1397  format (s, " Flow operation : %d (%s)\n",
1398  hm->ioam_flag,
1399  (hm->ioam_flag ==
1400  IOAM_HBYH_ADD) ? "Add" : ((hm->ioam_flag ==
1401  IOAM_HBYH_MOD) ? "Mod" : "Pop"));
1402  }
1403  else
1404  {
1405  s = format (s, " REWRITE FLOW CONFIGS - Not configured\n");
1406  }
1407 
1408 
1409  s = format (s, " TRACE OPTION - %d (%s)\n",
1410  hm->has_trace_option,
1411  (hm->has_trace_option ? "Enabled" : "Disabled"));
1412  if (hm->has_trace_option)
1413  s =
1414  format (s,
1415  "Try 'show ioam trace and show ioam-trace profile' for more information\n");
1416 
1417 
1418  s = format (s, " POT OPTION - %d (%s)\n",
1419  hm->has_pot_option,
1420  (hm->has_pot_option ? "Enabled" : "Disabled"));
1421  if (hm->has_pot_option)
1422  s =
1423  format (s,
1424  "Try 'show ioam pot and show pot profile' for more information\n");
1425 
1426  s = format (s, " EDGE TO EDGE - SeqNo OPTION - %d (%s)\n",
1427  hm->has_seqno_option,
1428  hm->has_seqno_option ? "Enabled" : "Disabled");
1429  if (hm->has_seqno_option)
1430  s = format (s, "Try 'show ioam e2e' for more information\n");
1431 
1432  s = format (s, " iOAM Analyse OPTION - %d (%s)\n",
1433  hm->has_analyse_option,
1434  hm->has_analyse_option ? "Enabled" : "Disabled");
1435 
1436  vlib_cli_output (vm, "%v", s);
1437  vec_free (s);
1438  return 0;
1439 }
1440 
1441 /*?
1442  * This command displays the current configuration data for In-band
1443  * OAM (iOAM).
1444  *
1445  * @cliexpar
1446  * Example to show the iOAM configuration:
1447  * @cliexstart{show ioam summary}
1448  * REWRITE FLOW CONFIGS -
1449  * Destination Address : ff02::1
1450  * Flow operation : 2 (Pop)
1451  * TRACE OPTION - 1 (Enabled)
1452  * Try 'show ioam trace and show ioam-trace profile' for more information
1453  * POT OPTION - 1 (Enabled)
1454  * Try 'show ioam pot and show pot profile' for more information
1455  * EDGE TO EDGE - PPC OPTION - 1 (Encap)
1456  * @cliexend
1457 ?*/
1458 /* *INDENT-OFF* */
1459 VLIB_CLI_COMMAND (ip6_show_ioam_run_cmd, static) = {
1460  .path = "show ioam summary",
1461  .short_help = "show ioam summary",
1462  .function = ip6_show_ioam_summary_cmd_fn,
1463 };
1464 /* *INDENT-ON* */
1465 
1466 void
1468 {
1470 
1471  hm->ioam_end_of_path_cb = cb;
1472 }
1473 
1474 #endif /* CLIB_MARCH_VARIANT */
1475 /*
1476  * fd.io coding-style-patch-verification: ON
1477  *
1478  * Local Variables:
1479  * eval: (c-set-style "gnu")
1480  * End:
1481  */
u32 * next_nodes
Definition: node.h:337
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:507
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:124
void ip6_local_hop_by_hop_register_protocol(u32 protocol, u32 node_index)
ip6_hop_by_hop_ioam_main_t ip6_hop_by_hop_ioam_main
#define CLIB_UNUSED(x)
Definition: clib.h:86
static void ioam_pop_hop_by_hop_processing(vlib_main_t *vm, ip6_header_t *ip0, ip6_hop_by_hop_header_t *hbh0, vlib_buffer_t *b)
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1664
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static clib_error_t * ip6_show_ioam_summary_cmd_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define PREDICT_TRUE(x)
Definition: clib.h:119
unsigned long u64
Definition: types.h:89
#define IOAM_HBYH_MOD
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:291
IP unicast adjacency.
Definition: adj.h:227
static clib_error_t * ip6_set_ioam_rewrite_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define foreach_ip6_local_hop_by_hop_error
static u8 * format_ip6_add_hop_by_hop_trace(u8 *s, va_list *args)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:472
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1092
unsigned char u8
Definition: types.h:56
ip_lookup_next_t
An adjacency is a representation of an attached L3 peer.
Definition: adj.h:50
int ip6_hbh_flow_handler_register(u8 option, u32 ioam_flow_handler(u32 flow_ctx, u8 add))
int ip6_hbh_flow_handler_unregister(u8 option)
int ip6_hbh_pop_unregister_option(u8 option)
int ip6_hbh_config_handler_unregister(u8 option)
vl_api_ip_proto_t protocol
Definition: lb_types.api:71
static char * ip6_add_hop_by_hop_error_strings[]
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:459
#define HBH_OPTION_TYPE_IOAM_PROOF_OF_TRANSIT
i64 word
Definition: types.h:111
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
#define HBH_OPTION_TYPE_IOAM_EDGE_TO_EDGE
int ip6_hbh_pop_register_option(u8 option, int options(vlib_buffer_t *b, ip6_header_t *ip, ip6_hop_by_hop_option_t *opt))
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
ip6_pop_hop_by_hop_error_t
vlib_node_registration_t ip6_pop_hop_by_hop_node
(constructor) VLIB_REGISTER_NODE (ip6_pop_hop_by_hop_node)
unsigned int u32
Definition: types.h:88
#define vlib_call_init_function(vm, x)
Definition: init.h:270
int ip6_ioam_set_rewrite(u8 **rwp, int has_trace_option, int has_pot_option, int has_seqno_option)
u8 options_size[MAX_IP6_HBH_OPTION]
#define VLIB_FRAME_SIZE
Definition: node.h:380
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
static uword unformat_opaque_ioam(unformat_input_t *input, va_list *args)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
#define foreach_ip6_pop_hop_by_hop_error
u64 size
Definition: vhost_user.h:150
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:229
#define PREDICT_FALSE(x)
Definition: clib.h:118
void vnet_classify_register_unformat_opaque_index_fn(unformat_function_t *fn)
#define always_inline
Definition: ipsec.h:28
vlib_node_registration_t ip6_local_hop_by_hop_node
(constructor) VLIB_REGISTER_NODE (ip6_local_hop_by_hop_node)
u32 node_index
Node index.
Definition: node.h:498
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:224
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:338
vlib_main_t * vm
Definition: in2out_ed.c:1599
ip6_local_hop_by_hop_runtime_t * ip6_local_hbh_runtime
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
clib_error_t * show_ip6_hbh_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
u8 * name
Definition: node.h:266
The fine-grained event logger allows lightweight, thread-safe event logging at minimum cost...
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
#define UNFORMAT_END_OF_INPUT
Definition: format.h:145
u8 flow_name[64]
u32 flags
Definition: vhost_user.h:248
u32(* flow_handler[MAX_IP6_HBH_OPTION])(u32 flow_ctx, u8 add)
u16 n_vectors
Definition: node.h:399
static u8 * format_ip6_pop_hop_by_hop_trace(u8 *s, va_list *args)
format_function_t format_ip6_address
Definition: format.h:91
static uword ip6_local_hop_by_hop_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, int is_trace)
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:80
int ip6_hbh_config_handler_register(u8 option, int config_handler(void *data, u8 disable))
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:339
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:380
int ip6_hbh_add_unregister_option(u8 option)
static u32 ioam_flow_add(u8 encap, u8 *flow_name)
#define clib_warning(format, args...)
Definition: error.h:59
u8 data[]
Packet data.
Definition: buffer.h:181
clib_error_t * ip6_ioam_enable(int has_trace_option, int has_pot_option, int has_seqno_option, int has_analyse_option)
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:299
#define ARRAY_LEN(x)
Definition: clib.h:66
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:483
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1599
static void * ip6_next_header(ip6_header_t *i)
Definition: ip6_packet.h:371
void vnet_register_ioam_end_of_path_callback(void *cb)
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:152
static char * ip6_pop_hop_by_hop_error_strings[]
#define ASSERT(truth)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:689
u8 data[128]
Definition: ipsec_types.api:89
static u8 is_zero_ip6_address(ip6_address_t *a)
static char * ip6_local_hop_by_hop_error_strings[]
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:248
#define HBH_OPTION_TYPE_IOAM_TRACE_DATA_LIST
int(* config_handler[MAX_IP6_HBH_OPTION])(void *data, u8 disable)
#define foreach_ip6_hbyh_ioam_input_next
static void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
struct _vlib_node_registration vlib_node_registration_t
u8 * get_flow_name_from_flow_ctx(u32 flow_ctx)
Definition: defs.h:47
u16 payload_length
Definition: ip6_packet.h:301
vl_api_address_t ip
Definition: l2.api:501
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip6_hbyh_ioam_input_next_t
static clib_error_t * ip6_hop_by_hop_ioam_init(vlib_main_t *vm)
ip_lookup_next_t lookup_next_index
Next hop after ip4-lookup.
Definition: adj.h:329
static u8 * format_ip6_local_hop_by_hop_trace(u8 *s, va_list *args)
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:244
clib_error_t * clear_ioam_rewrite_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static void * clib_mem_alloc_aligned(uword size, uword align)
Definition: mem.h:165
#define vnet_buffer(b)
Definition: buffer.h:417
static struct option options[]
Definition: main.c:52
#define foreach_ip6_add_hop_by_hop_error
#define IOAM_MASK_DECAP_BIT(x)
#define clib_error_return_code(e, code, flags, args...)
Definition: error.h:93
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
Definition: node_funcs.h:59
clib_error_t * clear_ioam_rewrite_fn(void)
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1600
int ip6_hbh_add_register_option(u8 option, u8 size, int rewrite_options(u8 *rewrite_string, u8 *rewrite_size))
int(* pop_options[MAX_IP6_HBH_OPTION])(vlib_buffer_t *b, ip6_header_t *ip, ip6_hop_by_hop_option_t *opt)
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:280
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:304
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2788
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
ip6_local_hop_by_hop_error_t
#define VLIB_INITS(...)
Definition: init.h:344
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
icmpr_flow_t * flow
Definition: main.c:123
vlib_node_registration_t ip6_add_hop_by_hop_node
(constructor) VLIB_REGISTER_NODE (ip6_add_hop_by_hop_node)
ip6_local_hop_by_hop_next_t
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
#define IOAM_HBYH_ADD
int(* add_options[MAX_IP6_HBH_OPTION])(u8 *rewrite_string, u8 *rewrite_size)
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:171
ip6_add_hop_by_hop_error_t