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