FD.io VPP  v16.12-rc0-308-g931be3a
Vector Packet Processing
sr.c
Go to the documentation of this file.
1 /*
2  * sr.c: ipv6 segment routing
3  *
4  * Copyright (c) 2013 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 Segment Routing main functions
21  *
22  */
23 #include <vnet/vnet.h>
24 #include <vnet/sr/sr.h>
25 #include <vnet/fib/ip6_fib.h>
26 #include <vnet/dpo/dpo.h>
27 
28 #include <openssl/hmac.h>
29 
32 
33 /**
34  * @brief Dynamically added SR DPO type
35  */
37 
38 /**
39  * @brief Use passed HMAC key in ip6_sr_header_t in OpenSSL HMAC routines
40  *
41  * @param sm ip6_sr_main_t *
42  * @param ip ip6_header_t *
43  * @param sr ip6_sr_header_t *
44  */
45 void
47 {
48  u32 key_index;
49  static u8 *keybuf;
50  u8 *copy_target;
51  int first_segment;
52  ip6_address_t *addrp;
53  int i;
54  ip6_sr_hmac_key_t *hmac_key;
55  u32 sig_len;
56 
57  key_index = sr->hmac_key;
58 
59  /* No signature? Pass... */
60  if (key_index == 0)
61  return;
62 
63  /* We don't know about this key? Fail... */
64  if (key_index >= vec_len (sm->hmac_keys))
65  return;
66 
67  hmac_key = sm->hmac_keys + key_index;
68 
69  vec_reset_length (keybuf);
70 
71  /* pkt ip6 src address */
72  vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
73  clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
74 
75  /* first segment */
76  vec_add2 (keybuf, copy_target, 1);
77  copy_target[0] = sr->first_segment;
78 
79  /* octet w/ bit 0 = "clean" flag */
80  vec_add2 (keybuf, copy_target, 1);
81  copy_target[0]
82  = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
83  ? 0x80 : 0;
84 
85  /* hmac key id */
86  vec_add2 (keybuf, copy_target, 1);
87  copy_target[0] = sr->hmac_key;
88 
89  first_segment = sr->first_segment;
90 
91  addrp = sr->segments;
92 
93  /* segments */
94  for (i = 0; i <= first_segment; i++)
95  {
96  vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
97  clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
98  addrp++;
99  }
100 
101  addrp++;
102 
103  HMAC_CTX_init (sm->hmac_ctx);
104  if (!HMAC_Init (sm->hmac_ctx, hmac_key->shared_secret,
105  vec_len (hmac_key->shared_secret), sm->md))
106  clib_warning ("barf1");
107  if (!HMAC_Update (sm->hmac_ctx, keybuf, vec_len (keybuf)))
108  clib_warning ("barf2");
109  if (!HMAC_Final (sm->hmac_ctx, (unsigned char *) addrp, &sig_len))
110  clib_warning ("barf3");
111  HMAC_CTX_cleanup (sm->hmac_ctx);
112 }
113 
114 /**
115  * @brief Format function for decoding various SR flags
116  *
117  * @param s u8 * - formatted string
118  * @param args va_list * - u16 flags
119  *
120  * @return formatted output string u8 *
121  */
122 u8 *
123 format_ip6_sr_header_flags (u8 * s, va_list * args)
124 {
125  u16 flags = (u16) va_arg (*args, int);
126  u8 pl_flag;
127  int bswap_needed = va_arg (*args, int);
128  int i;
129 
130  if (bswap_needed)
131  flags = clib_host_to_net_u16 (flags);
132 
133  if (flags & IP6_SR_HEADER_FLAG_CLEANUP)
134  s = format (s, "cleanup ");
135 
136  if (flags & IP6_SR_HEADER_FLAG_PROTECTED)
137  s = format (s, "reroute ");
138 
139  s = format (s, "pl: ");
140  for (i = 1; i <= 4; i++)
141  {
142  pl_flag = ip6_sr_policy_list_flags (flags, i);
143  s = format (s, "[%d] ", i);
144 
145  switch (pl_flag)
146  {
148  s = format (s, "NotPr ");
149  break;
151  s = format (s, "InPE ");
152  break;
154  s = format (s, "EgPE ");
155  break;
156 
158  s = format (s, "OrgSrc ");
159  break;
160  }
161  }
162  return s;
163 }
164 
165 /**
166  * @brief Format function for decoding ip6_sr_header_t
167  *
168  * @param s u8 * - formatted string
169  * @param args va_list * - ip6_sr_header_t
170  *
171  * @return formatted output string u8 *
172  */
173 u8 *
174 format_ip6_sr_header (u8 * s, va_list * args)
175 {
176  ip6_sr_header_t *h = va_arg (*args, ip6_sr_header_t *);
177  ip6_address_t placeholder_addr =
178  { {254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
179  254, 254}
180  };
181  int print_hmac = va_arg (*args, int);
182  int i, pl_index, max_segs;
183  int flags_host_byte_order = clib_net_to_host_u16 (h->flags);
184 
185  s = format (s, "next proto %d, len %d, type %d",
186  h->protocol, (h->length << 3) + 8, h->type);
187  s = format (s, "\n segs left %d, first_segment %d, hmac key %d",
189  s = format (s, "\n flags %U", format_ip6_sr_header_flags,
190  flags_host_byte_order, 0 /* bswap needed */ );
191 
192  /*
193  * Header length is in 8-byte units (minus one), so
194  * divide by 2 to ascertain the number of ip6 addresses in the
195  * segment list
196  */
197  max_segs = (h->length >> 1);
198 
199  if (!print_hmac && h->hmac_key)
200  max_segs -= 2;
201 
202  s = format (s, "\n Segments (in processing order):");
203 
204  for (i = h->first_segment; i >= 1; i--)
205  s = format (s, "\n %U", format_ip6_address, h->segments + i);
206  if (ip6_address_is_equal (&placeholder_addr, h->segments))
207  s = format (s, "\n (empty placeholder)");
208  else
209  s = format (s, "\n %U", format_ip6_address, h->segments);
210 
211  s = format (s, "\n Policy List:");
212 
213  pl_index = 1; /* to match the RFC text */
214  for (i = (h->first_segment + 1); i < max_segs; i++, pl_index++)
215  {
216  char *tag;
217  char *tags[] = { " ", "InPE: ", "EgPE: ", "OrgSrc: " };
218 
219  tag = tags[0];
220  if (pl_index >= 1 && pl_index <= 4)
221  {
222  int this_pl_flag = ip6_sr_policy_list_flags
223  (flags_host_byte_order, pl_index);
224  tag = tags[this_pl_flag];
225  }
226 
227  s = format (s, "\n %s%U", tag, format_ip6_address, h->segments + i);
228  }
229 
230  return s;
231 }
232 
233 /**
234  * @brief Format function for decoding ip6_sr_header_t with length
235  *
236  * @param s u8 * - formatted string
237  * @param args va_list * - ip6_header_t + ip6_sr_header_t
238  *
239  * @return formatted output string u8 *
240  */
241 u8 *
243 {
244  ip6_header_t *h = va_arg (*args, ip6_header_t *);
245  u32 max_header_bytes = va_arg (*args, u32);
246  uword header_bytes;
247 
248  header_bytes = sizeof (h[0]) + sizeof (ip6_sr_header_t);
249  if (max_header_bytes != 0 && header_bytes > max_header_bytes)
250  return format (s, "ip6_sr header truncated");
251 
252  s = format (s, "IP6: %U\n", format_ip6_header, h, max_header_bytes);
253  s =
254  format (s, "SR: %U\n", format_ip6_sr_header, (ip6_sr_header_t *) (h + 1),
255  0 /* print_hmac */ , max_header_bytes);
256  return s;
257 }
258 
259 /**
260  * @brief Defined valid next nodes
261  * @note Cannot call replicate yet without DPDK
262 */
263 #if DPDK > 0
264 #define foreach_sr_rewrite_next \
265 _(ERROR, "error-drop") \
266 _(IP6_LOOKUP, "ip6-lookup") \
267 _(SR_LOCAL, "sr-local") \
268 _(SR_REPLICATE,"sr-replicate")
269 #else
270 #define foreach_sr_rewrite_next \
271 _(ERROR, "error-drop") \
272 _(IP6_LOOKUP, "ip6-lookup") \
273 _(SR_LOCAL, "sr-local")
274 #endif /* DPDK */
275 
276 /**
277  * @brief Struct for defined valid next nodes
278 */
279 typedef enum
280 {
281 #define _(s,n) SR_REWRITE_NEXT_##s,
283 #undef _
286 
287 /**
288  * @brief Struct for data for SR rewrite packet trace
289  */
290 typedef struct
291 {
296  u8 sr[256];
298 
299 /**
300  * @brief Error strings for SR rewrite
301  */
302 static char *sr_rewrite_error_strings[] = {
303 #define sr_error(n,s) s,
304 #include "sr_error.def"
305 #undef sr_error
306 };
307 
308 /**
309  * @brief Struct for SR rewrite error strings
310  */
311 typedef enum
312 {
313 #define sr_error(n,s) SR_REWRITE_ERROR_##n,
314 #include "sr_error.def"
315 #undef sr_error
316  SR_REWRITE_N_ERROR,
318 
319 
320 /**
321  * @brief Format function for SR rewrite trace.
322  */
323 u8 *
324 format_sr_rewrite_trace (u8 * s, va_list * args)
325 {
326  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
327  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
328  sr_rewrite_trace_t *t = va_arg (*args, sr_rewrite_trace_t *);
331  ip6_fib_t *rx_fib, *tx_fib;
332 
333  rx_fib = ip6_fib_get (tun->rx_fib_index);
334  tx_fib = ip6_fib_get (tun->tx_fib_index);
335 
336  s = format
337  (s, "SR-REWRITE: next %s ip6 src %U dst %U len %u\n"
338  " rx-fib-id %d tx-fib-id %d\n%U",
339  (t->next_index == SR_REWRITE_NEXT_SR_LOCAL)
340  ? "sr-local" : "ip6-lookup",
341  format_ip6_address, &t->src,
342  format_ip6_address, &t->dst, t->length,
343  rx_fib->table_id, tx_fib->table_id,
344  format_ip6_sr_header, t->sr, 0 /* print_hmac */ );
345  return s;
346 }
347 
348 /**
349  * @brief Main processing dual-loop for Segment Routing Rewrite
350  * @node sr-rewrite
351  *
352  * @param vm vlib_main_t *
353  * @param node vlib_node_runtime_t *
354  * @param from_frame vlib_frame_t *
355  *
356  * @return from_frame->n_vectors uword
357  */
358 static uword
360  vlib_node_runtime_t * node, vlib_frame_t * from_frame)
361 {
362  u32 n_left_from, next_index, *from, *to_next;
363  ip6_main_t *im = &ip6_main;
364  ip_lookup_main_t *lm = &im->lookup_main;
365  ip6_sr_main_t *sm = &sr_main;
366  u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
368  sr_local_cb = sm->sr_local_cb;
369 
370  from = vlib_frame_vector_args (from_frame);
371  n_left_from = from_frame->n_vectors;
372 
373  next_index = node->cached_next_index;
374 
375  while (n_left_from > 0)
376  {
377  u32 n_left_to_next;
378 
379  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
380 
381  /* Note 2x loop disabled */
382  while (0 && n_left_from >= 4 && n_left_to_next >= 2)
383  {
384  u32 bi0, bi1;
385  vlib_buffer_t *b0, *b1;
386  ip6_header_t *ip0, *ip1;
387  ip_adjacency_t *adj0, *adj1;
388  ip6_sr_header_t *sr0, *sr1;
389  ip6_sr_tunnel_t *t0, *t1;
390  u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
391  u32 next1 = SR_REWRITE_NEXT_IP6_LOOKUP;
392  u16 new_l0 = 0;
393  u16 new_l1 = 0;
394 
395  /* Prefetch next iteration. */
396  {
397  vlib_buffer_t *p2, *p3;
398 
399  p2 = vlib_get_buffer (vm, from[2]);
400  p3 = vlib_get_buffer (vm, from[3]);
401 
402  vlib_prefetch_buffer_header (p2, LOAD);
403  vlib_prefetch_buffer_header (p3, LOAD);
404  }
405 
406  bi0 = from[0];
407  bi1 = from[1];
408  to_next[0] = bi0;
409  to_next[1] = bi1;
410  from += 2;
411  to_next += 2;
412  n_left_to_next -= 2;
413  n_left_from -= 2;
414 
415  b0 = vlib_get_buffer (vm, bi0);
416  b1 = vlib_get_buffer (vm, bi1);
417 
418  /*
419  * $$$ parse through header(s) to pick the point
420  * where we punch in the SR extention header
421  */
422 
423  adj0 =
424  ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
425  adj1 =
426  ip_get_adjacency (lm, vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
427  t0 =
428  pool_elt_at_index (sm->tunnels, adj0->rewrite_header.sw_if_index);
429  t1 =
430  pool_elt_at_index (sm->tunnels, adj1->rewrite_header.sw_if_index);
431 
433  >= ((word) vec_len (t0->rewrite)) + b0->current_data);
435  >= ((word) vec_len (t1->rewrite)) + b1->current_data);
436 
437  vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
438  vnet_buffer (b1)->sw_if_index[VLIB_TX] = t1->tx_fib_index;
439 
440  ip0 = vlib_buffer_get_current (b0);
441  ip1 = vlib_buffer_get_current (b1);
442 
443  /*
444  * SR-unaware service chaining case: pkt coming back from
445  * service has the original dst address, and will already
446  * have an SR header. If so, send it to sr-local
447  */
449  {
450  vlib_buffer_advance (b0, sizeof (ip0));
451  sr0 = (ip6_sr_header_t *) (ip0 + 1);
452  new_l0 = clib_net_to_host_u16 (ip0->payload_length);
453  next0 = SR_REWRITE_NEXT_SR_LOCAL;
454  }
455  else
456  {
457  /*
458  * Copy data before the punch-in point left by the
459  * required amount. Assume (for the moment) that only
460  * the main packet header needs to be copied.
461  */
462  clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
463  ip0, sizeof (ip6_header_t));
464  vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
465  ip0 = vlib_buffer_get_current (b0);
466  sr0 = (ip6_sr_header_t *) (ip0 + 1);
467  /* $$$ tune */
468  clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
469 
470  /* Fix the next header chain */
471  sr0->protocol = ip0->protocol;
472  ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
473  new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
474  vec_len (t0->rewrite);
475  ip0->payload_length = clib_host_to_net_u16 (new_l0);
476 
477  /* Copy dst address into the DA slot in the segment list */
479  sizeof (ip6_address_t));
480  /* Rewrite the ip6 dst address with the first hop */
482  sizeof (ip6_address_t));
483 
484  sr_fix_hmac (sm, ip0, sr0);
485 
486  next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
487  next0;
488 
489  /*
490  * Ignore "do not rewrite" shtik in this path
491  */
492  if (PREDICT_FALSE (next0 & 0x80000000))
493  {
494  next0 ^= 0xFFFFFFFF;
495  if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
496  b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
497  }
498  }
499 
501  {
502  vlib_buffer_advance (b1, sizeof (ip1));
503  sr1 = (ip6_sr_header_t *) (ip1 + 1);
504  new_l1 = clib_net_to_host_u16 (ip1->payload_length);
505  next1 = SR_REWRITE_NEXT_SR_LOCAL;
506  }
507  else
508  {
509  clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
510  ip0, sizeof (ip6_header_t));
511  vlib_buffer_advance (b1, -(word) vec_len (t1->rewrite));
512  ip1 = vlib_buffer_get_current (b1);
513  sr1 = (ip6_sr_header_t *) (ip1 + 1);
514  clib_memcpy (sr1, t1->rewrite, vec_len (t1->rewrite));
515 
516  sr1->protocol = ip1->protocol;
518  new_l1 = clib_net_to_host_u16 (ip1->payload_length) +
519  vec_len (t1->rewrite);
520  ip1->payload_length = clib_host_to_net_u16 (new_l1);
521 
522  /* Copy dst address into the DA slot in the segment list */
524  sizeof (ip6_address_t));
525  /* Rewrite the ip6 dst address with the first hop */
527  sizeof (ip6_address_t));
528 
529  sr_fix_hmac (sm, ip1, sr1);
530 
531  next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
532  next1;
533 
534  /*
535  * Ignore "do not rewrite" shtik in this path
536  */
537  if (PREDICT_FALSE (next1 & 0x80000000))
538  {
539  next1 ^= 0xFFFFFFFF;
540  if (PREDICT_FALSE (next1 == SR_REWRITE_NEXT_ERROR))
541  b1->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
542  }
543  }
544 
546  {
547  sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
548  b0, sizeof (*tr));
549  tr->tunnel_index = t0 - sm->tunnels;
551  sizeof (tr->src.as_u8));
553  sizeof (tr->dst.as_u8));
554  tr->length = new_l0;
555  tr->next_index = next0;
556  clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
557  }
559  {
560  sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
561  b1, sizeof (*tr));
562  tr->tunnel_index = t1 - sm->tunnels;
564  sizeof (tr->src.as_u8));
566  sizeof (tr->dst.as_u8));
567  tr->length = new_l1;
568  tr->next_index = next1;
569  clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
570  }
571 
572  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
573  to_next, n_left_to_next,
574  bi0, bi1, next0, next1);
575  }
576 
577  while (n_left_from > 0 && n_left_to_next > 0)
578  {
579  u32 bi0;
580  vlib_buffer_t *b0;
581  ip6_header_t *ip0 = 0;
582  ip_adjacency_t *adj0;
583  ip6_sr_header_t *sr0 = 0;
584  ip6_sr_tunnel_t *t0;
585  u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
586  u16 new_l0 = 0;
587 
588  bi0 = from[0];
589  to_next[0] = bi0;
590  from += 1;
591  to_next += 1;
592  n_left_from -= 1;
593  n_left_to_next -= 1;
594 
595  b0 = vlib_get_buffer (vm, bi0);
596 
597  /*
598  * $$$ parse through header(s) to pick the point
599  * where we punch in the SR extention header
600  */
601 
602  adj0 =
603  ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
604  t0 =
605  pool_elt_at_index (sm->tunnels, adj0->rewrite_header.sw_if_index);
606 
607 #if DPDK > 0 /* Cannot call replication node yet without DPDK */
608  /* add a replication node */
609  if (PREDICT_FALSE (t0->policy_index != ~0))
610  {
611  vnet_buffer (b0)->ip.save_protocol = t0->policy_index;
612  next0 = SR_REWRITE_NEXT_SR_REPLICATE;
613  goto trace0;
614  }
615 #endif /* DPDK */
616 
618  >= ((word) vec_len (t0->rewrite)) + b0->current_data);
619 
620  vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
621 
622  ip0 = vlib_buffer_get_current (b0);
623 
624  /*
625  * SR-unaware service chaining case: pkt coming back from
626  * service has the original dst address, and will already
627  * have an SR header. If so, send it to sr-local
628  */
630  {
631  vlib_buffer_advance (b0, sizeof (ip0));
632  sr0 = (ip6_sr_header_t *) (ip0 + 1);
633  new_l0 = clib_net_to_host_u16 (ip0->payload_length);
634  next0 = SR_REWRITE_NEXT_SR_LOCAL;
635  }
636  else
637  {
638  /*
639  * Copy data before the punch-in point left by the
640  * required amount. Assume (for the moment) that only
641  * the main packet header needs to be copied.
642  */
643  clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
644  ip0, sizeof (ip6_header_t));
645  vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
646  ip0 = vlib_buffer_get_current (b0);
647  sr0 = (ip6_sr_header_t *) (ip0 + 1);
648  /* $$$ tune */
649  clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
650 
651  /* Fix the next header chain */
652  sr0->protocol = ip0->protocol;
653  ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
654  new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
655  vec_len (t0->rewrite);
656  ip0->payload_length = clib_host_to_net_u16 (new_l0);
657 
658  /* Copy dst address into the DA slot in the segment list */
660  sizeof (ip6_address_t));
661  /* Rewrite the ip6 dst address with the first hop */
663  sizeof (ip6_address_t));
664 
665  sr_fix_hmac (sm, ip0, sr0);
666 
667  next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
668  next0;
669 
670  /*
671  * Ignore "do not rewrite" shtik in this path
672  */
673  if (PREDICT_FALSE (next0 & 0x80000000))
674  {
675  next0 ^= 0xFFFFFFFF;
676  if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
677  b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
678  }
679  }
680 
681 #if DPDK > 0 /* Cannot run replicate without DPDK and only replicate uses this label */
682  trace0:
683 #endif /* DPDK */
685  {
686  sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
687  b0, sizeof (*tr));
688  tr->tunnel_index = t0 - sm->tunnels;
689  if (ip0)
690  {
691  memcpy (tr->src.as_u8, ip0->src_address.as_u8,
692  sizeof (tr->src.as_u8));
693  memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
694  sizeof (tr->dst.as_u8));
695  }
696  tr->length = new_l0;
697  tr->next_index = next0;
698  clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
699  }
700 
701  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
702  to_next, n_left_to_next,
703  bi0, next0);
704  }
705 
706  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
707  }
708  return from_frame->n_vectors;
709 }
710 
711 /* *INDENT-OFF* */
713  .function = sr_rewrite,
714  .name = "sr-rewrite",
715  /* Takes a vector of packets. */
716  .vector_size = sizeof (u32),
717  .format_trace = format_sr_rewrite_trace,
718  .format_buffer = format_ip6_sr_header_with_length,
719 
720  .n_errors = SR_REWRITE_N_ERROR,
721  .error_strings = sr_rewrite_error_strings,
722 
723  .runtime_data_bytes = 0,
724 
725  .n_next_nodes = SR_REWRITE_N_NEXT,
726  .next_nodes = {
727 #define _(s,n) [SR_REWRITE_NEXT_##s] = n,
729 #undef _
730  },
731 };
732 
734 /* *INDENT-ON* */
735 
736 static int
738  u32 dst_address_length, u32 rx_table_id)
739 {
740  fib_prefix_t pfx = {
741  .fp_len = dst_address_length,
742  .fp_proto = FIB_PROTOCOL_IP6,
743  .fp_addr = {
744  .ip6 = *dst_address_arg,
745  }
746  };
747 
749  rx_table_id),
750  &pfx, FIB_SOURCE_SR);
751 
752  return 0;
753 }
754 
755 /**
756  * @brief Find or add if not found - HMAC shared secret
757  *
758  * @param sm ip6_sr_main_t *
759  * @param secret u8 *
760  * @param indexp u32 *
761  *
762  * @return ip6_sr_hmac_key_t *
763  */
764 static ip6_sr_hmac_key_t *
765 find_or_add_shared_secret (ip6_sr_main_t * sm, u8 * secret, u32 * indexp)
766 {
767  uword *p;
768  ip6_sr_hmac_key_t *key = 0;
769  int i;
770 
771  p = hash_get_mem (sm->hmac_key_by_shared_secret, secret);
772 
773  if (p)
774  {
775  key = vec_elt_at_index (sm->hmac_keys, p[0]);
776  if (indexp)
777  *indexp = p[0];
778  return (key);
779  }
780 
781  /* Specific key ID? */
782  if (indexp && *indexp)
783  {
784  vec_validate (sm->hmac_keys, *indexp);
785  key = sm->hmac_keys + *indexp;
786  }
787  else
788  {
789  for (i = 0; i < vec_len (sm->hmac_keys); i++)
790  {
791  if (sm->hmac_keys[i].shared_secret == 0)
792  {
793  key = sm->hmac_keys + i;
794  goto found;
795  }
796  }
797  vec_validate (sm->hmac_keys, i);
798  key = sm->hmac_keys + i;
799  found:
800  ;
801  }
802 
803  key->shared_secret = vec_dup (secret);
804 
806  key - sm->hmac_keys);
807 
808  if (indexp)
809  *indexp = key - sm->hmac_keys;
810  return (key);
811 }
812 
813 /**
814  * @brief Add or Delete a Segment Routing tunnel.
815  *
816  * @param a ip6_sr_add_del_tunnel_args_t *
817  *
818  * @return retval int
819  */
820 int
822 {
823  ip6_main_t *im = &ip6_main;
825  ip6_sr_tunnel_t *t;
826  uword *p, *n;
827  ip6_sr_header_t *h = 0;
828  u32 header_length;
829  ip6_address_t *addrp, *this_address;
830  ip6_sr_main_t *sm = &sr_main;
831  u8 *key_copy;
832  u32 rx_fib_index, tx_fib_index;
833  u32 hmac_key_index_u32;
834  u8 hmac_key_index = 0;
835  ip6_sr_policy_t *pt;
836  int i;
837  dpo_id_t dpo = DPO_INVALID;
838 
839  /* Make sure that the rx FIB exists */
841 
842  if (p == 0)
843  return -3;
844 
845  /* remember the FIB index */
846  rx_fib_index = p[0];
847 
848  /* Make sure that the supplied FIB exists */
850 
851  if (p == 0)
852  return -4;
853 
854  /* remember the FIB index */
855  tx_fib_index = p[0];
856 
857  clib_memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
858  clib_memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
859 
860  /* When adding a tunnel:
861  * - If a "name" is given, it must not exist.
862  * - The "key" is always checked, and must not exist.
863  * When deleting a tunnel:
864  * - If the "name" is given, and it exists, then use it.
865  * - If the "name" is not given, use the "key".
866  * - If the "name" and the "key" are given, then both must point to the same
867  * thing.
868  */
869 
870  /* Lookup the key */
871  p = hash_get_mem (sm->tunnel_index_by_key, &key);
872 
873  /* If the name is given, look it up */
874  if (a->name)
875  n = hash_get_mem (sm->tunnel_index_by_name, a->name);
876  else
877  n = 0;
878 
879  /* validate key/name parameters */
880  if (!a->is_del) /* adding a tunnel */
881  {
882  if (a->name && n) /* name given & exists already */
883  return -1;
884  if (p) /* key exists already */
885  return -1;
886  }
887  else /* deleting a tunnel */
888  {
889  if (!p) /* key doesn't exist */
890  return -2;
891  if (a->name && !n) /* name given & it doesn't exist */
892  return -2;
893 
894  if (n) /* name given & found */
895  {
896  if (n[0] != p[0]) /* name and key do not point to the same thing */
897  return -2;
898  }
899  }
900 
901 
902  if (a->is_del) /* delete the tunnel */
903  {
904  hash_pair_t *hp;
905 
906  /* Delete existing tunnel */
907  t = pool_elt_at_index (sm->tunnels, p[0]);
908 
910  a->rx_table_id);
911  vec_free (t->rewrite);
912  /* Remove tunnel from any policy if associated */
913  if (t->policy_index != ~0)
914  {
915  pt = pool_elt_at_index (sm->policies, t->policy_index);
916  for (i = 0; i < vec_len (pt->tunnel_indices); i++)
917  {
918  if (pt->tunnel_indices[i] == t - sm->tunnels)
919  {
920  vec_delete (pt->tunnel_indices, 1, i);
921  goto found;
922  }
923  }
924  clib_warning ("Tunnel index %d not found in policy_index %d",
925  t - sm->tunnels, pt - sm->policies);
926  found:
927  /* If this is last tunnel in the policy, clean up the policy too */
928  if (vec_len (pt->tunnel_indices) == 0)
929  {
931  vec_free (pt->name);
932  pool_put (sm->policies, pt);
933  }
934  }
935 
936  /* Clean up the tunnel by name */
937  if (t->name)
938  {
940  vec_free (t->name);
941  }
942  pool_put (sm->tunnels, t);
943  hp = hash_get_pair (sm->tunnel_index_by_key, &key);
944  key_copy = (void *) (hp->key);
946  vec_free (key_copy);
947  return 0;
948  }
949 
950  /* create a new tunnel */
951  pool_get (sm->tunnels, t);
952  memset (t, 0, sizeof (*t));
953  t->policy_index = ~0;
954 
955  clib_memcpy (&t->key, &key, sizeof (t->key));
957  t->rx_fib_index = rx_fib_index;
958  t->tx_fib_index = tx_fib_index;
959 
960  if (!vec_len (a->segments))
961  /* there must be at least one segment... */
962  return -4;
963 
964  /* The first specified hop goes right into the dst address */
965  clib_memcpy (&t->first_hop, &a->segments[0], sizeof (ip6_address_t));
966 
967  /*
968  * Create the sr header rewrite string
969  * The list of segments needs an extra slot for the ultimate destination
970  * which is taken from the packet we add the SRH to.
971  */
972  header_length = sizeof (*h) +
973  sizeof (ip6_address_t) * (vec_len (a->segments) + 1 + vec_len (a->tags));
974 
975  if (a->shared_secret)
976  {
977  /* Allocate a new key slot if we don't find the secret key */
978  hmac_key_index_u32 = 0;
980  &hmac_key_index_u32);
981 
982  /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
983  if (hmac_key_index_u32 >= 256)
984  return -5;
985  hmac_key_index = hmac_key_index_u32;
986  header_length += SHA256_DIGEST_LENGTH;
987  }
988 
989  vec_validate (t->rewrite, header_length - 1);
990 
991  h = (ip6_sr_header_t *) t->rewrite;
992 
993  h->protocol = 0xFF; /* we don't know yet */
994 
995  h->length = (header_length / 8) - 1;
997 
998  /* first_segment and segments_left need to have the index of the last
999  * element in the list; a->segments has one element less than ends up
1000  * in the header (it does not have the DA in it), so vec_len(a->segments)
1001  * is the value we want.
1002  */
1004 
1005  if (a->shared_secret)
1006  h->hmac_key = hmac_key_index & 0xFF;
1007 
1008  h->flags = a->flags_net_byte_order;
1009 
1010  /* Paint on the segment list, in reverse.
1011  * This is offset by one to leave room at the start for the ultimate
1012  * destination.
1013  */
1014  addrp = h->segments + vec_len (a->segments);
1015 
1016  vec_foreach (this_address, a->segments)
1017  {
1018  clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
1019  addrp--;
1020  }
1021 
1022  /*
1023  * Since the ultimate destination address is not yet known, set that slot
1024  * to a value we will instantly recognize as bogus.
1025  */
1026  memset (h->segments, 0xfe, sizeof (ip6_address_t));
1027 
1028  /* Paint on the tag list, not reversed */
1029  addrp = h->segments + vec_len (a->segments);
1030 
1031  vec_foreach (this_address, a->tags)
1032  {
1033  clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
1034  addrp++;
1035  }
1036 
1037  key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
1038  clib_memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
1039  hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
1040 
1041  /*
1042  * Stick the tunnel index into the rewrite header.
1043  *
1044  * Unfortunately, inserting an SR header according to the various
1045  * RFC's requires parsing through the ip6 header, perhaps consing a
1046  * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1047  * normal reverse bcopy rewrite code.
1048  *
1049  * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1050  * at some point...
1051  */
1052  dpo_set (&dpo, sr_dpo_type, DPO_PROTO_IP6, t - sm->tunnels);
1053 
1054  fib_prefix_t pfx = {
1056  .fp_len = a->dst_mask_width,
1057  .fp_addr = {
1058  .ip6 = *a->dst_address,
1059  }
1060  };
1061  fib_table_entry_special_dpo_add (rx_fib_index,
1062  &pfx,
1063  FIB_SOURCE_SR,
1064  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
1065  dpo_reset (&dpo);
1066 
1067  if (a->policy_name)
1068  {
1070  if (p)
1071  {
1072  pt = pool_elt_at_index (sm->policies, p[0]);
1073  }
1074  else /* no policy, lets create one */
1075  {
1076  pool_get (sm->policies, pt);
1077  memset (pt, 0, sizeof (*pt));
1078  pt->name = format (0, "%s%c", a->policy_name, 0);
1080  pt - sm->policies);
1082  }
1083  vec_add1 (pt->tunnel_indices, t - sm->tunnels);
1084  if (p == 0)
1085  clib_warning ("p is NULL!");
1086  t->policy_index = p ? p[0] : ~0; /* equiv. to (pt - sm->policies) */
1087  }
1088 
1089  if (a->name)
1090  {
1091  t->name = format (0, "%s%c", a->name, 0);
1092  hash_set_mem (sm->tunnel_index_by_name, t->name, t - sm->tunnels);
1093  }
1094 
1095  return 0;
1096 }
1097 
1098 /**
1099  * @brief no-op lock function.
1100  * The lifetime of the SR entry is managed by the control plane
1101  */
1102 static void
1104 {
1105 }
1106 
1107 /**
1108  * @brief no-op unlock function.
1109  * The lifetime of the SR entry is managed by the control plane
1110  */
1111 static void
1113 {
1114 }
1115 
1116 u8 *
1117 format_sr_dpo (u8 * s, va_list * args)
1118 {
1119  index_t index = va_arg (*args, index_t);
1120  CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
1121 
1122  return (format (s, "SR: tunnel:[%d]", index));
1123 }
1124 
1125 const static dpo_vft_t sr_vft = {
1126  .dv_lock = sr_dpo_lock,
1127  .dv_unlock = sr_dpo_unlock,
1128  .dv_format = format_sr_dpo,
1129 };
1130 
1131 const static char *const sr_ip6_nodes[] = {
1132  "sr-rewrite",
1133  NULL,
1134 };
1135 
1136 const static char *const *const sr_nodes[DPO_PROTO_NUM] = {
1138 };
1139 
1140 /**
1141  * @brief CLI parser for Add or Delete a Segment Routing tunnel.
1142  *
1143  * @param vm vlib_main_t *
1144  * @param input unformat_input_t *
1145  * @param cmd vlib_cli_command_t *
1146  *
1147  * @return error clib_error_t *
1148  */
1149 static clib_error_t *
1151  unformat_input_t * input,
1152  vlib_cli_command_t * cmd)
1153 {
1154  int is_del = 0;
1155  ip6_address_t src_address;
1156  int src_address_set = 0;
1157  ip6_address_t dst_address;
1158  u32 dst_mask_width;
1159  int dst_address_set = 0;
1160  u16 flags = 0;
1161  u8 *shared_secret = 0;
1162  u8 *name = 0;
1163  u8 *policy_name = 0;
1164  u32 rx_table_id = 0;
1165  u32 tx_table_id = 0;
1166  ip6_address_t *segments = 0;
1167  ip6_address_t *this_seg;
1168  ip6_address_t *tags = 0;
1169  ip6_address_t *this_tag;
1170  ip6_sr_add_del_tunnel_args_t _a, *a = &_a;
1171  ip6_address_t next_address, tag;
1172  int pl_index;
1173  int rv;
1174 
1175  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1176  {
1177  if (unformat (input, "del"))
1178  is_del = 1;
1179  else if (unformat (input, "rx-fib-id %d", &rx_table_id))
1180  ;
1181  else if (unformat (input, "tx-fib-id %d", &tx_table_id))
1182  ;
1183  else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
1184  src_address_set = 1;
1185  else if (unformat (input, "name %s", &name))
1186  ;
1187  else if (unformat (input, "policy %s", &policy_name))
1188  ;
1189  else if (unformat (input, "dst %U/%d",
1190  unformat_ip6_address, &dst_address, &dst_mask_width))
1191  dst_address_set = 1;
1192  else if (unformat (input, "next %U", unformat_ip6_address,
1193  &next_address))
1194  {
1195  vec_add2 (segments, this_seg, 1);
1196  clib_memcpy (this_seg->as_u8, next_address.as_u8,
1197  sizeof (*this_seg));
1198  }
1199  else if (unformat (input, "tag %U", unformat_ip6_address, &tag))
1200  {
1201  vec_add2 (tags, this_tag, 1);
1202  clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
1203  }
1204  else if (unformat (input, "clean"))
1205  flags |= IP6_SR_HEADER_FLAG_CLEANUP;
1206  else if (unformat (input, "protected"))
1208  else if (unformat (input, "key %s", &shared_secret))
1209  /* Do not include the trailing NULL byte. Guaranteed interop issue */
1210  _vec_len (shared_secret) -= 1;
1211  else if (unformat (input, "InPE %d", &pl_index))
1212  {
1213  if (pl_index <= 0 || pl_index > 4)
1214  {
1215  pl_index_range_error:
1216  return clib_error_return
1217  (0, "Policy List Element Index %d out of range (1-4)",
1218  pl_index);
1219 
1220  }
1223  }
1224  else if (unformat (input, "EgPE %d", &pl_index))
1225  {
1226  if (pl_index <= 0 || pl_index > 4)
1227  goto pl_index_range_error;
1230  }
1231  else if (unformat (input, "OrgSrc %d", &pl_index))
1232  {
1233  if (pl_index <= 0 || pl_index > 4)
1234  goto pl_index_range_error;
1237  }
1238  else
1239  break;
1240  }
1241 
1242  if (!src_address_set)
1243  return clib_error_return (0, "src address required");
1244 
1245  if (!dst_address_set)
1246  return clib_error_return (0, "dst address required");
1247 
1248  if (!segments)
1249  return clib_error_return (0, "at least one sr segment required");
1250 
1251  memset (a, 0, sizeof (*a));
1252  a->src_address = &src_address;
1253  a->dst_address = &dst_address;
1254  a->dst_mask_width = dst_mask_width;
1255  a->segments = segments;
1256  a->tags = tags;
1257  a->flags_net_byte_order = clib_host_to_net_u16 (flags);
1258  a->is_del = is_del;
1259  a->rx_table_id = rx_table_id;
1260  a->tx_table_id = tx_table_id;
1261  a->shared_secret = shared_secret;
1262 
1263  if (vec_len (name))
1264  a->name = name;
1265  else
1266  a->name = 0;
1267 
1268  if (vec_len (policy_name))
1269  a->policy_name = policy_name;
1270  else
1271  a->policy_name = 0;
1272 
1273  rv = ip6_sr_add_del_tunnel (a);
1274 
1275  vec_free (segments);
1276  vec_free (tags);
1277  vec_free (shared_secret);
1278 
1279  switch (rv)
1280  {
1281  case 0:
1282  break;
1283 
1284  case -1:
1285  return clib_error_return (0, "SR tunnel src %U dst %U already exists",
1286  format_ip6_address, &src_address,
1287  format_ip6_address, &dst_address);
1288 
1289  case -2:
1290  return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
1291  format_ip6_address, &src_address,
1292  format_ip6_address, &dst_address);
1293 
1294  case -3:
1295  return clib_error_return (0, "FIB table %d does not exist",
1296  rx_table_id);
1297 
1298  case -4:
1299  return clib_error_return (0, "At least one segment is required");
1300 
1301  default:
1302  return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
1303  rv);
1304  }
1305 
1306  return 0;
1307 }
1308 
1309 /* *INDENT-OFF* */
1311  .path = "sr tunnel",
1312  .short_help =
1313  "sr tunnel [del] [name <name>] src <addr> dst <addr> [next <addr>] "
1314  "[clean] [reroute] [key <secret>] [policy <policy_name>]"
1315  "[rx-fib-id <fib_id>] [tx-fib-id <fib_id>]",
1316  .function = sr_add_del_tunnel_command_fn,
1317 };
1318 /* *INDENT-ON* */
1319 
1320 /**
1321  * @brief Display Segment Routing tunnel
1322  *
1323  * @param vm vlib_main_t *
1324  * @param t ip6_sr_tunnel_t *
1325  *
1326  */
1327 void
1329 {
1330  ip6_sr_main_t *sm = &sr_main;
1331  ip6_fib_t *rx_fib, *tx_fib;
1332  ip6_sr_policy_t *pt;
1333 
1334  rx_fib = ip6_fib_get (t->rx_fib_index);
1335  tx_fib = ip6_fib_get (t->tx_fib_index);
1336 
1337  if (t->name)
1338  vlib_cli_output (vm, "sr tunnel name: %s", (char *) t->name);
1339 
1340  vlib_cli_output (vm, "src %U dst %U first hop %U",
1341  format_ip6_address, &t->key.src,
1342  format_ip6_address, &t->key.dst,
1344  vlib_cli_output (vm, " rx-fib-id %d tx-fib-id %d",
1345  rx_fib->table_id, tx_fib->table_id);
1346  vlib_cli_output (vm, " sr: %U", format_ip6_sr_header, t->rewrite,
1347  0 /* print_hmac */ );
1348 
1349  if (t->policy_index != ~0)
1350  {
1351  pt = pool_elt_at_index (sm->policies, t->policy_index);
1352  vlib_cli_output (vm, "sr policy: %s", (char *) pt->name);
1353  }
1354  vlib_cli_output (vm, "-------");
1355 
1356  return;
1357 }
1358 
1359 /**
1360  * @brief CLI Parser for Display Segment Routing tunnel
1361  *
1362  * @param vm vlib_main_t *
1363  * @param input unformat_input_t *
1364  * @param cmd vlib_cli_command_t *
1365  *
1366  * @return error clib_error_t *
1367  */
1368 static clib_error_t *
1370  unformat_input_t * input, vlib_cli_command_t * cmd)
1371 {
1372  static ip6_sr_tunnel_t **tunnels;
1373  ip6_sr_tunnel_t *t;
1374  ip6_sr_main_t *sm = &sr_main;
1375  int i;
1376  uword *p = 0;
1377  u8 *name = 0;
1378 
1379  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1380  {
1381  if (unformat (input, "name %s", &name))
1382  {
1383  p = hash_get_mem (sm->tunnel_index_by_name, name);
1384  if (!p)
1385  vlib_cli_output (vm, "No SR tunnel with name: %s. Showing all.",
1386  name);
1387  }
1388  else
1389  break;
1390  }
1391 
1392  vec_reset_length (tunnels);
1393 
1394  if (!p) /* Either name parm not passed or no tunnel with that name found, show all */
1395  {
1396  /* *INDENT-OFF* */
1397  pool_foreach (t, sm->tunnels,
1398  ({
1399  vec_add1 (tunnels, t);
1400  }));
1401  /* *INDENT-ON* */
1402  }
1403  else /* Just show the one tunnel by name */
1404  vec_add1 (tunnels, &sm->tunnels[p[0]]);
1405 
1406  if (vec_len (tunnels) == 0)
1407  vlib_cli_output (vm, "No SR tunnels configured");
1408 
1409  for (i = 0; i < vec_len (tunnels); i++)
1410  {
1411  t = tunnels[i];
1412  ip6_sr_tunnel_display (vm, t);
1413  }
1414 
1415  return 0;
1416 }
1417 
1418 /* *INDENT-OFF* */
1420  .path = "show sr tunnel",
1421  .short_help = "show sr tunnel [name <sr-tunnel-name>]",
1422  .function = show_sr_tunnel_fn,
1423 };
1424 /* *INDENT-ON* */
1425 
1426 /**
1427  * @brief Add or Delete a Segment Routing policy
1428  *
1429  * @param a ip6_sr_add_del_policy_args_t *
1430  *
1431  * @return retval int
1432  */
1433 int
1435 {
1436  ip6_sr_main_t *sm = &sr_main;
1437  uword *p;
1438  ip6_sr_tunnel_t *t = 0;
1439  ip6_sr_policy_t *policy;
1440  u32 *tunnel_indices = 0;
1441  int i;
1442 
1443 
1444 
1445  if (a->is_del)
1446  {
1448  if (!p)
1449  return -6; /* policy name not found */
1450 
1451  policy = pool_elt_at_index (sm->policies, p[0]);
1452 
1453  vec_foreach_index (i, policy->tunnel_indices)
1454  {
1455  t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1456  t->policy_index = ~0;
1457  }
1459  pool_put (sm->policies, policy);
1460  return 0;
1461  }
1462 
1463 
1464  if (!vec_len (a->tunnel_names))
1465  return -3; /*tunnel name is required case */
1466 
1467  vec_reset_length (tunnel_indices);
1468  /* Check tunnel names, add tunnel_index to policy */
1469  for (i = 0; i < vec_len (a->tunnel_names); i++)
1470  {
1472  if (!p)
1473  return -4; /* tunnel name not found case */
1474 
1475  t = pool_elt_at_index (sm->tunnels, p[0]);
1476  /*
1477  No need to check t==0. -3 condition above ensures name
1478  */
1479  if (t->policy_index != ~0)
1480  return -5; /* tunnel name already associated with a policy */
1481 
1482  /* Add to tunnel indicies */
1483  vec_add1 (tunnel_indices, p[0]);
1484  }
1485 
1486  /* Add policy to ip6_sr_main_t */
1487  pool_get (sm->policies, policy);
1488  policy->name = a->name;
1489  policy->tunnel_indices = tunnel_indices;
1491  policy - sm->policies);
1492 
1493  /* Yes, this could be construed as overkill but the last thing you should do is set
1494  the policy_index on the tunnel after everything is set in ip6_sr_main_t.
1495  If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop.
1496  */
1497  for (i = 0; i < vec_len (policy->tunnel_indices); i++)
1498  {
1499  t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1500  t->policy_index = policy - sm->policies;
1501  }
1502 
1503  return 0;
1504 }
1505 
1506 /**
1507  * @brief CLI Parser for Add or Delete a Segment Routing policy
1508  *
1509  * @param vm vlib_main_t *
1510  * @param input unformat_input_t *
1511  * @param cmd vlib_cli_command_t *
1512  *
1513  * @return error clib_error_t *
1514  */
1515 static clib_error_t *
1517  unformat_input_t * input,
1518  vlib_cli_command_t * cmd)
1519 {
1520  int is_del = 0;
1521  u8 **tunnel_names = 0;
1522  u8 *tunnel_name = 0;
1523  u8 *name = 0;
1524  ip6_sr_add_del_policy_args_t _a, *a = &_a;
1525  int rv;
1526 
1527  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1528  {
1529  if (unformat (input, "del"))
1530  is_del = 1;
1531  else if (unformat (input, "name %s", &name))
1532  ;
1533  else if (unformat (input, "tunnel %s", &tunnel_name))
1534  {
1535  if (tunnel_name)
1536  {
1537  vec_add1 (tunnel_names, tunnel_name);
1538  tunnel_name = 0;
1539  }
1540  }
1541  else
1542  break;
1543  }
1544 
1545  if (!name)
1546  return clib_error_return (0, "name of SR policy required");
1547 
1548 
1549  memset (a, 0, sizeof (*a));
1550 
1551  a->is_del = is_del;
1552  a->name = name;
1553  a->tunnel_names = tunnel_names;
1554 
1555  rv = ip6_sr_add_del_policy (a);
1556 
1557  vec_free (tunnel_names);
1558 
1559  switch (rv)
1560  {
1561  case 0:
1562  break;
1563 
1564  case -3:
1565  return clib_error_return (0,
1566  "tunnel name to associate to SR policy is required");
1567 
1568  case -4:
1569  return clib_error_return (0, "tunnel name not found");
1570 
1571  case -5:
1572  return clib_error_return (0, "tunnel already associated with policy");
1573 
1574  case -6:
1575  return clib_error_return (0, "policy name %s not found", name);
1576 
1577  case -7:
1578  return clib_error_return (0, "TODO: deleting policy name %s", name);
1579 
1580  default:
1581  return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1582  rv);
1583 
1584  }
1585  return 0;
1586 }
1587 
1588 /* *INDENT-OFF* */
1590  .path = "sr policy",
1591  .short_help =
1592  "sr policy [del] name <policy-name> tunnel <sr-tunnel-name> [tunnel <sr-tunnel-name>]*",
1593  .function = sr_add_del_policy_command_fn,
1594 };
1595 /* *INDENT-ON* */
1596 
1597 /**
1598  * @brief CLI Parser for Displaying Segment Routing policy
1599  *
1600  * @param vm vlib_main_t *
1601  * @param input unformat_input_t *
1602  * @param cmd vlib_cli_command_t *
1603  *
1604  * @return error clib_error_t *
1605  */
1606 static clib_error_t *
1608  unformat_input_t * input, vlib_cli_command_t * cmd)
1609 {
1610  static ip6_sr_policy_t **policies;
1611  ip6_sr_policy_t *policy;
1612  ip6_sr_tunnel_t *t;
1613  ip6_sr_main_t *sm = &sr_main;
1614  int i, j;
1615  uword *p = 0;
1616  u8 *name = 0;
1617 
1618  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1619  {
1620  if (unformat (input, "name %s", &name))
1621  {
1622  p = hash_get_mem (sm->policy_index_by_policy_name, name);
1623  if (!p)
1624  vlib_cli_output (vm,
1625  "policy with name %s not found. Showing all.",
1626  name);
1627  }
1628  else
1629  break;
1630  }
1631 
1632  vec_reset_length (policies);
1633 
1634  if (!p) /* Either name parm not passed or no policy with that name found, show all */
1635  {
1636  /* *INDENT-OFF* */
1637  pool_foreach (policy, sm->policies,
1638  ({
1639  vec_add1 (policies, policy);
1640  }));
1641  /* *INDENT-ON* */
1642  }
1643  else /* Just show the one policy by name and a summary of tunnel names */
1644  {
1645  policy = pool_elt_at_index (sm->policies, p[0]);
1646  vec_add1 (policies, policy);
1647  }
1648 
1649  if (vec_len (policies) == 0)
1650  vlib_cli_output (vm, "No SR policies configured");
1651 
1652  for (i = 0; i < vec_len (policies); i++)
1653  {
1654  policy = policies[i];
1655 
1656  if (policy->name)
1657  vlib_cli_output (vm, "SR policy name: %s", (char *) policy->name);
1658  for (j = 0; j < vec_len (policy->tunnel_indices); j++)
1659  {
1660  t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[j]);
1661  ip6_sr_tunnel_display (vm, t);
1662  }
1663  }
1664 
1665  return 0;
1666 
1667 }
1668 
1669 /* *INDENT-OFF* */
1671  .path = "show sr policy",
1672  .short_help = "show sr policy [name <sr-policy-name>]",
1673  .function = show_sr_policy_fn,
1674 };
1675 /* *INDENT-ON* */
1676 
1677 /**
1678  * @brief Add or Delete a mapping of IP6 multicast address
1679  * to Segment Routing policy.
1680  *
1681  * @param a ip6_sr_add_del_multicastmap_args_t *
1682  *
1683  * @return retval int
1684  */
1685 int
1687 {
1688  uword *p;
1689  ip6_sr_tunnel_t *t;
1690  ip6_sr_main_t *sm = &sr_main;
1691  ip6_sr_policy_t *pt;
1692 
1693  if (a->is_del)
1694  {
1695  /* clean up the adjacency */
1696  p =
1698  a->multicast_address);
1699  }
1700  else
1701  {
1702  /* Get our policy by policy_name */
1704 
1705  }
1706  if (!p)
1707  return -1;
1708 
1709  pt = pool_elt_at_index (sm->policies, p[0]);
1710 
1711  /*
1712  Get the first tunnel associated with policy populate the fib adjacency.
1713  From there, since this tunnel will have it's policy_index != ~0 it will
1714  be the trigger in the dual_loop to pull up the policy and make a copy-rewrite
1715  for each tunnel in the policy
1716  */
1717 
1718  t = pool_elt_at_index (sm->tunnels, pt->tunnel_indices[0]);
1719 
1720  /*
1721  * Stick the tunnel index into the rewrite header.
1722  *
1723  * Unfortunately, inserting an SR header according to the various
1724  * RFC's requires parsing through the ip6 header, perhaps consing a
1725  * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1726  * normal reverse bcopy rewrite code.
1727  *
1728  * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1729  * at some point...
1730  */
1731  dpo_id_t dpo = DPO_INVALID;
1732 
1733  dpo_set (&dpo, sr_dpo_type, DPO_PROTO_IP6, t - sm->tunnels);
1734 
1735  /* Construct a FIB entry for multicast using the rx/tx fib from the first tunnel */
1736  fib_prefix_t pfx = {
1738  .fp_len = 128,
1739  .fp_addr = {
1740  .ip6 = *a->multicast_address,
1741  }
1742  };
1744  &pfx,
1745  FIB_SOURCE_SR,
1746  FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
1747  dpo_reset (&dpo);
1748 
1749  u8 *mcast_copy = 0;
1750  mcast_copy = vec_new (ip6_address_t, 1);
1751  memcpy (mcast_copy, a->multicast_address, sizeof (ip6_address_t));
1752 
1753  if (a->is_del)
1754  {
1756  vec_free (mcast_copy);
1757  return 0;
1758  }
1759  /* else */
1760 
1762  pt - sm->policies);
1763 
1764 
1765  return 0;
1766 }
1767 
1768 /**
1769  * @brief CLI Parser for Adding or Delete a mapping of IP6 multicast address
1770  * to Segment Routing policy.
1771  *
1772  * @param vm vlib_main_t *
1773  * @param input unformat_input_t *
1774  * @param cmd vlib_cli_command_t *
1775  *
1776  * @return error clib_error_t *
1777  */
1778 static clib_error_t *
1780  unformat_input_t * input,
1781  vlib_cli_command_t * cmd)
1782 {
1783  int is_del = 0;
1784  ip6_address_t multicast_address;
1785  u8 *policy_name = 0;
1786  int multicast_address_set = 0;
1788  int rv;
1789 
1790  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1791  {
1792  if (unformat (input, "del"))
1793  is_del = 1;
1794  else
1795  if (unformat
1796  (input, "address %U", unformat_ip6_address, &multicast_address))
1797  multicast_address_set = 1;
1798  else if (unformat (input, "sr-policy %s", &policy_name))
1799  ;
1800  else
1801  break;
1802  }
1803 
1804  if (!is_del && !policy_name)
1805  return clib_error_return (0, "name of sr policy required");
1806 
1807  if (!multicast_address_set)
1808  return clib_error_return (0, "multicast address required");
1809 
1810  memset (a, 0, sizeof (*a));
1811 
1812  a->is_del = is_del;
1813  a->multicast_address = &multicast_address;
1814  a->policy_name = policy_name;
1815 
1816 #if DPDK > 0 /*Cannot call replicate or configure multicast map yet without DPDK */
1817  rv = ip6_sr_add_del_multicastmap (a);
1818 #else
1819  return clib_error_return (0,
1820  "cannot use multicast replicate spray case without DPDK installed");
1821 #endif /* DPDK */
1822 
1823  switch (rv)
1824  {
1825  case 0:
1826  break;
1827  case -1:
1828  return clib_error_return (0, "no policy with name: %s", policy_name);
1829 
1830  case -2:
1831  return clib_error_return (0, "multicast map someting ");
1832 
1833  case -3:
1834  return clib_error_return (0,
1835  "tunnel name to associate to SR policy is required");
1836 
1837  case -7:
1838  return clib_error_return (0, "TODO: deleting policy name %s",
1839  policy_name);
1840 
1841  default:
1842  return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1843  rv);
1844 
1845  }
1846  return 0;
1847 
1848 }
1849 
1850 
1851 /* *INDENT-OFF* */
1853  .path = "sr multicast-map",
1854  .short_help =
1855  "sr multicast-map address <multicast-ip6-address> sr-policy <sr-policy-name> [del]",
1857 };
1858 /* *INDENT-ON* */
1859 
1860 /**
1861  * @brief CLI Parser for Displaying a mapping of IP6 multicast address
1862  * to Segment Routing policy.
1863  *
1864  * @param vm vlib_main_t *
1865  * @param input unformat_input_t *
1866  * @param cmd vlib_cli_command_t *
1867  *
1868  * @return error clib_error_t *
1869  */
1870 static clib_error_t *
1872  unformat_input_t * input, vlib_cli_command_t * cmd)
1873 {
1874  ip6_sr_main_t *sm = &sr_main;
1875  u8 *key = 0;
1876  u32 value;
1877  ip6_address_t multicast_address;
1878  ip6_sr_policy_t *pt;
1879 
1880  /* pull all entries from the hash table into vector for display */
1881 
1882  /* *INDENT-OFF* */
1884  ({
1885  if (!key)
1886  vlib_cli_output (vm, "no multicast maps configured");
1887  else
1888  {
1889  multicast_address = *((ip6_address_t *)key);
1890  pt = pool_elt_at_index (sm->policies, value);
1891  if (pt)
1892  {
1893  vlib_cli_output (vm, "address: %U policy: %s",
1894  format_ip6_address, &multicast_address,
1895  pt->name);
1896  }
1897  else
1898  vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d",
1899  format_ip6_address, &multicast_address,
1900  value);
1901 
1902  }
1903 
1904  }));
1905  /* *INDENT-ON* */
1906 
1907  return 0;
1908 }
1909 
1910 /* *INDENT-OFF* */
1912  .path = "show sr multicast-map",
1913  .short_help = "show sr multicast-map",
1914  .function = show_sr_multicast_map_fn,
1915 };
1916 /* *INDENT-ON* */
1917 
1918 
1919 #define foreach_sr_fix_dst_addr_next \
1920 _(DROP, "error-drop")
1921 
1922 /**
1923  * @brief Struct for valid next-nodes for SR fix destination address node
1924  */
1925 typedef enum
1926 {
1927 #define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
1929 #undef _
1932 
1933 /**
1934  * @brief Error strings for SR Fix Destination rewrite
1935  */
1936 static char *sr_fix_dst_error_strings[] = {
1937 #define sr_fix_dst_error(n,s) s,
1938 #include "sr_fix_dst_error.def"
1939 #undef sr_fix_dst_error
1940 };
1941 
1942 /**
1943  * @brief Struct for errors for SR Fix Destination rewrite
1944  */
1945 typedef enum
1946 {
1947 #define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
1948 #include "sr_fix_dst_error.def"
1949 #undef sr_fix_dst_error
1950  SR_FIX_DST_N_ERROR,
1952 
1953 /**
1954  * @brief Information for fix address trace
1955  */
1956 typedef struct
1957 {
1961  u8 sr[256];
1964 /**
1965  * @brief Formatter for fix address trace
1966  */
1967 u8 *
1968 format_sr_fix_addr_trace (u8 * s, va_list * args)
1969 {
1970  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1971  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1972  sr_fix_addr_trace_t *t = va_arg (*args, sr_fix_addr_trace_t *);
1973  vnet_hw_interface_t *hi = 0;
1974  ip_adjacency_t *adj;
1975  ip6_main_t *im = &ip6_main;
1976  ip_lookup_main_t *lm = &im->lookup_main;
1977  vnet_main_t *vnm = vnet_get_main ();
1978 
1979  if (t->adj_index != ~0)
1980  {
1981  adj = ip_get_adjacency (lm, t->adj_index);
1982  hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
1983  }
1984 
1985  s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
1986  (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
1987  ? "drop" : "output",
1989  if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
1990  {
1991  s =
1992  format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
1993  s =
1994  format (s, " output via %s",
1995  hi ? (char *) (hi->name) : "Invalid adj");
1996  }
1997  return s;
1998 }
1999 
2000 /**
2001  * @brief Fix SR destination address - dual-loop
2002  *
2003  * @node sr-fix-dst-addr
2004  * @param vm vlib_main_t *
2005  * @param node vlib_node_runtime_t *
2006  * @param from_frame vlib_frame_t *
2007  *
2008  * @return from_frame->n_vectors uword
2009  */
2010 static uword
2012  vlib_node_runtime_t * node, vlib_frame_t * from_frame)
2013 {
2014  u32 n_left_from, next_index, *from, *to_next;
2015  ip6_main_t *im = &ip6_main;
2016  ip_lookup_main_t *lm = &im->lookup_main;
2017 
2018  from = vlib_frame_vector_args (from_frame);
2019  n_left_from = from_frame->n_vectors;
2020 
2021  next_index = node->cached_next_index;
2022 
2023  while (n_left_from > 0)
2024  {
2025  u32 n_left_to_next;
2026 
2027  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2028 
2029 #if 0
2030  while (0 && n_left_from >= 4 && n_left_to_next >= 2)
2031  {
2032  u32 bi0, bi1;
2033  __attribute__ ((unused)) vlib_buffer_t *b0, *b1;
2034  u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
2035  u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
2036 
2037  /* Prefetch next iteration. */
2038  {
2039  vlib_buffer_t *p2, *p3;
2040 
2041  p2 = vlib_get_buffer (vm, from[2]);
2042  p3 = vlib_get_buffer (vm, from[3]);
2043 
2044  vlib_prefetch_buffer_header (p2, LOAD);
2045  vlib_prefetch_buffer_header (p3, LOAD);
2046  }
2047 
2048  bi0 = from[0];
2049  bi1 = from[1];
2050  to_next[0] = bi0;
2051  to_next[1] = bi1;
2052  from += 2;
2053  to_next += 2;
2054  n_left_to_next -= 2;
2055  n_left_from -= 2;
2056 
2057  b0 = vlib_get_buffer (vm, bi0);
2058  b1 = vlib_get_buffer (vm, bi1);
2059 
2060 
2061  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2062  to_next, n_left_to_next,
2063  bi0, bi1, next0, next1);
2064  }
2065 #endif
2066 
2067  while (n_left_from > 0 && n_left_to_next > 0)
2068  {
2069  u32 bi0;
2070  vlib_buffer_t *b0;
2071  ip6_header_t *ip0;
2072  ip_adjacency_t *adj0;
2073  ip6_sr_header_t *sr0;
2074  u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
2075  ip6_address_t *new_dst0;
2076  ethernet_header_t *eh0;
2077 
2078  bi0 = from[0];
2079  to_next[0] = bi0;
2080  from += 1;
2081  to_next += 1;
2082  n_left_from -= 1;
2083  n_left_to_next -= 1;
2084 
2085  b0 = vlib_get_buffer (vm, bi0);
2086 
2087  adj0 =
2088  ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2089  next0 = adj0->mcast_group_index;
2090 
2091  /* We should be pointing at an Ethernet header... */
2092  eh0 = vlib_buffer_get_current (b0);
2093  ip0 = (ip6_header_t *) (eh0 + 1);
2094  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2095 
2096  /* We'd better find an SR header... */
2098  {
2099  b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
2100  goto do_trace0;
2101  }
2102  else
2103  {
2104  /*
2105  * We get here from sr_rewrite or sr_local, with
2106  * sr->segments_left pointing at the (copy of the original) dst
2107  * address. Use it, then increment sr0->segments_left.
2108  */
2109 
2110  /* Out of segments? Turf the packet */
2111  if (PREDICT_FALSE (sr0->segments_left == 0))
2112  {
2113  b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
2114  goto do_trace0;
2115  }
2116 
2117  /*
2118  * Rewrite the packet with the original dst address
2119  * We assume that the last segment (in processing order) contains
2120  * the original dst address. The list is reversed, so sr0->segments
2121  * contains the original dst address.
2122  */
2123  new_dst0 = sr0->segments;
2124  ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2125  ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2126  }
2127 
2128  do_trace0:
2129 
2131  {
2132  sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
2133  b0, sizeof (*t));
2134  t->next_index = next0;
2135  t->adj_index = ~0;
2136 
2137  if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
2138  {
2139  t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2141  sizeof (t->src.as_u8));
2143  sizeof (t->dst.as_u8));
2144  clib_memcpy (t->sr, sr0, sizeof (t->sr));
2145  }
2146  }
2147 
2148  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2149  to_next, n_left_to_next,
2150  bi0, next0);
2151  }
2152 
2153  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2154  }
2155  return from_frame->n_vectors;
2156 }
2157 
2158 
2159 /* *INDENT-OFF* */
2161  .function = sr_fix_dst_addr,
2162  .name = "sr-fix-dst-addr",
2163  /* Takes a vector of packets. */
2164  .vector_size = sizeof (u32),
2165  .format_trace = format_sr_fix_addr_trace,
2166  .format_buffer = format_ip6_sr_header_with_length,
2167 
2168  .runtime_data_bytes = 0,
2169 
2170  .n_errors = SR_FIX_DST_N_ERROR,
2171  .error_strings = sr_fix_dst_error_strings,
2172 
2173  .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
2174  .next_nodes = {
2175 #define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
2177 #undef _
2178  },
2179 };
2180 
2182 /* *INDENT-ON* */
2183 
2184 static clib_error_t *
2186 {
2187  ip6_sr_main_t *sm = &sr_main;
2188  clib_error_t *error = 0;
2190 
2191  if ((error = vlib_call_init_function (vm, ip_main_init)))
2192  return error;
2193 
2194  if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
2195  return error;
2196 
2197  sm->vlib_main = vm;
2198  sm->vnet_main = vnet_get_main ();
2199 
2200  vec_validate (sm->hmac_keys, 0);
2201  sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
2202 
2203  sm->tunnel_index_by_key =
2204  hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
2205 
2206  sm->tunnel_index_by_name = hash_create_string (0, sizeof (uword));
2207 
2209 
2211  hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
2212 
2214 
2216 
2217  ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
2218  ASSERT (ip6_lookup_node);
2219 
2220  ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
2221  ASSERT (ip6_rewrite_node);
2222 
2223 #if DPDK > 0 /* Cannot run replicate without DPDK */
2224  /* Add a disposition to sr_replicate for the sr multicast replicate node */
2226  vlib_node_add_next (vm, ip6_lookup_node->index, sr_replicate_node.index);
2227 #endif /* DPDK */
2228 
2229  /* Add a disposition to ip6_rewrite for the sr dst address hack node */
2231  vlib_node_add_next (vm, ip6_rewrite_node->index,
2232  sr_fix_dst_addr_node.index);
2233 
2234  OpenSSL_add_all_digests ();
2235 
2236  sm->md = (void *) EVP_get_digestbyname ("sha1");
2237  sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
2238 
2240 
2241  return error;
2242 }
2243 
2245 
2246 /**
2247  * @brief Definition of next-nodes for SR local
2248  */
2249 #define foreach_sr_local_next \
2250  _ (ERROR, "error-drop") \
2251  _ (IP6_LOOKUP, "ip6-lookup")
2252 
2253 /**
2254  * @brief Struct for definition of next-nodes for SR local
2255  */
2256 typedef enum
2257 {
2258 #define _(s,n) SR_LOCAL_NEXT_##s,
2260 #undef _
2262 } sr_local_next_t;
2263 
2264 /**
2265  * @brief Struct for packet trace of SR local
2266  */
2267 typedef struct
2268 {
2273  u8 sr[256];
2275 
2276 /**
2277  * @brief Definition of SR local error-strings
2278  */
2279 static char *sr_local_error_strings[] = {
2280 #define sr_error(n,s) s,
2281 #include "sr_error.def"
2282 #undef sr_error
2283 };
2284 
2285 /**
2286  * @brief Struct for definition of SR local error-strings
2287  */
2288 typedef enum
2289 {
2290 #define sr_error(n,s) SR_LOCAL_ERROR_##n,
2291 #include "sr_error.def"
2292 #undef sr_error
2293  SR_LOCAL_N_ERROR,
2295 
2296 /**
2297  * @brief Format SR local trace
2298  *
2299  * @param s u8 *
2300  * @param args va_list *
2301  *
2302  * @return s u8 *
2303  */
2304 u8 *
2305 format_sr_local_trace (u8 * s, va_list * args)
2306 {
2307  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2308  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2309  sr_local_trace_t *t = va_arg (*args, sr_local_trace_t *);
2310 
2311  s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
2312  format_ip6_address, &t->src,
2313  format_ip6_address, &t->dst, t->length, t->next_index);
2314  if (t->sr_valid)
2315  s =
2316  format (s, "\n %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
2317  else
2318  s = format (s, "\n popped SR header");
2319 
2320  return s;
2321 }
2322 
2323 
2324 /* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
2325 /**
2326  * @brief Validate the SR HMAC
2327  *
2328  * @param sm ip6_sr_main_t *
2329  * @param ip ip6_header_t *
2330  * @param sr ip6_sr_header_t *
2331  *
2332  * @return retval int
2333  */
2334 static int
2336 {
2337  u32 key_index;
2338  static u8 *keybuf;
2339  u8 *copy_target;
2340  int first_segment;
2341  ip6_address_t *addrp;
2342  int i;
2343  ip6_sr_hmac_key_t *hmac_key;
2344  static u8 *signature;
2345  u32 sig_len;
2346 
2347  key_index = sr->hmac_key;
2348 
2349  /* No signature? Pass... */
2350  if (key_index == 0)
2351  return 0;
2352 
2353  /* We don't know about this key? Fail... */
2354  if (key_index >= vec_len (sm->hmac_keys))
2355  return 1;
2356 
2357  vec_validate (signature, SHA256_DIGEST_LENGTH - 1);
2358 
2359  hmac_key = sm->hmac_keys + key_index;
2360 
2361  vec_reset_length (keybuf);
2362 
2363  /* pkt ip6 src address */
2364  vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2365  clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
2366 
2367  /* last segment */
2368  vec_add2 (keybuf, copy_target, 1);
2369  copy_target[0] = sr->first_segment;
2370 
2371  /* octet w/ bit 0 = "clean" flag */
2372  vec_add2 (keybuf, copy_target, 1);
2373  copy_target[0]
2374  = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
2375  ? 0x80 : 0;
2376 
2377  /* hmac key id */
2378  vec_add2 (keybuf, copy_target, 1);
2379  copy_target[0] = sr->hmac_key;
2380 
2381  first_segment = sr->first_segment;
2382 
2383  addrp = sr->segments;
2384 
2385  /* segments */
2386  for (i = 0; i <= first_segment; i++)
2387  {
2388  vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2389  clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
2390  addrp++;
2391  }
2392 
2393  if (sm->is_debug)
2394  clib_warning ("verify key index %d keybuf: %U", key_index,
2395  format_hex_bytes, keybuf, vec_len (keybuf));
2396 
2397  /* shared secret */
2398 
2399  /* SHA1 is shorter than SHA-256 */
2400  memset (signature, 0, vec_len (signature));
2401 
2402  HMAC_CTX_init (sm->hmac_ctx);
2403  if (!HMAC_Init (sm->hmac_ctx, hmac_key->shared_secret,
2404  vec_len (hmac_key->shared_secret), sm->md))
2405  clib_warning ("barf1");
2406  if (!HMAC_Update (sm->hmac_ctx, keybuf, vec_len (keybuf)))
2407  clib_warning ("barf2");
2408  if (!HMAC_Final (sm->hmac_ctx, signature, &sig_len))
2409  clib_warning ("barf3");
2410  HMAC_CTX_cleanup (sm->hmac_ctx);
2411 
2412  if (sm->is_debug)
2413  clib_warning ("computed signature len %d, value %U", sig_len,
2414  format_hex_bytes, signature, vec_len (signature));
2415 
2416  /* Point at the SHA signature in the packet */
2417  addrp++;
2418  if (sm->is_debug)
2419  clib_warning ("read signature %U", format_hex_bytes, addrp,
2420  SHA256_DIGEST_LENGTH);
2421 
2422  return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
2423 }
2424 
2425 /**
2426  * @brief SR local node
2427  * @node sr-local
2428  *
2429  * @param vm vlib_main_t *
2430  * @param node vlib_node_runtime_t *
2431  * @param from_frame vlib_frame_t *
2432  *
2433  * @return from_frame->n_vectors uword
2434  */
2435 static uword
2437  vlib_node_runtime_t * node, vlib_frame_t * from_frame)
2438 {
2439  u32 n_left_from, next_index, *from, *to_next;
2440  ip6_sr_main_t *sm = &sr_main;
2441  u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
2443  sr_local_cb = sm->sr_local_cb;
2444 
2445  from = vlib_frame_vector_args (from_frame);
2446  n_left_from = from_frame->n_vectors;
2447 
2448  next_index = node->cached_next_index;
2449 
2450  while (n_left_from > 0)
2451  {
2452  u32 n_left_to_next;
2453 
2454  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2455 
2456  while (n_left_from >= 4 && n_left_to_next >= 2)
2457  {
2458  u32 bi0, bi1;
2459  vlib_buffer_t *b0, *b1;
2460  ip6_header_t *ip0, *ip1;
2461  ip6_sr_header_t *sr0, *sr1;
2462  ip6_address_t *new_dst0, *new_dst1;
2463  u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2464  u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
2465  /* Prefetch next iteration. */
2466  {
2467  vlib_buffer_t *p2, *p3;
2468 
2469  p2 = vlib_get_buffer (vm, from[2]);
2470  p3 = vlib_get_buffer (vm, from[3]);
2471 
2472  vlib_prefetch_buffer_header (p2, LOAD);
2473  vlib_prefetch_buffer_header (p3, LOAD);
2474 
2475  CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2476  CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2477  }
2478 
2479  bi0 = from[0];
2480  bi1 = from[1];
2481  to_next[0] = bi0;
2482  to_next[1] = bi1;
2483  from += 2;
2484  to_next += 2;
2485  n_left_to_next -= 2;
2486  n_left_from -= 2;
2487 
2488 
2489  b0 = vlib_get_buffer (vm, bi0);
2490  ip0 = vlib_buffer_get_current (b0);
2491  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2492 
2494  {
2495  next0 = SR_LOCAL_NEXT_ERROR;
2496  b0->error =
2497  node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2498  goto do_trace0;
2499  }
2500 
2501  /* Out of segments? Turf the packet */
2502  if (PREDICT_FALSE (sr0->segments_left == 0))
2503  {
2504  next0 = SR_LOCAL_NEXT_ERROR;
2505  b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2506  goto do_trace0;
2507  }
2508 
2509  if (PREDICT_FALSE (sm->validate_hmac))
2510  {
2511  if (sr_validate_hmac (sm, ip0, sr0))
2512  {
2513  next0 = SR_LOCAL_NEXT_ERROR;
2514  b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2515  goto do_trace0;
2516  }
2517  }
2518 
2519  next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
2520 
2521  /*
2522  * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2523  */
2524  if (PREDICT_FALSE (next0 & 0x80000000))
2525  {
2526  next0 ^= 0xFFFFFFFF;
2527  if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2528  b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2529  }
2530  else
2531  {
2532  u32 segment_index0;
2533 
2534  segment_index0 = sr0->segments_left - 1;
2535 
2536  /* Rewrite the packet */
2537  new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2538  ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2539  ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2540 
2541  if (PREDICT_TRUE (sr0->segments_left > 0))
2542  sr0->segments_left -= 1;
2543  }
2544 
2545  /* End of the path. Clean up the SR header, or not */
2546  if (PREDICT_FALSE
2547  (sr0->segments_left == 0 &&
2548  (sr0->flags &
2549  clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2550  {
2551  u64 *copy_dst0, *copy_src0;
2552  u16 new_l0;
2553  /*
2554  * Copy the ip6 header right by the (real) length of the
2555  * sr header. Here's another place which assumes that
2556  * the sr header is the only extention header.
2557  */
2558 
2559  ip0->protocol = sr0->protocol;
2560  vlib_buffer_advance (b0, (sr0->length + 1) * 8);
2561 
2562  new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2563  (sr0->length + 1) * 8;
2564  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2565 
2566  copy_src0 = (u64 *) ip0;
2567  copy_dst0 = copy_src0 + (sr0->length + 1);
2568 
2569  copy_dst0[4] = copy_src0[4];
2570  copy_dst0[3] = copy_src0[3];
2571  copy_dst0[2] = copy_src0[2];
2572  copy_dst0[1] = copy_src0[1];
2573  copy_dst0[0] = copy_src0[0];
2574 
2575  sr0 = 0;
2576  }
2577 
2578  do_trace0:
2580  {
2581  sr_local_trace_t *tr = vlib_add_trace (vm, node,
2582  b0, sizeof (*tr));
2583  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2584  sizeof (tr->src.as_u8));
2585  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2586  sizeof (tr->dst.as_u8));
2587  tr->length = vlib_buffer_length_in_chain (vm, b0);
2588  tr->next_index = next0;
2589  tr->sr_valid = sr0 != 0;
2590  if (tr->sr_valid)
2591  clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2592  }
2593 
2594  b1 = vlib_get_buffer (vm, bi1);
2595  ip1 = vlib_buffer_get_current (b1);
2596  sr1 = (ip6_sr_header_t *) (ip1 + 1);
2597 
2599  {
2600  next1 = SR_LOCAL_NEXT_ERROR;
2601  b1->error =
2602  node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2603  goto do_trace1;
2604  }
2605 
2606  /* Out of segments? Turf the packet */
2607  if (PREDICT_FALSE (sr1->segments_left == 0))
2608  {
2609  next1 = SR_LOCAL_NEXT_ERROR;
2610  b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2611  goto do_trace1;
2612  }
2613 
2614  if (PREDICT_FALSE (sm->validate_hmac))
2615  {
2616  if (sr_validate_hmac (sm, ip1, sr1))
2617  {
2618  next1 = SR_LOCAL_NEXT_ERROR;
2619  b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2620  goto do_trace1;
2621  }
2622  }
2623 
2624  next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) : next1;
2625 
2626  /*
2627  * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2628  */
2629  if (PREDICT_FALSE (next1 & 0x80000000))
2630  {
2631  next1 ^= 0xFFFFFFFF;
2632  if (PREDICT_FALSE (next1 == SR_LOCAL_NEXT_ERROR))
2633  b1->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2634  }
2635  else
2636  {
2637  u32 segment_index1;
2638 
2639  segment_index1 = sr1->segments_left - 1;
2640 
2641  /* Rewrite the packet */
2642  new_dst1 = (ip6_address_t *) (sr1->segments + segment_index1);
2643  ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
2644  ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
2645 
2646  if (PREDICT_TRUE (sr1->segments_left > 0))
2647  sr1->segments_left -= 1;
2648  }
2649 
2650  /* End of the path. Clean up the SR header, or not */
2651  if (PREDICT_FALSE
2652  (sr1->segments_left == 0 &&
2653  (sr1->flags &
2654  clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2655  {
2656  u64 *copy_dst1, *copy_src1;
2657  u16 new_l1;
2658  /*
2659  * Copy the ip6 header right by the (real) length of the
2660  * sr header. Here's another place which assumes that
2661  * the sr header is the only extention header.
2662  */
2663 
2664  ip1->protocol = sr1->protocol;
2665  vlib_buffer_advance (b1, (sr1->length + 1) * 8);
2666 
2667  new_l1 = clib_net_to_host_u16 (ip1->payload_length) -
2668  (sr1->length + 1) * 8;
2669  ip1->payload_length = clib_host_to_net_u16 (new_l1);
2670 
2671  copy_src1 = (u64 *) ip1;
2672  copy_dst1 = copy_src1 + (sr1->length + 1);
2673 
2674  copy_dst1[4] = copy_src1[4];
2675  copy_dst1[3] = copy_src1[3];
2676  copy_dst1[2] = copy_src1[2];
2677  copy_dst1[1] = copy_src1[1];
2678  copy_dst1[0] = copy_src1[0];
2679 
2680  sr1 = 0;
2681  }
2682 
2683  do_trace1:
2685  {
2686  sr_local_trace_t *tr = vlib_add_trace (vm, node,
2687  b1, sizeof (*tr));
2688  clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2689  sizeof (tr->src.as_u8));
2690  clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2691  sizeof (tr->dst.as_u8));
2692  tr->length = vlib_buffer_length_in_chain (vm, b1);
2693  tr->next_index = next1;
2694  tr->sr_valid = sr1 != 0;
2695  if (tr->sr_valid)
2696  clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
2697  }
2698 
2699  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2700  to_next, n_left_to_next,
2701  bi0, bi1, next0, next1);
2702  }
2703 
2704  while (n_left_from > 0 && n_left_to_next > 0)
2705  {
2706  u32 bi0;
2707  vlib_buffer_t *b0;
2708  ip6_header_t *ip0 = 0;
2709  ip6_sr_header_t *sr0;
2710  ip6_address_t *new_dst0;
2711  u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2712 
2713  bi0 = from[0];
2714  to_next[0] = bi0;
2715  from += 1;
2716  to_next += 1;
2717  n_left_from -= 1;
2718  n_left_to_next -= 1;
2719 
2720  b0 = vlib_get_buffer (vm, bi0);
2721  ip0 = vlib_buffer_get_current (b0);
2722  sr0 = (ip6_sr_header_t *) (ip0 + 1);
2723 
2725  {
2726  next0 = SR_LOCAL_NEXT_ERROR;
2727  b0->error =
2728  node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2729  goto do_trace;
2730  }
2731 
2732  /* Out of segments? Turf the packet */
2733  if (PREDICT_FALSE (sr0->segments_left == 0))
2734  {
2735  next0 = SR_LOCAL_NEXT_ERROR;
2736  b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2737  goto do_trace;
2738  }
2739 
2740  if (PREDICT_FALSE (sm->validate_hmac))
2741  {
2742  if (sr_validate_hmac (sm, ip0, sr0))
2743  {
2744  next0 = SR_LOCAL_NEXT_ERROR;
2745  b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2746  goto do_trace;
2747  }
2748  }
2749 
2750  next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
2751 
2752  /*
2753  * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2754  */
2755  if (PREDICT_FALSE (next0 & 0x80000000))
2756  {
2757  next0 ^= 0xFFFFFFFF;
2758  if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2759  b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2760  }
2761  else
2762  {
2763  u32 segment_index0;
2764 
2765  segment_index0 = sr0->segments_left - 1;
2766 
2767  /* Rewrite the packet */
2768  new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2769  ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2770  ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2771 
2772  if (PREDICT_TRUE (sr0->segments_left > 0))
2773  sr0->segments_left -= 1;
2774  }
2775 
2776  /* End of the path. Clean up the SR header, or not */
2777  if (PREDICT_FALSE
2778  (sr0->segments_left == 0 &&
2779  (sr0->flags &
2780  clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2781  {
2782  u64 *copy_dst0, *copy_src0;
2783  u16 new_l0;
2784  /*
2785  * Copy the ip6 header right by the (real) length of the
2786  * sr header. Here's another place which assumes that
2787  * the sr header is the only extention header.
2788  */
2789 
2790  ip0->protocol = sr0->protocol;
2791  vlib_buffer_advance (b0, (sr0->length + 1) * 8);
2792 
2793  new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2794  (sr0->length + 1) * 8;
2795  ip0->payload_length = clib_host_to_net_u16 (new_l0);
2796 
2797  copy_src0 = (u64 *) ip0;
2798  copy_dst0 = copy_src0 + (sr0->length + 1);
2799 
2800  copy_dst0[4] = copy_src0[4];
2801  copy_dst0[3] = copy_src0[3];
2802  copy_dst0[2] = copy_src0[2];
2803  copy_dst0[1] = copy_src0[1];
2804  copy_dst0[0] = copy_src0[0];
2805 
2806  sr0 = 0;
2807  }
2808 
2809  do_trace:
2811  {
2812  sr_local_trace_t *tr = vlib_add_trace (vm, node,
2813  b0, sizeof (*tr));
2814  clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2815  sizeof (tr->src.as_u8));
2816  clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2817  sizeof (tr->dst.as_u8));
2818  tr->length = vlib_buffer_length_in_chain (vm, b0);
2819  tr->next_index = next0;
2820  tr->sr_valid = sr0 != 0;
2821  if (tr->sr_valid)
2822  clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2823  }
2824 
2825  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2826  to_next, n_left_to_next,
2827  bi0, next0);
2828  }
2829 
2830  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2831  }
2833  SR_LOCAL_ERROR_PKTS_PROCESSED,
2834  from_frame->n_vectors);
2835  return from_frame->n_vectors;
2836 }
2837 
2838 /* *INDENT-OFF* */
2839 VLIB_REGISTER_NODE (sr_local_node, static) = {
2840  .function = sr_local,
2841  .name = "sr-local",
2842  /* Takes a vector of packets. */
2843  .vector_size = sizeof (u32),
2844  .format_trace = format_sr_local_trace,
2845 
2846  .runtime_data_bytes = 0,
2847 
2848  .n_errors = SR_LOCAL_N_ERROR,
2849  .error_strings = sr_local_error_strings,
2850 
2851  .n_next_nodes = SR_LOCAL_N_NEXT,
2852  .next_nodes = {
2853 #define _(s,n) [SR_LOCAL_NEXT_##s] = n,
2855 #undef _
2856  },
2857 };
2858 
2860 /* *INDENT-ON* */
2861 
2862 ip6_sr_main_t *
2864 {
2866  ASSERT (sr_local_node.index);
2867  return &sr_main;
2868 }
2869 
2870 /**
2871  * @brief CLI parser for SR fix destination rewrite node
2872  *
2873  * @param vm vlib_main_t *
2874  * @param input unformat_input_t *
2875  * @param cmd vlib_cli_command_t *
2876  *
2877  * @return error clib_error_t *
2878  */
2879 static clib_error_t *
2881  unformat_input_t * input, vlib_cli_command_t * cmd)
2882 {
2883  fib_prefix_t pfx = {
2885  .fp_len = 128,
2886  };
2887  u32 fib_index = 0;
2888  u32 fib_id = 0;
2889  u32 adj_index;
2890  ip_adjacency_t *adj;
2892  u32 sw_if_index;
2893  ip6_sr_main_t *sm = &sr_main;
2894  vnet_main_t *vnm = vnet_get_main ();
2895  fib_node_index_t fei;
2896 
2897  if (!unformat (input, "%U", unformat_ip6_address, &pfx.fp_addr.ip6))
2898  return clib_error_return (0, "ip6 address missing in '%U'",
2899  format_unformat_error, input);
2900 
2901  if (unformat (input, "rx-table-id %d", &fib_id))
2902  {
2903  fib_index = fib_table_id_find_fib_index (FIB_PROTOCOL_IP6, fib_id);
2904  if (fib_index == ~0)
2905  return clib_error_return (0, "fib-id %d not found", fib_id);
2906  }
2907 
2908  fei = fib_table_lookup_exact_match (fib_index, &pfx);
2909 
2910  if (FIB_NODE_INDEX_INVALID == fei)
2911  return clib_error_return (0, "no match for %U",
2912  format_ip6_address, &pfx.fp_addr.ip6);
2913 
2914  adj_index = fib_entry_get_adj_for_source (fei, FIB_SOURCE_SR);
2915 
2916  if (ADJ_INDEX_INVALID == adj_index)
2917  return clib_error_return (0, "%U not SR sourced",
2918  format_ip6_address, &pfx.fp_addr.ip6);
2919 
2920  adj = adj_get (adj_index);
2921 
2923  return clib_error_return (0, "%U unresolved (not a rewrite adj)",
2924  format_ip6_address, &pfx.fp_addr.ip6);
2925 
2926  adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
2927 
2928  sw_if_index = adj->rewrite_header.sw_if_index;
2929  hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2930  adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
2931 
2932  /* $$$$$ hack... steal the mcast group index */
2933  adj->mcast_group_index =
2935  hi->output_node_index);
2936 
2937  return 0;
2938 }
2939 
2940 /* *INDENT-OFF* */
2942  .path = "set ip6 sr rewrite",
2943  .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
2944  .function = set_ip6_sr_rewrite_fn,
2945 };
2946 /* *INDENT-ON* */
2947 
2948 /**
2949  * @brief Register a callback routine to set next0 in sr_local
2950  *
2951  * @param cb void *
2952  */
2953 void
2955 {
2956  ip6_sr_main_t *sm = &sr_main;
2957 
2958  sm->sr_local_cb = cb;
2959 }
2960 
2961 /**
2962  * @brief Test routine for validation of HMAC
2963  */
2964 static clib_error_t *
2966  unformat_input_t * input, vlib_cli_command_t * cmd)
2967 {
2968  ip6_sr_main_t *sm = &sr_main;
2969 
2970  if (unformat (input, "validate on"))
2971  sm->validate_hmac = 1;
2972  else if (unformat (input, "chunk-offset off"))
2973  sm->validate_hmac = 0;
2974  else
2975  return clib_error_return (0, "expected validate on|off in '%U'",
2976  format_unformat_error, input);
2977 
2978  vlib_cli_output (vm, "hmac signature validation %s",
2979  sm->validate_hmac ? "on" : "off");
2980  return 0;
2981 }
2982 
2983 /* *INDENT-OFF* */
2985  .path = "test sr hmac",
2986  .short_help = "test sr hmac validate [on|off]",
2987  .function = test_sr_hmac_validate_fn,
2988 };
2989 /* *INDENT-ON* */
2990 
2991 /**
2992  * @brief Add or Delete HMAC key
2993  *
2994  * @param sm ip6_sr_main_t *
2995  * @param key_id u32
2996  * @param shared_secret u8 *
2997  * @param is_del u8
2998  *
2999  * @return retval i32
3000  */
3001 // $$$ fixme shouldn't return i32
3002 i32
3003 sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
3004  u8 is_del)
3005 {
3006  u32 index;
3007  ip6_sr_hmac_key_t *key;
3008 
3009  if (is_del == 0)
3010  {
3011  /* Specific key in use? Fail. */
3012  if (key_id && vec_len (sm->hmac_keys) > key_id
3013  && sm->hmac_keys[key_id].shared_secret)
3014  return -2;
3015 
3016  index = key_id;
3017  key = find_or_add_shared_secret (sm, shared_secret, &index);
3018  ASSERT (index == key_id);
3019  return 0;
3020  }
3021 
3022  /* delete */
3023 
3024  if (key_id) /* delete by key ID */
3025  {
3026  if (vec_len (sm->hmac_keys) <= key_id)
3027  return -3;
3028 
3029  key = sm->hmac_keys + key_id;
3030 
3032  vec_free (key->shared_secret);
3033  return 0;
3034  }
3035 
3036  index = 0;
3037  key = find_or_add_shared_secret (sm, shared_secret, &index);
3039  vec_free (key->shared_secret);
3040  return 0;
3041 }
3042 
3043 
3044 static clib_error_t *
3046  unformat_input_t * input, vlib_cli_command_t * cmd)
3047 {
3048  ip6_sr_main_t *sm = &sr_main;
3049  u8 is_del = 0;
3050  u32 key_id = 0;
3051  u8 key_id_set = 0;
3052  u8 *shared_secret = 0;
3053  i32 rv;
3054 
3055  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3056  {
3057  if (unformat (input, "del"))
3058  is_del = 1;
3059  else if (unformat (input, "id %d", &key_id))
3060  key_id_set = 1;
3061  else if (unformat (input, "key %s", &shared_secret))
3062  {
3063  /* Do not include the trailing NULL byte. Guaranteed interop issue */
3064  _vec_len (shared_secret) -= 1;
3065  }
3066  else
3067  break;
3068  }
3069 
3070  if (is_del == 0 && shared_secret == 0)
3071  return clib_error_return (0, "shared secret must be set to add a key");
3072 
3073  if (shared_secret == 0 && key_id_set == 0)
3074  return clib_error_return (0, "shared secret and key id both unset");
3075 
3076  rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
3077 
3078  vec_free (shared_secret);
3079 
3080  switch (rv)
3081  {
3082  case 0:
3083  break;
3084 
3085  default:
3086  return clib_error_return (0, "sr_hmac_add_del_key returned %d", rv);
3087  }
3088 
3089  return 0;
3090 }
3091 
3092 /* *INDENT-OFF* */
3094  .path = "sr hmac",
3095  .short_help = "sr hmac [del] id <nn> key <str>",
3096  .function = sr_hmac_add_del_key_fn,
3097 };
3098 /* *INDENT-ON* */
3099 
3100 /**
3101  * @brief CLI parser for show HMAC key shared secrets
3102  *
3103  * @param vm vlib_main_t *
3104  * @param input unformat_input_t *
3105  * @param cmd vlib_cli_command_t *
3106  *
3107  * @return error clib_error_t *
3108  */
3109 static clib_error_t *
3111  unformat_input_t * input, vlib_cli_command_t * cmd)
3112 {
3113  ip6_sr_main_t *sm = &sr_main;
3114  int i;
3115 
3116  for (i = 1; i < vec_len (sm->hmac_keys); i++)
3117  {
3118  if (sm->hmac_keys[i].shared_secret)
3119  vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
3120  }
3121 
3122  return 0;
3123 }
3124 
3125 /* *INDENT-OFF* */
3127  .path = "show sr hmac",
3128  .short_help = "show sr hmac",
3129  .function = show_sr_hmac_fn,
3130 };
3131 /* *INDENT-ON* */
3132 
3133 /**
3134  * @brief Test for SR debug flag
3135  *
3136  * @param vm vlib_main_t *
3137  * @param input unformat_input_t *
3138  * @param cmd vlib_cli_command_t *
3139  *
3140  * @return error clib_error_t *
3141  */
3142 static clib_error_t *
3144  unformat_input_t * input, vlib_cli_command_t * cmd)
3145 {
3146  ip6_sr_main_t *sm = &sr_main;
3147 
3148  if (unformat (input, "on"))
3149  sm->is_debug = 1;
3150  else if (unformat (input, "off"))
3151  sm->is_debug = 0;
3152  else
3153  return clib_error_return (0, "expected on|off in '%U'",
3154  format_unformat_error, input);
3155 
3156  vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
3157 
3158  return 0;
3159 }
3160 
3161 /* *INDENT-OFF* */
3163  .path = "test sr debug",
3164  .short_help = "test sr debug on|off",
3165  .function = test_sr_debug_fn,
3166 };
3167 /* *INDENT-ON* */
3168 
3169 /*
3170  * fd.io coding-style-patch-verification: ON
3171  *
3172  * Local Variables:
3173  * eval: (c-set-style "gnu")
3174  * End:
3175  */
static int ip6_delete_route_no_next_hop(ip6_address_t *dst_address_arg, u32 dst_address_length, u32 rx_table_id)
Definition: sr.c:737
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
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:457
u32 fib_table_id_find_fib_index(fib_protocol_t proto, u32 table_id)
Definition: lookup.c:316
fib_protocol_t fp_proto
protocol type
Definition: fib_types.h:158
HMAC_CTX * hmac_ctx
Openssl var.
Definition: sr.h:223
ip6_sr_main_t sr_main
Definition: sr.c:30
dpo_lock_fn_t dv_lock
A reference counting lock function.
Definition: dpo.h:318
Segment Route tunnel key.
Definition: sr.h:40
u8 * format_sr_dpo(u8 *s, va_list *args)
Definition: sr.c:1117
vmrglw vmrglh hi
static vlib_cli_command_t test_sr_debug
(constructor) VLIB_CLI_COMMAND (test_sr_debug)
Definition: sr.c:3162
#define vec_foreach_index(var, v)
Iterate over vector indices.
sr_fix_dst_error_t
Struct for errors for SR Fix Destination rewrite.
Definition: sr.c:1945
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
u8 sr[256]
Definition: sr.c:1961
Args for creating a policy.
Definition: sr.h:130
#define CLIB_UNUSED(x)
Definition: clib.h:79
A virtual function table regisitered for a DPO type.
Definition: dpo.h:313
static vlib_cli_command_t show_sr_multicast_map_command
(constructor) VLIB_CLI_COMMAND (show_sr_multicast_map_command)
Definition: sr.c:1911
static char * sr_rewrite_error_strings[]
Error strings for SR rewrite.
Definition: sr.c:302
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
uword * tunnel_index_by_key
find an sr "tunnel" by its outer-IP src/dst
Definition: sr.h:188
#define IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
Flag bits.
Definition: sr_packet.h:211
fib_node_index_t fib_table_lookup_exact_match(u32 fib_index, const fib_prefix_t *prefix)
Perfom an exact match in the non-forwarding table.
Definition: fib_table.c:95
a
Definition: bitmap.h:516
void ip6_register_protocol(u32 protocol, u32 node_index)
Definition: ip6_forward.c:1477
u32 tx_fib_index
TX Fib index.
Definition: sr.h:66
static ip6_fib_t * ip6_fib_get(fib_node_index_t index)
Definition: ip6_fib.h:108
format_function_t format_ip6_address
Definition: format.h:94
u32 policy_index
Indicates that this tunnel is part of a policy comprising of multiple tunnels.
Definition: sr.h:73
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define IP6_SR_HEADER_FLAG_PROTECTED
Flag bits.
Definition: sr_packet.h:203
ip6_address_t dst
Definition: sr.c:2271
u32 dst_mask_width
Mask width for FIB entry.
Definition: sr.h:58
ip6_address_t * multicast_address
multicast IP6 address
Definition: sr.h:169
#define PREDICT_TRUE(x)
Definition: clib.h:98
u8 as_u8[16]
Definition: ip6_packet.h:47
u64 as_u64[2]
Definition: ip6_packet.h:50
u8 * format_sr_rewrite_trace(u8 *s, va_list *args)
Format function for SR rewrite trace.
Definition: sr.c:324
static clib_error_t * test_sr_hmac_validate_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Test routine for validation of HMAC.
Definition: sr.c:2965
u8 next_index
Definition: sr.c:2269
ip6_address_t src
Definition: sr.c:1958
u8 segments_left
Next segment in the segment list.
Definition: sr_packet.h:192
void ip6_sr_tunnel_display(vlib_main_t *vm, ip6_sr_tunnel_t *t)
Display Segment Routing tunnel.
Definition: sr.c:1328
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
#define NULL
Definition: clib.h:55
u32 index
Definition: node.h:237
u8 * name
Pptional tunnel name.
Definition: sr.h:55
IP unicast adjacency.
Definition: lookup.h:174
static const char *const sr_ip6_nodes[]
Definition: sr.c:1131
int ip6_sr_add_del_policy(ip6_sr_add_del_policy_args_t *a)
Add or Delete a Segment Routing policy.
Definition: sr.c:1434
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
vlib_node_registration_t ip6_rewrite_node
(constructor) VLIB_REGISTER_NODE (ip6_rewrite_node)
Definition: ip6_forward.c:2188
struct _vlib_node_registration vlib_node_registration_t
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:521
static vlib_cli_command_t show_sr_tunnel_command
(constructor) VLIB_CLI_COMMAND (show_sr_tunnel_command)
Definition: sr.c:1419
ip6_address_t * tags
"Tag" list, aka segments inserted at the end of the list, past last_seg
Definition: sr.h:111
#define hash_set_mem(h, key, value)
Definition: hash.h:274
ip6_sr_tunnel_key_t key
src, dst address
Definition: sr.h:52
i32 sr_hmac_add_del_key(ip6_sr_main_t *sm, u32 key_id, u8 *shared_secret, u8 is_del)
Add or Delete HMAC key.
Definition: sr.c:3003
#define ROUTING_HEADER_TYPE_SR
Definition: sr_packet.h:173
u32 rx_fib_index
RX Fib index.
Definition: sr.h:64
vlib_error_t * errors
Definition: node.h:419
ip6_address_t dst
Definition: sr.h:43
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:112
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
ip6_address_t src_address
Definition: ip6_packet.h:300
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1063
static clib_error_t * sr_add_del_policy_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI Parser for Add or Delete a Segment Routing policy.
Definition: sr.c:1516
static dpo_type_t sr_dpo_type
Dynamically added SR DPO type.
Definition: sr.c:36
ip6_sr_main_t * sr_get_main(vlib_main_t *vm)
Definition: sr.c:2863
ip6_address_t src
Definition: sr.h:42
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
sr_local_error_t
Struct for definition of SR local error-strings.
Definition: sr.c:2288
u8 * name
name of policy
Definition: sr.h:152
int ip6_sr_add_del_multicastmap(ip6_sr_add_del_multicastmap_args_t *a)
Add or Delete a mapping of IP6 multicast address to Segment Routing policy.
Definition: sr.c:1686
static char * sr_fix_dst_error_strings[]
Error strings for SR Fix Destination rewrite.
Definition: sr.c:1936
u8 * format_ip6_sr_header_flags(u8 *s, va_list *args)
Format function for decoding various SR flags.
Definition: sr.c:123
ip6_address_t * segments
segment list, when inserting an ip6 SR header
Definition: sr.h:105
EVP_MD * md
Openssl var.
Definition: sr.h:221
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:117
static uword sr_rewrite(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Main processing dual-loop for Segment Routing Rewrite.
Definition: sr.c:359
ip6_address_t dst
Definition: sr.c:292
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:78
static uword sr_local(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
SR local node.
Definition: sr.c:2436
enum dpo_type_t_ dpo_type_t
Common types of data-path objects New types can be dynamically added using dpo_register_new_type() ...
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
ip6_sr_hmac_key_t * hmac_keys
pool of hmac keys
Definition: sr.h:218
sr_rewrite_error_t
Struct for SR rewrite error strings.
Definition: sr.c:311
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:190
#define vec_new(T, N)
Create new vector of given type and length (unspecified alignment, no header).
Definition: vec.h:270
static uword ip6_address_is_equal(ip6_address_t *a, ip6_address_t *b)
Definition: ip6_packet.h:176
static vlib_cli_command_t test_sr_hmac_validate
(constructor) VLIB_CLI_COMMAND (test_sr_hmac_validate)
Definition: sr.c:2984
int i32
Definition: types.h:81
u8 * name
optional name argument - for referencing SR tunnel/policy by name
Definition: sr.h:99
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u8 protocol
Protocol for next header.
Definition: sr_packet.h:180
Aggregrate type for a prefix.
Definition: fib_types.h:149
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:84
static vlib_cli_command_t show_sr_hmac
(constructor) VLIB_CLI_COMMAND (show_sr_hmac)
Definition: sr.c:3126
static vlib_cli_command_t show_sr_policy_command
(constructor) VLIB_CLI_COMMAND (show_sr_policy_command)
Definition: sr.c:1670
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
Struct for data for SR rewrite packet trace.
Definition: sr.c:290
static vlib_cli_command_t sr_multicast_map_command
(constructor) VLIB_CLI_COMMAND (sr_multicast_map_command)
Definition: sr.c:1852
#define hash_get_pair(h, key)
Definition: hash.h:251
#define IPPROTO_IPV6_ROUTE
Definition: sr_packet.h:170
u16 fp_len
The mask length.
Definition: fib_types.h:153
#define vlib_call_init_function(vm, x)
Definition: init.h:161
static const char *const *const sr_nodes[DPO_PROTO_NUM]
Definition: sr.c:1136
#define foreach_sr_rewrite_next
Defined valid next nodes.
Definition: sr.c:264
u8 sr[256]
Definition: sr.c:2273
dpo_type_t dpo_register_new_type(const dpo_vft_t *vft, const char *const *const *nodes)
Create and register a new DPO type.
Definition: dpo.c:233
#define IP6_SR_HEADER_FLAG_CLEANUP
Flag bits.
Definition: sr_packet.h:201
static clib_error_t * sr_add_del_tunnel_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI parser for Add or Delete a Segment Routing tunnel.
Definition: sr.c:1150
#define hash_create_string(elts, value_bytes)
Definition: hash.h:652
sr_fix_dst_addr_next_t
Struct for valid next-nodes for SR fix destination address node.
Definition: sr.c:1925
Information for fix address trace.
Definition: sr.c:1956
static vlib_cli_command_t sr_policy_command
(constructor) VLIB_CLI_COMMAND (sr_policy_command)
Definition: sr.c:1589
static clib_error_t * test_sr_debug_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Test for SR debug flag.
Definition: sr.c:3143
#define VLIB_BUFFER_PRE_DATA_SIZE
Definition: buffer.h:52
The identity of a DPO is a combination of its type and its instance number/index of objects of that t...
Definition: dpo.h:138
Args required for add/del tunnel.
Definition: sr.h:89
ip6_address_t dst
Definition: sr.c:1958
#define hash_create_mem(elts, key_bytes, value_bytes)
Definition: hash.h:637
#define hash_get(h, key)
Definition: hash.h:248
Definition: fib_entry.h:219
u8 is_del
Delete the tunnnel?
Definition: sr.h:120
#define ADJ_INDEX_INVALID
Invalid ADJ index - used when no adj is known likewise blazoned capitals INVALID speak volumes where ...
Definition: adj_types.h:36
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
#define hash_unset_mem(h, key)
Definition: hash.h:280
static char * sr_local_error_strings[]
Definition of SR local error-strings.
Definition: sr.c:2279
Args for mapping of multicast address to policy name.
Definition: sr.h:166
u8 * format_sr_fix_addr_trace(u8 *s, va_list *args)
Formatter for fix address trace.
Definition: sr.c:1968
ip46_address_t fp_addr
The address type is not deriveable from the fp_addr member.
Definition: fib_types.h:172
vlib_main_t * vlib_main
convenience
Definition: sr.h:229
void * sr_local_cb
application API callback
Definition: sr.h:212
u8 type
Type of routing header; type 4 = segement routing.
Definition: sr_packet.h:189
u8 * shared_secret
Definition: sr.h:81
u8 is_debug
enable debug spew
Definition: sr.h:226
ip6_address_t src
Definition: sr.c:2271
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:334
#define PREDICT_FALSE(x)
Definition: clib.h:97
u8 sr[256]
Definition: sr.c:296
u8 * format_ip6_sr_header_with_length(u8 *s, va_list *args)
Format function for decoding ip6_sr_header_t with length.
Definition: sr.c:242
u16 flags_net_byte_order
Flags, e.g.
Definition: sr.h:117
void vnet_register_sr_app_callback(void *cb)
Register a callback routine to set next0 in sr_local.
Definition: sr.c:2954
static clib_error_t * sr_hmac_add_del_key_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: sr.c:3045
u32 ip6_lookup_sr_replicate_index
ip6-replicate next index for multicast tunnel
Definition: sr.h:209
u32 next_index
Definition: sr.c:294
#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:216
int ip6_sr_add_del_tunnel(ip6_sr_add_del_tunnel_args_t *a)
Add or Delete a Segment Routing tunnel.
Definition: sr.c:821
#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:350
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
#define hash_foreach_mem(key_var, value_var, h, body)
Definition: hash.h:437
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:121
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1113
unformat_function_t unformat_ip6_address
Definition: format.h:93
uword * fib_index_by_table_id
Definition: ip6.h:148
ip6_address_t * src_address
Key (header imposition case)
Definition: sr.h:92
u8 * policy_name
optional policy name
Definition: sr.h:102
vnet_main_t * vnet_main
convenience
Definition: sr.h:231
u8 * rewrite
The actual ip6 SR header.
Definition: sr.h:69
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
u16 n_vectors
Definition: node.h:344
u16 length
Definition: sr.c:2272
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
u16 mcast_group_index
Force re-lookup in a different FIB.
Definition: lookup.h:191
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
void fib_table_entry_delete(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source)
Delete a FIB entry.
Definition: fib_table.c:793
Definition: ip6.h:66
static void sr_dpo_unlock(dpo_id_t *dpo)
no-op unlock function.
Definition: sr.c:1112
static clib_error_t * show_sr_multicast_map_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI Parser for Displaying a mapping of IP6 multicast address to Segment Routing policy.
Definition: sr.c:1871
#define clib_memcpy(a, b, c)
Definition: string.h:64
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:203
#define IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
Flag bits.
Definition: sr_packet.h:213
u32 fib_node_index_t
A typedef of a node index.
Definition: fib_types.h:28
#define IP6_SR_HEADER_FLAG_PL_ELT_NOT_PRESENT
Flag bits.
Definition: sr_packet.h:207
u16 flags
values 0x4 - 0x7 are reserved
Definition: sr_packet.h:215
u32 * tunnel_indices
vector to SR tunnel index
Definition: sr.h:155
void dpo_set(dpo_id_t *dpo, dpo_type_t type, dpo_proto_t proto, index_t index)
Set/create a DPO ID The DPO will be locked.
Definition: dpo.c:134
static clib_error_t * show_sr_hmac_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI parser for show HMAC key shared secrets.
Definition: sr.c:3110
void sr_fix_hmac(ip6_sr_main_t *sm, ip6_header_t *ip, ip6_sr_header_t *sr)
Use passed HMAC key in ip6_sr_header_t in OpenSSL HMAC routines.
Definition: sr.c:46
sr_local_next_t
Struct for definition of next-nodes for SR local.
Definition: sr.c:2256
u8 * policy_name
name of policy to map to
Definition: sr.h:172
static vlib_cli_command_t sr_tunnel_command
(constructor) VLIB_CLI_COMMAND (sr_tunnel_command)
Definition: sr.c:1310
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
Segment Route tunnel.
Definition: sr.h:49
u8 * format_ip6_sr_header(u8 *s, va_list *args)
Format function for decoding ip6_sr_header_t.
Definition: sr.c:174
u8 validate_hmac
validate hmac keys
Definition: sr.h:215
fib_node_index_t fib_table_entry_special_dpo_add(u32 fib_index, const fib_prefix_t *prefix, fib_source_t source, fib_entry_flag_t flags, const dpo_id_t *dpo)
Add a &#39;special&#39; entry to the FIB that links to the DPO passed A special entry is an entry that the FI...
Definition: fib_table.c:288
ip6_address_t first_hop
First hop, to save 1 elt in the segment list.
Definition: sr.h:61
static ip6_sr_hmac_key_t * find_or_add_shared_secret(ip6_sr_main_t *sm, u8 *secret, u32 *indexp)
Find or add if not found - HMAC shared secret.
Definition: sr.c:765
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:768
static void sr_dpo_lock(dpo_id_t *dpo)
no-op lock function.
Definition: sr.c:1103
u16 cached_next_index
Definition: node.h:463
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static vlib_cli_command_t sr_hmac
(constructor) VLIB_CLI_COMMAND (sr_hmac)
Definition: sr.c:3093
adj_index_t fib_entry_get_adj_for_source(fib_node_index_t fib_entry_index, fib_source_t source)
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
#define vnet_buffer(b)
Definition: buffer.h:333
ip6_main_t ip6_main
Definition: ip6_forward.c:2655
ip_lookup_main_t lookup_main
Definition: ip6.h:132
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:745
static clib_error_t * sr_init(vlib_main_t *vm)
Definition: sr.c:2185
u8 * name
policy name
Definition: sr.h:133
static uword sr_fix_dst_addr(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Fix SR destination address - dual-loop.
Definition: sr.c:2011
ip6_sr_tunnel_t * tunnels
pool of tunnel instances, sr entry only
Definition: sr.h:185
static int sr_validate_hmac(ip6_sr_main_t *sm, ip6_header_t *ip, ip6_sr_header_t *sr)
Validate the SR HMAC.
Definition: sr.c:2335
#define foreach_sr_local_next
Definition of next-nodes for SR local.
Definition: sr.c:2249
uword * policy_index_by_policy_name
find a policy by name
Definition: sr.h:197
u8 is_del
Delete the policy?
Definition: sr.h:139
uword * tunnel_index_by_name
find an sr "tunnel" by its name
Definition: sr.h:191
vlib_node_registration_t sr_fix_dst_addr_node
(constructor) VLIB_REGISTER_NODE (sr_fix_dst_addr_node)
Definition: sr.c:2160
static clib_error_t * show_sr_policy_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI Parser for Displaying Segment Routing policy.
Definition: sr.c:1607
static void * clib_mem_alloc(uword size)
Definition: mem.h:109
static clib_error_t * set_ip6_sr_rewrite_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI parser for SR fix destination rewrite node.
Definition: sr.c:2880
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:95
static vlib_cli_command_t set_ip6_sr_rewrite
(constructor) VLIB_CLI_COMMAND (set_ip6_sr_rewrite)
Definition: sr.c:2941
#define IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
Flag bits.
Definition: sr_packet.h:209
static clib_error_t * sr_add_del_multicast_map_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI Parser for Adding or Delete a mapping of IP6 multicast address to Segment Routing policy...
Definition: sr.c:1779
u64 uword
Definition: types.h:112
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 for packet trace of SR local.
Definition: sr.c:2267
u8 * shared_secret
Shared secret => generate SHA-256 HMAC security fields.
Definition: sr.h:114
vlib_node_t * vlib_get_node_by_name(vlib_main_t *vm, u8 *name)
Definition: node.c:45
Definition: defs.h:47
uword * hmac_key_by_shared_secret
hmac key id by shared secret
Definition: sr.h:203
unsigned short u16
Definition: types.h:57
#define DPO_PROTO_NUM
Definition: dpo.h:72
SRv6.
Definition: fib_entry.h:69
u16 payload_length
Definition: ip6_packet.h:291
i64 word
Definition: types.h:111
static const dpo_vft_t sr_vft
Definition: sr.c:1125
#define FIB_NODE_INDEX_INVALID
Definition: fib_types.h:29
uword * policy_index_by_multicast_address
multicast address to policy mapping
Definition: sr.h:200
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
ip6_address_t src
Definition: sr.c:292
unsigned char u8
Definition: types.h:56
ip_lookup_next_t lookup_next_index
Definition: lookup.h:183
ip6_address_t segments[0]
The segment + policy list elts.
Definition: sr_packet.h:219
Segment Routing policy.
Definition: sr.h:149
vlib_node_registration_t sr_replicate_node
(constructor) VLIB_REGISTER_NODE (sr_replicate_node)
Definition: sr_replicate.c:384
ip6_sr_policy_t * policies
policy pool
Definition: sr.h:194
SR header struct.
Definition: sr_packet.h:177
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
u32 tunnel_index
Definition: sr.c:295
#define DPO_INVALID
An initialiser for DPos declared on the stack.
Definition: dpo.h:164
ip6_address_t * dst_address
Definition: sr.h:93
u8 ** tunnel_names
tunnel names
Definition: sr.h:136
static int ip6_sr_policy_list_shift_from_index(int pl_index)
Definition: sr_packet.h:223
#define hash_get_mem(h, key)
Definition: hash.h:268
Shared secret for keyed-hash message authentication code (HMAC).
Definition: sr.h:79
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:166
static clib_error_t * show_sr_tunnel_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
CLI Parser for Display Segment Routing tunnel.
Definition: sr.c:1369
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
Segment Routing header.
Segment Routing state.
Definition: sr.h:182
u8 length
Length of routing header in 8 octet units, not including the first 8 octets.
Definition: sr_packet.h:186
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u8 data[0]
Packet data.
Definition: buffer.h:154
This packet is to be rewritten and forwarded to the next processing node.
Definition: lookup.h:82
void dpo_reset(dpo_id_t *dpo)
reset a DPO ID The DPO will be unlocked.
Definition: dpo.c:171
#define vec_foreach(var, vec)
Vector iterator.
u8 * format_sr_local_trace(u8 *s, va_list *args)
Format SR local trace.
Definition: sr.c:2305
#define foreach_sr_fix_dst_addr_next
Definition: sr.c:1919
u32 table_id
Definition: ip6.h:68
#define clib_error_return(e, args...)
Definition: error.h:111
struct _unformat_input_t unformat_input_t
format_function_t format_ip6_header
Definition: format.h:97
static clib_error_t * ip6_lookup_init(vlib_main_t *vm)
Definition: ip6_forward.c:2658
u32 flags
Definition: vhost-user.h:75
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
u8 is_del
Delete the mapping.
Definition: sr.h:175
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
u8 first_segment
Policy list pointer: offset in the SRH of the policy list - in 16-octet units - not including the fir...
Definition: sr_packet.h:198
uword key
Definition: hash.h:161
sr_rewrite_next_t
Struct for defined valid next nodes.
Definition: sr.c:279
vlib_node_registration_t sr_rewrite_node
(constructor) VLIB_REGISTER_NODE (sr_rewrite_node)
Definition: sr.c:712
static int ip6_sr_policy_list_flags(u16 flags_host_byte_order, int pl_index)
pl_index is one-origined
Definition: sr_packet.h:230
ip6_address_t dst_address
Definition: ip6_packet.h:300
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:385
static vlib_node_registration_t sr_local_node
(constructor) VLIB_REGISTER_NODE (sr_local_node)
Definition: sr.c:31
u32 ip6_rewrite_sr_next_index
ip6-rewrite next index for reinstalling the original dst address
Definition: sr.h:206