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