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;
26 void sr_fix_hmac (ip6_sr_main_t * sm, ip6_header_t * ip,
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);
95 u8 * format_ip6_sr_header_flags (u8 * s, va_list * args)
97 u16 flags = (u16) va_arg (*args, int);
99 int bswap_needed = va_arg (*args, int);
103 flags = clib_host_to_net_u16 (flags);
105 if (flags & IP6_SR_HEADER_FLAG_CLEANUP)
106 s = format (s, "cleanup ");
108 if (flags & IP6_SR_HEADER_FLAG_PROTECTED)
109 s = format (s, "reroute ");
111 s = format (s, "pl: ");
112 for (i = 1; i <= 4; i++)
114 pl_flag = ip6_sr_policy_list_flags (flags, i);
115 s = format (s, "[%d] ", i);
119 case IP6_SR_HEADER_FLAG_PL_ELT_NOT_PRESENT:
120 s = format (s, "NotPr ");
122 case IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE:
123 s = format (s, "InPE ");
125 case IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE:
126 s = format (s, "EgPE ");
129 case IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR:
130 s = format (s, "OrgSrc ");
137 u8 * format_ip6_sr_header (u8 * s, va_list * args)
139 ip6_sr_header_t * h = va_arg (*args, ip6_sr_header_t *);
140 ip6_address_t placeholder_addr = {{254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254}};
141 int print_hmac = va_arg (*args, int);
142 int i, pl_index, max_segs;
143 int flags_host_byte_order = clib_net_to_host_u16(h->flags);
145 s = format (s, "next proto %d, len %d, type %d",
146 h->protocol, (h->length<<3)+8, h->type);
147 s = format (s, "\n segs left %d, first_segment %d, hmac key %d",
148 h->segments_left, h->first_segment, h->hmac_key);
149 s = format (s, "\n flags %U", format_ip6_sr_header_flags,
150 flags_host_byte_order, 0 /* bswap needed */ );
153 * Header length is in 8-byte units (minus one), so
154 * divide by 2 to ascertain the number of ip6 addresses in the
157 max_segs = (h->length>>1);
159 if (!print_hmac && h->hmac_key)
162 s = format (s, "\n Segments (in processing order):");
164 for (i = h->first_segment; i >= 1; i--)
165 s = format (s, "\n %U", format_ip6_address, h->segments + i);
166 if (ip6_address_is_equal(&placeholder_addr, h->segments))
167 s = format (s, "\n (empty placeholder)");
169 s = format (s, "\n %U", format_ip6_address, h->segments);
171 s = format (s, "\n Policy List:");
173 pl_index = 1; /* to match the RFC text */
174 for (i = (h->first_segment+1); i < max_segs; i++, pl_index++)
177 char * tags[] = {" ", "InPE: ", "EgPE: ", "OrgSrc: "};
180 if (pl_index >=1 && pl_index <= 4)
182 int this_pl_flag = ip6_sr_policy_list_flags
183 (flags_host_byte_order, pl_index);
184 tag = tags[this_pl_flag];
187 s = format (s, "\n %s%U", tag, format_ip6_address, h->segments + i);
193 u8 * format_ip6_sr_header_with_length (u8 * s, va_list * args)
195 ip6_header_t * h = va_arg (*args, ip6_header_t *);
196 u32 max_header_bytes = va_arg (*args, u32);
199 header_bytes = sizeof (h[0]) + sizeof (ip6_sr_header_t);
200 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
201 return format (s, "ip6_sr header truncated");
203 s = format (s, "IP6: %U\n", format_ip6_header, h, max_header_bytes);
204 s = format (s, "SR: %U\n", format_ip6_sr_header, (ip6_sr_header_t *)(h+1),
205 0 /* print_hmac */, max_header_bytes);
209 #if DPDK > 0 /* Cannot call replicate yet without DPDK */
210 #define foreach_sr_rewrite_next \
211 _(ERROR, "error-drop") \
212 _(IP6_LOOKUP, "ip6-lookup") \
213 _(SR_LOCAL, "sr-local") \
214 _(SR_REPLICATE,"sr-replicate")
216 #define foreach_sr_rewrite_next \
217 _(ERROR, "error-drop") \
218 _(IP6_LOOKUP, "ip6-lookup") \
219 _(SR_LOCAL, "sr-local")
223 #define _(s,n) SR_REWRITE_NEXT_##s,
224 foreach_sr_rewrite_next
230 ip6_address_t src, dst;
235 } sr_rewrite_trace_t;
237 static char * sr_rewrite_error_strings[] = {
238 #define sr_error(n,s) s,
239 #include "sr_error.def"
244 #define sr_error(n,s) SR_REWRITE_ERROR_##n,
245 #include "sr_error.def"
248 } sr_rewrite_error_t;
251 u8 * format_sr_rewrite_trace (u8 * s, va_list * args)
253 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
254 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
255 sr_rewrite_trace_t * t = va_arg (*args, sr_rewrite_trace_t *);
256 ip6_main_t * im = &ip6_main;
257 ip6_sr_main_t * sm = &sr_main;
258 ip6_sr_tunnel_t *tun = pool_elt_at_index (sm->tunnels, t->tunnel_index);
259 ip6_fib_t * rx_fib, * tx_fib;
261 rx_fib = find_ip6_fib_by_table_index_or_id (im, tun->rx_fib_index,
262 IP6_ROUTE_FLAG_FIB_INDEX);
264 tx_fib = find_ip6_fib_by_table_index_or_id (im, tun->tx_fib_index,
265 IP6_ROUTE_FLAG_FIB_INDEX);
268 (s, "SR-REWRITE: next %s ip6 src %U dst %U len %u\n"
269 " rx-fib-id %d tx-fib-id %d\n%U",
270 (t->next_index == SR_REWRITE_NEXT_SR_LOCAL)
271 ? "sr-local" : "ip6-lookup",
272 format_ip6_address, &t->src,
273 format_ip6_address, &t->dst, t->length,
274 rx_fib->table_id, tx_fib->table_id,
275 format_ip6_sr_header, t->sr, 0 /* print_hmac */);
280 sr_rewrite (vlib_main_t * vm,
281 vlib_node_runtime_t * node,
282 vlib_frame_t * from_frame)
284 u32 n_left_from, next_index, * from, * to_next;
285 ip6_main_t * im = &ip6_main;
286 ip_lookup_main_t * lm = &im->lookup_main;
287 ip6_sr_main_t * sm = &sr_main;
288 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
289 vlib_buffer_t *, ip6_header_t *,
291 sr_local_cb = sm->sr_local_cb;
293 from = vlib_frame_vector_args (from_frame);
294 n_left_from = from_frame->n_vectors;
296 next_index = node->cached_next_index;
298 while (n_left_from > 0)
302 vlib_get_next_frame (vm, node, next_index,
303 to_next, n_left_to_next);
305 /* Note 2x loop disabled */
306 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
309 vlib_buffer_t * b0, * b1;
310 ip6_header_t * ip0, * ip1;
311 ip_adjacency_t * adj0, * adj1;
312 ip6_sr_header_t * sr0, * sr1;
313 ip6_sr_tunnel_t * t0, *t1;
314 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
315 u32 next1 = SR_REWRITE_NEXT_IP6_LOOKUP;
319 /* Prefetch next iteration. */
321 vlib_buffer_t * p2, * p3;
323 p2 = vlib_get_buffer (vm, from[2]);
324 p3 = vlib_get_buffer (vm, from[3]);
326 vlib_prefetch_buffer_header (p2, LOAD);
327 vlib_prefetch_buffer_header (p3, LOAD);
339 b0 = vlib_get_buffer (vm, bi0);
340 b1 = vlib_get_buffer (vm, bi1);
343 * $$$ parse through header(s) to pick the point
344 * where we punch in the SR extention header
347 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
348 adj1 = ip_get_adjacency (lm, vnet_buffer(b1)->ip.adj_index[VLIB_TX]);
349 t0 = pool_elt_at_index (sm->tunnels,
350 adj0->rewrite_header.sw_if_index);
351 t1 = pool_elt_at_index (sm->tunnels,
352 adj1->rewrite_header.sw_if_index);
354 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
355 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
356 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
357 >= ((word) vec_len (t1->rewrite)) + b1->current_data);
359 vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
360 vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->tx_fib_index;
362 ip0 = vlib_buffer_get_current (b0);
363 ip1 = vlib_buffer_get_current (b1);
366 * SR-unaware service chaining case: pkt coming back from
367 * service has the original dst address, and will already
368 * have an SR header. If so, send it to sr-local
370 if (PREDICT_FALSE(ip0->protocol == IPPROTO_IPV6_ROUTE))
372 vlib_buffer_advance (b0, sizeof(ip0));
373 sr0 = (ip6_sr_header_t *) (ip0+1);
374 new_l0 = clib_net_to_host_u16(ip0->payload_length);
375 next0 = SR_REWRITE_NEXT_SR_LOCAL;
380 * Copy data before the punch-in point left by the
381 * required amount. Assume (for the moment) that only
382 * the main packet header needs to be copied.
384 clib_memcpy (((u8 *)ip0) - vec_len (t0->rewrite),
385 ip0, sizeof (ip6_header_t));
386 vlib_buffer_advance (b0, - (word) vec_len(t0->rewrite));
387 ip0 = vlib_buffer_get_current (b0);
388 sr0 = (ip6_sr_header_t *) (ip0+1);
390 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
392 /* Fix the next header chain */
393 sr0->protocol = ip0->protocol;
394 ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
395 new_l0 = clib_net_to_host_u16(ip0->payload_length) +
396 vec_len (t0->rewrite);
397 ip0->payload_length = clib_host_to_net_u16(new_l0);
399 /* Copy dst address into the DA slot in the segment list */
400 clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
401 sizeof (ip6_address_t));
402 /* Rewrite the ip6 dst address with the first hop */
403 clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
404 sizeof (ip6_address_t));
406 sr_fix_hmac (sm, ip0, sr0);
408 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
412 * Ignore "do not rewrite" shtik in this path
414 if (PREDICT_FALSE (next0 & 0x80000000))
417 if (PREDICT_FALSE(next0 == SR_REWRITE_NEXT_ERROR))
419 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
423 if (PREDICT_FALSE(ip1->protocol == IPPROTO_IPV6_ROUTE))
425 vlib_buffer_advance (b1, sizeof(ip1));
426 sr1 = (ip6_sr_header_t *) (ip1+1);
427 new_l1 = clib_net_to_host_u16(ip1->payload_length);
428 next1 = SR_REWRITE_NEXT_SR_LOCAL;
432 clib_memcpy (((u8 *)ip0) - vec_len (t0->rewrite),
433 ip0, sizeof (ip6_header_t));
434 vlib_buffer_advance (b1, - (word) vec_len(t1->rewrite));
435 ip1 = vlib_buffer_get_current (b1);
436 sr1 = (ip6_sr_header_t *) (ip1+1);
437 clib_memcpy (sr1, t1->rewrite, vec_len (t1->rewrite));
439 sr1->protocol = ip1->protocol;
440 ip1->protocol = IPPROTO_IPV6_ROUTE;
441 new_l1 = clib_net_to_host_u16(ip1->payload_length) +
442 vec_len (t1->rewrite);
443 ip1->payload_length = clib_host_to_net_u16(new_l1);
445 /* Copy dst address into the DA slot in the segment list */
446 clib_memcpy (sr1->segments, ip1->dst_address.as_u64,
447 sizeof (ip6_address_t));
448 /* Rewrite the ip6 dst address with the first hop */
449 clib_memcpy (ip1->dst_address.as_u64, t1->first_hop.as_u64,
450 sizeof (ip6_address_t));
452 sr_fix_hmac (sm, ip1, sr1);
454 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
458 * Ignore "do not rewrite" shtik in this path
460 if (PREDICT_FALSE (next1 & 0x80000000))
463 if (PREDICT_FALSE(next1 == SR_REWRITE_NEXT_ERROR))
465 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
469 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
471 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
473 tr->tunnel_index = t0 - sm->tunnels;
474 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
475 sizeof (tr->src.as_u8));
476 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
477 sizeof (tr->dst.as_u8));
479 tr->next_index = next0;
480 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
482 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
484 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
486 tr->tunnel_index = t1 - sm->tunnels;
487 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
488 sizeof (tr->src.as_u8));
489 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
490 sizeof (tr->dst.as_u8));
492 tr->next_index = next1;
493 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
496 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
497 to_next, n_left_to_next,
498 bi0, bi1, next0, next1);
501 while (n_left_from > 0 && n_left_to_next > 0)
505 ip6_header_t * ip0 = 0;
506 ip_adjacency_t * adj0;
507 ip6_sr_header_t * sr0 = 0;
508 ip6_sr_tunnel_t * t0;
509 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
519 b0 = vlib_get_buffer (vm, bi0);
522 * $$$ parse through header(s) to pick the point
523 * where we punch in the SR extention header
526 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
527 t0 = pool_elt_at_index (sm->tunnels,
528 adj0->rewrite_header.sw_if_index);
530 #if DPDK > 0 /* Cannot call replication node yet without DPDK */
531 /* add a replication node */
532 if(PREDICT_FALSE(t0->policy_index != ~0))
534 vnet_buffer(b0)->ip.save_protocol = t0->policy_index;
535 next0=SR_REWRITE_NEXT_SR_REPLICATE;
540 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
541 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
543 vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
545 ip0 = vlib_buffer_get_current (b0);
548 * SR-unaware service chaining case: pkt coming back from
549 * service has the original dst address, and will already
550 * have an SR header. If so, send it to sr-local
552 if (PREDICT_FALSE(ip0->protocol == IPPROTO_IPV6_ROUTE))
554 vlib_buffer_advance (b0, sizeof(ip0));
555 sr0 = (ip6_sr_header_t *) (ip0+1);
556 new_l0 = clib_net_to_host_u16(ip0->payload_length);
557 next0 = SR_REWRITE_NEXT_SR_LOCAL;
562 * Copy data before the punch-in point left by the
563 * required amount. Assume (for the moment) that only
564 * the main packet header needs to be copied.
566 clib_memcpy (((u8 *)ip0) - vec_len (t0->rewrite),
567 ip0, sizeof (ip6_header_t));
568 vlib_buffer_advance (b0, - (word) vec_len(t0->rewrite));
569 ip0 = vlib_buffer_get_current (b0);
570 sr0 = (ip6_sr_header_t *) (ip0+1);
572 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
574 /* Fix the next header chain */
575 sr0->protocol = ip0->protocol;
576 ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
577 new_l0 = clib_net_to_host_u16(ip0->payload_length) +
578 vec_len (t0->rewrite);
579 ip0->payload_length = clib_host_to_net_u16(new_l0);
581 /* Copy dst address into the DA slot in the segment list */
582 clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
583 sizeof (ip6_address_t));
584 /* Rewrite the ip6 dst address with the first hop */
585 clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
586 sizeof (ip6_address_t));
588 sr_fix_hmac (sm, ip0, sr0);
590 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
594 * Ignore "do not rewrite" shtik in this path
596 if (PREDICT_FALSE (next0 & 0x80000000))
599 if (PREDICT_FALSE(next0 == SR_REWRITE_NEXT_ERROR))
601 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
605 #if DPDK > 0 /* Cannot run replicate without DPDK and only replicate uses this label */
608 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
610 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
612 tr->tunnel_index = t0 - sm->tunnels;
615 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
616 sizeof (tr->src.as_u8));
617 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
618 sizeof (tr->dst.as_u8));
621 tr->next_index = next0;
622 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
625 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
626 to_next, n_left_to_next,
630 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
632 return from_frame->n_vectors;
635 VLIB_REGISTER_NODE (sr_rewrite_node) = {
636 .function = sr_rewrite,
637 .name = "sr-rewrite",
638 /* Takes a vector of packets. */
639 .vector_size = sizeof (u32),
640 .format_trace = format_sr_rewrite_trace,
641 .format_buffer = format_ip6_sr_header_with_length,
643 .n_errors = SR_REWRITE_N_ERROR,
644 .error_strings = sr_rewrite_error_strings,
646 .runtime_data_bytes = 0,
648 .n_next_nodes = SR_REWRITE_N_NEXT,
650 #define _(s,n) [SR_REWRITE_NEXT_##s] = n,
651 foreach_sr_rewrite_next
656 VLIB_NODE_FUNCTION_MULTIARCH (sr_rewrite_node, sr_rewrite)
658 static int ip6_delete_route_no_next_hop (ip6_address_t *dst_address_arg,
659 u32 dst_address_length,
662 ip6_add_del_route_args_t a;
663 ip6_address_t dst_address;
665 ip6_main_t * im6 = &ip6_main;
666 BVT(clib_bihash_kv) kv, value;
668 fib = find_ip6_fib_by_table_index_or_id (im6, rx_table_id,
669 IP6_ROUTE_FLAG_TABLE_ID);
670 memset (&a, 0, sizeof (a));
671 a.flags |= IP4_ROUTE_FLAG_DEL;
672 a.dst_address_length = dst_address_length;
674 dst_address = *dst_address_arg;
676 ip6_address_mask (&dst_address,
677 &im6->fib_masks[dst_address_length]);
679 kv.key[0] = dst_address.as_u64[0];
680 kv.key[1] = dst_address.as_u64[1];
681 kv.key[2] = ((u64)((fib - im6->fibs))<<32) | dst_address_length;
683 if (BV(clib_bihash_search)(&im6->ip6_lookup_table, &kv, &value) < 0)
685 clib_warning ("%U/%d not in FIB",
686 format_ip6_address, &a.dst_address,
687 a.dst_address_length);
691 a.adj_index = value.value;
692 a.dst_address = dst_address;
694 ip6_add_del_route (im6, &a);
695 ip6_maybe_remap_adjacencies (im6, rx_table_id, IP6_ROUTE_FLAG_TABLE_ID);
699 static ip6_sr_hmac_key_t *
700 find_or_add_shared_secret (ip6_sr_main_t * sm, u8 * secret, u32 * indexp)
703 ip6_sr_hmac_key_t * key = 0;
706 p = hash_get_mem (sm->hmac_key_by_shared_secret, secret);
710 key = vec_elt_at_index (sm->hmac_keys, p[0]);
716 /* Specific key ID? */
717 if (indexp && *indexp)
719 vec_validate (sm->hmac_keys, *indexp);
720 key = sm->hmac_keys + *indexp;
724 for (i = 0; i < vec_len (sm->hmac_keys); i++)
726 if (sm->hmac_keys[i].shared_secret == 0)
727 key = sm->hmac_keys + i;
730 vec_validate (sm->hmac_keys, i);
731 key = sm->hmac_keys + i;
736 key->shared_secret = vec_dup (secret);
738 hash_set_mem (sm->hmac_key_by_shared_secret, key->shared_secret,
739 key - sm->hmac_keys);
742 *indexp = key - sm->hmac_keys;
747 int ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
749 ip6_main_t * im = &ip6_main;
750 ip_lookup_main_t * lm = &im->lookup_main;
751 ip6_sr_tunnel_key_t key;
754 ip6_sr_header_t * h = 0;
756 ip6_address_t * addrp, *this_address;
757 ip_adjacency_t adj, * ap, * add_adj = 0;
759 ip6_sr_main_t * sm = &sr_main;
761 u32 rx_fib_index, tx_fib_index;
762 ip6_add_del_route_args_t aa;
763 u32 hmac_key_index_u32;
764 u8 hmac_key_index = 0;
765 ip6_sr_policy_t * pt;
768 /* Make sure that the rx FIB exists */
769 p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
774 /* remember the FIB index */
777 /* Make sure that the supplied FIB exists */
778 p = hash_get (im->fib_index_by_table_id, a->tx_table_id);
783 /* remember the FIB index */
786 clib_memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
787 clib_memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
789 /* When adding a tunnel:
790 * - If a "name" is given, it must not exist.
791 * - The "key" is always checked, and must not exist.
792 * When deleting a tunnel:
793 * - If the "name" is given, and it exists, then use it.
794 * - If the "name" is not given, use the "key".
795 * - If the "name" and the "key" are given, then both must point to the same
800 p = hash_get_mem (sm->tunnel_index_by_key, &key);
802 /* If the name is given, look it up */
804 n = hash_get_mem(sm->tunnel_index_by_name, a->name);
808 /* validate key/name parameters */
809 if (!a->is_del) /* adding a tunnel */
811 if (a->name && n) /* name given & exists already */
813 if (p) /* key exists already */
816 else /* deleting a tunnel */
818 if (!p) /* key doesn't exist */
820 if (a->name && !n) /* name given & it doesn't exist */
823 if (n) /* name given & found */
825 if (n[0] != p[0]) /* name and key do not point to the same thing */
831 if (a->is_del) /* delete the tunnel */
835 /* Delete existing tunnel */
836 t = pool_elt_at_index (sm->tunnels, p[0]);
838 ip6_delete_route_no_next_hop (&t->key.dst, t->dst_mask_width,
840 vec_free (t->rewrite);
841 /* Remove tunnel from any policy if associated */
842 if (t->policy_index != ~0)
844 pt=pool_elt_at_index (sm->policies, t->policy_index);
845 for (i=0; i< vec_len (pt->tunnel_indices); i++)
847 if (pt->tunnel_indices[i] == t - sm->tunnels)
849 vec_delete (pt->tunnel_indices, 1, i);
853 clib_warning ("Tunnel index %d not found in policy_index %d",
854 t - sm->tunnels, pt - sm->policies);
856 /* If this is last tunnel in the policy, clean up the policy too */
857 if (vec_len (pt->tunnel_indices) == 0)
859 hash_unset_mem (sm->policy_index_by_policy_name, pt->name);
861 pool_put (sm->policies, pt);
865 /* Clean up the tunnel by name */
868 hash_unset_mem (sm->tunnel_index_by_name, t->name);
871 pool_put (sm->tunnels, t);
872 hp = hash_get_pair (sm->tunnel_index_by_key, &key);
873 key_copy = (void *)(hp->key);
874 hash_unset_mem (sm->tunnel_index_by_key, &key);
879 /* create a new tunnel */
880 pool_get (sm->tunnels, t);
881 memset (t, 0, sizeof (*t));
882 t->policy_index = ~0;
884 clib_memcpy (&t->key, &key, sizeof (t->key));
885 t->dst_mask_width = a->dst_mask_width;
886 t->rx_fib_index = rx_fib_index;
887 t->tx_fib_index = tx_fib_index;
889 if (!vec_len (a->segments))
890 /* there must be at least one segment... */
893 /* The first specified hop goes right into the dst address */
894 clib_memcpy(&t->first_hop, &a->segments[0], sizeof (ip6_address_t));
897 * Create the sr header rewrite string
898 * The list of segments needs an extra slot for the ultimate destination
899 * which is taken from the packet we add the SRH to.
901 header_length = sizeof (*h) +
902 sizeof (ip6_address_t) * (vec_len (a->segments) + 1 + vec_len (a->tags));
904 if (a->shared_secret)
906 /* Allocate a new key slot if we don't find the secret key */
907 hmac_key_index_u32 = 0;
908 (void) find_or_add_shared_secret (sm, a->shared_secret,
909 &hmac_key_index_u32);
911 /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
912 if (hmac_key_index_u32 >= 256)
914 hmac_key_index = hmac_key_index_u32;
915 header_length += SHA256_DIGEST_LENGTH;
918 vec_validate (t->rewrite, header_length-1);
920 h = (ip6_sr_header_t *) t->rewrite;
922 h->protocol = 0xFF; /* we don't know yet */
924 h->length = (header_length/8) - 1;
925 h->type = ROUTING_HEADER_TYPE_SR;
927 /* first_segment and segments_left need to have the index of the last
928 * element in the list; a->segments has one element less than ends up
929 * in the header (it does not have the DA in it), so vec_len(a->segments)
930 * is the value we want.
932 h->first_segment = h->segments_left = vec_len (a->segments);
934 if (a->shared_secret)
935 h->hmac_key = hmac_key_index & 0xFF;
937 h->flags = a->flags_net_byte_order;
939 /* Paint on the segment list, in reverse.
940 * This is offset by one to leave room at the start for the ultimate
943 addrp = h->segments + vec_len (a->segments);
945 vec_foreach (this_address, a->segments)
947 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
952 * Since the ultimate destination address is not yet known, set that slot
953 * to a value we will instantly recognize as bogus.
955 memset (h->segments, 0xfe, sizeof (ip6_address_t));
957 /* Paint on the tag list, not reversed */
958 addrp = h->segments + vec_len(a->segments);
960 vec_foreach (this_address, a->tags)
962 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
966 key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
967 clib_memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
968 hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
970 memset(&adj, 0, sizeof (adj));
972 /* Create an adjacency and add to v6 fib */
973 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
974 adj.lookup_next_index = sm->ip6_lookup_sr_next_index;
975 adj.explicit_fib_index = ~0;
977 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */,
981 * Stick the tunnel index into the rewrite header.
983 * Unfortunately, inserting an SR header according to the various
984 * RFC's requires parsing through the ip6 header, perhaps consing a
985 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
986 * normal reverse bcopy rewrite code.
988 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
991 ap->rewrite_header.sw_if_index = t - sm->tunnels;
993 vec_add1 (add_adj, ap[0]);
995 clib_memcpy (aa.dst_address.as_u8, a->dst_address, sizeof (aa.dst_address.as_u8));
996 aa.dst_address_length = a->dst_mask_width;
998 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
999 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1000 aa.table_index_or_table_id = rx_fib_index;
1001 aa.add_adj = add_adj;
1002 aa.adj_index = adj_index;
1004 ip6_add_del_route (im, &aa);
1009 p=hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1012 pt = pool_elt_at_index (sm->policies, p[0]);
1014 else /* no policy, lets create one */
1016 pool_get (sm->policies, pt);
1017 memset (pt, 0, sizeof(*pt));
1018 pt->name = format (0, "%s%c", a->policy_name, 0);
1019 hash_set_mem (sm->policy_index_by_policy_name, pt->name, pt - sm->policies);
1020 p=hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1022 vec_add1 (pt->tunnel_indices, t - sm->tunnels);
1023 t->policy_index = p[0]; /* equiv. to (pt - sm->policies) */
1028 t->name = format (0, "%s%c", a->name, 0);
1029 hash_set_mem(sm->tunnel_index_by_name, t->name, t - sm->tunnels);
1035 static clib_error_t *
1036 sr_add_del_tunnel_command_fn (vlib_main_t * vm,
1037 unformat_input_t * input,
1038 vlib_cli_command_t * cmd)
1041 ip6_address_t src_address;
1042 int src_address_set = 0;
1043 ip6_address_t dst_address;
1045 int dst_address_set = 0;
1047 u8 *shared_secret = 0;
1049 u8 *policy_name = 0;
1050 u32 rx_table_id = 0;
1051 u32 tx_table_id = 0;
1052 ip6_address_t * segments = 0;
1053 ip6_address_t * this_seg;
1054 ip6_address_t * tags = 0;
1055 ip6_address_t * this_tag;
1056 ip6_sr_add_del_tunnel_args_t _a, *a=&_a;
1057 ip6_address_t next_address, tag;
1061 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1063 if (unformat (input, "del"))
1065 else if (unformat (input, "rx-fib-id %d", &rx_table_id))
1067 else if (unformat (input, "tx-fib-id %d", &tx_table_id))
1069 else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
1070 src_address_set = 1;
1071 else if (unformat (input, "name %s", &name))
1073 else if (unformat (input, "policy %s", &policy_name))
1075 else if (unformat (input, "dst %U/%d",
1076 unformat_ip6_address, &dst_address,
1078 dst_address_set = 1;
1079 else if (unformat (input, "next %U", unformat_ip6_address,
1082 vec_add2 (segments, this_seg, 1);
1083 clib_memcpy (this_seg->as_u8, next_address.as_u8, sizeof (*this_seg));
1085 else if (unformat (input, "tag %U", unformat_ip6_address,
1088 vec_add2 (tags, this_tag, 1);
1089 clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
1091 else if (unformat (input, "clean"))
1092 flags |= IP6_SR_HEADER_FLAG_CLEANUP;
1093 else if (unformat (input, "protected"))
1094 flags |= IP6_SR_HEADER_FLAG_PROTECTED;
1095 else if (unformat (input, "key %s", &shared_secret))
1096 /* Do not include the trailing NULL byte. Guaranteed interop issue */
1097 _vec_len (shared_secret) -= 1;
1098 else if (unformat (input, "InPE %d", &pl_index))
1100 if (pl_index <= 0 || pl_index > 4)
1102 pl_index_range_error:
1103 return clib_error_return
1104 (0, "Policy List Element Index %d out of range (1-4)", pl_index);
1107 flags |= IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
1108 << ip6_sr_policy_list_shift_from_index (pl_index);
1110 else if (unformat (input, "EgPE %d", &pl_index))
1112 if (pl_index <= 0 || pl_index > 4)
1113 goto pl_index_range_error;
1114 flags |= IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
1115 << ip6_sr_policy_list_shift_from_index (pl_index);
1117 else if (unformat (input, "OrgSrc %d", &pl_index))
1119 if (pl_index <= 0 || pl_index > 4)
1120 goto pl_index_range_error;
1121 flags |= IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
1122 << ip6_sr_policy_list_shift_from_index (pl_index);
1128 if (!src_address_set)
1129 return clib_error_return (0, "src address required");
1131 if (!dst_address_set)
1132 return clib_error_return (0, "dst address required");
1135 return clib_error_return (0, "at least one sr segment required");
1137 memset (a, 0, sizeof (*a));
1138 a->src_address = &src_address;
1139 a->dst_address = &dst_address;
1140 a->dst_mask_width = dst_mask_width;
1141 a->segments = segments;
1143 a->flags_net_byte_order = clib_host_to_net_u16(flags);
1145 a->rx_table_id = rx_table_id;
1146 a->tx_table_id = tx_table_id;
1147 a->shared_secret = shared_secret;
1154 if (vec_len(policy_name))
1155 a->policy_name = policy_name;
1159 rv = ip6_sr_add_del_tunnel (a);
1161 vec_free (segments);
1163 vec_free (shared_secret);
1171 return clib_error_return (0, "SR tunnel src %U dst %U already exists",
1172 format_ip6_address, &src_address,
1173 format_ip6_address, &dst_address);
1176 return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
1177 format_ip6_address, &src_address,
1178 format_ip6_address, &dst_address);
1181 return clib_error_return (0, "FIB table %d does not exist", rx_table_id);
1184 return clib_error_return (0, "At least one segment is required");
1187 return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
1194 VLIB_CLI_COMMAND (sr_tunnel_command, static) = {
1195 .path = "sr tunnel",
1197 "sr tunnel [del] [name <name>] src <addr> dst <addr> [next <addr>] "
1198 "[clean] [reroute] [key <secret>] [policy <policy_name>]"
1199 "[rx-fib-id <fib_id>] [tx-fib-id <fib_id>]",
1200 .function = sr_add_del_tunnel_command_fn,
1204 ip6_sr_tunnel_display (vlib_main_t * vm,
1205 ip6_sr_tunnel_t * t)
1207 ip6_main_t * im = &ip6_main;
1208 ip6_sr_main_t * sm = &sr_main;
1209 ip6_fib_t * rx_fib, * tx_fib;
1210 ip6_sr_policy_t * pt;
1212 rx_fib = find_ip6_fib_by_table_index_or_id (im, t->rx_fib_index,
1213 IP6_ROUTE_FLAG_FIB_INDEX);
1215 tx_fib = find_ip6_fib_by_table_index_or_id (im, t->tx_fib_index,
1216 IP6_ROUTE_FLAG_FIB_INDEX);
1219 vlib_cli_output (vm,"sr tunnel name: %s", (char *)t->name);
1221 vlib_cli_output (vm, "src %U dst %U first hop %U",
1222 format_ip6_address, &t->key.src,
1223 format_ip6_address, &t->key.dst,
1224 format_ip6_address, &t->first_hop);
1225 vlib_cli_output (vm, " rx-fib-id %d tx-fib-id %d",
1226 rx_fib->table_id, tx_fib->table_id);
1227 vlib_cli_output (vm, " sr: %U", format_ip6_sr_header, t->rewrite,
1228 0 /* print_hmac */);
1230 if (t->policy_index != ~0)
1232 pt=pool_elt_at_index(sm->policies, t->policy_index);
1233 vlib_cli_output (vm,"sr policy: %s", (char *)pt->name);
1235 vlib_cli_output (vm, "-------");
1240 static clib_error_t *
1241 show_sr_tunnel_fn (vlib_main_t * vm,
1242 unformat_input_t * input,
1243 vlib_cli_command_t * cmd)
1245 static ip6_sr_tunnel_t ** tunnels;
1246 ip6_sr_tunnel_t * t;
1247 ip6_sr_main_t * sm = &sr_main;
1252 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1254 if (unformat (input, "name %s", &name))
1256 p=hash_get_mem (sm->tunnel_index_by_name, name);
1258 vlib_cli_output (vm, "No SR tunnel with name: %s. Showing all.", name);
1264 vec_reset_length (tunnels);
1266 if(!p) /* Either name parm not passed or no tunnel with that name found, show all */
1268 pool_foreach (t, sm->tunnels,
1270 vec_add1 (tunnels, t);
1273 else /* Just show the one tunnel by name */
1274 vec_add1 (tunnels, &sm->tunnels[p[0]]);
1276 if (vec_len (tunnels) == 0)
1277 vlib_cli_output (vm, "No SR tunnels configured");
1279 for (i = 0; i < vec_len (tunnels); i++)
1282 ip6_sr_tunnel_display (vm, t);
1288 VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
1289 .path = "show sr tunnel",
1290 .short_help = "show sr tunnel [name <sr-tunnel-name>]",
1291 .function = show_sr_tunnel_fn,
1294 int ip6_sr_add_del_policy (ip6_sr_add_del_policy_args_t * a)
1296 ip6_sr_main_t * sm = &sr_main;
1298 ip6_sr_tunnel_t * t = 0;
1299 ip6_sr_policy_t * policy;
1300 u32 * tunnel_indices = 0;
1307 p=hash_get_mem (sm->policy_index_by_policy_name, a->name);
1309 return -6; /* policy name not found */
1311 policy = pool_elt_at_index(sm->policies, p[0]);
1313 vec_foreach_index (i, policy->tunnel_indices)
1315 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1316 t->policy_index = ~0;
1318 hash_unset_mem (sm->policy_index_by_policy_name, a->name);
1319 pool_put (sm->policies, policy);
1324 if (!vec_len(a->tunnel_names))
1325 return -3; /*tunnel name is required case */
1327 vec_reset_length (tunnel_indices);
1328 /* Check tunnel names, add tunnel_index to policy */
1329 for (i=0; i < vec_len (a->tunnel_names); i++)
1331 p = hash_get_mem (sm->tunnel_index_by_name, a->tunnel_names[i]);
1333 return -4; /* tunnel name not found case */
1335 t = pool_elt_at_index (sm->tunnels, p[0]);
1337 No need to check t==0. -3 condition above ensures name
1339 if (t->policy_index != ~0)
1340 return -5; /* tunnel name already associated with a policy */
1342 /* Add to tunnel indicies */
1343 vec_add1 (tunnel_indices, p[0]);
1346 /* Add policy to ip6_sr_main_t */
1347 pool_get (sm->policies, policy);
1348 policy->name = a->name;
1349 policy->tunnel_indices = tunnel_indices;
1350 hash_set_mem (sm->policy_index_by_policy_name, policy->name, policy - sm->policies);
1352 /* Yes, this could be construed as overkill but the last thing you should do is set
1353 the policy_index on the tunnel after everything is set in ip6_sr_main_t.
1354 If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop.
1356 for (i=0; i < vec_len(policy->tunnel_indices); i++)
1358 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1359 t->policy_index = policy - sm->policies;
1366 static clib_error_t *
1367 sr_add_del_policy_command_fn (vlib_main_t * vm,
1368 unformat_input_t * input,
1369 vlib_cli_command_t * cmd)
1372 u8 ** tunnel_names = 0;
1373 u8 * tunnel_name = 0;
1375 ip6_sr_add_del_policy_args_t _a, *a=&_a;
1378 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1380 if (unformat (input, "del"))
1382 else if (unformat (input, "name %s", &name))
1384 else if (unformat (input, "tunnel %s", &tunnel_name))
1388 vec_add1 (tunnel_names, tunnel_name);
1397 return clib_error_return (0, "name of SR policy required");
1400 memset(a, 0, sizeof(*a));
1404 a->tunnel_names = tunnel_names;
1406 rv = ip6_sr_add_del_policy (a);
1408 vec_free(tunnel_names);
1416 return clib_error_return (0, "tunnel name to associate to SR policy is required");
1419 return clib_error_return (0, "tunnel name not found");
1422 return clib_error_return (0, "tunnel already associated with policy");
1425 return clib_error_return (0, "policy name %s not found", name);
1428 return clib_error_return (0, "TODO: deleting policy name %s", name);
1431 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d", rv);
1437 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1438 .path = "sr policy",
1440 "sr policy [del] name <policy-name> tunnel <sr-tunnel-name> [tunnel <sr-tunnel-name>]*",
1441 .function = sr_add_del_policy_command_fn,
1444 static clib_error_t *
1445 show_sr_policy_fn (vlib_main_t * vm,
1446 unformat_input_t * input,
1447 vlib_cli_command_t * cmd)
1449 static ip6_sr_policy_t ** policies;
1450 ip6_sr_policy_t * policy;
1451 ip6_sr_tunnel_t * t;
1452 ip6_sr_main_t * sm = &sr_main;
1457 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1459 if (unformat (input, "name %s", &name))
1461 p=hash_get_mem (sm->policy_index_by_policy_name, name);
1463 vlib_cli_output (vm, "policy with name %s not found. Showing all.", name);
1469 vec_reset_length (policies);
1471 if(!p) /* Either name parm not passed or no policy with that name found, show all */
1473 pool_foreach (policy, sm->policies,
1475 vec_add1 (policies, policy);
1478 else /* Just show the one policy by name and a summary of tunnel names */
1480 policy = pool_elt_at_index(sm->policies, p[0]);
1481 vec_add1 (policies, policy);
1484 if (vec_len (policies) == 0)
1485 vlib_cli_output (vm, "No SR policies configured");
1487 for (i = 0; i < vec_len (policies); i++)
1489 policy = policies [i];
1492 vlib_cli_output (vm,"SR policy name: %s", (char *)policy->name);
1493 for(j = 0; j < vec_len (policy->tunnel_indices); j++)
1495 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[j]);
1496 ip6_sr_tunnel_display (vm, t);
1504 VLIB_CLI_COMMAND (show_sr_policy_command, static) = {
1505 .path = "show sr policy",
1506 .short_help = "show sr policy [name <sr-policy-name>]",
1507 .function = show_sr_policy_fn,
1510 int ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a)
1513 ip6_main_t * im = &ip6_main;
1514 ip_lookup_main_t * lm = &im->lookup_main;
1515 ip6_sr_tunnel_t * t;
1516 ip_adjacency_t adj, * ap, * add_adj = 0;
1518 ip6_sr_main_t * sm = &sr_main;
1519 ip6_add_del_route_args_t aa;
1520 ip6_sr_policy_t * pt;
1524 /* clean up the adjacency */
1525 p = hash_get_mem (sm->policy_index_by_multicast_address, a->multicast_address);
1529 /* Get our policy by policy_name */
1530 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1536 pt=pool_elt_at_index (sm->policies, p[0]);
1539 Get the first tunnel associated with policy populate the fib adjacency.
1540 From there, since this tunnel will have it's policy_index != ~0 it will
1541 be the trigger in the dual_loop to pull up the policy and make a copy-rewrite
1542 for each tunnel in the policy
1545 t = pool_elt_at_index (sm->tunnels, pt->tunnel_indices[0]);
1547 /* Construct a FIB entry for multicast using the rx/tx fib from the first tunnel */
1548 memset(&adj, 0, sizeof (adj));
1550 /* Create an adjacency and add to v6 fib */
1551 adj.lookup_next_index = sm->ip6_lookup_sr_replicate_index;
1552 adj.explicit_fib_index = ~0;
1554 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */,
1558 * Stick the tunnel index into the rewrite header.
1560 * Unfortunately, inserting an SR header according to the various
1561 * RFC's requires parsing through the ip6 header, perhaps consing a
1562 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1563 * normal reverse bcopy rewrite code.
1565 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1568 ap->rewrite_header.sw_if_index = t - sm->tunnels;
1570 vec_add1 (add_adj, ap[0]);
1572 memcpy (aa.dst_address.as_u8, a->multicast_address, sizeof (aa.dst_address.as_u8));
1573 aa.dst_address_length = 128;
1575 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1576 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1577 aa.table_index_or_table_id = t->rx_fib_index;
1578 aa.add_adj = add_adj;
1579 aa.adj_index = adj_index;
1581 ip6_add_del_route (im, &aa);
1584 u8 * mcast_copy = 0;
1585 mcast_copy = vec_new (ip6_address_t, 1);
1586 memcpy (mcast_copy, a->multicast_address, sizeof (ip6_address_t));
1590 hash_unset_mem (sm->policy_index_by_multicast_address, mcast_copy);
1591 vec_free (mcast_copy);
1596 hash_set_mem (sm->policy_index_by_multicast_address, mcast_copy, pt - sm->policies);
1602 static clib_error_t *
1603 sr_add_del_multicast_map_command_fn (vlib_main_t * vm,
1604 unformat_input_t * input,
1605 vlib_cli_command_t * cmd)
1608 ip6_address_t multicast_address;
1609 u8 * policy_name = 0;
1610 int multicast_address_set = 0;
1611 ip6_sr_add_del_multicastmap_args_t _a, *a=&_a;
1614 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1616 if (unformat (input, "del"))
1618 else if (unformat (input, "address %U", unformat_ip6_address, &multicast_address))
1619 multicast_address_set = 1;
1620 else if (unformat (input, "sr-policy %s", &policy_name))
1626 if (!is_del && !policy_name)
1627 return clib_error_return (0, "name of sr policy required");
1629 if (!multicast_address_set)
1630 return clib_error_return (0, "multicast address required");
1632 memset(a, 0, sizeof(*a));
1635 a->multicast_address = &multicast_address;
1636 a->policy_name = policy_name;
1638 #if DPDK > 0 /*Cannot call replicate or configure multicast map yet without DPDK */
1639 rv = ip6_sr_add_del_multicastmap (a);
1641 return clib_error_return (0, "cannot use multicast replicate spray case without DPDK installed");
1649 return clib_error_return (0, "no policy with name: %s", policy_name);
1652 return clib_error_return (0, "multicast map someting ");
1655 return clib_error_return (0, "tunnel name to associate to SR policy is required");
1658 return clib_error_return (0, "TODO: deleting policy name %s", policy_name);
1661 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d", rv);
1669 VLIB_CLI_COMMAND (sr_multicast_map_command, static) = {
1670 .path = "sr multicast-map",
1672 "sr multicast-map address <multicast-ip6-address> sr-policy <sr-policy-name> [del]",
1673 .function = sr_add_del_multicast_map_command_fn,
1676 static clib_error_t *
1677 show_sr_multicast_map_fn (vlib_main_t * vm,
1678 unformat_input_t * input,
1679 vlib_cli_command_t * cmd)
1681 ip6_sr_main_t * sm = &sr_main;
1684 ip6_address_t multicast_address;
1685 ip6_sr_policy_t * pt ;
1687 /* pull all entries from the hash table into vector for display */
1689 hash_foreach_mem (key, value, sm->policy_index_by_multicast_address,
1692 vlib_cli_output (vm, "no multicast maps configured");
1695 multicast_address = *((ip6_address_t *)key);
1696 pt = pool_elt_at_index (sm->policies, value);
1699 vlib_cli_output (vm, "address: %U policy: %s",
1700 format_ip6_address, &multicast_address,
1704 vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d",
1705 format_ip6_address, &multicast_address,
1715 VLIB_CLI_COMMAND (show_sr_multicast_map_command, static) = {
1716 .path = "show sr multicast-map",
1717 .short_help = "show sr multicast-map",
1718 .function = show_sr_multicast_map_fn,
1722 #define foreach_sr_fix_dst_addr_next \
1723 _(DROP, "error-drop")
1726 #define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
1727 foreach_sr_fix_dst_addr_next
1729 SR_FIX_DST_ADDR_N_NEXT,
1730 } sr_fix_dst_addr_next_t;
1732 static char * sr_fix_dst_error_strings[] = {
1733 #define sr_fix_dst_error(n,s) s,
1734 #include "sr_fix_dst_error.def"
1735 #undef sr_fix_dst_error
1739 #define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
1740 #include "sr_fix_dst_error.def"
1741 #undef sr_fix_dst_error
1743 } sr_fix_dst_error_t;
1746 ip6_address_t src, dst;
1750 } sr_fix_addr_trace_t;
1752 u8 * format_sr_fix_addr_trace (u8 * s, va_list * args)
1754 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1755 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1756 sr_fix_addr_trace_t * t = va_arg (*args, sr_fix_addr_trace_t *);
1757 vnet_hw_interface_t * hi = 0;
1758 ip_adjacency_t * adj;
1759 ip6_main_t * im = &ip6_main;
1760 ip_lookup_main_t * lm = &im->lookup_main;
1761 vnet_main_t * vnm = vnet_get_main();
1763 if (t->adj_index != ~0)
1765 adj = ip_get_adjacency (lm, t->adj_index);
1766 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
1769 s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
1770 (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
1771 ? "drop" : "output",
1772 format_ip6_address, &t->src,
1773 format_ip6_address, &t->dst);
1774 if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
1776 s = format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
1777 s = format (s, " output via %s", hi ? (char *)(hi->name)
1784 sr_fix_dst_addr (vlib_main_t * vm,
1785 vlib_node_runtime_t * node,
1786 vlib_frame_t * from_frame)
1788 u32 n_left_from, next_index, * from, * to_next;
1789 ip6_main_t * im = &ip6_main;
1790 ip_lookup_main_t * lm = &im->lookup_main;
1792 from = vlib_frame_vector_args (from_frame);
1793 n_left_from = from_frame->n_vectors;
1795 next_index = node->cached_next_index;
1797 while (n_left_from > 0)
1801 vlib_get_next_frame (vm, node, next_index,
1802 to_next, n_left_to_next);
1805 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
1808 __attribute__((unused)) vlib_buffer_t * b0, * b1;
1809 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1810 u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
1812 /* Prefetch next iteration. */
1814 vlib_buffer_t * p2, * p3;
1816 p2 = vlib_get_buffer (vm, from[2]);
1817 p3 = vlib_get_buffer (vm, from[3]);
1819 vlib_prefetch_buffer_header (p2, LOAD);
1820 vlib_prefetch_buffer_header (p3, LOAD);
1829 n_left_to_next -= 2;
1832 b0 = vlib_get_buffer (vm, bi0);
1833 b1 = vlib_get_buffer (vm, bi1);
1836 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1837 to_next, n_left_to_next,
1838 bi0, bi1, next0, next1);
1842 while (n_left_from > 0 && n_left_to_next > 0)
1847 ip_adjacency_t * adj0;
1848 ip6_sr_header_t * sr0;
1849 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1850 ip6_address_t *new_dst0;
1851 ethernet_header_t * eh0;
1858 n_left_to_next -= 1;
1860 b0 = vlib_get_buffer (vm, bi0);
1862 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
1863 next0 = adj0->mcast_group_index;
1865 /* We should be pointing at an Ethernet header... */
1866 eh0 = vlib_buffer_get_current (b0);
1867 ip0 = (ip6_header_t *)(eh0+1);
1868 sr0 = (ip6_sr_header_t *) (ip0+1);
1870 /* We'd better find an SR header... */
1871 if (PREDICT_FALSE(ip0->protocol != IPPROTO_IPV6_ROUTE))
1873 b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
1879 * We get here from sr_rewrite or sr_local, with
1880 * sr->segments_left pointing at the (copy of the original) dst
1881 * address. Use it, then increment sr0->segments_left.
1884 /* Out of segments? Turf the packet */
1885 if (PREDICT_FALSE (sr0->segments_left == 0))
1887 b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
1892 * Rewrite the packet with the original dst address
1893 * We assume that the last segment (in processing order) contains
1894 * the original dst address. The list is reversed, so sr0->segments
1895 * contains the original dst address.
1897 new_dst0 = sr0->segments;
1898 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1899 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1904 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1906 sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
1908 t->next_index = next0;
1911 if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
1913 t->adj_index = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
1914 clib_memcpy (t->src.as_u8, ip0->src_address.as_u8,
1915 sizeof (t->src.as_u8));
1916 clib_memcpy (t->dst.as_u8, ip0->dst_address.as_u8,
1917 sizeof (t->dst.as_u8));
1918 clib_memcpy (t->sr, sr0, sizeof (t->sr));
1922 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1923 to_next, n_left_to_next,
1927 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1929 return from_frame->n_vectors;
1933 VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
1934 .function = sr_fix_dst_addr,
1935 .name = "sr-fix-dst-addr",
1936 /* Takes a vector of packets. */
1937 .vector_size = sizeof (u32),
1938 .format_trace = format_sr_fix_addr_trace,
1939 .format_buffer = format_ip6_sr_header_with_length,
1941 .runtime_data_bytes = 0,
1943 .n_errors = SR_FIX_DST_N_ERROR,
1944 .error_strings = sr_fix_dst_error_strings,
1946 .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
1948 #define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
1949 foreach_sr_fix_dst_addr_next
1954 VLIB_NODE_FUNCTION_MULTIARCH (sr_fix_dst_addr_node, sr_fix_dst_addr)
1956 static clib_error_t * sr_init (vlib_main_t * vm)
1958 ip6_sr_main_t * sm = &sr_main;
1959 clib_error_t * error = 0;
1960 vlib_node_t * ip6_lookup_node, * ip6_rewrite_node;
1962 if ((error = vlib_call_init_function (vm, ip_main_init)))
1965 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
1969 sm->vnet_main = vnet_get_main();
1971 vec_validate (sm->hmac_keys, 0);
1972 sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
1974 sm->tunnel_index_by_key =
1975 hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
1977 sm->tunnel_index_by_name =
1978 hash_create_string (0, sizeof (uword));
1980 sm->policy_index_by_policy_name =
1981 hash_create_string(0, sizeof (uword));
1983 sm->policy_index_by_multicast_address =
1984 hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
1986 sm->hmac_key_by_shared_secret = hash_create_string (0, sizeof(uword));
1988 ip6_register_protocol (IPPROTO_IPV6_ROUTE, sr_local_node.index);
1990 ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *)"ip6-lookup");
1991 ASSERT(ip6_lookup_node);
1993 ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *)"ip6-rewrite");
1994 ASSERT(ip6_rewrite_node);
1996 /* Add a disposition to ip6_lookup for the sr rewrite node */
1997 sm->ip6_lookup_sr_next_index =
1998 vlib_node_add_next (vm, ip6_lookup_node->index, sr_rewrite_node.index);
2000 #if DPDK > 0 /* Cannot run replicate without DPDK */
2001 /* Add a disposition to sr_replicate for the sr multicast replicate node */
2002 sm->ip6_lookup_sr_replicate_index =
2003 vlib_node_add_next (vm, ip6_lookup_node->index, sr_replicate_node.index);
2006 /* Add a disposition to ip6_rewrite for the sr dst address hack node */
2007 sm->ip6_rewrite_sr_next_index =
2008 vlib_node_add_next (vm, ip6_rewrite_node->index,
2009 sr_fix_dst_addr_node.index);
2011 OpenSSL_add_all_digests();
2013 sm->md = (void *) EVP_get_digestbyname ("sha1");
2014 sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
2019 VLIB_INIT_FUNCTION (sr_init);
2021 #define foreach_sr_local_next \
2022 _ (ERROR, "error-drop") \
2023 _ (IP6_LOOKUP, "ip6-lookup")
2026 #define _(s,n) SR_LOCAL_NEXT_##s,
2027 foreach_sr_local_next
2035 ip6_address_t src, dst;
2040 static char * sr_local_error_strings[] = {
2041 #define sr_error(n,s) s,
2042 #include "sr_error.def"
2047 #define sr_error(n,s) SR_LOCAL_ERROR_##n,
2048 #include "sr_error.def"
2053 u8 * format_sr_local_trace (u8 * s, va_list * args)
2055 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2056 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2057 sr_local_trace_t * t = va_arg (*args, sr_local_trace_t *);
2059 s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
2060 format_ip6_address, &t->src,
2061 format_ip6_address, &t->dst, t->length, t->next_index);
2063 s = format (s, "\n %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
2065 s = format (s, "\n popped SR header");
2071 /* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
2073 static int sr_validate_hmac (ip6_sr_main_t * sm, ip6_header_t * ip,
2074 ip6_sr_header_t * sr)
2080 ip6_address_t *addrp;
2082 ip6_sr_hmac_key_t * hmac_key;
2083 static u8 * signature;
2086 key_index = sr->hmac_key;
2088 /* No signature? Pass... */
2092 /* We don't know about this key? Fail... */
2093 if (key_index >= vec_len (sm->hmac_keys))
2096 vec_validate (signature, SHA256_DIGEST_LENGTH-1);
2098 hmac_key = sm->hmac_keys + key_index;
2100 vec_reset_length (keybuf);
2102 /* pkt ip6 src address */
2103 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2104 clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
2107 vec_add2 (keybuf, copy_target, 1);
2108 copy_target[0] = sr->first_segment;
2110 /* octet w/ bit 0 = "clean" flag */
2111 vec_add2 (keybuf, copy_target, 1);
2113 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
2117 vec_add2 (keybuf, copy_target, 1);
2118 copy_target[0] = sr->hmac_key;
2120 first_segment = sr->first_segment;
2122 addrp = sr->segments;
2125 for (i = 0; i <= first_segment; i++)
2127 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2128 clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
2133 clib_warning ("verify key index %d keybuf: %U", key_index,
2134 format_hex_bytes, keybuf, vec_len(keybuf));
2138 /* SHA1 is shorter than SHA-256 */
2139 memset (signature, 0, vec_len(signature));
2141 HMAC_CTX_init(sm->hmac_ctx);
2142 if (!HMAC_Init(sm->hmac_ctx, hmac_key->shared_secret,
2143 vec_len(hmac_key->shared_secret),sm->md))
2144 clib_warning ("barf1");
2145 if (!HMAC_Update(sm->hmac_ctx,keybuf,vec_len(keybuf)))
2146 clib_warning ("barf2");
2147 if (!HMAC_Final(sm->hmac_ctx,signature,&sig_len))
2148 clib_warning ("barf3");
2149 HMAC_CTX_cleanup(sm->hmac_ctx);
2152 clib_warning ("computed signature len %d, value %U", sig_len,
2153 format_hex_bytes, signature, vec_len(signature));
2155 /* Point at the SHA signature in the packet */
2158 clib_warning ("read signature %U", format_hex_bytes, addrp,
2159 SHA256_DIGEST_LENGTH);
2161 return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
2165 sr_local (vlib_main_t * vm,
2166 vlib_node_runtime_t * node,
2167 vlib_frame_t * from_frame)
2169 u32 n_left_from, next_index, * from, * to_next;
2170 ip6_sr_main_t * sm = &sr_main;
2171 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
2172 vlib_buffer_t *, ip6_header_t *,
2174 sr_local_cb = sm->sr_local_cb;
2176 from = vlib_frame_vector_args (from_frame);
2177 n_left_from = from_frame->n_vectors;
2179 next_index = node->cached_next_index;
2181 while (n_left_from > 0)
2185 vlib_get_next_frame (vm, node, next_index,
2186 to_next, n_left_to_next);
2188 while (n_left_from >= 4 && n_left_to_next >= 2)
2191 vlib_buffer_t * b0, * b1;
2192 ip6_header_t * ip0, *ip1;
2193 ip6_sr_header_t * sr0, *sr1;
2194 ip6_address_t * new_dst0, * new_dst1;
2195 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2196 u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
2197 /* Prefetch next iteration. */
2199 vlib_buffer_t * p2, * p3;
2201 p2 = vlib_get_buffer (vm, from[2]);
2202 p3 = vlib_get_buffer (vm, from[3]);
2204 vlib_prefetch_buffer_header (p2, LOAD);
2205 vlib_prefetch_buffer_header (p3, LOAD);
2207 CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
2208 CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
2217 n_left_to_next -= 2;
2221 b0 = vlib_get_buffer (vm, bi0);
2222 ip0 = vlib_buffer_get_current (b0);
2223 sr0 = (ip6_sr_header_t *)(ip0+1);
2225 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
2227 next0 = SR_LOCAL_NEXT_ERROR;
2228 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2232 /* Out of segments? Turf the packet */
2233 if (PREDICT_FALSE (sr0->segments_left == 0))
2235 next0 = SR_LOCAL_NEXT_ERROR;
2236 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2240 if (PREDICT_FALSE(sm->validate_hmac))
2242 if (sr_validate_hmac (sm, ip0, sr0))
2244 next0 = SR_LOCAL_NEXT_ERROR;
2245 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2250 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
2254 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2256 if (PREDICT_FALSE (next0 & 0x80000000))
2258 next0 ^= 0xFFFFFFFF;
2259 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
2261 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2267 segment_index0 = sr0->segments_left - 1;
2269 /* Rewrite the packet */
2270 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
2271 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2272 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2274 if (PREDICT_TRUE (sr0->segments_left > 0))
2275 sr0->segments_left -= 1;
2278 /* End of the path. Clean up the SR header, or not */
2280 (sr0->segments_left == 0 &&
2281 (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2283 u64 *copy_dst0, *copy_src0;
2286 * Copy the ip6 header right by the (real) length of the
2287 * sr header. Here's another place which assumes that
2288 * the sr header is the only extention header.
2291 ip0->protocol = sr0->protocol;
2292 vlib_buffer_advance (b0, (sr0->length+1)*8);
2294 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
2296 ip0->payload_length = clib_host_to_net_u16(new_l0);
2298 copy_src0 = (u64 *)ip0;
2299 copy_dst0 = copy_src0 + (sr0->length + 1);
2301 copy_dst0 [4] = copy_src0[4];
2302 copy_dst0 [3] = copy_src0[3];
2303 copy_dst0 [2] = copy_src0[2];
2304 copy_dst0 [1] = copy_src0[1];
2305 copy_dst0 [0] = copy_src0[0];
2311 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2313 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2315 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2316 sizeof (tr->src.as_u8));
2317 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2318 sizeof (tr->dst.as_u8));
2319 tr->length = vlib_buffer_length_in_chain (vm, b0);
2320 tr->next_index = next0;
2321 tr->sr_valid = sr0 != 0;
2323 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2326 b1 = vlib_get_buffer (vm, bi1);
2327 ip1 = vlib_buffer_get_current (b1);
2328 sr1 = (ip6_sr_header_t *)(ip1+1);
2330 if (PREDICT_FALSE(sr1->type != ROUTING_HEADER_TYPE_SR))
2332 next1 = SR_LOCAL_NEXT_ERROR;
2333 b1->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2337 /* Out of segments? Turf the packet */
2338 if (PREDICT_FALSE (sr1->segments_left == 0))
2340 next1 = SR_LOCAL_NEXT_ERROR;
2341 b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2345 if (PREDICT_FALSE(sm->validate_hmac))
2347 if (sr_validate_hmac (sm, ip1, sr1))
2349 next1 = SR_LOCAL_NEXT_ERROR;
2350 b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2355 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
2359 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2361 if (PREDICT_FALSE (next1 & 0x80000000))
2363 next1 ^= 0xFFFFFFFF;
2364 if (PREDICT_FALSE(next1 == SR_LOCAL_NEXT_ERROR))
2366 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2372 segment_index1 = sr1->segments_left - 1;
2374 /* Rewrite the packet */
2375 new_dst1 = (ip6_address_t *)(sr1->segments + segment_index1);
2376 ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
2377 ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
2379 if (PREDICT_TRUE (sr1->segments_left > 0))
2380 sr1->segments_left -= 1;
2383 /* End of the path. Clean up the SR header, or not */
2385 (sr1->segments_left == 0 &&
2386 (sr1->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2388 u64 *copy_dst1, *copy_src1;
2391 * Copy the ip6 header right by the (real) length of the
2392 * sr header. Here's another place which assumes that
2393 * the sr header is the only extention header.
2396 ip1->protocol = sr1->protocol;
2397 vlib_buffer_advance (b1, (sr1->length+1)*8);
2399 new_l1 = clib_net_to_host_u16(ip1->payload_length) -
2401 ip1->payload_length = clib_host_to_net_u16(new_l1);
2403 copy_src1 = (u64 *)ip1;
2404 copy_dst1 = copy_src1 + (sr1->length + 1);
2406 copy_dst1 [4] = copy_src1[4];
2407 copy_dst1 [3] = copy_src1[3];
2408 copy_dst1 [2] = copy_src1[2];
2409 copy_dst1 [1] = copy_src1[1];
2410 copy_dst1 [0] = copy_src1[0];
2416 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
2418 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2420 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2421 sizeof (tr->src.as_u8));
2422 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2423 sizeof (tr->dst.as_u8));
2424 tr->length = vlib_buffer_length_in_chain (vm, b1);
2425 tr->next_index = next1;
2426 tr->sr_valid = sr1 != 0;
2428 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
2431 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2432 to_next, n_left_to_next,
2433 bi0, bi1, next0, next1);
2436 while (n_left_from > 0 && n_left_to_next > 0)
2440 ip6_header_t * ip0 = 0;
2441 ip6_sr_header_t * sr0;
2442 ip6_address_t * new_dst0;
2443 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2450 n_left_to_next -= 1;
2452 b0 = vlib_get_buffer (vm, bi0);
2453 ip0 = vlib_buffer_get_current (b0);
2454 sr0 = (ip6_sr_header_t *)(ip0+1);
2456 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
2458 next0 = SR_LOCAL_NEXT_ERROR;
2459 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2463 /* Out of segments? Turf the packet */
2464 if (PREDICT_FALSE (sr0->segments_left == 0))
2466 next0 = SR_LOCAL_NEXT_ERROR;
2467 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2471 if (PREDICT_FALSE(sm->validate_hmac))
2473 if (sr_validate_hmac (sm, ip0, sr0))
2475 next0 = SR_LOCAL_NEXT_ERROR;
2476 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2481 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
2485 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2487 if (PREDICT_FALSE (next0 & 0x80000000))
2489 next0 ^= 0xFFFFFFFF;
2490 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
2492 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2498 segment_index0 = sr0->segments_left - 1;
2500 /* Rewrite the packet */
2501 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
2502 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2503 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2505 if (PREDICT_TRUE (sr0->segments_left > 0))
2506 sr0->segments_left -= 1;
2509 /* End of the path. Clean up the SR header, or not */
2511 (sr0->segments_left == 0 &&
2512 (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2514 u64 *copy_dst0, *copy_src0;
2517 * Copy the ip6 header right by the (real) length of the
2518 * sr header. Here's another place which assumes that
2519 * the sr header is the only extention header.
2522 ip0->protocol = sr0->protocol;
2523 vlib_buffer_advance (b0, (sr0->length+1)*8);
2525 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
2527 ip0->payload_length = clib_host_to_net_u16(new_l0);
2529 copy_src0 = (u64 *)ip0;
2530 copy_dst0 = copy_src0 + (sr0->length + 1);
2532 copy_dst0 [4] = copy_src0[4];
2533 copy_dst0 [3] = copy_src0[3];
2534 copy_dst0 [2] = copy_src0[2];
2535 copy_dst0 [1] = copy_src0[1];
2536 copy_dst0 [0] = copy_src0[0];
2542 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2544 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2546 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2547 sizeof (tr->src.as_u8));
2548 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2549 sizeof (tr->dst.as_u8));
2550 tr->length = vlib_buffer_length_in_chain (vm, b0);
2551 tr->next_index = next0;
2552 tr->sr_valid = sr0 != 0;
2554 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2557 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2558 to_next, n_left_to_next,
2562 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2564 vlib_node_increment_counter (vm, sr_local_node.index,
2565 SR_LOCAL_ERROR_PKTS_PROCESSED,
2566 from_frame->n_vectors);
2567 return from_frame->n_vectors;
2570 VLIB_REGISTER_NODE (sr_local_node, static) = {
2571 .function = sr_local,
2573 /* Takes a vector of packets. */
2574 .vector_size = sizeof (u32),
2575 .format_trace = format_sr_local_trace,
2577 .runtime_data_bytes = 0,
2579 .n_errors = SR_LOCAL_N_ERROR,
2580 .error_strings = sr_local_error_strings,
2582 .n_next_nodes = SR_LOCAL_N_NEXT,
2584 #define _(s,n) [SR_LOCAL_NEXT_##s] = n,
2585 foreach_sr_local_next
2590 VLIB_NODE_FUNCTION_MULTIARCH (sr_local_node, sr_local)
2592 ip6_sr_main_t * sr_get_main (vlib_main_t * vm)
2594 vlib_call_init_function (vm, sr_init);
2595 ASSERT(sr_local_node.index);
2600 static clib_error_t *
2601 set_ip6_sr_rewrite_fn (vlib_main_t * vm,
2602 unformat_input_t * input,
2603 vlib_cli_command_t * cmd)
2606 ip6_main_t * im = &ip6_main;
2607 ip_lookup_main_t * lm = &im->lookup_main;
2612 ip_adjacency_t * adj;
2613 vnet_hw_interface_t * hi;
2615 ip6_sr_main_t * sm = &sr_main;
2616 vnet_main_t * vnm = vnet_get_main();
2618 if (!unformat (input, "%U", unformat_ip6_address, &a))
2619 return clib_error_return (0, "ip6 address missing in '%U'",
2620 format_unformat_error, input);
2622 if (unformat (input, "rx-table-id %d", &fib_id))
2624 p = hash_get (im->fib_index_by_table_id, fib_id);
2626 return clib_error_return (0, "fib-id %d not found");
2630 adj_index = ip6_fib_lookup_with_table (im, fib_index, &a);
2632 if (adj_index == lm->miss_adj_index)
2633 return clib_error_return (0, "no match for %U",
2634 format_ip6_address, &a);
2636 adj = ip_get_adjacency (lm, adj_index);
2638 if (adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
2639 return clib_error_return (0, "%U unresolved (not a rewrite adj)",
2640 format_ip6_address, &a);
2642 adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
2644 sw_if_index = adj->rewrite_header.sw_if_index;
2645 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2646 adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
2648 /* $$$$$ hack... steal the mcast group index */
2649 adj->mcast_group_index =
2650 vlib_node_add_next (vm, sr_fix_dst_addr_node.index, hi->output_node_index);
2655 VLIB_CLI_COMMAND (set_ip6_sr_rewrite, static) = {
2656 .path = "set ip6 sr rewrite",
2657 .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
2658 .function = set_ip6_sr_rewrite_fn,
2661 void vnet_register_sr_app_callback (void *cb)
2663 ip6_sr_main_t * sm = &sr_main;
2665 sm->sr_local_cb = cb;
2668 static clib_error_t *
2669 test_sr_hmac_validate_fn (vlib_main_t * vm,
2670 unformat_input_t * input,
2671 vlib_cli_command_t * cmd)
2673 ip6_sr_main_t * sm = &sr_main;
2675 if (unformat (input, "validate on"))
2676 sm->validate_hmac = 1;
2677 else if (unformat (input, "chunk-offset off"))
2678 sm->validate_hmac = 0;
2680 return clib_error_return (0, "expected validate on|off in '%U'",
2681 format_unformat_error, input);
2683 vlib_cli_output (vm, "hmac signature validation %s",
2689 VLIB_CLI_COMMAND (test_sr_hmac_validate, static) = {
2690 .path = "test sr hmac",
2691 .short_help = "test sr hmac validate [on|off]",
2692 .function = test_sr_hmac_validate_fn,
2695 i32 sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
2699 ip6_sr_hmac_key_t * key;
2703 /* Specific key in use? Fail. */
2704 if (key_id && vec_len (sm->hmac_keys) > key_id
2705 && sm->hmac_keys[key_id].shared_secret)
2709 key = find_or_add_shared_secret (sm, shared_secret, &index);
2710 ASSERT(index == key_id);
2716 if (key_id) /* delete by key ID */
2718 if (vec_len (sm->hmac_keys) <= key_id)
2721 key = sm->hmac_keys + key_id;
2723 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2724 vec_free (key->shared_secret);
2729 key = find_or_add_shared_secret (sm, shared_secret, &index);
2730 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2731 vec_free (key->shared_secret);
2736 static clib_error_t *
2737 sr_hmac_add_del_key_fn (vlib_main_t * vm,
2738 unformat_input_t * input,
2739 vlib_cli_command_t * cmd)
2741 ip6_sr_main_t * sm = &sr_main;
2745 u8 * shared_secret = 0;
2748 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2750 if (unformat (input, "del"))
2752 else if (unformat (input, "id %d", &key_id))
2754 else if (unformat (input, "key %s", &shared_secret))
2756 /* Do not include the trailing NULL byte. Guaranteed interop issue */
2757 _vec_len (shared_secret) -= 1;
2763 if (is_del == 0 && shared_secret == 0)
2764 return clib_error_return (0, "shared secret must be set to add a key");
2766 if (shared_secret == 0 && key_id_set == 0)
2767 return clib_error_return (0, "shared secret and key id both unset");
2769 rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
2771 vec_free (shared_secret);
2779 return clib_error_return (0, "sr_hmac_add_del_key returned %d",
2786 VLIB_CLI_COMMAND (sr_hmac, static) = {
2788 .short_help = "sr hmac [del] id <nn> key <str>",
2789 .function = sr_hmac_add_del_key_fn,
2793 static clib_error_t *
2794 show_sr_hmac_fn (vlib_main_t * vm,
2795 unformat_input_t * input,
2796 vlib_cli_command_t * cmd)
2798 ip6_sr_main_t * sm = &sr_main;
2801 for (i = 1; i < vec_len (sm->hmac_keys); i++)
2803 if (sm->hmac_keys[i].shared_secret)
2804 vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
2810 VLIB_CLI_COMMAND (show_sr_hmac, static) = {
2811 .path = "show sr hmac",
2812 .short_help = "show sr hmac",
2813 .function = show_sr_hmac_fn,
2816 static clib_error_t *
2817 test_sr_debug_fn (vlib_main_t * vm,
2818 unformat_input_t * input,
2819 vlib_cli_command_t * cmd)
2821 ip6_sr_main_t * sm = &sr_main;
2823 if (unformat (input, "on"))
2825 else if (unformat (input, "off"))
2828 return clib_error_return (0, "expected on|off in '%U'",
2829 format_unformat_error, input);
2831 vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
2836 VLIB_CLI_COMMAND (test_sr_debug, static) = {
2837 .path = "test sr debug",
2838 .short_help = "test sr debug on|off",
2839 .function = test_sr_debug_fn,