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