2 * sr.c: ipv6 segment routing
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/vnet.h>
19 #include <vnet/sr/sr.h>
21 #include <openssl/hmac.h>
23 ip6_sr_main_t sr_main;
24 static vlib_node_registration_t sr_local_node;
27 sr_fix_hmac (ip6_sr_main_t * sm, ip6_header_t * ip, ip6_sr_header_t * sr)
35 ip6_sr_hmac_key_t *hmac_key;
38 key_index = sr->hmac_key;
40 /* No signature? Pass... */
44 /* We don't know about this key? Fail... */
45 if (key_index >= vec_len (sm->hmac_keys))
48 hmac_key = sm->hmac_keys + key_index;
50 vec_reset_length (keybuf);
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));
57 vec_add2 (keybuf, copy_target, 1);
58 copy_target[0] = sr->first_segment;
60 /* octet w/ bit 0 = "clean" flag */
61 vec_add2 (keybuf, copy_target, 1);
63 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
67 vec_add2 (keybuf, copy_target, 1);
68 copy_target[0] = sr->hmac_key;
70 first_segment = sr->first_segment;
75 for (i = 0; i <= first_segment; i++)
77 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
78 clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
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);
96 format_ip6_sr_header_flags (u8 * s, va_list * args)
98 u16 flags = (u16) va_arg (*args, int);
100 int bswap_needed = va_arg (*args, int);
104 flags = clib_host_to_net_u16 (flags);
106 if (flags & IP6_SR_HEADER_FLAG_CLEANUP)
107 s = format (s, "cleanup ");
109 if (flags & IP6_SR_HEADER_FLAG_PROTECTED)
110 s = format (s, "reroute ");
112 s = format (s, "pl: ");
113 for (i = 1; i <= 4; i++)
115 pl_flag = ip6_sr_policy_list_flags (flags, i);
116 s = format (s, "[%d] ", i);
120 case IP6_SR_HEADER_FLAG_PL_ELT_NOT_PRESENT:
121 s = format (s, "NotPr ");
123 case IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE:
124 s = format (s, "InPE ");
126 case IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE:
127 s = format (s, "EgPE ");
130 case IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR:
131 s = format (s, "OrgSrc ");
139 format_ip6_sr_header (u8 * s, va_list * args)
141 ip6_sr_header_t *h = va_arg (*args, ip6_sr_header_t *);
142 ip6_address_t placeholder_addr =
143 { {254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
146 int print_hmac = va_arg (*args, int);
147 int i, pl_index, max_segs;
148 int flags_host_byte_order = clib_net_to_host_u16 (h->flags);
150 s = format (s, "next proto %d, len %d, type %d",
151 h->protocol, (h->length << 3) + 8, h->type);
152 s = format (s, "\n segs left %d, first_segment %d, hmac key %d",
153 h->segments_left, h->first_segment, h->hmac_key);
154 s = format (s, "\n flags %U", format_ip6_sr_header_flags,
155 flags_host_byte_order, 0 /* bswap needed */ );
158 * Header length is in 8-byte units (minus one), so
159 * divide by 2 to ascertain the number of ip6 addresses in the
162 max_segs = (h->length >> 1);
164 if (!print_hmac && h->hmac_key)
167 s = format (s, "\n Segments (in processing order):");
169 for (i = h->first_segment; i >= 1; i--)
170 s = format (s, "\n %U", format_ip6_address, h->segments + i);
171 if (ip6_address_is_equal (&placeholder_addr, h->segments))
172 s = format (s, "\n (empty placeholder)");
174 s = format (s, "\n %U", format_ip6_address, h->segments);
176 s = format (s, "\n Policy List:");
178 pl_index = 1; /* to match the RFC text */
179 for (i = (h->first_segment + 1); i < max_segs; i++, pl_index++)
182 char *tags[] = { " ", "InPE: ", "EgPE: ", "OrgSrc: " };
185 if (pl_index >= 1 && pl_index <= 4)
187 int this_pl_flag = ip6_sr_policy_list_flags
188 (flags_host_byte_order, pl_index);
189 tag = tags[this_pl_flag];
192 s = format (s, "\n %s%U", tag, format_ip6_address, h->segments + i);
199 format_ip6_sr_header_with_length (u8 * s, va_list * args)
201 ip6_header_t *h = va_arg (*args, ip6_header_t *);
202 u32 max_header_bytes = va_arg (*args, u32);
205 header_bytes = sizeof (h[0]) + sizeof (ip6_sr_header_t);
206 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
207 return format (s, "ip6_sr header truncated");
209 s = format (s, "IP6: %U\n", format_ip6_header, h, max_header_bytes);
211 format (s, "SR: %U\n", format_ip6_sr_header, (ip6_sr_header_t *) (h + 1),
212 0 /* print_hmac */ , max_header_bytes);
216 #if DPDK > 0 /* Cannot call replicate yet without DPDK */
217 #define foreach_sr_rewrite_next \
218 _(ERROR, "error-drop") \
219 _(IP6_LOOKUP, "ip6-lookup") \
220 _(SR_LOCAL, "sr-local") \
221 _(SR_REPLICATE,"sr-replicate")
223 #define foreach_sr_rewrite_next \
224 _(ERROR, "error-drop") \
225 _(IP6_LOOKUP, "ip6-lookup") \
226 _(SR_LOCAL, "sr-local")
231 #define _(s,n) SR_REWRITE_NEXT_##s,
232 foreach_sr_rewrite_next
239 ip6_address_t src, dst;
244 } sr_rewrite_trace_t;
246 static char *sr_rewrite_error_strings[] = {
247 #define sr_error(n,s) s,
248 #include "sr_error.def"
254 #define sr_error(n,s) SR_REWRITE_ERROR_##n,
255 #include "sr_error.def"
258 } sr_rewrite_error_t;
262 format_sr_rewrite_trace (u8 * s, va_list * args)
264 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
265 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
266 sr_rewrite_trace_t *t = va_arg (*args, sr_rewrite_trace_t *);
267 ip6_main_t *im = &ip6_main;
268 ip6_sr_main_t *sm = &sr_main;
269 ip6_sr_tunnel_t *tun = pool_elt_at_index (sm->tunnels, t->tunnel_index);
270 ip6_fib_t *rx_fib, *tx_fib;
272 rx_fib = find_ip6_fib_by_table_index_or_id (im, tun->rx_fib_index,
273 IP6_ROUTE_FLAG_FIB_INDEX);
275 tx_fib = find_ip6_fib_by_table_index_or_id (im, tun->tx_fib_index,
276 IP6_ROUTE_FLAG_FIB_INDEX);
279 (s, "SR-REWRITE: next %s ip6 src %U dst %U len %u\n"
280 " rx-fib-id %d tx-fib-id %d\n%U",
281 (t->next_index == SR_REWRITE_NEXT_SR_LOCAL)
282 ? "sr-local" : "ip6-lookup",
283 format_ip6_address, &t->src,
284 format_ip6_address, &t->dst, t->length,
285 rx_fib->table_id, tx_fib->table_id,
286 format_ip6_sr_header, t->sr, 0 /* print_hmac */ );
291 sr_rewrite (vlib_main_t * vm,
292 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
294 u32 n_left_from, next_index, *from, *to_next;
295 ip6_main_t *im = &ip6_main;
296 ip_lookup_main_t *lm = &im->lookup_main;
297 ip6_sr_main_t *sm = &sr_main;
298 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
299 vlib_buffer_t *, ip6_header_t *, ip6_sr_header_t *);
300 sr_local_cb = sm->sr_local_cb;
302 from = vlib_frame_vector_args (from_frame);
303 n_left_from = from_frame->n_vectors;
305 next_index = node->cached_next_index;
307 while (n_left_from > 0)
311 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
313 /* Note 2x loop disabled */
314 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
317 vlib_buffer_t *b0, *b1;
318 ip6_header_t *ip0, *ip1;
319 ip_adjacency_t *adj0, *adj1;
320 ip6_sr_header_t *sr0, *sr1;
321 ip6_sr_tunnel_t *t0, *t1;
322 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
323 u32 next1 = SR_REWRITE_NEXT_IP6_LOOKUP;
327 /* Prefetch next iteration. */
329 vlib_buffer_t *p2, *p3;
331 p2 = vlib_get_buffer (vm, from[2]);
332 p3 = vlib_get_buffer (vm, from[3]);
334 vlib_prefetch_buffer_header (p2, LOAD);
335 vlib_prefetch_buffer_header (p3, LOAD);
347 b0 = vlib_get_buffer (vm, bi0);
348 b1 = vlib_get_buffer (vm, bi1);
351 * $$$ parse through header(s) to pick the point
352 * where we punch in the SR extention header
356 ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
358 ip_get_adjacency (lm, vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
360 pool_elt_at_index (sm->tunnels, adj0->rewrite_header.sw_if_index);
362 pool_elt_at_index (sm->tunnels, adj1->rewrite_header.sw_if_index);
364 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
365 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
366 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
367 >= ((word) vec_len (t1->rewrite)) + b1->current_data);
369 vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
370 vnet_buffer (b1)->sw_if_index[VLIB_TX] = t1->tx_fib_index;
372 ip0 = vlib_buffer_get_current (b0);
373 ip1 = vlib_buffer_get_current (b1);
376 * SR-unaware service chaining case: pkt coming back from
377 * service has the original dst address, and will already
378 * have an SR header. If so, send it to sr-local
380 if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE))
382 vlib_buffer_advance (b0, sizeof (ip0));
383 sr0 = (ip6_sr_header_t *) (ip0 + 1);
384 new_l0 = clib_net_to_host_u16 (ip0->payload_length);
385 next0 = SR_REWRITE_NEXT_SR_LOCAL;
390 * Copy data before the punch-in point left by the
391 * required amount. Assume (for the moment) that only
392 * the main packet header needs to be copied.
394 clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
395 ip0, sizeof (ip6_header_t));
396 vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
397 ip0 = vlib_buffer_get_current (b0);
398 sr0 = (ip6_sr_header_t *) (ip0 + 1);
400 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
402 /* Fix the next header chain */
403 sr0->protocol = ip0->protocol;
404 ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
405 new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
406 vec_len (t0->rewrite);
407 ip0->payload_length = clib_host_to_net_u16 (new_l0);
409 /* Copy dst address into the DA slot in the segment list */
410 clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
411 sizeof (ip6_address_t));
412 /* Rewrite the ip6 dst address with the first hop */
413 clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
414 sizeof (ip6_address_t));
416 sr_fix_hmac (sm, ip0, sr0);
418 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
422 * Ignore "do not rewrite" shtik in this path
424 if (PREDICT_FALSE (next0 & 0x80000000))
427 if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
428 b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
432 if (PREDICT_FALSE (ip1->protocol == IPPROTO_IPV6_ROUTE))
434 vlib_buffer_advance (b1, sizeof (ip1));
435 sr1 = (ip6_sr_header_t *) (ip1 + 1);
436 new_l1 = clib_net_to_host_u16 (ip1->payload_length);
437 next1 = SR_REWRITE_NEXT_SR_LOCAL;
441 clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
442 ip0, sizeof (ip6_header_t));
443 vlib_buffer_advance (b1, -(word) vec_len (t1->rewrite));
444 ip1 = vlib_buffer_get_current (b1);
445 sr1 = (ip6_sr_header_t *) (ip1 + 1);
446 clib_memcpy (sr1, t1->rewrite, vec_len (t1->rewrite));
448 sr1->protocol = ip1->protocol;
449 ip1->protocol = IPPROTO_IPV6_ROUTE;
450 new_l1 = clib_net_to_host_u16 (ip1->payload_length) +
451 vec_len (t1->rewrite);
452 ip1->payload_length = clib_host_to_net_u16 (new_l1);
454 /* Copy dst address into the DA slot in the segment list */
455 clib_memcpy (sr1->segments, ip1->dst_address.as_u64,
456 sizeof (ip6_address_t));
457 /* Rewrite the ip6 dst address with the first hop */
458 clib_memcpy (ip1->dst_address.as_u64, t1->first_hop.as_u64,
459 sizeof (ip6_address_t));
461 sr_fix_hmac (sm, ip1, sr1);
463 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
467 * Ignore "do not rewrite" shtik in this path
469 if (PREDICT_FALSE (next1 & 0x80000000))
472 if (PREDICT_FALSE (next1 == SR_REWRITE_NEXT_ERROR))
473 b1->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
477 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
479 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
481 tr->tunnel_index = t0 - sm->tunnels;
482 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
483 sizeof (tr->src.as_u8));
484 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
485 sizeof (tr->dst.as_u8));
487 tr->next_index = next0;
488 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
490 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
492 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
494 tr->tunnel_index = t1 - sm->tunnels;
495 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
496 sizeof (tr->src.as_u8));
497 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
498 sizeof (tr->dst.as_u8));
500 tr->next_index = next1;
501 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
504 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
505 to_next, n_left_to_next,
506 bi0, bi1, next0, next1);
509 while (n_left_from > 0 && n_left_to_next > 0)
513 ip6_header_t *ip0 = 0;
514 ip_adjacency_t *adj0;
515 ip6_sr_header_t *sr0 = 0;
517 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
527 b0 = vlib_get_buffer (vm, bi0);
530 * $$$ parse through header(s) to pick the point
531 * where we punch in the SR extention header
535 ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
537 pool_elt_at_index (sm->tunnels, adj0->rewrite_header.sw_if_index);
539 #if DPDK > 0 /* Cannot call replication node yet without DPDK */
540 /* add a replication node */
541 if (PREDICT_FALSE (t0->policy_index != ~0))
543 vnet_buffer (b0)->ip.save_protocol = t0->policy_index;
544 next0 = SR_REWRITE_NEXT_SR_REPLICATE;
549 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
550 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
552 vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
554 ip0 = vlib_buffer_get_current (b0);
557 * SR-unaware service chaining case: pkt coming back from
558 * service has the original dst address, and will already
559 * have an SR header. If so, send it to sr-local
561 if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE))
563 vlib_buffer_advance (b0, sizeof (ip0));
564 sr0 = (ip6_sr_header_t *) (ip0 + 1);
565 new_l0 = clib_net_to_host_u16 (ip0->payload_length);
566 next0 = SR_REWRITE_NEXT_SR_LOCAL;
571 * Copy data before the punch-in point left by the
572 * required amount. Assume (for the moment) that only
573 * the main packet header needs to be copied.
575 clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
576 ip0, sizeof (ip6_header_t));
577 vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
578 ip0 = vlib_buffer_get_current (b0);
579 sr0 = (ip6_sr_header_t *) (ip0 + 1);
581 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
583 /* Fix the next header chain */
584 sr0->protocol = ip0->protocol;
585 ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
586 new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
587 vec_len (t0->rewrite);
588 ip0->payload_length = clib_host_to_net_u16 (new_l0);
590 /* Copy dst address into the DA slot in the segment list */
591 clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
592 sizeof (ip6_address_t));
593 /* Rewrite the ip6 dst address with the first hop */
594 clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
595 sizeof (ip6_address_t));
597 sr_fix_hmac (sm, ip0, sr0);
599 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
603 * Ignore "do not rewrite" shtik in this path
605 if (PREDICT_FALSE (next0 & 0x80000000))
608 if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
609 b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
613 #if DPDK > 0 /* Cannot run replicate without DPDK and only replicate uses this label */
616 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
618 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
620 tr->tunnel_index = t0 - sm->tunnels;
623 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
624 sizeof (tr->src.as_u8));
625 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
626 sizeof (tr->dst.as_u8));
629 tr->next_index = next0;
630 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
633 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
634 to_next, n_left_to_next,
638 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
640 return from_frame->n_vectors;
644 VLIB_REGISTER_NODE (sr_rewrite_node) = {
645 .function = sr_rewrite,
646 .name = "sr-rewrite",
647 /* Takes a vector of packets. */
648 .vector_size = sizeof (u32),
649 .format_trace = format_sr_rewrite_trace,
650 .format_buffer = format_ip6_sr_header_with_length,
652 .n_errors = SR_REWRITE_N_ERROR,
653 .error_strings = sr_rewrite_error_strings,
655 .runtime_data_bytes = 0,
657 .n_next_nodes = SR_REWRITE_N_NEXT,
659 #define _(s,n) [SR_REWRITE_NEXT_##s] = n,
660 foreach_sr_rewrite_next
666 VLIB_NODE_FUNCTION_MULTIARCH (sr_rewrite_node, sr_rewrite)
667 static int ip6_delete_route_no_next_hop (ip6_address_t * dst_address_arg,
668 u32 dst_address_length,
671 ip6_add_del_route_args_t a;
672 ip6_address_t dst_address;
674 ip6_main_t *im6 = &ip6_main;
675 BVT (clib_bihash_kv) kv, value;
677 fib = find_ip6_fib_by_table_index_or_id (im6, rx_table_id,
678 IP6_ROUTE_FLAG_TABLE_ID);
679 memset (&a, 0, sizeof (a));
680 a.flags |= IP4_ROUTE_FLAG_DEL;
681 a.dst_address_length = dst_address_length;
683 dst_address = *dst_address_arg;
685 ip6_address_mask (&dst_address, &im6->fib_masks[dst_address_length]);
687 kv.key[0] = dst_address.as_u64[0];
688 kv.key[1] = dst_address.as_u64[1];
689 kv.key[2] = ((u64) ((fib - im6->fibs)) << 32) | dst_address_length;
691 if (BV (clib_bihash_search) (&im6->ip6_lookup_table, &kv, &value) < 0)
693 clib_warning ("%U/%d not in FIB",
694 format_ip6_address, &a.dst_address, a.dst_address_length);
698 a.adj_index = value.value;
699 a.dst_address = dst_address;
701 ip6_add_del_route (im6, &a);
702 ip6_maybe_remap_adjacencies (im6, rx_table_id, IP6_ROUTE_FLAG_TABLE_ID);
706 static ip6_sr_hmac_key_t *
707 find_or_add_shared_secret (ip6_sr_main_t * sm, u8 * secret, u32 * indexp)
710 ip6_sr_hmac_key_t *key = 0;
713 p = hash_get_mem (sm->hmac_key_by_shared_secret, secret);
717 key = vec_elt_at_index (sm->hmac_keys, p[0]);
723 /* Specific key ID? */
724 if (indexp && *indexp)
726 vec_validate (sm->hmac_keys, *indexp);
727 key = sm->hmac_keys + *indexp;
731 for (i = 0; i < vec_len (sm->hmac_keys); i++)
733 if (sm->hmac_keys[i].shared_secret == 0)
735 key = sm->hmac_keys + i;
739 vec_validate (sm->hmac_keys, i);
740 key = sm->hmac_keys + i;
745 key->shared_secret = vec_dup (secret);
747 hash_set_mem (sm->hmac_key_by_shared_secret, key->shared_secret,
748 key - sm->hmac_keys);
751 *indexp = key - sm->hmac_keys;
757 ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
759 ip6_main_t *im = &ip6_main;
760 ip_lookup_main_t *lm = &im->lookup_main;
761 ip6_sr_tunnel_key_t key;
764 ip6_sr_header_t *h = 0;
766 ip6_address_t *addrp, *this_address;
767 ip_adjacency_t adj, *ap, *add_adj = 0;
769 ip6_sr_main_t *sm = &sr_main;
771 u32 rx_fib_index, tx_fib_index;
772 ip6_add_del_route_args_t aa;
773 u32 hmac_key_index_u32;
774 u8 hmac_key_index = 0;
778 /* Make sure that the rx FIB exists */
779 p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
784 /* remember the FIB index */
787 /* Make sure that the supplied FIB exists */
788 p = hash_get (im->fib_index_by_table_id, a->tx_table_id);
793 /* remember the FIB index */
796 clib_memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
797 clib_memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
799 /* When adding a tunnel:
800 * - If a "name" is given, it must not exist.
801 * - The "key" is always checked, and must not exist.
802 * When deleting a tunnel:
803 * - If the "name" is given, and it exists, then use it.
804 * - If the "name" is not given, use the "key".
805 * - If the "name" and the "key" are given, then both must point to the same
810 p = hash_get_mem (sm->tunnel_index_by_key, &key);
812 /* If the name is given, look it up */
814 n = hash_get_mem (sm->tunnel_index_by_name, a->name);
818 /* validate key/name parameters */
819 if (!a->is_del) /* adding a tunnel */
821 if (a->name && n) /* name given & exists already */
823 if (p) /* key exists already */
826 else /* deleting a tunnel */
828 if (!p) /* key doesn't exist */
830 if (a->name && !n) /* name given & it doesn't exist */
833 if (n) /* name given & found */
835 if (n[0] != p[0]) /* name and key do not point to the same thing */
841 if (a->is_del) /* delete the tunnel */
845 /* Delete existing tunnel */
846 t = pool_elt_at_index (sm->tunnels, p[0]);
848 ip6_delete_route_no_next_hop (&t->key.dst, t->dst_mask_width,
850 vec_free (t->rewrite);
851 /* Remove tunnel from any policy if associated */
852 if (t->policy_index != ~0)
854 pt = pool_elt_at_index (sm->policies, t->policy_index);
855 for (i = 0; i < vec_len (pt->tunnel_indices); i++)
857 if (pt->tunnel_indices[i] == t - sm->tunnels)
859 vec_delete (pt->tunnel_indices, 1, i);
863 clib_warning ("Tunnel index %d not found in policy_index %d",
864 t - sm->tunnels, pt - sm->policies);
866 /* If this is last tunnel in the policy, clean up the policy too */
867 if (vec_len (pt->tunnel_indices) == 0)
869 hash_unset_mem (sm->policy_index_by_policy_name, pt->name);
871 pool_put (sm->policies, pt);
875 /* Clean up the tunnel by name */
878 hash_unset_mem (sm->tunnel_index_by_name, t->name);
881 pool_put (sm->tunnels, t);
882 hp = hash_get_pair (sm->tunnel_index_by_key, &key);
883 key_copy = (void *) (hp->key);
884 hash_unset_mem (sm->tunnel_index_by_key, &key);
889 /* create a new tunnel */
890 pool_get (sm->tunnels, t);
891 memset (t, 0, sizeof (*t));
892 t->policy_index = ~0;
894 clib_memcpy (&t->key, &key, sizeof (t->key));
895 t->dst_mask_width = a->dst_mask_width;
896 t->rx_fib_index = rx_fib_index;
897 t->tx_fib_index = tx_fib_index;
899 if (!vec_len (a->segments))
900 /* there must be at least one segment... */
903 /* The first specified hop goes right into the dst address */
904 clib_memcpy (&t->first_hop, &a->segments[0], sizeof (ip6_address_t));
907 * Create the sr header rewrite string
908 * The list of segments needs an extra slot for the ultimate destination
909 * which is taken from the packet we add the SRH to.
911 header_length = sizeof (*h) +
912 sizeof (ip6_address_t) * (vec_len (a->segments) + 1 + vec_len (a->tags));
914 if (a->shared_secret)
916 /* Allocate a new key slot if we don't find the secret key */
917 hmac_key_index_u32 = 0;
918 (void) find_or_add_shared_secret (sm, a->shared_secret,
919 &hmac_key_index_u32);
921 /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
922 if (hmac_key_index_u32 >= 256)
924 hmac_key_index = hmac_key_index_u32;
925 header_length += SHA256_DIGEST_LENGTH;
928 vec_validate (t->rewrite, header_length - 1);
930 h = (ip6_sr_header_t *) t->rewrite;
932 h->protocol = 0xFF; /* we don't know yet */
934 h->length = (header_length / 8) - 1;
935 h->type = ROUTING_HEADER_TYPE_SR;
937 /* first_segment and segments_left need to have the index of the last
938 * element in the list; a->segments has one element less than ends up
939 * in the header (it does not have the DA in it), so vec_len(a->segments)
940 * is the value we want.
942 h->first_segment = h->segments_left = vec_len (a->segments);
944 if (a->shared_secret)
945 h->hmac_key = hmac_key_index & 0xFF;
947 h->flags = a->flags_net_byte_order;
949 /* Paint on the segment list, in reverse.
950 * This is offset by one to leave room at the start for the ultimate
953 addrp = h->segments + vec_len (a->segments);
955 vec_foreach (this_address, a->segments)
957 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
962 * Since the ultimate destination address is not yet known, set that slot
963 * to a value we will instantly recognize as bogus.
965 memset (h->segments, 0xfe, sizeof (ip6_address_t));
967 /* Paint on the tag list, not reversed */
968 addrp = h->segments + vec_len (a->segments);
970 vec_foreach (this_address, a->tags)
972 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
976 key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
977 clib_memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
978 hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
980 memset (&adj, 0, sizeof (adj));
982 /* Create an adjacency and add to v6 fib */
983 adj.lookup_next_index = sm->ip6_lookup_sr_next_index;
984 adj.explicit_fib_index = ~0;
986 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */ ,
990 * Stick the tunnel index into the rewrite header.
992 * Unfortunately, inserting an SR header according to the various
993 * RFC's requires parsing through the ip6 header, perhaps consing a
994 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
995 * normal reverse bcopy rewrite code.
997 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1000 ap->rewrite_header.sw_if_index = t - sm->tunnels;
1002 vec_add1 (add_adj, ap[0]);
1004 clib_memcpy (aa.dst_address.as_u8, a->dst_address,
1005 sizeof (aa.dst_address.as_u8));
1006 aa.dst_address_length = a->dst_mask_width;
1008 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1009 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1010 aa.table_index_or_table_id = rx_fib_index;
1011 aa.add_adj = add_adj;
1012 aa.adj_index = adj_index;
1014 ip6_add_del_route (im, &aa);
1019 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1022 pt = pool_elt_at_index (sm->policies, p[0]);
1024 else /* no policy, lets create one */
1026 pool_get (sm->policies, pt);
1027 memset (pt, 0, sizeof (*pt));
1028 pt->name = format (0, "%s%c", a->policy_name, 0);
1029 hash_set_mem (sm->policy_index_by_policy_name, pt->name,
1031 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1033 vec_add1 (pt->tunnel_indices, t - sm->tunnels);
1035 clib_warning ("p is NULL!");
1036 t->policy_index = p ? p[0] : ~0; /* equiv. to (pt - sm->policies) */
1041 t->name = format (0, "%s%c", a->name, 0);
1042 hash_set_mem (sm->tunnel_index_by_name, t->name, t - sm->tunnels);
1048 static clib_error_t *
1049 sr_add_del_tunnel_command_fn (vlib_main_t * vm,
1050 unformat_input_t * input,
1051 vlib_cli_command_t * cmd)
1054 ip6_address_t src_address;
1055 int src_address_set = 0;
1056 ip6_address_t dst_address;
1058 int dst_address_set = 0;
1060 u8 *shared_secret = 0;
1062 u8 *policy_name = 0;
1063 u32 rx_table_id = 0;
1064 u32 tx_table_id = 0;
1065 ip6_address_t *segments = 0;
1066 ip6_address_t *this_seg;
1067 ip6_address_t *tags = 0;
1068 ip6_address_t *this_tag;
1069 ip6_sr_add_del_tunnel_args_t _a, *a = &_a;
1070 ip6_address_t next_address, tag;
1074 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1076 if (unformat (input, "del"))
1078 else if (unformat (input, "rx-fib-id %d", &rx_table_id))
1080 else if (unformat (input, "tx-fib-id %d", &tx_table_id))
1082 else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
1083 src_address_set = 1;
1084 else if (unformat (input, "name %s", &name))
1086 else if (unformat (input, "policy %s", &policy_name))
1088 else if (unformat (input, "dst %U/%d",
1089 unformat_ip6_address, &dst_address, &dst_mask_width))
1090 dst_address_set = 1;
1091 else if (unformat (input, "next %U", unformat_ip6_address,
1094 vec_add2 (segments, this_seg, 1);
1095 clib_memcpy (this_seg->as_u8, next_address.as_u8,
1096 sizeof (*this_seg));
1098 else if (unformat (input, "tag %U", unformat_ip6_address, &tag))
1100 vec_add2 (tags, this_tag, 1);
1101 clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
1103 else if (unformat (input, "clean"))
1104 flags |= IP6_SR_HEADER_FLAG_CLEANUP;
1105 else if (unformat (input, "protected"))
1106 flags |= IP6_SR_HEADER_FLAG_PROTECTED;
1107 else if (unformat (input, "key %s", &shared_secret))
1108 /* Do not include the trailing NULL byte. Guaranteed interop issue */
1109 _vec_len (shared_secret) -= 1;
1110 else if (unformat (input, "InPE %d", &pl_index))
1112 if (pl_index <= 0 || pl_index > 4)
1114 pl_index_range_error:
1115 return clib_error_return
1116 (0, "Policy List Element Index %d out of range (1-4)",
1120 flags |= IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
1121 << ip6_sr_policy_list_shift_from_index (pl_index);
1123 else if (unformat (input, "EgPE %d", &pl_index))
1125 if (pl_index <= 0 || pl_index > 4)
1126 goto pl_index_range_error;
1127 flags |= IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
1128 << ip6_sr_policy_list_shift_from_index (pl_index);
1130 else if (unformat (input, "OrgSrc %d", &pl_index))
1132 if (pl_index <= 0 || pl_index > 4)
1133 goto pl_index_range_error;
1134 flags |= IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
1135 << ip6_sr_policy_list_shift_from_index (pl_index);
1141 if (!src_address_set)
1142 return clib_error_return (0, "src address required");
1144 if (!dst_address_set)
1145 return clib_error_return (0, "dst address required");
1148 return clib_error_return (0, "at least one sr segment required");
1150 memset (a, 0, sizeof (*a));
1151 a->src_address = &src_address;
1152 a->dst_address = &dst_address;
1153 a->dst_mask_width = dst_mask_width;
1154 a->segments = segments;
1156 a->flags_net_byte_order = clib_host_to_net_u16 (flags);
1158 a->rx_table_id = rx_table_id;
1159 a->tx_table_id = tx_table_id;
1160 a->shared_secret = shared_secret;
1167 if (vec_len (policy_name))
1168 a->policy_name = policy_name;
1172 rv = ip6_sr_add_del_tunnel (a);
1174 vec_free (segments);
1176 vec_free (shared_secret);
1184 return clib_error_return (0, "SR tunnel src %U dst %U already exists",
1185 format_ip6_address, &src_address,
1186 format_ip6_address, &dst_address);
1189 return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
1190 format_ip6_address, &src_address,
1191 format_ip6_address, &dst_address);
1194 return clib_error_return (0, "FIB table %d does not exist",
1198 return clib_error_return (0, "At least one segment is required");
1201 return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
1209 VLIB_CLI_COMMAND (sr_tunnel_command, static) = {
1210 .path = "sr tunnel",
1212 "sr tunnel [del] [name <name>] src <addr> dst <addr> [next <addr>] "
1213 "[clean] [reroute] [key <secret>] [policy <policy_name>]"
1214 "[rx-fib-id <fib_id>] [tx-fib-id <fib_id>]",
1215 .function = sr_add_del_tunnel_command_fn,
1220 ip6_sr_tunnel_display (vlib_main_t * vm, ip6_sr_tunnel_t * t)
1222 ip6_main_t *im = &ip6_main;
1223 ip6_sr_main_t *sm = &sr_main;
1224 ip6_fib_t *rx_fib, *tx_fib;
1225 ip6_sr_policy_t *pt;
1227 rx_fib = find_ip6_fib_by_table_index_or_id (im, t->rx_fib_index,
1228 IP6_ROUTE_FLAG_FIB_INDEX);
1230 tx_fib = find_ip6_fib_by_table_index_or_id (im, t->tx_fib_index,
1231 IP6_ROUTE_FLAG_FIB_INDEX);
1234 vlib_cli_output (vm, "sr tunnel name: %s", (char *) t->name);
1236 vlib_cli_output (vm, "src %U dst %U first hop %U",
1237 format_ip6_address, &t->key.src,
1238 format_ip6_address, &t->key.dst,
1239 format_ip6_address, &t->first_hop);
1240 vlib_cli_output (vm, " rx-fib-id %d tx-fib-id %d",
1241 rx_fib->table_id, tx_fib->table_id);
1242 vlib_cli_output (vm, " sr: %U", format_ip6_sr_header, t->rewrite,
1243 0 /* print_hmac */ );
1245 if (t->policy_index != ~0)
1247 pt = pool_elt_at_index (sm->policies, t->policy_index);
1248 vlib_cli_output (vm, "sr policy: %s", (char *) pt->name);
1250 vlib_cli_output (vm, "-------");
1255 static clib_error_t *
1256 show_sr_tunnel_fn (vlib_main_t * vm,
1257 unformat_input_t * input, vlib_cli_command_t * cmd)
1259 static ip6_sr_tunnel_t **tunnels;
1261 ip6_sr_main_t *sm = &sr_main;
1266 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1268 if (unformat (input, "name %s", &name))
1270 p = hash_get_mem (sm->tunnel_index_by_name, name);
1272 vlib_cli_output (vm, "No SR tunnel with name: %s. Showing all.",
1279 vec_reset_length (tunnels);
1281 if (!p) /* Either name parm not passed or no tunnel with that name found, show all */
1284 pool_foreach (t, sm->tunnels,
1286 vec_add1 (tunnels, t);
1290 else /* Just show the one tunnel by name */
1291 vec_add1 (tunnels, &sm->tunnels[p[0]]);
1293 if (vec_len (tunnels) == 0)
1294 vlib_cli_output (vm, "No SR tunnels configured");
1296 for (i = 0; i < vec_len (tunnels); i++)
1299 ip6_sr_tunnel_display (vm, t);
1306 VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
1307 .path = "show sr tunnel",
1308 .short_help = "show sr tunnel [name <sr-tunnel-name>]",
1309 .function = show_sr_tunnel_fn,
1314 ip6_sr_add_del_policy (ip6_sr_add_del_policy_args_t * a)
1316 ip6_sr_main_t *sm = &sr_main;
1318 ip6_sr_tunnel_t *t = 0;
1319 ip6_sr_policy_t *policy;
1320 u32 *tunnel_indices = 0;
1327 p = hash_get_mem (sm->policy_index_by_policy_name, a->name);
1329 return -6; /* policy name not found */
1331 policy = pool_elt_at_index (sm->policies, p[0]);
1333 vec_foreach_index (i, policy->tunnel_indices)
1335 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1336 t->policy_index = ~0;
1338 hash_unset_mem (sm->policy_index_by_policy_name, a->name);
1339 pool_put (sm->policies, policy);
1344 if (!vec_len (a->tunnel_names))
1345 return -3; /*tunnel name is required case */
1347 vec_reset_length (tunnel_indices);
1348 /* Check tunnel names, add tunnel_index to policy */
1349 for (i = 0; i < vec_len (a->tunnel_names); i++)
1351 p = hash_get_mem (sm->tunnel_index_by_name, a->tunnel_names[i]);
1353 return -4; /* tunnel name not found case */
1355 t = pool_elt_at_index (sm->tunnels, p[0]);
1357 No need to check t==0. -3 condition above ensures name
1359 if (t->policy_index != ~0)
1360 return -5; /* tunnel name already associated with a policy */
1362 /* Add to tunnel indicies */
1363 vec_add1 (tunnel_indices, p[0]);
1366 /* Add policy to ip6_sr_main_t */
1367 pool_get (sm->policies, policy);
1368 policy->name = a->name;
1369 policy->tunnel_indices = tunnel_indices;
1370 hash_set_mem (sm->policy_index_by_policy_name, policy->name,
1371 policy - sm->policies);
1373 /* Yes, this could be construed as overkill but the last thing you should do is set
1374 the policy_index on the tunnel after everything is set in ip6_sr_main_t.
1375 If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop.
1377 for (i = 0; i < vec_len (policy->tunnel_indices); i++)
1379 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1380 t->policy_index = policy - sm->policies;
1387 static clib_error_t *
1388 sr_add_del_policy_command_fn (vlib_main_t * vm,
1389 unformat_input_t * input,
1390 vlib_cli_command_t * cmd)
1393 u8 **tunnel_names = 0;
1394 u8 *tunnel_name = 0;
1396 ip6_sr_add_del_policy_args_t _a, *a = &_a;
1399 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1401 if (unformat (input, "del"))
1403 else if (unformat (input, "name %s", &name))
1405 else if (unformat (input, "tunnel %s", &tunnel_name))
1409 vec_add1 (tunnel_names, tunnel_name);
1418 return clib_error_return (0, "name of SR policy required");
1421 memset (a, 0, sizeof (*a));
1425 a->tunnel_names = tunnel_names;
1427 rv = ip6_sr_add_del_policy (a);
1429 vec_free (tunnel_names);
1437 return clib_error_return (0,
1438 "tunnel name to associate to SR policy is required");
1441 return clib_error_return (0, "tunnel name not found");
1444 return clib_error_return (0, "tunnel already associated with policy");
1447 return clib_error_return (0, "policy name %s not found", name);
1450 return clib_error_return (0, "TODO: deleting policy name %s", name);
1453 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1461 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1462 .path = "sr policy",
1464 "sr policy [del] name <policy-name> tunnel <sr-tunnel-name> [tunnel <sr-tunnel-name>]*",
1465 .function = sr_add_del_policy_command_fn,
1469 static clib_error_t *
1470 show_sr_policy_fn (vlib_main_t * vm,
1471 unformat_input_t * input, vlib_cli_command_t * cmd)
1473 static ip6_sr_policy_t **policies;
1474 ip6_sr_policy_t *policy;
1476 ip6_sr_main_t *sm = &sr_main;
1481 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1483 if (unformat (input, "name %s", &name))
1485 p = hash_get_mem (sm->policy_index_by_policy_name, name);
1487 vlib_cli_output (vm,
1488 "policy with name %s not found. Showing all.",
1495 vec_reset_length (policies);
1497 if (!p) /* Either name parm not passed or no policy with that name found, show all */
1500 pool_foreach (policy, sm->policies,
1502 vec_add1 (policies, policy);
1506 else /* Just show the one policy by name and a summary of tunnel names */
1508 policy = pool_elt_at_index (sm->policies, p[0]);
1509 vec_add1 (policies, policy);
1512 if (vec_len (policies) == 0)
1513 vlib_cli_output (vm, "No SR policies configured");
1515 for (i = 0; i < vec_len (policies); i++)
1517 policy = policies[i];
1520 vlib_cli_output (vm, "SR policy name: %s", (char *) policy->name);
1521 for (j = 0; j < vec_len (policy->tunnel_indices); j++)
1523 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[j]);
1524 ip6_sr_tunnel_display (vm, t);
1533 VLIB_CLI_COMMAND (show_sr_policy_command, static) = {
1534 .path = "show sr policy",
1535 .short_help = "show sr policy [name <sr-policy-name>]",
1536 .function = show_sr_policy_fn,
1541 ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a)
1544 ip6_main_t *im = &ip6_main;
1545 ip_lookup_main_t *lm = &im->lookup_main;
1547 ip_adjacency_t adj, *ap, *add_adj = 0;
1549 ip6_sr_main_t *sm = &sr_main;
1550 ip6_add_del_route_args_t aa;
1551 ip6_sr_policy_t *pt;
1555 /* clean up the adjacency */
1557 hash_get_mem (sm->policy_index_by_multicast_address,
1558 a->multicast_address);
1562 /* Get our policy by policy_name */
1563 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1569 pt = pool_elt_at_index (sm->policies, p[0]);
1572 Get the first tunnel associated with policy populate the fib adjacency.
1573 From there, since this tunnel will have it's policy_index != ~0 it will
1574 be the trigger in the dual_loop to pull up the policy and make a copy-rewrite
1575 for each tunnel in the policy
1578 t = pool_elt_at_index (sm->tunnels, pt->tunnel_indices[0]);
1580 /* Construct a FIB entry for multicast using the rx/tx fib from the first tunnel */
1581 memset (&adj, 0, sizeof (adj));
1583 /* Create an adjacency and add to v6 fib */
1584 adj.lookup_next_index = sm->ip6_lookup_sr_replicate_index;
1585 adj.explicit_fib_index = ~0;
1587 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */ ,
1591 * Stick the tunnel index into the rewrite header.
1593 * Unfortunately, inserting an SR header according to the various
1594 * RFC's requires parsing through the ip6 header, perhaps consing a
1595 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1596 * normal reverse bcopy rewrite code.
1598 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1601 ap->rewrite_header.sw_if_index = t - sm->tunnels;
1603 vec_add1 (add_adj, ap[0]);
1605 memcpy (aa.dst_address.as_u8, a->multicast_address,
1606 sizeof (aa.dst_address.as_u8));
1607 aa.dst_address_length = 128;
1609 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1610 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1611 aa.table_index_or_table_id = t->rx_fib_index;
1612 aa.add_adj = add_adj;
1613 aa.adj_index = adj_index;
1615 ip6_add_del_route (im, &aa);
1619 mcast_copy = vec_new (ip6_address_t, 1);
1620 memcpy (mcast_copy, a->multicast_address, sizeof (ip6_address_t));
1624 hash_unset_mem (sm->policy_index_by_multicast_address, mcast_copy);
1625 vec_free (mcast_copy);
1630 hash_set_mem (sm->policy_index_by_multicast_address, mcast_copy,
1637 static clib_error_t *
1638 sr_add_del_multicast_map_command_fn (vlib_main_t * vm,
1639 unformat_input_t * input,
1640 vlib_cli_command_t * cmd)
1643 ip6_address_t multicast_address;
1644 u8 *policy_name = 0;
1645 int multicast_address_set = 0;
1646 ip6_sr_add_del_multicastmap_args_t _a, *a = &_a;
1649 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1651 if (unformat (input, "del"))
1655 (input, "address %U", unformat_ip6_address, &multicast_address))
1656 multicast_address_set = 1;
1657 else if (unformat (input, "sr-policy %s", &policy_name))
1663 if (!is_del && !policy_name)
1664 return clib_error_return (0, "name of sr policy required");
1666 if (!multicast_address_set)
1667 return clib_error_return (0, "multicast address required");
1669 memset (a, 0, sizeof (*a));
1672 a->multicast_address = &multicast_address;
1673 a->policy_name = policy_name;
1675 #if DPDK > 0 /*Cannot call replicate or configure multicast map yet without DPDK */
1676 rv = ip6_sr_add_del_multicastmap (a);
1678 return clib_error_return (0,
1679 "cannot use multicast replicate spray case without DPDK installed");
1687 return clib_error_return (0, "no policy with name: %s", policy_name);
1690 return clib_error_return (0, "multicast map someting ");
1693 return clib_error_return (0,
1694 "tunnel name to associate to SR policy is required");
1697 return clib_error_return (0, "TODO: deleting policy name %s",
1701 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1711 VLIB_CLI_COMMAND (sr_multicast_map_command, static) = {
1712 .path = "sr multicast-map",
1714 "sr multicast-map address <multicast-ip6-address> sr-policy <sr-policy-name> [del]",
1715 .function = sr_add_del_multicast_map_command_fn,
1719 static clib_error_t *
1720 show_sr_multicast_map_fn (vlib_main_t * vm,
1721 unformat_input_t * input, vlib_cli_command_t * cmd)
1723 ip6_sr_main_t *sm = &sr_main;
1726 ip6_address_t multicast_address;
1727 ip6_sr_policy_t *pt;
1729 /* pull all entries from the hash table into vector for display */
1732 hash_foreach_mem (key, value, sm->policy_index_by_multicast_address,
1735 vlib_cli_output (vm, "no multicast maps configured");
1738 multicast_address = *((ip6_address_t *)key);
1739 pt = pool_elt_at_index (sm->policies, value);
1742 vlib_cli_output (vm, "address: %U policy: %s",
1743 format_ip6_address, &multicast_address,
1747 vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d",
1748 format_ip6_address, &multicast_address,
1760 VLIB_CLI_COMMAND (show_sr_multicast_map_command, static) = {
1761 .path = "show sr multicast-map",
1762 .short_help = "show sr multicast-map",
1763 .function = show_sr_multicast_map_fn,
1768 #define foreach_sr_fix_dst_addr_next \
1769 _(DROP, "error-drop")
1773 #define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
1774 foreach_sr_fix_dst_addr_next
1776 SR_FIX_DST_ADDR_N_NEXT,
1777 } sr_fix_dst_addr_next_t;
1779 static char *sr_fix_dst_error_strings[] = {
1780 #define sr_fix_dst_error(n,s) s,
1781 #include "sr_fix_dst_error.def"
1782 #undef sr_fix_dst_error
1787 #define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
1788 #include "sr_fix_dst_error.def"
1789 #undef sr_fix_dst_error
1791 } sr_fix_dst_error_t;
1795 ip6_address_t src, dst;
1799 } sr_fix_addr_trace_t;
1802 format_sr_fix_addr_trace (u8 * s, va_list * args)
1804 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1805 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1806 sr_fix_addr_trace_t *t = va_arg (*args, sr_fix_addr_trace_t *);
1807 vnet_hw_interface_t *hi = 0;
1808 ip_adjacency_t *adj;
1809 ip6_main_t *im = &ip6_main;
1810 ip_lookup_main_t *lm = &im->lookup_main;
1811 vnet_main_t *vnm = vnet_get_main ();
1813 if (t->adj_index != ~0)
1815 adj = ip_get_adjacency (lm, t->adj_index);
1816 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
1819 s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
1820 (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
1821 ? "drop" : "output",
1822 format_ip6_address, &t->src, format_ip6_address, &t->dst);
1823 if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
1826 format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
1828 format (s, " output via %s",
1829 hi ? (char *) (hi->name) : "Invalid adj");
1835 sr_fix_dst_addr (vlib_main_t * vm,
1836 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
1838 u32 n_left_from, next_index, *from, *to_next;
1839 ip6_main_t *im = &ip6_main;
1840 ip_lookup_main_t *lm = &im->lookup_main;
1842 from = vlib_frame_vector_args (from_frame);
1843 n_left_from = from_frame->n_vectors;
1845 next_index = node->cached_next_index;
1847 while (n_left_from > 0)
1851 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1854 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
1857 __attribute__ ((unused)) vlib_buffer_t *b0, *b1;
1858 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1859 u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
1861 /* Prefetch next iteration. */
1863 vlib_buffer_t *p2, *p3;
1865 p2 = vlib_get_buffer (vm, from[2]);
1866 p3 = vlib_get_buffer (vm, from[3]);
1868 vlib_prefetch_buffer_header (p2, LOAD);
1869 vlib_prefetch_buffer_header (p3, LOAD);
1878 n_left_to_next -= 2;
1881 b0 = vlib_get_buffer (vm, bi0);
1882 b1 = vlib_get_buffer (vm, bi1);
1885 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1886 to_next, n_left_to_next,
1887 bi0, bi1, next0, next1);
1891 while (n_left_from > 0 && n_left_to_next > 0)
1896 ip_adjacency_t *adj0;
1897 ip6_sr_header_t *sr0;
1898 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1899 ip6_address_t *new_dst0;
1900 ethernet_header_t *eh0;
1907 n_left_to_next -= 1;
1909 b0 = vlib_get_buffer (vm, bi0);
1912 ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
1913 next0 = adj0->mcast_group_index;
1915 /* We should be pointing at an Ethernet header... */
1916 eh0 = vlib_buffer_get_current (b0);
1917 ip0 = (ip6_header_t *) (eh0 + 1);
1918 sr0 = (ip6_sr_header_t *) (ip0 + 1);
1920 /* We'd better find an SR header... */
1921 if (PREDICT_FALSE (ip0->protocol != IPPROTO_IPV6_ROUTE))
1923 b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
1929 * We get here from sr_rewrite or sr_local, with
1930 * sr->segments_left pointing at the (copy of the original) dst
1931 * address. Use it, then increment sr0->segments_left.
1934 /* Out of segments? Turf the packet */
1935 if (PREDICT_FALSE (sr0->segments_left == 0))
1937 b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
1942 * Rewrite the packet with the original dst address
1943 * We assume that the last segment (in processing order) contains
1944 * the original dst address. The list is reversed, so sr0->segments
1945 * contains the original dst address.
1947 new_dst0 = sr0->segments;
1948 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1949 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1954 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1956 sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
1958 t->next_index = next0;
1961 if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
1963 t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
1964 clib_memcpy (t->src.as_u8, ip0->src_address.as_u8,
1965 sizeof (t->src.as_u8));
1966 clib_memcpy (t->dst.as_u8, ip0->dst_address.as_u8,
1967 sizeof (t->dst.as_u8));
1968 clib_memcpy (t->sr, sr0, sizeof (t->sr));
1972 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1973 to_next, n_left_to_next,
1977 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1979 return from_frame->n_vectors;
1984 VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
1985 .function = sr_fix_dst_addr,
1986 .name = "sr-fix-dst-addr",
1987 /* Takes a vector of packets. */
1988 .vector_size = sizeof (u32),
1989 .format_trace = format_sr_fix_addr_trace,
1990 .format_buffer = format_ip6_sr_header_with_length,
1992 .runtime_data_bytes = 0,
1994 .n_errors = SR_FIX_DST_N_ERROR,
1995 .error_strings = sr_fix_dst_error_strings,
1997 .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
1999 #define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
2000 foreach_sr_fix_dst_addr_next
2006 VLIB_NODE_FUNCTION_MULTIARCH (sr_fix_dst_addr_node, sr_fix_dst_addr)
2007 static clib_error_t *sr_init (vlib_main_t * vm)
2009 ip6_sr_main_t *sm = &sr_main;
2010 clib_error_t *error = 0;
2011 vlib_node_t *ip6_lookup_node, *ip6_rewrite_node;
2013 if ((error = vlib_call_init_function (vm, ip_main_init)))
2016 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
2020 sm->vnet_main = vnet_get_main ();
2022 vec_validate (sm->hmac_keys, 0);
2023 sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
2025 sm->tunnel_index_by_key =
2026 hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
2028 sm->tunnel_index_by_name = hash_create_string (0, sizeof (uword));
2030 sm->policy_index_by_policy_name = hash_create_string (0, sizeof (uword));
2032 sm->policy_index_by_multicast_address =
2033 hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
2035 sm->hmac_key_by_shared_secret = hash_create_string (0, sizeof (uword));
2037 ip6_register_protocol (IPPROTO_IPV6_ROUTE, sr_local_node.index);
2039 ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
2040 ASSERT (ip6_lookup_node);
2042 ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
2043 ASSERT (ip6_rewrite_node);
2045 /* Add a disposition to ip6_lookup for the sr rewrite node */
2046 sm->ip6_lookup_sr_next_index =
2047 vlib_node_add_next (vm, ip6_lookup_node->index, sr_rewrite_node.index);
2049 #if DPDK > 0 /* Cannot run replicate without DPDK */
2050 /* Add a disposition to sr_replicate for the sr multicast replicate node */
2051 sm->ip6_lookup_sr_replicate_index =
2052 vlib_node_add_next (vm, ip6_lookup_node->index, sr_replicate_node.index);
2055 /* Add a disposition to ip6_rewrite for the sr dst address hack node */
2056 sm->ip6_rewrite_sr_next_index =
2057 vlib_node_add_next (vm, ip6_rewrite_node->index,
2058 sr_fix_dst_addr_node.index);
2060 OpenSSL_add_all_digests ();
2062 sm->md = (void *) EVP_get_digestbyname ("sha1");
2063 sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
2068 VLIB_INIT_FUNCTION (sr_init);
2070 #define foreach_sr_local_next \
2071 _ (ERROR, "error-drop") \
2072 _ (IP6_LOOKUP, "ip6-lookup")
2076 #define _(s,n) SR_LOCAL_NEXT_##s,
2077 foreach_sr_local_next
2086 ip6_address_t src, dst;
2091 static char *sr_local_error_strings[] = {
2092 #define sr_error(n,s) s,
2093 #include "sr_error.def"
2099 #define sr_error(n,s) SR_LOCAL_ERROR_##n,
2100 #include "sr_error.def"
2106 format_sr_local_trace (u8 * s, va_list * args)
2108 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2109 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2110 sr_local_trace_t *t = va_arg (*args, sr_local_trace_t *);
2112 s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
2113 format_ip6_address, &t->src,
2114 format_ip6_address, &t->dst, t->length, t->next_index);
2117 format (s, "\n %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
2119 s = format (s, "\n popped SR header");
2125 /* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
2128 sr_validate_hmac (ip6_sr_main_t * sm, ip6_header_t * ip, ip6_sr_header_t * sr)
2134 ip6_address_t *addrp;
2136 ip6_sr_hmac_key_t *hmac_key;
2137 static u8 *signature;
2140 key_index = sr->hmac_key;
2142 /* No signature? Pass... */
2146 /* We don't know about this key? Fail... */
2147 if (key_index >= vec_len (sm->hmac_keys))
2150 vec_validate (signature, SHA256_DIGEST_LENGTH - 1);
2152 hmac_key = sm->hmac_keys + key_index;
2154 vec_reset_length (keybuf);
2156 /* pkt ip6 src address */
2157 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2158 clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
2161 vec_add2 (keybuf, copy_target, 1);
2162 copy_target[0] = sr->first_segment;
2164 /* octet w/ bit 0 = "clean" flag */
2165 vec_add2 (keybuf, copy_target, 1);
2167 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
2171 vec_add2 (keybuf, copy_target, 1);
2172 copy_target[0] = sr->hmac_key;
2174 first_segment = sr->first_segment;
2176 addrp = sr->segments;
2179 for (i = 0; i <= first_segment; i++)
2181 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2182 clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
2187 clib_warning ("verify key index %d keybuf: %U", key_index,
2188 format_hex_bytes, keybuf, vec_len (keybuf));
2192 /* SHA1 is shorter than SHA-256 */
2193 memset (signature, 0, vec_len (signature));
2195 HMAC_CTX_init (sm->hmac_ctx);
2196 if (!HMAC_Init (sm->hmac_ctx, hmac_key->shared_secret,
2197 vec_len (hmac_key->shared_secret), sm->md))
2198 clib_warning ("barf1");
2199 if (!HMAC_Update (sm->hmac_ctx, keybuf, vec_len (keybuf)))
2200 clib_warning ("barf2");
2201 if (!HMAC_Final (sm->hmac_ctx, signature, &sig_len))
2202 clib_warning ("barf3");
2203 HMAC_CTX_cleanup (sm->hmac_ctx);
2206 clib_warning ("computed signature len %d, value %U", sig_len,
2207 format_hex_bytes, signature, vec_len (signature));
2209 /* Point at the SHA signature in the packet */
2212 clib_warning ("read signature %U", format_hex_bytes, addrp,
2213 SHA256_DIGEST_LENGTH);
2215 return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
2219 sr_local (vlib_main_t * vm,
2220 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
2222 u32 n_left_from, next_index, *from, *to_next;
2223 ip6_sr_main_t *sm = &sr_main;
2224 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
2225 vlib_buffer_t *, ip6_header_t *, ip6_sr_header_t *);
2226 sr_local_cb = sm->sr_local_cb;
2228 from = vlib_frame_vector_args (from_frame);
2229 n_left_from = from_frame->n_vectors;
2231 next_index = node->cached_next_index;
2233 while (n_left_from > 0)
2237 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2239 while (n_left_from >= 4 && n_left_to_next >= 2)
2242 vlib_buffer_t *b0, *b1;
2243 ip6_header_t *ip0, *ip1;
2244 ip6_sr_header_t *sr0, *sr1;
2245 ip6_address_t *new_dst0, *new_dst1;
2246 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2247 u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
2248 /* Prefetch next iteration. */
2250 vlib_buffer_t *p2, *p3;
2252 p2 = vlib_get_buffer (vm, from[2]);
2253 p3 = vlib_get_buffer (vm, from[3]);
2255 vlib_prefetch_buffer_header (p2, LOAD);
2256 vlib_prefetch_buffer_header (p3, LOAD);
2258 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2259 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2268 n_left_to_next -= 2;
2272 b0 = vlib_get_buffer (vm, bi0);
2273 ip0 = vlib_buffer_get_current (b0);
2274 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2276 if (PREDICT_FALSE (sr0->type != ROUTING_HEADER_TYPE_SR))
2278 next0 = SR_LOCAL_NEXT_ERROR;
2280 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2284 /* Out of segments? Turf the packet */
2285 if (PREDICT_FALSE (sr0->segments_left == 0))
2287 next0 = SR_LOCAL_NEXT_ERROR;
2288 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2292 if (PREDICT_FALSE (sm->validate_hmac))
2294 if (sr_validate_hmac (sm, ip0, sr0))
2296 next0 = SR_LOCAL_NEXT_ERROR;
2297 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2302 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
2305 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2307 if (PREDICT_FALSE (next0 & 0x80000000))
2309 next0 ^= 0xFFFFFFFF;
2310 if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2311 b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2317 segment_index0 = sr0->segments_left - 1;
2319 /* Rewrite the packet */
2320 new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2321 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2322 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2324 if (PREDICT_TRUE (sr0->segments_left > 0))
2325 sr0->segments_left -= 1;
2328 /* End of the path. Clean up the SR header, or not */
2330 (sr0->segments_left == 0 &&
2332 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2334 u64 *copy_dst0, *copy_src0;
2337 * Copy the ip6 header right by the (real) length of the
2338 * sr header. Here's another place which assumes that
2339 * the sr header is the only extention header.
2342 ip0->protocol = sr0->protocol;
2343 vlib_buffer_advance (b0, (sr0->length + 1) * 8);
2345 new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2346 (sr0->length + 1) * 8;
2347 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2349 copy_src0 = (u64 *) ip0;
2350 copy_dst0 = copy_src0 + (sr0->length + 1);
2352 copy_dst0[4] = copy_src0[4];
2353 copy_dst0[3] = copy_src0[3];
2354 copy_dst0[2] = copy_src0[2];
2355 copy_dst0[1] = copy_src0[1];
2356 copy_dst0[0] = copy_src0[0];
2362 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2364 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2366 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2367 sizeof (tr->src.as_u8));
2368 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2369 sizeof (tr->dst.as_u8));
2370 tr->length = vlib_buffer_length_in_chain (vm, b0);
2371 tr->next_index = next0;
2372 tr->sr_valid = sr0 != 0;
2374 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2377 b1 = vlib_get_buffer (vm, bi1);
2378 ip1 = vlib_buffer_get_current (b1);
2379 sr1 = (ip6_sr_header_t *) (ip1 + 1);
2381 if (PREDICT_FALSE (sr1->type != ROUTING_HEADER_TYPE_SR))
2383 next1 = SR_LOCAL_NEXT_ERROR;
2385 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2389 /* Out of segments? Turf the packet */
2390 if (PREDICT_FALSE (sr1->segments_left == 0))
2392 next1 = SR_LOCAL_NEXT_ERROR;
2393 b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2397 if (PREDICT_FALSE (sm->validate_hmac))
2399 if (sr_validate_hmac (sm, ip1, sr1))
2401 next1 = SR_LOCAL_NEXT_ERROR;
2402 b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2407 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) : next1;
2410 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2412 if (PREDICT_FALSE (next1 & 0x80000000))
2414 next1 ^= 0xFFFFFFFF;
2415 if (PREDICT_FALSE (next1 == SR_LOCAL_NEXT_ERROR))
2416 b1->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2422 segment_index1 = sr1->segments_left - 1;
2424 /* Rewrite the packet */
2425 new_dst1 = (ip6_address_t *) (sr1->segments + segment_index1);
2426 ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
2427 ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
2429 if (PREDICT_TRUE (sr1->segments_left > 0))
2430 sr1->segments_left -= 1;
2433 /* End of the path. Clean up the SR header, or not */
2435 (sr1->segments_left == 0 &&
2437 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2439 u64 *copy_dst1, *copy_src1;
2442 * Copy the ip6 header right by the (real) length of the
2443 * sr header. Here's another place which assumes that
2444 * the sr header is the only extention header.
2447 ip1->protocol = sr1->protocol;
2448 vlib_buffer_advance (b1, (sr1->length + 1) * 8);
2450 new_l1 = clib_net_to_host_u16 (ip1->payload_length) -
2451 (sr1->length + 1) * 8;
2452 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2454 copy_src1 = (u64 *) ip1;
2455 copy_dst1 = copy_src1 + (sr1->length + 1);
2457 copy_dst1[4] = copy_src1[4];
2458 copy_dst1[3] = copy_src1[3];
2459 copy_dst1[2] = copy_src1[2];
2460 copy_dst1[1] = copy_src1[1];
2461 copy_dst1[0] = copy_src1[0];
2467 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2469 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2471 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2472 sizeof (tr->src.as_u8));
2473 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2474 sizeof (tr->dst.as_u8));
2475 tr->length = vlib_buffer_length_in_chain (vm, b1);
2476 tr->next_index = next1;
2477 tr->sr_valid = sr1 != 0;
2479 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
2482 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2483 to_next, n_left_to_next,
2484 bi0, bi1, next0, next1);
2487 while (n_left_from > 0 && n_left_to_next > 0)
2491 ip6_header_t *ip0 = 0;
2492 ip6_sr_header_t *sr0;
2493 ip6_address_t *new_dst0;
2494 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2501 n_left_to_next -= 1;
2503 b0 = vlib_get_buffer (vm, bi0);
2504 ip0 = vlib_buffer_get_current (b0);
2505 sr0 = (ip6_sr_header_t *) (ip0 + 1);
2507 if (PREDICT_FALSE (sr0->type != ROUTING_HEADER_TYPE_SR))
2509 next0 = SR_LOCAL_NEXT_ERROR;
2511 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2515 /* Out of segments? Turf the packet */
2516 if (PREDICT_FALSE (sr0->segments_left == 0))
2518 next0 = SR_LOCAL_NEXT_ERROR;
2519 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2523 if (PREDICT_FALSE (sm->validate_hmac))
2525 if (sr_validate_hmac (sm, ip0, sr0))
2527 next0 = SR_LOCAL_NEXT_ERROR;
2528 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2533 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
2536 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2538 if (PREDICT_FALSE (next0 & 0x80000000))
2540 next0 ^= 0xFFFFFFFF;
2541 if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2542 b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2548 segment_index0 = sr0->segments_left - 1;
2550 /* Rewrite the packet */
2551 new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2552 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2553 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2555 if (PREDICT_TRUE (sr0->segments_left > 0))
2556 sr0->segments_left -= 1;
2559 /* End of the path. Clean up the SR header, or not */
2561 (sr0->segments_left == 0 &&
2563 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2565 u64 *copy_dst0, *copy_src0;
2568 * Copy the ip6 header right by the (real) length of the
2569 * sr header. Here's another place which assumes that
2570 * the sr header is the only extention header.
2573 ip0->protocol = sr0->protocol;
2574 vlib_buffer_advance (b0, (sr0->length + 1) * 8);
2576 new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2577 (sr0->length + 1) * 8;
2578 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2580 copy_src0 = (u64 *) ip0;
2581 copy_dst0 = copy_src0 + (sr0->length + 1);
2583 copy_dst0[4] = copy_src0[4];
2584 copy_dst0[3] = copy_src0[3];
2585 copy_dst0[2] = copy_src0[2];
2586 copy_dst0[1] = copy_src0[1];
2587 copy_dst0[0] = copy_src0[0];
2593 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2595 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2597 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2598 sizeof (tr->src.as_u8));
2599 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2600 sizeof (tr->dst.as_u8));
2601 tr->length = vlib_buffer_length_in_chain (vm, b0);
2602 tr->next_index = next0;
2603 tr->sr_valid = sr0 != 0;
2605 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2608 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2609 to_next, n_left_to_next,
2613 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2615 vlib_node_increment_counter (vm, sr_local_node.index,
2616 SR_LOCAL_ERROR_PKTS_PROCESSED,
2617 from_frame->n_vectors);
2618 return from_frame->n_vectors;
2622 VLIB_REGISTER_NODE (sr_local_node, static) = {
2623 .function = sr_local,
2625 /* Takes a vector of packets. */
2626 .vector_size = sizeof (u32),
2627 .format_trace = format_sr_local_trace,
2629 .runtime_data_bytes = 0,
2631 .n_errors = SR_LOCAL_N_ERROR,
2632 .error_strings = sr_local_error_strings,
2634 .n_next_nodes = SR_LOCAL_N_NEXT,
2636 #define _(s,n) [SR_LOCAL_NEXT_##s] = n,
2637 foreach_sr_local_next
2643 VLIB_NODE_FUNCTION_MULTIARCH (sr_local_node, sr_local)
2644 ip6_sr_main_t *sr_get_main (vlib_main_t * vm)
2646 vlib_call_init_function (vm, sr_init);
2647 ASSERT (sr_local_node.index);
2652 static clib_error_t *
2653 set_ip6_sr_rewrite_fn (vlib_main_t * vm,
2654 unformat_input_t * input, vlib_cli_command_t * cmd)
2657 ip6_main_t *im = &ip6_main;
2658 ip_lookup_main_t *lm = &im->lookup_main;
2663 ip_adjacency_t *adj;
2664 vnet_hw_interface_t *hi;
2666 ip6_sr_main_t *sm = &sr_main;
2667 vnet_main_t *vnm = vnet_get_main ();
2669 if (!unformat (input, "%U", unformat_ip6_address, &a))
2670 return clib_error_return (0, "ip6 address missing in '%U'",
2671 format_unformat_error, input);
2673 if (unformat (input, "rx-table-id %d", &fib_id))
2675 p = hash_get (im->fib_index_by_table_id, fib_id);
2677 return clib_error_return (0, "fib-id %d not found");
2681 adj_index = ip6_fib_lookup_with_table (im, fib_index, &a);
2683 if (adj_index == lm->miss_adj_index)
2684 return clib_error_return (0, "no match for %U", format_ip6_address, &a);
2686 adj = ip_get_adjacency (lm, adj_index);
2688 if (adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
2689 return clib_error_return (0, "%U unresolved (not a rewrite adj)",
2690 format_ip6_address, &a);
2692 adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
2694 sw_if_index = adj->rewrite_header.sw_if_index;
2695 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2696 adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
2698 /* $$$$$ hack... steal the mcast group index */
2699 adj->mcast_group_index =
2700 vlib_node_add_next (vm, sr_fix_dst_addr_node.index,
2701 hi->output_node_index);
2707 VLIB_CLI_COMMAND (set_ip6_sr_rewrite, static) = {
2708 .path = "set ip6 sr rewrite",
2709 .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
2710 .function = set_ip6_sr_rewrite_fn,
2715 vnet_register_sr_app_callback (void *cb)
2717 ip6_sr_main_t *sm = &sr_main;
2719 sm->sr_local_cb = cb;
2722 static clib_error_t *
2723 test_sr_hmac_validate_fn (vlib_main_t * vm,
2724 unformat_input_t * input, vlib_cli_command_t * cmd)
2726 ip6_sr_main_t *sm = &sr_main;
2728 if (unformat (input, "validate on"))
2729 sm->validate_hmac = 1;
2730 else if (unformat (input, "chunk-offset off"))
2731 sm->validate_hmac = 0;
2733 return clib_error_return (0, "expected validate on|off in '%U'",
2734 format_unformat_error, input);
2736 vlib_cli_output (vm, "hmac signature validation %s",
2737 sm->validate_hmac ? "on" : "off");
2742 VLIB_CLI_COMMAND (test_sr_hmac_validate, static) = {
2743 .path = "test sr hmac",
2744 .short_help = "test sr hmac validate [on|off]",
2745 .function = test_sr_hmac_validate_fn,
2750 sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
2754 ip6_sr_hmac_key_t *key;
2758 /* Specific key in use? Fail. */
2759 if (key_id && vec_len (sm->hmac_keys) > key_id
2760 && sm->hmac_keys[key_id].shared_secret)
2764 key = find_or_add_shared_secret (sm, shared_secret, &index);
2765 ASSERT (index == key_id);
2771 if (key_id) /* delete by key ID */
2773 if (vec_len (sm->hmac_keys) <= key_id)
2776 key = sm->hmac_keys + key_id;
2778 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2779 vec_free (key->shared_secret);
2784 key = find_or_add_shared_secret (sm, shared_secret, &index);
2785 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2786 vec_free (key->shared_secret);
2791 static clib_error_t *
2792 sr_hmac_add_del_key_fn (vlib_main_t * vm,
2793 unformat_input_t * input, vlib_cli_command_t * cmd)
2795 ip6_sr_main_t *sm = &sr_main;
2799 u8 *shared_secret = 0;
2802 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2804 if (unformat (input, "del"))
2806 else if (unformat (input, "id %d", &key_id))
2808 else if (unformat (input, "key %s", &shared_secret))
2810 /* Do not include the trailing NULL byte. Guaranteed interop issue */
2811 _vec_len (shared_secret) -= 1;
2817 if (is_del == 0 && shared_secret == 0)
2818 return clib_error_return (0, "shared secret must be set to add a key");
2820 if (shared_secret == 0 && key_id_set == 0)
2821 return clib_error_return (0, "shared secret and key id both unset");
2823 rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
2825 vec_free (shared_secret);
2833 return clib_error_return (0, "sr_hmac_add_del_key returned %d", rv);
2840 VLIB_CLI_COMMAND (sr_hmac, static) = {
2842 .short_help = "sr hmac [del] id <nn> key <str>",
2843 .function = sr_hmac_add_del_key_fn,
2848 static clib_error_t *
2849 show_sr_hmac_fn (vlib_main_t * vm,
2850 unformat_input_t * input, vlib_cli_command_t * cmd)
2852 ip6_sr_main_t *sm = &sr_main;
2855 for (i = 1; i < vec_len (sm->hmac_keys); i++)
2857 if (sm->hmac_keys[i].shared_secret)
2858 vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
2865 VLIB_CLI_COMMAND (show_sr_hmac, static) = {
2866 .path = "show sr hmac",
2867 .short_help = "show sr hmac",
2868 .function = show_sr_hmac_fn,
2872 static clib_error_t *
2873 test_sr_debug_fn (vlib_main_t * vm,
2874 unformat_input_t * input, vlib_cli_command_t * cmd)
2876 ip6_sr_main_t *sm = &sr_main;
2878 if (unformat (input, "on"))
2880 else if (unformat (input, "off"))
2883 return clib_error_return (0, "expected on|off in '%U'",
2884 format_unformat_error, input);
2886 vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
2892 VLIB_CLI_COMMAND (test_sr_debug, static) = {
2893 .path = "test sr debug",
2894 .short_help = "test sr debug on|off",
2895 .function = test_sr_debug_fn,
2900 * fd.io coding-style-patch-verification: ON
2903 * eval: (c-set-style "gnu")