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)
728 key = sm->hmac_keys + i;
732 vec_validate (sm->hmac_keys, i);
733 key = sm->hmac_keys + i;
738 key->shared_secret = vec_dup (secret);
740 hash_set_mem (sm->hmac_key_by_shared_secret, key->shared_secret,
741 key - sm->hmac_keys);
744 *indexp = key - sm->hmac_keys;
749 int ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
751 ip6_main_t * im = &ip6_main;
752 ip_lookup_main_t * lm = &im->lookup_main;
753 ip6_sr_tunnel_key_t key;
756 ip6_sr_header_t * h = 0;
758 ip6_address_t * addrp, *this_address;
759 ip_adjacency_t adj, * ap, * add_adj = 0;
761 ip6_sr_main_t * sm = &sr_main;
763 u32 rx_fib_index, tx_fib_index;
764 ip6_add_del_route_args_t aa;
765 u32 hmac_key_index_u32;
766 u8 hmac_key_index = 0;
767 ip6_sr_policy_t * pt;
770 /* Make sure that the rx FIB exists */
771 p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
776 /* remember the FIB index */
779 /* Make sure that the supplied FIB exists */
780 p = hash_get (im->fib_index_by_table_id, a->tx_table_id);
785 /* remember the FIB index */
788 clib_memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
789 clib_memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
791 /* When adding a tunnel:
792 * - If a "name" is given, it must not exist.
793 * - The "key" is always checked, and must not exist.
794 * When deleting a tunnel:
795 * - If the "name" is given, and it exists, then use it.
796 * - If the "name" is not given, use the "key".
797 * - If the "name" and the "key" are given, then both must point to the same
802 p = hash_get_mem (sm->tunnel_index_by_key, &key);
804 /* If the name is given, look it up */
806 n = hash_get_mem(sm->tunnel_index_by_name, a->name);
810 /* validate key/name parameters */
811 if (!a->is_del) /* adding a tunnel */
813 if (a->name && n) /* name given & exists already */
815 if (p) /* key exists already */
818 else /* deleting a tunnel */
820 if (!p) /* key doesn't exist */
822 if (a->name && !n) /* name given & it doesn't exist */
825 if (n) /* name given & found */
827 if (n[0] != p[0]) /* name and key do not point to the same thing */
833 if (a->is_del) /* delete the tunnel */
837 /* Delete existing tunnel */
838 t = pool_elt_at_index (sm->tunnels, p[0]);
840 ip6_delete_route_no_next_hop (&t->key.dst, t->dst_mask_width,
842 vec_free (t->rewrite);
843 /* Remove tunnel from any policy if associated */
844 if (t->policy_index != ~0)
846 pt=pool_elt_at_index (sm->policies, t->policy_index);
847 for (i=0; i< vec_len (pt->tunnel_indices); i++)
849 if (pt->tunnel_indices[i] == t - sm->tunnels)
851 vec_delete (pt->tunnel_indices, 1, i);
855 clib_warning ("Tunnel index %d not found in policy_index %d",
856 t - sm->tunnels, pt - sm->policies);
858 /* If this is last tunnel in the policy, clean up the policy too */
859 if (vec_len (pt->tunnel_indices) == 0)
861 hash_unset_mem (sm->policy_index_by_policy_name, pt->name);
863 pool_put (sm->policies, pt);
867 /* Clean up the tunnel by name */
870 hash_unset_mem (sm->tunnel_index_by_name, t->name);
873 pool_put (sm->tunnels, t);
874 hp = hash_get_pair (sm->tunnel_index_by_key, &key);
875 key_copy = (void *)(hp->key);
876 hash_unset_mem (sm->tunnel_index_by_key, &key);
881 /* create a new tunnel */
882 pool_get (sm->tunnels, t);
883 memset (t, 0, sizeof (*t));
884 t->policy_index = ~0;
886 clib_memcpy (&t->key, &key, sizeof (t->key));
887 t->dst_mask_width = a->dst_mask_width;
888 t->rx_fib_index = rx_fib_index;
889 t->tx_fib_index = tx_fib_index;
891 if (!vec_len (a->segments))
892 /* there must be at least one segment... */
895 /* The first specified hop goes right into the dst address */
896 clib_memcpy(&t->first_hop, &a->segments[0], sizeof (ip6_address_t));
899 * Create the sr header rewrite string
900 * The list of segments needs an extra slot for the ultimate destination
901 * which is taken from the packet we add the SRH to.
903 header_length = sizeof (*h) +
904 sizeof (ip6_address_t) * (vec_len (a->segments) + 1 + vec_len (a->tags));
906 if (a->shared_secret)
908 /* Allocate a new key slot if we don't find the secret key */
909 hmac_key_index_u32 = 0;
910 (void) find_or_add_shared_secret (sm, a->shared_secret,
911 &hmac_key_index_u32);
913 /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
914 if (hmac_key_index_u32 >= 256)
916 hmac_key_index = hmac_key_index_u32;
917 header_length += SHA256_DIGEST_LENGTH;
920 vec_validate (t->rewrite, header_length-1);
922 h = (ip6_sr_header_t *) t->rewrite;
924 h->protocol = 0xFF; /* we don't know yet */
926 h->length = (header_length/8) - 1;
927 h->type = ROUTING_HEADER_TYPE_SR;
929 /* first_segment and segments_left need to have the index of the last
930 * element in the list; a->segments has one element less than ends up
931 * in the header (it does not have the DA in it), so vec_len(a->segments)
932 * is the value we want.
934 h->first_segment = h->segments_left = vec_len (a->segments);
936 if (a->shared_secret)
937 h->hmac_key = hmac_key_index & 0xFF;
939 h->flags = a->flags_net_byte_order;
941 /* Paint on the segment list, in reverse.
942 * This is offset by one to leave room at the start for the ultimate
945 addrp = h->segments + vec_len (a->segments);
947 vec_foreach (this_address, a->segments)
949 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
954 * Since the ultimate destination address is not yet known, set that slot
955 * to a value we will instantly recognize as bogus.
957 memset (h->segments, 0xfe, sizeof (ip6_address_t));
959 /* Paint on the tag list, not reversed */
960 addrp = h->segments + vec_len(a->segments);
962 vec_foreach (this_address, a->tags)
964 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
968 key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
969 clib_memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
970 hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
972 memset(&adj, 0, sizeof (adj));
974 /* Create an adjacency and add to v6 fib */
975 adj.lookup_next_index = sm->ip6_lookup_sr_next_index;
976 adj.explicit_fib_index = ~0;
978 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */,
982 * Stick the tunnel index into the rewrite header.
984 * Unfortunately, inserting an SR header according to the various
985 * RFC's requires parsing through the ip6 header, perhaps consing a
986 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
987 * normal reverse bcopy rewrite code.
989 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
992 ap->rewrite_header.sw_if_index = t - sm->tunnels;
994 vec_add1 (add_adj, ap[0]);
996 clib_memcpy (aa.dst_address.as_u8, a->dst_address, sizeof (aa.dst_address.as_u8));
997 aa.dst_address_length = a->dst_mask_width;
999 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1000 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1001 aa.table_index_or_table_id = rx_fib_index;
1002 aa.add_adj = add_adj;
1003 aa.adj_index = adj_index;
1005 ip6_add_del_route (im, &aa);
1010 p=hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1013 pt = pool_elt_at_index (sm->policies, p[0]);
1015 else /* no policy, lets create one */
1017 pool_get (sm->policies, pt);
1018 memset (pt, 0, sizeof(*pt));
1019 pt->name = format (0, "%s%c", a->policy_name, 0);
1020 hash_set_mem (sm->policy_index_by_policy_name, pt->name, pt - sm->policies);
1021 p=hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1023 vec_add1 (pt->tunnel_indices, t - sm->tunnels);
1025 clib_warning ("p is NULL!");
1026 t->policy_index = p ? p[0] : ~0; /* equiv. to (pt - sm->policies) */
1031 t->name = format (0, "%s%c", a->name, 0);
1032 hash_set_mem(sm->tunnel_index_by_name, t->name, t - sm->tunnels);
1038 static clib_error_t *
1039 sr_add_del_tunnel_command_fn (vlib_main_t * vm,
1040 unformat_input_t * input,
1041 vlib_cli_command_t * cmd)
1044 ip6_address_t src_address;
1045 int src_address_set = 0;
1046 ip6_address_t dst_address;
1048 int dst_address_set = 0;
1050 u8 *shared_secret = 0;
1052 u8 *policy_name = 0;
1053 u32 rx_table_id = 0;
1054 u32 tx_table_id = 0;
1055 ip6_address_t * segments = 0;
1056 ip6_address_t * this_seg;
1057 ip6_address_t * tags = 0;
1058 ip6_address_t * this_tag;
1059 ip6_sr_add_del_tunnel_args_t _a, *a=&_a;
1060 ip6_address_t next_address, tag;
1064 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1066 if (unformat (input, "del"))
1068 else if (unformat (input, "rx-fib-id %d", &rx_table_id))
1070 else if (unformat (input, "tx-fib-id %d", &tx_table_id))
1072 else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
1073 src_address_set = 1;
1074 else if (unformat (input, "name %s", &name))
1076 else if (unformat (input, "policy %s", &policy_name))
1078 else if (unformat (input, "dst %U/%d",
1079 unformat_ip6_address, &dst_address,
1081 dst_address_set = 1;
1082 else if (unformat (input, "next %U", unformat_ip6_address,
1085 vec_add2 (segments, this_seg, 1);
1086 clib_memcpy (this_seg->as_u8, next_address.as_u8, sizeof (*this_seg));
1088 else if (unformat (input, "tag %U", unformat_ip6_address,
1091 vec_add2 (tags, this_tag, 1);
1092 clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
1094 else if (unformat (input, "clean"))
1095 flags |= IP6_SR_HEADER_FLAG_CLEANUP;
1096 else if (unformat (input, "protected"))
1097 flags |= IP6_SR_HEADER_FLAG_PROTECTED;
1098 else if (unformat (input, "key %s", &shared_secret))
1099 /* Do not include the trailing NULL byte. Guaranteed interop issue */
1100 _vec_len (shared_secret) -= 1;
1101 else if (unformat (input, "InPE %d", &pl_index))
1103 if (pl_index <= 0 || pl_index > 4)
1105 pl_index_range_error:
1106 return clib_error_return
1107 (0, "Policy List Element Index %d out of range (1-4)", pl_index);
1110 flags |= IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
1111 << ip6_sr_policy_list_shift_from_index (pl_index);
1113 else if (unformat (input, "EgPE %d", &pl_index))
1115 if (pl_index <= 0 || pl_index > 4)
1116 goto pl_index_range_error;
1117 flags |= IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
1118 << ip6_sr_policy_list_shift_from_index (pl_index);
1120 else if (unformat (input, "OrgSrc %d", &pl_index))
1122 if (pl_index <= 0 || pl_index > 4)
1123 goto pl_index_range_error;
1124 flags |= IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
1125 << ip6_sr_policy_list_shift_from_index (pl_index);
1131 if (!src_address_set)
1132 return clib_error_return (0, "src address required");
1134 if (!dst_address_set)
1135 return clib_error_return (0, "dst address required");
1138 return clib_error_return (0, "at least one sr segment required");
1140 memset (a, 0, sizeof (*a));
1141 a->src_address = &src_address;
1142 a->dst_address = &dst_address;
1143 a->dst_mask_width = dst_mask_width;
1144 a->segments = segments;
1146 a->flags_net_byte_order = clib_host_to_net_u16(flags);
1148 a->rx_table_id = rx_table_id;
1149 a->tx_table_id = tx_table_id;
1150 a->shared_secret = shared_secret;
1157 if (vec_len(policy_name))
1158 a->policy_name = policy_name;
1162 rv = ip6_sr_add_del_tunnel (a);
1164 vec_free (segments);
1166 vec_free (shared_secret);
1174 return clib_error_return (0, "SR tunnel src %U dst %U already exists",
1175 format_ip6_address, &src_address,
1176 format_ip6_address, &dst_address);
1179 return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
1180 format_ip6_address, &src_address,
1181 format_ip6_address, &dst_address);
1184 return clib_error_return (0, "FIB table %d does not exist", rx_table_id);
1187 return clib_error_return (0, "At least one segment is required");
1190 return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
1197 VLIB_CLI_COMMAND (sr_tunnel_command, static) = {
1198 .path = "sr tunnel",
1200 "sr tunnel [del] [name <name>] src <addr> dst <addr> [next <addr>] "
1201 "[clean] [reroute] [key <secret>] [policy <policy_name>]"
1202 "[rx-fib-id <fib_id>] [tx-fib-id <fib_id>]",
1203 .function = sr_add_del_tunnel_command_fn,
1207 ip6_sr_tunnel_display (vlib_main_t * vm,
1208 ip6_sr_tunnel_t * t)
1210 ip6_main_t * im = &ip6_main;
1211 ip6_sr_main_t * sm = &sr_main;
1212 ip6_fib_t * rx_fib, * tx_fib;
1213 ip6_sr_policy_t * pt;
1215 rx_fib = find_ip6_fib_by_table_index_or_id (im, t->rx_fib_index,
1216 IP6_ROUTE_FLAG_FIB_INDEX);
1218 tx_fib = find_ip6_fib_by_table_index_or_id (im, t->tx_fib_index,
1219 IP6_ROUTE_FLAG_FIB_INDEX);
1222 vlib_cli_output (vm,"sr tunnel name: %s", (char *)t->name);
1224 vlib_cli_output (vm, "src %U dst %U first hop %U",
1225 format_ip6_address, &t->key.src,
1226 format_ip6_address, &t->key.dst,
1227 format_ip6_address, &t->first_hop);
1228 vlib_cli_output (vm, " rx-fib-id %d tx-fib-id %d",
1229 rx_fib->table_id, tx_fib->table_id);
1230 vlib_cli_output (vm, " sr: %U", format_ip6_sr_header, t->rewrite,
1231 0 /* print_hmac */);
1233 if (t->policy_index != ~0)
1235 pt=pool_elt_at_index(sm->policies, t->policy_index);
1236 vlib_cli_output (vm,"sr policy: %s", (char *)pt->name);
1238 vlib_cli_output (vm, "-------");
1243 static clib_error_t *
1244 show_sr_tunnel_fn (vlib_main_t * vm,
1245 unformat_input_t * input,
1246 vlib_cli_command_t * cmd)
1248 static ip6_sr_tunnel_t ** tunnels;
1249 ip6_sr_tunnel_t * t;
1250 ip6_sr_main_t * sm = &sr_main;
1255 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1257 if (unformat (input, "name %s", &name))
1259 p=hash_get_mem (sm->tunnel_index_by_name, name);
1261 vlib_cli_output (vm, "No SR tunnel with name: %s. Showing all.", name);
1267 vec_reset_length (tunnels);
1269 if(!p) /* Either name parm not passed or no tunnel with that name found, show all */
1271 pool_foreach (t, sm->tunnels,
1273 vec_add1 (tunnels, t);
1276 else /* Just show the one tunnel by name */
1277 vec_add1 (tunnels, &sm->tunnels[p[0]]);
1279 if (vec_len (tunnels) == 0)
1280 vlib_cli_output (vm, "No SR tunnels configured");
1282 for (i = 0; i < vec_len (tunnels); i++)
1285 ip6_sr_tunnel_display (vm, t);
1291 VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
1292 .path = "show sr tunnel",
1293 .short_help = "show sr tunnel [name <sr-tunnel-name>]",
1294 .function = show_sr_tunnel_fn,
1297 int ip6_sr_add_del_policy (ip6_sr_add_del_policy_args_t * a)
1299 ip6_sr_main_t * sm = &sr_main;
1301 ip6_sr_tunnel_t * t = 0;
1302 ip6_sr_policy_t * policy;
1303 u32 * tunnel_indices = 0;
1310 p=hash_get_mem (sm->policy_index_by_policy_name, a->name);
1312 return -6; /* policy name not found */
1314 policy = pool_elt_at_index(sm->policies, p[0]);
1316 vec_foreach_index (i, policy->tunnel_indices)
1318 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1319 t->policy_index = ~0;
1321 hash_unset_mem (sm->policy_index_by_policy_name, a->name);
1322 pool_put (sm->policies, policy);
1327 if (!vec_len(a->tunnel_names))
1328 return -3; /*tunnel name is required case */
1330 vec_reset_length (tunnel_indices);
1331 /* Check tunnel names, add tunnel_index to policy */
1332 for (i=0; i < vec_len (a->tunnel_names); i++)
1334 p = hash_get_mem (sm->tunnel_index_by_name, a->tunnel_names[i]);
1336 return -4; /* tunnel name not found case */
1338 t = pool_elt_at_index (sm->tunnels, p[0]);
1340 No need to check t==0. -3 condition above ensures name
1342 if (t->policy_index != ~0)
1343 return -5; /* tunnel name already associated with a policy */
1345 /* Add to tunnel indicies */
1346 vec_add1 (tunnel_indices, p[0]);
1349 /* Add policy to ip6_sr_main_t */
1350 pool_get (sm->policies, policy);
1351 policy->name = a->name;
1352 policy->tunnel_indices = tunnel_indices;
1353 hash_set_mem (sm->policy_index_by_policy_name, policy->name, policy - sm->policies);
1355 /* Yes, this could be construed as overkill but the last thing you should do is set
1356 the policy_index on the tunnel after everything is set in ip6_sr_main_t.
1357 If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop.
1359 for (i=0; i < vec_len(policy->tunnel_indices); i++)
1361 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1362 t->policy_index = policy - sm->policies;
1369 static clib_error_t *
1370 sr_add_del_policy_command_fn (vlib_main_t * vm,
1371 unformat_input_t * input,
1372 vlib_cli_command_t * cmd)
1375 u8 ** tunnel_names = 0;
1376 u8 * tunnel_name = 0;
1378 ip6_sr_add_del_policy_args_t _a, *a=&_a;
1381 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1383 if (unformat (input, "del"))
1385 else if (unformat (input, "name %s", &name))
1387 else if (unformat (input, "tunnel %s", &tunnel_name))
1391 vec_add1 (tunnel_names, tunnel_name);
1400 return clib_error_return (0, "name of SR policy required");
1403 memset(a, 0, sizeof(*a));
1407 a->tunnel_names = tunnel_names;
1409 rv = ip6_sr_add_del_policy (a);
1411 vec_free(tunnel_names);
1419 return clib_error_return (0, "tunnel name to associate to SR policy is required");
1422 return clib_error_return (0, "tunnel name not found");
1425 return clib_error_return (0, "tunnel already associated with policy");
1428 return clib_error_return (0, "policy name %s not found", name);
1431 return clib_error_return (0, "TODO: deleting policy name %s", name);
1434 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d", rv);
1440 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1441 .path = "sr policy",
1443 "sr policy [del] name <policy-name> tunnel <sr-tunnel-name> [tunnel <sr-tunnel-name>]*",
1444 .function = sr_add_del_policy_command_fn,
1447 static clib_error_t *
1448 show_sr_policy_fn (vlib_main_t * vm,
1449 unformat_input_t * input,
1450 vlib_cli_command_t * cmd)
1452 static ip6_sr_policy_t ** policies;
1453 ip6_sr_policy_t * policy;
1454 ip6_sr_tunnel_t * t;
1455 ip6_sr_main_t * sm = &sr_main;
1460 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1462 if (unformat (input, "name %s", &name))
1464 p=hash_get_mem (sm->policy_index_by_policy_name, name);
1466 vlib_cli_output (vm, "policy with name %s not found. Showing all.", name);
1472 vec_reset_length (policies);
1474 if(!p) /* Either name parm not passed or no policy with that name found, show all */
1476 pool_foreach (policy, sm->policies,
1478 vec_add1 (policies, policy);
1481 else /* Just show the one policy by name and a summary of tunnel names */
1483 policy = pool_elt_at_index(sm->policies, p[0]);
1484 vec_add1 (policies, policy);
1487 if (vec_len (policies) == 0)
1488 vlib_cli_output (vm, "No SR policies configured");
1490 for (i = 0; i < vec_len (policies); i++)
1492 policy = policies [i];
1495 vlib_cli_output (vm,"SR policy name: %s", (char *)policy->name);
1496 for(j = 0; j < vec_len (policy->tunnel_indices); j++)
1498 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[j]);
1499 ip6_sr_tunnel_display (vm, t);
1507 VLIB_CLI_COMMAND (show_sr_policy_command, static) = {
1508 .path = "show sr policy",
1509 .short_help = "show sr policy [name <sr-policy-name>]",
1510 .function = show_sr_policy_fn,
1513 int ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a)
1516 ip6_main_t * im = &ip6_main;
1517 ip_lookup_main_t * lm = &im->lookup_main;
1518 ip6_sr_tunnel_t * t;
1519 ip_adjacency_t adj, * ap, * add_adj = 0;
1521 ip6_sr_main_t * sm = &sr_main;
1522 ip6_add_del_route_args_t aa;
1523 ip6_sr_policy_t * pt;
1527 /* clean up the adjacency */
1528 p = hash_get_mem (sm->policy_index_by_multicast_address, a->multicast_address);
1532 /* Get our policy by policy_name */
1533 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1539 pt=pool_elt_at_index (sm->policies, p[0]);
1542 Get the first tunnel associated with policy populate the fib adjacency.
1543 From there, since this tunnel will have it's policy_index != ~0 it will
1544 be the trigger in the dual_loop to pull up the policy and make a copy-rewrite
1545 for each tunnel in the policy
1548 t = pool_elt_at_index (sm->tunnels, pt->tunnel_indices[0]);
1550 /* Construct a FIB entry for multicast using the rx/tx fib from the first tunnel */
1551 memset(&adj, 0, sizeof (adj));
1553 /* Create an adjacency and add to v6 fib */
1554 adj.lookup_next_index = sm->ip6_lookup_sr_replicate_index;
1555 adj.explicit_fib_index = ~0;
1557 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */,
1561 * Stick the tunnel index into the rewrite header.
1563 * Unfortunately, inserting an SR header according to the various
1564 * RFC's requires parsing through the ip6 header, perhaps consing a
1565 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1566 * normal reverse bcopy rewrite code.
1568 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1571 ap->rewrite_header.sw_if_index = t - sm->tunnels;
1573 vec_add1 (add_adj, ap[0]);
1575 memcpy (aa.dst_address.as_u8, a->multicast_address, sizeof (aa.dst_address.as_u8));
1576 aa.dst_address_length = 128;
1578 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1579 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1580 aa.table_index_or_table_id = t->rx_fib_index;
1581 aa.add_adj = add_adj;
1582 aa.adj_index = adj_index;
1584 ip6_add_del_route (im, &aa);
1587 u8 * mcast_copy = 0;
1588 mcast_copy = vec_new (ip6_address_t, 1);
1589 memcpy (mcast_copy, a->multicast_address, sizeof (ip6_address_t));
1593 hash_unset_mem (sm->policy_index_by_multicast_address, mcast_copy);
1594 vec_free (mcast_copy);
1599 hash_set_mem (sm->policy_index_by_multicast_address, mcast_copy, pt - sm->policies);
1605 static clib_error_t *
1606 sr_add_del_multicast_map_command_fn (vlib_main_t * vm,
1607 unformat_input_t * input,
1608 vlib_cli_command_t * cmd)
1611 ip6_address_t multicast_address;
1612 u8 * policy_name = 0;
1613 int multicast_address_set = 0;
1614 ip6_sr_add_del_multicastmap_args_t _a, *a=&_a;
1617 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1619 if (unformat (input, "del"))
1621 else if (unformat (input, "address %U", unformat_ip6_address, &multicast_address))
1622 multicast_address_set = 1;
1623 else if (unformat (input, "sr-policy %s", &policy_name))
1629 if (!is_del && !policy_name)
1630 return clib_error_return (0, "name of sr policy required");
1632 if (!multicast_address_set)
1633 return clib_error_return (0, "multicast address required");
1635 memset(a, 0, sizeof(*a));
1638 a->multicast_address = &multicast_address;
1639 a->policy_name = policy_name;
1641 #if DPDK > 0 /*Cannot call replicate or configure multicast map yet without DPDK */
1642 rv = ip6_sr_add_del_multicastmap (a);
1644 return clib_error_return (0, "cannot use multicast replicate spray case without DPDK installed");
1652 return clib_error_return (0, "no policy with name: %s", policy_name);
1655 return clib_error_return (0, "multicast map someting ");
1658 return clib_error_return (0, "tunnel name to associate to SR policy is required");
1661 return clib_error_return (0, "TODO: deleting policy name %s", policy_name);
1664 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d", rv);
1672 VLIB_CLI_COMMAND (sr_multicast_map_command, static) = {
1673 .path = "sr multicast-map",
1675 "sr multicast-map address <multicast-ip6-address> sr-policy <sr-policy-name> [del]",
1676 .function = sr_add_del_multicast_map_command_fn,
1679 static clib_error_t *
1680 show_sr_multicast_map_fn (vlib_main_t * vm,
1681 unformat_input_t * input,
1682 vlib_cli_command_t * cmd)
1684 ip6_sr_main_t * sm = &sr_main;
1687 ip6_address_t multicast_address;
1688 ip6_sr_policy_t * pt ;
1690 /* pull all entries from the hash table into vector for display */
1692 hash_foreach_mem (key, value, sm->policy_index_by_multicast_address,
1695 vlib_cli_output (vm, "no multicast maps configured");
1698 multicast_address = *((ip6_address_t *)key);
1699 pt = pool_elt_at_index (sm->policies, value);
1702 vlib_cli_output (vm, "address: %U policy: %s",
1703 format_ip6_address, &multicast_address,
1707 vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d",
1708 format_ip6_address, &multicast_address,
1718 VLIB_CLI_COMMAND (show_sr_multicast_map_command, static) = {
1719 .path = "show sr multicast-map",
1720 .short_help = "show sr multicast-map",
1721 .function = show_sr_multicast_map_fn,
1725 #define foreach_sr_fix_dst_addr_next \
1726 _(DROP, "error-drop")
1729 #define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
1730 foreach_sr_fix_dst_addr_next
1732 SR_FIX_DST_ADDR_N_NEXT,
1733 } sr_fix_dst_addr_next_t;
1735 static char * sr_fix_dst_error_strings[] = {
1736 #define sr_fix_dst_error(n,s) s,
1737 #include "sr_fix_dst_error.def"
1738 #undef sr_fix_dst_error
1742 #define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
1743 #include "sr_fix_dst_error.def"
1744 #undef sr_fix_dst_error
1746 } sr_fix_dst_error_t;
1749 ip6_address_t src, dst;
1753 } sr_fix_addr_trace_t;
1755 u8 * format_sr_fix_addr_trace (u8 * s, va_list * args)
1757 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1758 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1759 sr_fix_addr_trace_t * t = va_arg (*args, sr_fix_addr_trace_t *);
1760 vnet_hw_interface_t * hi = 0;
1761 ip_adjacency_t * adj;
1762 ip6_main_t * im = &ip6_main;
1763 ip_lookup_main_t * lm = &im->lookup_main;
1764 vnet_main_t * vnm = vnet_get_main();
1766 if (t->adj_index != ~0)
1768 adj = ip_get_adjacency (lm, t->adj_index);
1769 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
1772 s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
1773 (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
1774 ? "drop" : "output",
1775 format_ip6_address, &t->src,
1776 format_ip6_address, &t->dst);
1777 if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
1779 s = format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
1780 s = format (s, " output via %s", hi ? (char *)(hi->name)
1787 sr_fix_dst_addr (vlib_main_t * vm,
1788 vlib_node_runtime_t * node,
1789 vlib_frame_t * from_frame)
1791 u32 n_left_from, next_index, * from, * to_next;
1792 ip6_main_t * im = &ip6_main;
1793 ip_lookup_main_t * lm = &im->lookup_main;
1795 from = vlib_frame_vector_args (from_frame);
1796 n_left_from = from_frame->n_vectors;
1798 next_index = node->cached_next_index;
1800 while (n_left_from > 0)
1804 vlib_get_next_frame (vm, node, next_index,
1805 to_next, n_left_to_next);
1808 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
1811 __attribute__((unused)) vlib_buffer_t * b0, * b1;
1812 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1813 u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
1815 /* Prefetch next iteration. */
1817 vlib_buffer_t * p2, * p3;
1819 p2 = vlib_get_buffer (vm, from[2]);
1820 p3 = vlib_get_buffer (vm, from[3]);
1822 vlib_prefetch_buffer_header (p2, LOAD);
1823 vlib_prefetch_buffer_header (p3, LOAD);
1832 n_left_to_next -= 2;
1835 b0 = vlib_get_buffer (vm, bi0);
1836 b1 = vlib_get_buffer (vm, bi1);
1839 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1840 to_next, n_left_to_next,
1841 bi0, bi1, next0, next1);
1845 while (n_left_from > 0 && n_left_to_next > 0)
1850 ip_adjacency_t * adj0;
1851 ip6_sr_header_t * sr0;
1852 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1853 ip6_address_t *new_dst0;
1854 ethernet_header_t * eh0;
1861 n_left_to_next -= 1;
1863 b0 = vlib_get_buffer (vm, bi0);
1865 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
1866 next0 = adj0->mcast_group_index;
1868 /* We should be pointing at an Ethernet header... */
1869 eh0 = vlib_buffer_get_current (b0);
1870 ip0 = (ip6_header_t *)(eh0+1);
1871 sr0 = (ip6_sr_header_t *) (ip0+1);
1873 /* We'd better find an SR header... */
1874 if (PREDICT_FALSE(ip0->protocol != IPPROTO_IPV6_ROUTE))
1876 b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
1882 * We get here from sr_rewrite or sr_local, with
1883 * sr->segments_left pointing at the (copy of the original) dst
1884 * address. Use it, then increment sr0->segments_left.
1887 /* Out of segments? Turf the packet */
1888 if (PREDICT_FALSE (sr0->segments_left == 0))
1890 b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
1895 * Rewrite the packet with the original dst address
1896 * We assume that the last segment (in processing order) contains
1897 * the original dst address. The list is reversed, so sr0->segments
1898 * contains the original dst address.
1900 new_dst0 = sr0->segments;
1901 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1902 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1907 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1909 sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
1911 t->next_index = next0;
1914 if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
1916 t->adj_index = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
1917 clib_memcpy (t->src.as_u8, ip0->src_address.as_u8,
1918 sizeof (t->src.as_u8));
1919 clib_memcpy (t->dst.as_u8, ip0->dst_address.as_u8,
1920 sizeof (t->dst.as_u8));
1921 clib_memcpy (t->sr, sr0, sizeof (t->sr));
1925 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1926 to_next, n_left_to_next,
1930 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1932 return from_frame->n_vectors;
1936 VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
1937 .function = sr_fix_dst_addr,
1938 .name = "sr-fix-dst-addr",
1939 /* Takes a vector of packets. */
1940 .vector_size = sizeof (u32),
1941 .format_trace = format_sr_fix_addr_trace,
1942 .format_buffer = format_ip6_sr_header_with_length,
1944 .runtime_data_bytes = 0,
1946 .n_errors = SR_FIX_DST_N_ERROR,
1947 .error_strings = sr_fix_dst_error_strings,
1949 .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
1951 #define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
1952 foreach_sr_fix_dst_addr_next
1957 VLIB_NODE_FUNCTION_MULTIARCH (sr_fix_dst_addr_node, sr_fix_dst_addr)
1959 static clib_error_t * sr_init (vlib_main_t * vm)
1961 ip6_sr_main_t * sm = &sr_main;
1962 clib_error_t * error = 0;
1963 vlib_node_t * ip6_lookup_node, * ip6_rewrite_node;
1965 if ((error = vlib_call_init_function (vm, ip_main_init)))
1968 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
1972 sm->vnet_main = vnet_get_main();
1974 vec_validate (sm->hmac_keys, 0);
1975 sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
1977 sm->tunnel_index_by_key =
1978 hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
1980 sm->tunnel_index_by_name =
1981 hash_create_string (0, sizeof (uword));
1983 sm->policy_index_by_policy_name =
1984 hash_create_string(0, sizeof (uword));
1986 sm->policy_index_by_multicast_address =
1987 hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
1989 sm->hmac_key_by_shared_secret = hash_create_string (0, sizeof(uword));
1991 ip6_register_protocol (IPPROTO_IPV6_ROUTE, sr_local_node.index);
1993 ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *)"ip6-lookup");
1994 ASSERT(ip6_lookup_node);
1996 ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *)"ip6-rewrite");
1997 ASSERT(ip6_rewrite_node);
1999 /* Add a disposition to ip6_lookup for the sr rewrite node */
2000 sm->ip6_lookup_sr_next_index =
2001 vlib_node_add_next (vm, ip6_lookup_node->index, sr_rewrite_node.index);
2003 #if DPDK > 0 /* Cannot run replicate without DPDK */
2004 /* Add a disposition to sr_replicate for the sr multicast replicate node */
2005 sm->ip6_lookup_sr_replicate_index =
2006 vlib_node_add_next (vm, ip6_lookup_node->index, sr_replicate_node.index);
2009 /* Add a disposition to ip6_rewrite for the sr dst address hack node */
2010 sm->ip6_rewrite_sr_next_index =
2011 vlib_node_add_next (vm, ip6_rewrite_node->index,
2012 sr_fix_dst_addr_node.index);
2014 OpenSSL_add_all_digests();
2016 sm->md = (void *) EVP_get_digestbyname ("sha1");
2017 sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
2022 VLIB_INIT_FUNCTION (sr_init);
2024 #define foreach_sr_local_next \
2025 _ (ERROR, "error-drop") \
2026 _ (IP6_LOOKUP, "ip6-lookup")
2029 #define _(s,n) SR_LOCAL_NEXT_##s,
2030 foreach_sr_local_next
2038 ip6_address_t src, dst;
2043 static char * sr_local_error_strings[] = {
2044 #define sr_error(n,s) s,
2045 #include "sr_error.def"
2050 #define sr_error(n,s) SR_LOCAL_ERROR_##n,
2051 #include "sr_error.def"
2056 u8 * format_sr_local_trace (u8 * s, va_list * args)
2058 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2059 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2060 sr_local_trace_t * t = va_arg (*args, sr_local_trace_t *);
2062 s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
2063 format_ip6_address, &t->src,
2064 format_ip6_address, &t->dst, t->length, t->next_index);
2066 s = format (s, "\n %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
2068 s = format (s, "\n popped SR header");
2074 /* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
2076 static int sr_validate_hmac (ip6_sr_main_t * sm, ip6_header_t * ip,
2077 ip6_sr_header_t * sr)
2083 ip6_address_t *addrp;
2085 ip6_sr_hmac_key_t * hmac_key;
2086 static u8 * signature;
2089 key_index = sr->hmac_key;
2091 /* No signature? Pass... */
2095 /* We don't know about this key? Fail... */
2096 if (key_index >= vec_len (sm->hmac_keys))
2099 vec_validate (signature, SHA256_DIGEST_LENGTH-1);
2101 hmac_key = sm->hmac_keys + key_index;
2103 vec_reset_length (keybuf);
2105 /* pkt ip6 src address */
2106 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2107 clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
2110 vec_add2 (keybuf, copy_target, 1);
2111 copy_target[0] = sr->first_segment;
2113 /* octet w/ bit 0 = "clean" flag */
2114 vec_add2 (keybuf, copy_target, 1);
2116 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
2120 vec_add2 (keybuf, copy_target, 1);
2121 copy_target[0] = sr->hmac_key;
2123 first_segment = sr->first_segment;
2125 addrp = sr->segments;
2128 for (i = 0; i <= first_segment; i++)
2130 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2131 clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
2136 clib_warning ("verify key index %d keybuf: %U", key_index,
2137 format_hex_bytes, keybuf, vec_len(keybuf));
2141 /* SHA1 is shorter than SHA-256 */
2142 memset (signature, 0, vec_len(signature));
2144 HMAC_CTX_init(sm->hmac_ctx);
2145 if (!HMAC_Init(sm->hmac_ctx, hmac_key->shared_secret,
2146 vec_len(hmac_key->shared_secret),sm->md))
2147 clib_warning ("barf1");
2148 if (!HMAC_Update(sm->hmac_ctx,keybuf,vec_len(keybuf)))
2149 clib_warning ("barf2");
2150 if (!HMAC_Final(sm->hmac_ctx,signature,&sig_len))
2151 clib_warning ("barf3");
2152 HMAC_CTX_cleanup(sm->hmac_ctx);
2155 clib_warning ("computed signature len %d, value %U", sig_len,
2156 format_hex_bytes, signature, vec_len(signature));
2158 /* Point at the SHA signature in the packet */
2161 clib_warning ("read signature %U", format_hex_bytes, addrp,
2162 SHA256_DIGEST_LENGTH);
2164 return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
2168 sr_local (vlib_main_t * vm,
2169 vlib_node_runtime_t * node,
2170 vlib_frame_t * from_frame)
2172 u32 n_left_from, next_index, * from, * to_next;
2173 ip6_sr_main_t * sm = &sr_main;
2174 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
2175 vlib_buffer_t *, ip6_header_t *,
2177 sr_local_cb = sm->sr_local_cb;
2179 from = vlib_frame_vector_args (from_frame);
2180 n_left_from = from_frame->n_vectors;
2182 next_index = node->cached_next_index;
2184 while (n_left_from > 0)
2188 vlib_get_next_frame (vm, node, next_index,
2189 to_next, n_left_to_next);
2191 while (n_left_from >= 4 && n_left_to_next >= 2)
2194 vlib_buffer_t * b0, * b1;
2195 ip6_header_t * ip0, *ip1;
2196 ip6_sr_header_t * sr0, *sr1;
2197 ip6_address_t * new_dst0, * new_dst1;
2198 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2199 u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
2200 /* Prefetch next iteration. */
2202 vlib_buffer_t * p2, * p3;
2204 p2 = vlib_get_buffer (vm, from[2]);
2205 p3 = vlib_get_buffer (vm, from[3]);
2207 vlib_prefetch_buffer_header (p2, LOAD);
2208 vlib_prefetch_buffer_header (p3, LOAD);
2210 CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
2211 CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
2220 n_left_to_next -= 2;
2224 b0 = vlib_get_buffer (vm, bi0);
2225 ip0 = vlib_buffer_get_current (b0);
2226 sr0 = (ip6_sr_header_t *)(ip0+1);
2228 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
2230 next0 = SR_LOCAL_NEXT_ERROR;
2231 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2235 /* Out of segments? Turf the packet */
2236 if (PREDICT_FALSE (sr0->segments_left == 0))
2238 next0 = SR_LOCAL_NEXT_ERROR;
2239 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2243 if (PREDICT_FALSE(sm->validate_hmac))
2245 if (sr_validate_hmac (sm, ip0, sr0))
2247 next0 = SR_LOCAL_NEXT_ERROR;
2248 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2253 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
2257 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2259 if (PREDICT_FALSE (next0 & 0x80000000))
2261 next0 ^= 0xFFFFFFFF;
2262 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
2264 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2270 segment_index0 = sr0->segments_left - 1;
2272 /* Rewrite the packet */
2273 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
2274 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2275 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2277 if (PREDICT_TRUE (sr0->segments_left > 0))
2278 sr0->segments_left -= 1;
2281 /* End of the path. Clean up the SR header, or not */
2283 (sr0->segments_left == 0 &&
2284 (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2286 u64 *copy_dst0, *copy_src0;
2289 * Copy the ip6 header right by the (real) length of the
2290 * sr header. Here's another place which assumes that
2291 * the sr header is the only extention header.
2294 ip0->protocol = sr0->protocol;
2295 vlib_buffer_advance (b0, (sr0->length+1)*8);
2297 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
2299 ip0->payload_length = clib_host_to_net_u16(new_l0);
2301 copy_src0 = (u64 *)ip0;
2302 copy_dst0 = copy_src0 + (sr0->length + 1);
2304 copy_dst0 [4] = copy_src0[4];
2305 copy_dst0 [3] = copy_src0[3];
2306 copy_dst0 [2] = copy_src0[2];
2307 copy_dst0 [1] = copy_src0[1];
2308 copy_dst0 [0] = copy_src0[0];
2314 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2316 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2318 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2319 sizeof (tr->src.as_u8));
2320 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2321 sizeof (tr->dst.as_u8));
2322 tr->length = vlib_buffer_length_in_chain (vm, b0);
2323 tr->next_index = next0;
2324 tr->sr_valid = sr0 != 0;
2326 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2329 b1 = vlib_get_buffer (vm, bi1);
2330 ip1 = vlib_buffer_get_current (b1);
2331 sr1 = (ip6_sr_header_t *)(ip1+1);
2333 if (PREDICT_FALSE(sr1->type != ROUTING_HEADER_TYPE_SR))
2335 next1 = SR_LOCAL_NEXT_ERROR;
2336 b1->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2340 /* Out of segments? Turf the packet */
2341 if (PREDICT_FALSE (sr1->segments_left == 0))
2343 next1 = SR_LOCAL_NEXT_ERROR;
2344 b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2348 if (PREDICT_FALSE(sm->validate_hmac))
2350 if (sr_validate_hmac (sm, ip1, sr1))
2352 next1 = SR_LOCAL_NEXT_ERROR;
2353 b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2358 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
2362 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2364 if (PREDICT_FALSE (next1 & 0x80000000))
2366 next1 ^= 0xFFFFFFFF;
2367 if (PREDICT_FALSE(next1 == SR_LOCAL_NEXT_ERROR))
2369 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2375 segment_index1 = sr1->segments_left - 1;
2377 /* Rewrite the packet */
2378 new_dst1 = (ip6_address_t *)(sr1->segments + segment_index1);
2379 ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
2380 ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
2382 if (PREDICT_TRUE (sr1->segments_left > 0))
2383 sr1->segments_left -= 1;
2386 /* End of the path. Clean up the SR header, or not */
2388 (sr1->segments_left == 0 &&
2389 (sr1->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2391 u64 *copy_dst1, *copy_src1;
2394 * Copy the ip6 header right by the (real) length of the
2395 * sr header. Here's another place which assumes that
2396 * the sr header is the only extention header.
2399 ip1->protocol = sr1->protocol;
2400 vlib_buffer_advance (b1, (sr1->length+1)*8);
2402 new_l1 = clib_net_to_host_u16(ip1->payload_length) -
2404 ip1->payload_length = clib_host_to_net_u16(new_l1);
2406 copy_src1 = (u64 *)ip1;
2407 copy_dst1 = copy_src1 + (sr1->length + 1);
2409 copy_dst1 [4] = copy_src1[4];
2410 copy_dst1 [3] = copy_src1[3];
2411 copy_dst1 [2] = copy_src1[2];
2412 copy_dst1 [1] = copy_src1[1];
2413 copy_dst1 [0] = copy_src1[0];
2419 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
2421 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2423 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2424 sizeof (tr->src.as_u8));
2425 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2426 sizeof (tr->dst.as_u8));
2427 tr->length = vlib_buffer_length_in_chain (vm, b1);
2428 tr->next_index = next1;
2429 tr->sr_valid = sr1 != 0;
2431 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
2434 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2435 to_next, n_left_to_next,
2436 bi0, bi1, next0, next1);
2439 while (n_left_from > 0 && n_left_to_next > 0)
2443 ip6_header_t * ip0 = 0;
2444 ip6_sr_header_t * sr0;
2445 ip6_address_t * new_dst0;
2446 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2453 n_left_to_next -= 1;
2455 b0 = vlib_get_buffer (vm, bi0);
2456 ip0 = vlib_buffer_get_current (b0);
2457 sr0 = (ip6_sr_header_t *)(ip0+1);
2459 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
2461 next0 = SR_LOCAL_NEXT_ERROR;
2462 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2466 /* Out of segments? Turf the packet */
2467 if (PREDICT_FALSE (sr0->segments_left == 0))
2469 next0 = SR_LOCAL_NEXT_ERROR;
2470 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2474 if (PREDICT_FALSE(sm->validate_hmac))
2476 if (sr_validate_hmac (sm, ip0, sr0))
2478 next0 = SR_LOCAL_NEXT_ERROR;
2479 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2484 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
2488 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2490 if (PREDICT_FALSE (next0 & 0x80000000))
2492 next0 ^= 0xFFFFFFFF;
2493 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
2495 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2501 segment_index0 = sr0->segments_left - 1;
2503 /* Rewrite the packet */
2504 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
2505 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2506 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2508 if (PREDICT_TRUE (sr0->segments_left > 0))
2509 sr0->segments_left -= 1;
2512 /* End of the path. Clean up the SR header, or not */
2514 (sr0->segments_left == 0 &&
2515 (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2517 u64 *copy_dst0, *copy_src0;
2520 * Copy the ip6 header right by the (real) length of the
2521 * sr header. Here's another place which assumes that
2522 * the sr header is the only extention header.
2525 ip0->protocol = sr0->protocol;
2526 vlib_buffer_advance (b0, (sr0->length+1)*8);
2528 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
2530 ip0->payload_length = clib_host_to_net_u16(new_l0);
2532 copy_src0 = (u64 *)ip0;
2533 copy_dst0 = copy_src0 + (sr0->length + 1);
2535 copy_dst0 [4] = copy_src0[4];
2536 copy_dst0 [3] = copy_src0[3];
2537 copy_dst0 [2] = copy_src0[2];
2538 copy_dst0 [1] = copy_src0[1];
2539 copy_dst0 [0] = copy_src0[0];
2545 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2547 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2549 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2550 sizeof (tr->src.as_u8));
2551 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2552 sizeof (tr->dst.as_u8));
2553 tr->length = vlib_buffer_length_in_chain (vm, b0);
2554 tr->next_index = next0;
2555 tr->sr_valid = sr0 != 0;
2557 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2560 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2561 to_next, n_left_to_next,
2565 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2567 vlib_node_increment_counter (vm, sr_local_node.index,
2568 SR_LOCAL_ERROR_PKTS_PROCESSED,
2569 from_frame->n_vectors);
2570 return from_frame->n_vectors;
2573 VLIB_REGISTER_NODE (sr_local_node, static) = {
2574 .function = sr_local,
2576 /* Takes a vector of packets. */
2577 .vector_size = sizeof (u32),
2578 .format_trace = format_sr_local_trace,
2580 .runtime_data_bytes = 0,
2582 .n_errors = SR_LOCAL_N_ERROR,
2583 .error_strings = sr_local_error_strings,
2585 .n_next_nodes = SR_LOCAL_N_NEXT,
2587 #define _(s,n) [SR_LOCAL_NEXT_##s] = n,
2588 foreach_sr_local_next
2593 VLIB_NODE_FUNCTION_MULTIARCH (sr_local_node, sr_local)
2595 ip6_sr_main_t * sr_get_main (vlib_main_t * vm)
2597 vlib_call_init_function (vm, sr_init);
2598 ASSERT(sr_local_node.index);
2603 static clib_error_t *
2604 set_ip6_sr_rewrite_fn (vlib_main_t * vm,
2605 unformat_input_t * input,
2606 vlib_cli_command_t * cmd)
2609 ip6_main_t * im = &ip6_main;
2610 ip_lookup_main_t * lm = &im->lookup_main;
2615 ip_adjacency_t * adj;
2616 vnet_hw_interface_t * hi;
2618 ip6_sr_main_t * sm = &sr_main;
2619 vnet_main_t * vnm = vnet_get_main();
2621 if (!unformat (input, "%U", unformat_ip6_address, &a))
2622 return clib_error_return (0, "ip6 address missing in '%U'",
2623 format_unformat_error, input);
2625 if (unformat (input, "rx-table-id %d", &fib_id))
2627 p = hash_get (im->fib_index_by_table_id, fib_id);
2629 return clib_error_return (0, "fib-id %d not found");
2633 adj_index = ip6_fib_lookup_with_table (im, fib_index, &a);
2635 if (adj_index == lm->miss_adj_index)
2636 return clib_error_return (0, "no match for %U",
2637 format_ip6_address, &a);
2639 adj = ip_get_adjacency (lm, adj_index);
2641 if (adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
2642 return clib_error_return (0, "%U unresolved (not a rewrite adj)",
2643 format_ip6_address, &a);
2645 adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
2647 sw_if_index = adj->rewrite_header.sw_if_index;
2648 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2649 adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
2651 /* $$$$$ hack... steal the mcast group index */
2652 adj->mcast_group_index =
2653 vlib_node_add_next (vm, sr_fix_dst_addr_node.index, hi->output_node_index);
2658 VLIB_CLI_COMMAND (set_ip6_sr_rewrite, static) = {
2659 .path = "set ip6 sr rewrite",
2660 .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
2661 .function = set_ip6_sr_rewrite_fn,
2664 void vnet_register_sr_app_callback (void *cb)
2666 ip6_sr_main_t * sm = &sr_main;
2668 sm->sr_local_cb = cb;
2671 static clib_error_t *
2672 test_sr_hmac_validate_fn (vlib_main_t * vm,
2673 unformat_input_t * input,
2674 vlib_cli_command_t * cmd)
2676 ip6_sr_main_t * sm = &sr_main;
2678 if (unformat (input, "validate on"))
2679 sm->validate_hmac = 1;
2680 else if (unformat (input, "chunk-offset off"))
2681 sm->validate_hmac = 0;
2683 return clib_error_return (0, "expected validate on|off in '%U'",
2684 format_unformat_error, input);
2686 vlib_cli_output (vm, "hmac signature validation %s",
2692 VLIB_CLI_COMMAND (test_sr_hmac_validate, static) = {
2693 .path = "test sr hmac",
2694 .short_help = "test sr hmac validate [on|off]",
2695 .function = test_sr_hmac_validate_fn,
2698 i32 sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
2702 ip6_sr_hmac_key_t * key;
2706 /* Specific key in use? Fail. */
2707 if (key_id && vec_len (sm->hmac_keys) > key_id
2708 && sm->hmac_keys[key_id].shared_secret)
2712 key = find_or_add_shared_secret (sm, shared_secret, &index);
2713 ASSERT(index == key_id);
2719 if (key_id) /* delete by key ID */
2721 if (vec_len (sm->hmac_keys) <= key_id)
2724 key = sm->hmac_keys + key_id;
2726 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2727 vec_free (key->shared_secret);
2732 key = find_or_add_shared_secret (sm, shared_secret, &index);
2733 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2734 vec_free (key->shared_secret);
2739 static clib_error_t *
2740 sr_hmac_add_del_key_fn (vlib_main_t * vm,
2741 unformat_input_t * input,
2742 vlib_cli_command_t * cmd)
2744 ip6_sr_main_t * sm = &sr_main;
2748 u8 * shared_secret = 0;
2751 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2753 if (unformat (input, "del"))
2755 else if (unformat (input, "id %d", &key_id))
2757 else if (unformat (input, "key %s", &shared_secret))
2759 /* Do not include the trailing NULL byte. Guaranteed interop issue */
2760 _vec_len (shared_secret) -= 1;
2766 if (is_del == 0 && shared_secret == 0)
2767 return clib_error_return (0, "shared secret must be set to add a key");
2769 if (shared_secret == 0 && key_id_set == 0)
2770 return clib_error_return (0, "shared secret and key id both unset");
2772 rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
2774 vec_free (shared_secret);
2782 return clib_error_return (0, "sr_hmac_add_del_key returned %d",
2789 VLIB_CLI_COMMAND (sr_hmac, static) = {
2791 .short_help = "sr hmac [del] id <nn> key <str>",
2792 .function = sr_hmac_add_del_key_fn,
2796 static clib_error_t *
2797 show_sr_hmac_fn (vlib_main_t * vm,
2798 unformat_input_t * input,
2799 vlib_cli_command_t * cmd)
2801 ip6_sr_main_t * sm = &sr_main;
2804 for (i = 1; i < vec_len (sm->hmac_keys); i++)
2806 if (sm->hmac_keys[i].shared_secret)
2807 vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
2813 VLIB_CLI_COMMAND (show_sr_hmac, static) = {
2814 .path = "show sr hmac",
2815 .short_help = "show sr hmac",
2816 .function = show_sr_hmac_fn,
2819 static clib_error_t *
2820 test_sr_debug_fn (vlib_main_t * vm,
2821 unformat_input_t * input,
2822 vlib_cli_command_t * cmd)
2824 ip6_sr_main_t * sm = &sr_main;
2826 if (unformat (input, "on"))
2828 else if (unformat (input, "off"))
2831 return clib_error_return (0, "expected on|off in '%U'",
2832 format_unformat_error, input);
2834 vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
2839 VLIB_CLI_COMMAND (test_sr_debug, static) = {
2840 .path = "test sr debug",
2841 .short_help = "test sr debug on|off",
2842 .function = test_sr_debug_fn,