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 static 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 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 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 int print_hmac = va_arg (*args, int);
141 int i, pl_index, max_segs;
142 int flags_host_byte_order = clib_net_to_host_u16(h->flags);
144 s = format (s, "next proto %d, len %d, type %d",
145 h->protocol, (h->length<<3)+8, h->type);
146 s = format (s, "\n segs left %d, first_segment %d, hmac key %d",
147 h->segments_left, h->first_segment, h->hmac_key);
148 s = format (s, "\n flags %U", format_ip6_sr_header_flags,
149 flags_host_byte_order, 0 /* bswap needed */ );
152 * Header length is in 8-byte units (minus one), so
153 * divide by 2 to ascertain the number of ip6 addresses in the
156 max_segs = (h->length>>1);
158 if (!print_hmac && h->hmac_key)
161 s = format (s, "\n Segments (in processing order):");
163 for (i = h->first_segment; i >= 0; i--)
164 s = format (s, "\n %U", format_ip6_address, h->segments + i);
166 s = format (s, "\n Policy List:");
168 pl_index = 1; /* to match the RFC text */
169 for (i = (h->first_segment+1); i < max_segs; i++, pl_index++)
172 char * tags[] = {" ", "InPE: ", "EgPE: ", "OrgSrc: "};
175 if (pl_index >=1 && pl_index <= 4)
177 int this_pl_flag = ip6_sr_policy_list_flags
178 (flags_host_byte_order, pl_index);
179 tag = tags[this_pl_flag];
182 s = format (s, "\n %s%U", tag, format_ip6_address, h->segments + i);
188 u8 * format_ip6_sr_header_with_length (u8 * s, va_list * args)
190 ip6_header_t * h = va_arg (*args, ip6_header_t *);
191 u32 max_header_bytes = va_arg (*args, u32);
194 header_bytes = sizeof (h[0]) + sizeof (ip6_sr_header_t);
195 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
196 return format (s, "ip6_sr header truncated");
198 s = format (s, "IP6: %U\n", format_ip6_header, h, max_header_bytes);
199 s = format (s, "SR: %U\n", format_ip6_sr_header, (ip6_sr_header_t *)(h+1),
200 0 /* print_hmac */, max_header_bytes);
204 #define foreach_sr_rewrite_next \
205 _(ERROR, "error-drop") \
206 _(IP6_LOOKUP, "ip6-lookup") \
207 _(SR_LOCAL, "sr-local")
210 #define _(s,n) SR_REWRITE_NEXT_##s,
211 foreach_sr_rewrite_next
217 ip6_address_t src, dst;
222 } sr_rewrite_trace_t;
224 static char * sr_rewrite_error_strings[] = {
225 #define sr_error(n,s) s,
226 #include "sr_error.def"
231 #define sr_error(n,s) SR_REWRITE_ERROR_##n,
232 #include "sr_error.def"
235 } sr_rewrite_error_t;
238 u8 * format_sr_rewrite_trace (u8 * s, va_list * args)
240 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
241 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
242 sr_rewrite_trace_t * t = va_arg (*args, sr_rewrite_trace_t *);
243 ip6_main_t * im = &ip6_main;
244 ip6_sr_main_t * sm = &sr_main;
245 ip6_sr_tunnel_t *tun = pool_elt_at_index (sm->tunnels, t->tunnel_index);
246 ip6_fib_t * rx_fib, * tx_fib;
248 rx_fib = find_ip6_fib_by_table_index_or_id (im, tun->rx_fib_index,
249 IP6_ROUTE_FLAG_FIB_INDEX);
251 tx_fib = find_ip6_fib_by_table_index_or_id (im, tun->tx_fib_index,
252 IP6_ROUTE_FLAG_FIB_INDEX);
255 (s, "SR-REWRITE: next %s ip6 src %U dst %U len %u\n"
256 " rx-fib-id %d tx-fib-id %d\n%U",
257 (t->next_index == SR_REWRITE_NEXT_SR_LOCAL)
258 ? "sr-local" : "ip6-lookup",
259 format_ip6_address, &t->src,
260 format_ip6_address, &t->dst, t->length,
261 rx_fib->table_id, tx_fib->table_id,
262 format_ip6_sr_header, t->sr, 0 /* print_hmac */);
267 sr_rewrite (vlib_main_t * vm,
268 vlib_node_runtime_t * node,
269 vlib_frame_t * from_frame)
271 u32 n_left_from, next_index, * from, * to_next;
272 ip6_main_t * im = &ip6_main;
273 ip_lookup_main_t * lm = &im->lookup_main;
274 ip6_sr_main_t * sm = &sr_main;
275 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
276 vlib_buffer_t *, ip6_header_t *,
278 sr_local_cb = sm->sr_local_cb;
280 from = vlib_frame_vector_args (from_frame);
281 n_left_from = from_frame->n_vectors;
283 next_index = node->cached_next_index;
285 while (n_left_from > 0)
289 vlib_get_next_frame (vm, node, next_index,
290 to_next, n_left_to_next);
292 while (n_left_from >= 4 && n_left_to_next >= 2)
295 vlib_buffer_t * b0, * b1;
296 ip6_header_t * ip0, * ip1;
297 ip_adjacency_t * adj0, * adj1;
298 ip6_sr_header_t * sr0, * sr1;
299 ip6_sr_tunnel_t * t0, *t1;
300 u64 * copy_src0, * copy_dst0;
301 u64 * copy_src1, * copy_dst1;
302 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
303 u32 next1 = SR_REWRITE_NEXT_IP6_LOOKUP;
306 /* Prefetch next iteration. */
308 vlib_buffer_t * p2, * p3;
310 p2 = vlib_get_buffer (vm, from[2]);
311 p3 = vlib_get_buffer (vm, from[3]);
313 vlib_prefetch_buffer_header (p2, LOAD);
314 vlib_prefetch_buffer_header (p3, LOAD);
326 b0 = vlib_get_buffer (vm, bi0);
327 b1 = vlib_get_buffer (vm, bi1);
330 * $$$ parse through header(s) to pick the point
331 * where we punch in the SR extention header
334 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
335 adj1 = ip_get_adjacency (lm, vnet_buffer(b1)->ip.adj_index[VLIB_TX]);
336 t0 = pool_elt_at_index (sm->tunnels,
337 adj0->rewrite_header.sw_if_index);
338 t1 = pool_elt_at_index (sm->tunnels,
339 adj1->rewrite_header.sw_if_index);
341 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
342 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
343 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
344 >= ((word) vec_len (t1->rewrite)) + b1->current_data);
346 vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
347 vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->tx_fib_index;
349 ip0 = vlib_buffer_get_current (b0);
350 ip1 = vlib_buffer_get_current (b1);
353 * SR-unaware service chaining case: pkt coming back from
354 * service has the original dst address, and will already
355 * have an SR header. If so, send it to sr-local
357 if (PREDICT_FALSE(ip0->protocol == 43))
359 vlib_buffer_advance (b0, sizeof(ip0));
360 sr0 = (ip6_sr_header_t *) (ip0+1);
361 new_l0 = clib_net_to_host_u16(ip0->payload_length);
362 next0 = SR_REWRITE_NEXT_SR_LOCAL;
366 copy_dst0 = (u64 *)(((u8 *)ip0) - vec_len (t0->rewrite));
367 copy_src0 = (u64 *) ip0;
370 * Copy data before the punch-in point left by the
371 * required amount. Assume (for the moment) that only
372 * the main packet header needs to be copied.
374 copy_dst0 [0] = copy_src0 [0];
375 copy_dst0 [1] = copy_src0 [1];
376 copy_dst0 [2] = copy_src0 [2];
377 copy_dst0 [3] = copy_src0 [3];
378 copy_dst0 [4] = copy_src0 [4];
379 vlib_buffer_advance (b0, - (word) vec_len(t0->rewrite));
380 ip0 = vlib_buffer_get_current (b0);
381 sr0 = (ip6_sr_header_t *) (ip0+1);
383 memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
384 /* Fix the next header chain */
385 sr0->protocol = ip0->protocol;
386 ip0->protocol = 43; /* routing extension header */
387 new_l0 = clib_net_to_host_u16(ip0->payload_length) +
388 vec_len (t0->rewrite);
389 ip0->payload_length = clib_host_to_net_u16(new_l0);
390 /* Rewrite the ip6 dst address */
391 ip0->dst_address.as_u64[0] = t0->first_hop.as_u64[0];
392 ip0->dst_address.as_u64[1] = t0->first_hop.as_u64[1];
394 sr_fix_hmac (sm, ip0, sr0);
396 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
400 * Ignore "do not rewrite" shtik in this path
402 if (PREDICT_FALSE (next0 & 0x80000000))
405 if (PREDICT_FALSE(next0 == SR_REWRITE_NEXT_ERROR))
407 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
411 if (PREDICT_FALSE(ip1->protocol == 43))
413 vlib_buffer_advance (b1, sizeof(ip1));
414 sr1 = (ip6_sr_header_t *) (ip1+1);
415 new_l1 = clib_net_to_host_u16(ip1->payload_length);
416 next1 = SR_REWRITE_NEXT_SR_LOCAL;
420 copy_dst1 = (u64 *)(((u8 *)ip1) - vec_len (t1->rewrite));
421 copy_src1 = (u64 *) ip1;
423 copy_dst1 [0] = copy_src1 [0];
424 copy_dst1 [1] = copy_src1 [1];
425 copy_dst1 [2] = copy_src1 [2];
426 copy_dst1 [3] = copy_src1 [3];
427 copy_dst1 [4] = copy_src1 [4];
428 vlib_buffer_advance (b1, - (word) vec_len(t1->rewrite));
429 ip1 = vlib_buffer_get_current (b1);
430 sr1 = (ip6_sr_header_t *) (ip1+1);
431 memcpy (sr1, t1->rewrite, vec_len (t1->rewrite));
432 sr1->protocol = ip1->protocol;
434 new_l1 = clib_net_to_host_u16(ip1->payload_length) +
435 vec_len (t1->rewrite);
436 ip1->payload_length = clib_host_to_net_u16(new_l1);
437 ip1->dst_address.as_u64[0] = t1->first_hop.as_u64[0];
438 ip1->dst_address.as_u64[1] = t1->first_hop.as_u64[1];
440 sr_fix_hmac (sm, ip1, sr1);
442 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
446 * Ignore "do not rewrite" shtik in this path
448 if (PREDICT_FALSE (next1 & 0x80000000))
451 if (PREDICT_FALSE(next1 == SR_REWRITE_NEXT_ERROR))
453 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
457 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
459 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
461 tr->tunnel_index = t0 - sm->tunnels;
462 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
463 sizeof (tr->src.as_u8));
464 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
465 sizeof (tr->dst.as_u8));
467 tr->next_index = next0;
468 memcpy (tr->sr, sr0, sizeof (tr->sr));
470 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
472 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
474 tr->tunnel_index = t1 - sm->tunnels;
475 memcpy (tr->src.as_u8, ip1->src_address.as_u8,
476 sizeof (tr->src.as_u8));
477 memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
478 sizeof (tr->dst.as_u8));
480 tr->next_index = next1;
481 memcpy (tr->sr, sr1, sizeof (tr->sr));
484 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
485 to_next, n_left_to_next,
486 bi0, bi1, next0, next1);
489 while (n_left_from > 0 && n_left_to_next > 0)
494 ip_adjacency_t * adj0;
495 ip6_sr_header_t * sr0;
496 ip6_sr_tunnel_t * t0;
497 u64 * copy_src0, * copy_dst0;
498 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
508 b0 = vlib_get_buffer (vm, bi0);
511 * $$$ parse through header(s) to pick the point
512 * where we punch in the SR extention header
515 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
516 t0 = pool_elt_at_index (sm->tunnels,
517 adj0->rewrite_header.sw_if_index);
519 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
520 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
522 vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
524 ip0 = vlib_buffer_get_current (b0);
527 * SR-unaware service chaining case: pkt coming back from
528 * service has the original dst address, and will already
529 * have an SR header. If so, send it to sr-local
531 if (PREDICT_FALSE(ip0->protocol == 43))
533 vlib_buffer_advance (b0, sizeof(ip0));
534 sr0 = (ip6_sr_header_t *) (ip0+1);
535 new_l0 = clib_net_to_host_u16(ip0->payload_length);
536 next0 = SR_REWRITE_NEXT_SR_LOCAL;
540 copy_dst0 = (u64 *)(((u8 *)ip0) - vec_len (t0->rewrite));
541 copy_src0 = (u64 *) ip0;
544 * Copy data before the punch-in point left by the
545 * required amount. Assume (for the moment) that only
546 * the main packet header needs to be copied.
548 copy_dst0 [0] = copy_src0 [0];
549 copy_dst0 [1] = copy_src0 [1];
550 copy_dst0 [2] = copy_src0 [2];
551 copy_dst0 [3] = copy_src0 [3];
552 copy_dst0 [4] = copy_src0 [4];
553 vlib_buffer_advance (b0, - (word) vec_len(t0->rewrite));
554 ip0 = vlib_buffer_get_current (b0);
555 sr0 = (ip6_sr_header_t *) (ip0+1);
557 memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
558 /* Fix the next header chain */
559 sr0->protocol = ip0->protocol;
560 ip0->protocol = 43; /* routing extension header */
561 new_l0 = clib_net_to_host_u16(ip0->payload_length) +
562 vec_len (t0->rewrite);
563 ip0->payload_length = clib_host_to_net_u16(new_l0);
564 /* Rewrite the ip6 dst address */
565 ip0->dst_address.as_u64[0] = t0->first_hop.as_u64[0];
566 ip0->dst_address.as_u64[1] = t0->first_hop.as_u64[1];
568 sr_fix_hmac (sm, ip0, sr0);
570 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
574 * Ignore "do not rewrite" shtik in this path
576 if (PREDICT_FALSE (next0 & 0x80000000))
579 if (PREDICT_FALSE(next0 == SR_REWRITE_NEXT_ERROR))
581 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
585 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
587 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
589 tr->tunnel_index = t0 - sm->tunnels;
590 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
591 sizeof (tr->src.as_u8));
592 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
593 sizeof (tr->dst.as_u8));
595 tr->next_index = next0;
596 memcpy (tr->sr, sr0, sizeof (tr->sr));
599 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
600 to_next, n_left_to_next,
604 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
606 return from_frame->n_vectors;
609 VLIB_REGISTER_NODE (sr_rewrite_node) = {
610 .function = sr_rewrite,
611 .name = "sr-rewrite",
612 /* Takes a vector of packets. */
613 .vector_size = sizeof (u32),
614 .format_trace = format_sr_rewrite_trace,
615 .format_buffer = format_ip6_sr_header_with_length,
617 .n_errors = SR_REWRITE_N_ERROR,
618 .error_strings = sr_rewrite_error_strings,
620 .runtime_data_bytes = 0,
622 .n_next_nodes = SR_REWRITE_N_NEXT,
624 #define _(s,n) [SR_REWRITE_NEXT_##s] = n,
625 foreach_sr_rewrite_next
630 static int ip6_delete_route_no_next_hop (ip6_address_t *dst_address_arg,
631 u32 dst_address_length,
634 ip6_add_del_route_args_t a;
635 ip6_address_t dst_address;
637 ip6_main_t * im6 = &ip6_main;
638 BVT(clib_bihash_kv) kv, value;
640 fib = find_ip6_fib_by_table_index_or_id (im6, rx_table_id,
641 IP6_ROUTE_FLAG_TABLE_ID);
642 memset (&a, 0, sizeof (a));
643 a.flags |= IP4_ROUTE_FLAG_DEL;
644 a.dst_address_length = dst_address_length;
646 dst_address = *dst_address_arg;
648 ip6_address_mask (&dst_address,
649 &im6->fib_masks[dst_address_length]);
651 kv.key[0] = dst_address.as_u64[0];
652 kv.key[1] = dst_address.as_u64[1];
653 kv.key[2] = ((u64)((fib - im6->fibs))<<32) | dst_address_length;
655 if (BV(clib_bihash_search)(&im6->ip6_lookup_table, &kv, &value) < 0)
657 clib_warning ("%U/%d not in FIB",
658 format_ip6_address, &a.dst_address,
659 a.dst_address_length);
663 a.adj_index = value.value;
664 a.dst_address = dst_address;
666 ip6_add_del_route (im6, &a);
667 ip6_maybe_remap_adjacencies (im6, rx_table_id, IP6_ROUTE_FLAG_TABLE_ID);
671 static ip6_sr_hmac_key_t *
672 find_or_add_shared_secret (ip6_sr_main_t * sm, u8 * secret, u32 * indexp)
675 ip6_sr_hmac_key_t * key = 0;
678 p = hash_get_mem (sm->hmac_key_by_shared_secret, secret);
682 key = vec_elt_at_index (sm->hmac_keys, p[0]);
688 /* Specific key ID? */
689 if (indexp && *indexp)
691 vec_validate (sm->hmac_keys, *indexp);
692 key = sm->hmac_keys + *indexp;
696 for (i = 0; i < vec_len (sm->hmac_keys); i++)
698 if (sm->hmac_keys[i].shared_secret == 0)
699 key = sm->hmac_keys + i;
702 vec_validate (sm->hmac_keys, i);
703 key = sm->hmac_keys + i;
708 key->shared_secret = vec_dup (secret);
710 hash_set_mem (sm->hmac_key_by_shared_secret, key->shared_secret,
711 key - sm->hmac_keys);
714 *indexp = key - sm->hmac_keys;
718 int ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
720 ip6_main_t * im = &ip6_main;
721 ip_lookup_main_t * lm = &im->lookup_main;
722 ip6_sr_tunnel_key_t key;
725 ip6_sr_header_t * h = 0;
727 ip6_address_t * addrp, *this_address;
728 ip_adjacency_t adj, * ap, * add_adj = 0;
730 ip6_sr_main_t * sm = &sr_main;
732 u32 rx_fib_index, tx_fib_index;
733 ip6_add_del_route_args_t aa;
734 u32 hmac_key_index_u32;
735 u8 hmac_key_index = 0;
737 /* Make sure that the rx FIB exists */
738 p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
743 /* remember the FIB index */
746 /* Make sure that the supplied FIB exists */
747 p = hash_get (im->fib_index_by_table_id, a->tx_table_id);
752 /* remember the FIB index */
755 memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
756 memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
758 p = hash_get_mem (sm->tunnel_index_by_key, &key);
766 /* Delete existing tunnel */
767 t = pool_elt_at_index (sm->tunnels, p[0]);
769 ip6_delete_route_no_next_hop (&t->key.dst, t->dst_mask_width,
771 vec_free (t->rewrite);
772 pool_put (sm->tunnels, t);
773 hp = hash_get_pair (sm->tunnel_index_by_key, &key);
774 key_copy = (void *)(hp->key);
775 hash_unset_mem (sm->tunnel_index_by_key, &key);
779 else /* create; tunnel already exists; complain */
784 /* delete; tunnel does not exist; complain */
789 /* create a new tunnel */
790 pool_get (sm->tunnels, t);
791 memset (t, 0, sizeof (*t));
793 memcpy (&t->key, &key, sizeof (t->key));
794 t->dst_mask_width = a->dst_mask_width;
795 t->rx_fib_index = rx_fib_index;
796 t->tx_fib_index = tx_fib_index;
798 /* The first specified hop goes right into the dst address */
799 if (vec_len(a->segments))
801 t->first_hop = a->segments[0];
802 /* It won't feel nice if we do it twice */
803 vec_delete (a->segments, 1, 0);
805 else /* there must be at least one segment... */
809 * Create the sr header rewrite string
810 * We append the dst address to the set of next hops
811 * so the ultimate recipient can tell where the
812 * packet entered the SR domain
814 header_length = sizeof (*h) +
815 sizeof (ip6_address_t) * (vec_len (a->segments) + vec_len (a->tags));
817 if (a->shared_secret)
819 /* Allocate a new key slot if we don't find the secret key */
820 hmac_key_index_u32 = 0;
821 (void) find_or_add_shared_secret (sm, a->shared_secret,
822 &hmac_key_index_u32);
824 /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
825 if (hmac_key_index_u32 >= 256)
827 hmac_key_index = hmac_key_index_u32;
828 header_length += SHA256_DIGEST_LENGTH;
831 vec_validate (t->rewrite, header_length-1);
833 h = (ip6_sr_header_t *) t->rewrite;
835 h->protocol = 0xFF; /* we don't know yet */
837 h->length = (header_length/8) - 1;
838 h->type = ROUTING_HEADER_TYPE_SR;
839 h->segments_left = vec_len (a->segments);
840 h->first_segment = vec_len(a->segments) -1;
841 if (a->shared_secret)
842 h->hmac_key = hmac_key_index & 0xFF;
844 h->flags = a->flags_net_byte_order;
846 /* Paint on the segment list, in reverse */
847 addrp = h->segments + (vec_len (a->segments) - 1);
849 vec_foreach (this_address, a->segments)
851 memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
855 /* Paint on the tag list, not reversed */
856 addrp = h->segments + vec_len(a->segments);
858 vec_foreach (this_address, a->tags)
860 memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
864 key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
865 memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
866 hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
868 memset(&adj, 0, sizeof (adj));
870 /* Create an adjacency and add to v6 fib */
871 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
872 adj.lookup_next_index = sm->ip6_lookup_sr_next_index;
873 adj.explicit_fib_index = ~0;
875 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */,
879 * Stick the tunnel index into the rewrite header.
881 * Unfortunately, inserting an SR header according to the various
882 * RFC's requires parsing through the ip6 header, perhaps consing a
883 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
884 * normal reverse bcopy rewrite code.
886 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
889 ap->rewrite_header.sw_if_index = t - sm->tunnels;
891 vec_add1 (add_adj, ap[0]);
893 memcpy (aa.dst_address.as_u8, a->dst_address, sizeof (aa.dst_address.as_u8));
894 aa.dst_address_length = a->dst_mask_width;
896 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
897 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
898 aa.table_index_or_table_id = rx_fib_index;
899 aa.add_adj = add_adj;
900 aa.adj_index = adj_index;
902 ip6_add_del_route (im, &aa);
908 static clib_error_t *
909 sr_add_del_tunnel_command_fn (vlib_main_t * vm,
910 unformat_input_t * input,
911 vlib_cli_command_t * cmd)
914 ip6_address_t src_address;
915 int src_address_set = 0;
916 ip6_address_t dst_address;
918 int dst_address_set = 0;
920 u8 *shared_secret = 0;
923 ip6_address_t * segments = 0;
924 ip6_address_t * this_seg;
925 ip6_address_t * tags = 0;
926 ip6_address_t * this_tag;
927 ip6_sr_add_del_tunnel_args_t _a, *a=&_a;
928 ip6_address_t next_address, tag;
932 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
934 if (unformat (input, "del"))
936 else if (unformat (input, "rx-fib-id %d", &rx_table_id))
938 else if (unformat (input, "tx-fib-id %d", &tx_table_id))
940 else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
942 else if (unformat (input, "dst %U/%d",
943 unformat_ip6_address, &dst_address,
946 else if (unformat (input, "next %U", unformat_ip6_address,
949 vec_add2 (segments, this_seg, 1);
950 memcpy (this_seg->as_u8, next_address.as_u8, sizeof (*this_seg));
952 else if (unformat (input, "tag %U", unformat_ip6_address,
955 vec_add2 (tags, this_tag, 1);
956 memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
958 else if (unformat (input, "clean"))
959 flags |= IP6_SR_HEADER_FLAG_CLEANUP;
960 else if (unformat (input, "protected"))
961 flags |= IP6_SR_HEADER_FLAG_PROTECTED;
962 else if (unformat (input, "key %s", &shared_secret))
963 /* Do not include the trailing NULL byte. Guaranteed interop issue */
964 _vec_len (shared_secret) -= 1;
965 else if (unformat (input, "InPE %d", &pl_index))
967 if (pl_index <= 0 || pl_index > 4)
969 pl_index_range_error:
970 return clib_error_return
971 (0, "Policy List Element Index %d out of range (1-4)", pl_index);
974 flags |= IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
975 << ip6_sr_policy_list_shift_from_index (pl_index);
977 else if (unformat (input, "EgPE %d", &pl_index))
979 if (pl_index <= 0 || pl_index > 4)
980 goto pl_index_range_error;
981 flags |= IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
982 << ip6_sr_policy_list_shift_from_index (pl_index);
984 else if (unformat (input, "OrgSrc %d", &pl_index))
986 if (pl_index <= 0 || pl_index > 4)
987 goto pl_index_range_error;
988 flags |= IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
989 << ip6_sr_policy_list_shift_from_index (pl_index);
995 if (!src_address_set)
996 return clib_error_return (0, "src address required");
998 if (!dst_address_set)
999 return clib_error_return (0, "dst address required");
1002 return clib_error_return (0, "at least one sr segment required");
1004 memset (a, 0, sizeof (*a));
1005 a->src_address = &src_address;
1006 a->dst_address = &dst_address;
1007 a->dst_mask_width = dst_mask_width;
1008 a->segments = segments;
1010 a->flags_net_byte_order = clib_host_to_net_u16(flags);
1012 a->rx_table_id = rx_table_id;
1013 a->tx_table_id = tx_table_id;
1014 a->shared_secret = shared_secret;
1016 rv = ip6_sr_add_del_tunnel (a);
1018 vec_free (segments);
1020 vec_free (shared_secret);
1028 return clib_error_return (0, "SR tunnel src %U dst %U already exists",
1029 format_ip6_address, &src_address,
1030 format_ip6_address, &dst_address);
1033 return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
1034 format_ip6_address, &src_address,
1035 format_ip6_address, &dst_address);
1038 return clib_error_return (0, "FIB table %d does not exist", rx_table_id);
1041 return clib_error_return (0, "At least one segment is required");
1044 return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
1051 VLIB_CLI_COMMAND (sr_tunnel_command, static) = {
1052 .path = "sr tunnel",
1054 "sr tunnel [del] <src> <dst> [next <addr>] [cleanup] [reroute] [key %s]",
1055 .function = sr_add_del_tunnel_command_fn,
1059 static clib_error_t *
1060 show_sr_tunnel_fn (vlib_main_t * vm,
1061 unformat_input_t * input,
1062 vlib_cli_command_t * cmd)
1064 static ip6_sr_tunnel_t ** tunnels;
1065 ip6_sr_tunnel_t * t;
1066 ip6_sr_main_t * sm = &sr_main;
1067 ip6_main_t * im = &ip6_main;
1068 ip6_fib_t * rx_fib, * tx_fib;
1071 vec_reset_length (tunnels);
1073 pool_foreach (t, sm->tunnels,
1075 vec_add1 (tunnels, t);
1078 if (vec_len (tunnels) == 0)
1079 vlib_cli_output (vm, "No SR tunnels configured");
1081 for (i = 0; i < vec_len (tunnels); i++)
1085 rx_fib = find_ip6_fib_by_table_index_or_id (im, t->rx_fib_index,
1086 IP6_ROUTE_FLAG_FIB_INDEX);
1088 tx_fib = find_ip6_fib_by_table_index_or_id (im, t->tx_fib_index,
1089 IP6_ROUTE_FLAG_FIB_INDEX);
1091 vlib_cli_output (vm, "src %U dst %U first hop %U",
1092 format_ip6_address, &t->key.src,
1093 format_ip6_address, &t->key.dst,
1094 format_ip6_address, &t->first_hop);
1095 vlib_cli_output (vm, " rx-fib-id %d tx-fib-id %d",
1096 rx_fib->table_id, tx_fib->table_id);
1097 vlib_cli_output (vm, " sr: %U", format_ip6_sr_header, t->rewrite,
1098 0 /* print_hmac */);
1099 vlib_cli_output (vm, "-------");
1105 VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
1106 .path = "show sr tunnel",
1107 .short_help = "show sr tunnel",
1108 .function = show_sr_tunnel_fn,
1111 #define foreach_sr_fix_dst_addr_next \
1112 _(DROP, "error-drop")
1115 #define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
1116 foreach_sr_fix_dst_addr_next
1118 SR_FIX_DST_ADDR_N_NEXT,
1119 } sr_fix_dst_addr_next_t;
1121 static char * sr_fix_dst_error_strings[] = {
1122 #define sr_fix_dst_error(n,s) s,
1123 #include "sr_fix_dst_error.def"
1124 #undef sr_fix_dst_error
1128 #define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
1129 #include "sr_fix_dst_error.def"
1130 #undef sr_fix_dst_error
1132 } sr_fix_dst_error_t;
1135 ip6_address_t src, dst;
1139 } sr_fix_addr_trace_t;
1141 u8 * format_sr_fix_addr_trace (u8 * s, va_list * args)
1143 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1144 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1145 sr_fix_addr_trace_t * t = va_arg (*args, sr_fix_addr_trace_t *);
1146 vnet_hw_interface_t * hi = 0;
1147 ip_adjacency_t * adj;
1148 ip6_main_t * im = &ip6_main;
1149 ip_lookup_main_t * lm = &im->lookup_main;
1150 vnet_main_t * vnm = vnet_get_main();
1152 if (t->adj_index != ~0)
1154 adj = ip_get_adjacency (lm, t->adj_index);
1155 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
1158 s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
1159 (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
1160 ? "drop" : "output",
1161 format_ip6_address, &t->src,
1162 format_ip6_address, &t->dst);
1163 if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
1165 s = format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
1166 s = format (s, " output via %s", hi ? (char *)(hi->name)
1173 sr_fix_dst_addr (vlib_main_t * vm,
1174 vlib_node_runtime_t * node,
1175 vlib_frame_t * from_frame)
1177 u32 n_left_from, next_index, * from, * to_next;
1178 ip6_main_t * im = &ip6_main;
1179 ip_lookup_main_t * lm = &im->lookup_main;
1181 from = vlib_frame_vector_args (from_frame);
1182 n_left_from = from_frame->n_vectors;
1184 next_index = node->cached_next_index;
1186 while (n_left_from > 0)
1190 vlib_get_next_frame (vm, node, next_index,
1191 to_next, n_left_to_next);
1194 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
1197 __attribute__((unused)) vlib_buffer_t * b0, * b1;
1198 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1199 u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
1201 /* Prefetch next iteration. */
1203 vlib_buffer_t * p2, * p3;
1205 p2 = vlib_get_buffer (vm, from[2]);
1206 p3 = vlib_get_buffer (vm, from[3]);
1208 vlib_prefetch_buffer_header (p2, LOAD);
1209 vlib_prefetch_buffer_header (p3, LOAD);
1218 n_left_to_next -= 2;
1221 b0 = vlib_get_buffer (vm, bi0);
1222 b1 = vlib_get_buffer (vm, bi1);
1225 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1226 to_next, n_left_to_next,
1227 bi0, bi1, next0, next1);
1231 while (n_left_from > 0 && n_left_to_next > 0)
1236 ip_adjacency_t * adj0;
1237 ip6_sr_header_t * sr0;
1238 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1239 ip6_address_t *new_dst0;
1240 ethernet_header_t * eh0;
1247 n_left_to_next -= 1;
1249 b0 = vlib_get_buffer (vm, bi0);
1251 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
1252 next0 = adj0->mcast_group_index;
1254 /* We should be pointing at an Ethernet header... */
1255 eh0 = vlib_buffer_get_current (b0);
1256 ip0 = (ip6_header_t *)(eh0+1);
1257 sr0 = (ip6_sr_header_t *) (ip0+1);
1259 /* We'd better find an SR header... */
1260 if (PREDICT_FALSE(ip0->protocol != 43))
1262 b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
1268 * We get here from sr_rewrite or sr_local, with
1269 * sr->segments_left pointing at the (copy of the original) dst
1270 * address. Use it, then increment sr0->segments_left.
1273 /* Out of segments? Turf the packet */
1274 if (PREDICT_FALSE (sr0->segments_left == 0))
1276 b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
1281 * Rewrite the packet with the original dst address
1282 * We assume that the last segment (in processing order) contains
1283 * the original dst address. The list is reversed, so sr0->segments
1284 * contains the original dst address.
1286 new_dst0 = sr0->segments;
1287 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1288 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1293 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1295 sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
1297 t->next_index = next0;
1300 if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
1302 t->adj_index = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
1303 memcpy (t->src.as_u8, ip0->src_address.as_u8,
1304 sizeof (t->src.as_u8));
1305 memcpy (t->dst.as_u8, ip0->dst_address.as_u8,
1306 sizeof (t->dst.as_u8));
1307 memcpy (t->sr, sr0, sizeof (t->sr));
1311 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1312 to_next, n_left_to_next,
1316 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1318 return from_frame->n_vectors;
1322 VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
1323 .function = sr_fix_dst_addr,
1324 .name = "sr-fix-dst-addr",
1325 /* Takes a vector of packets. */
1326 .vector_size = sizeof (u32),
1327 .format_trace = format_sr_fix_addr_trace,
1328 .format_buffer = format_ip6_sr_header_with_length,
1330 .runtime_data_bytes = 0,
1332 .n_errors = SR_FIX_DST_N_ERROR,
1333 .error_strings = sr_fix_dst_error_strings,
1335 .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
1337 #define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
1338 foreach_sr_fix_dst_addr_next
1343 static clib_error_t * sr_init (vlib_main_t * vm)
1345 ip6_sr_main_t * sm = &sr_main;
1346 clib_error_t * error = 0;
1347 vlib_node_t * ip6_lookup_node, * ip6_rewrite_node;
1348 vlib_node_t * ip6_rewrite_local_node;
1349 u32 verify_next_index;
1351 if ((error = vlib_call_init_function (vm, ip_main_init)))
1354 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
1358 sm->vnet_main = vnet_get_main();
1360 vec_validate (sm->hmac_keys, 0);
1361 sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
1363 sm->tunnel_index_by_key =
1364 hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
1366 sm->hmac_key_by_shared_secret = hash_create_string (0, sizeof(uword));
1368 ip6_register_protocol (43, sr_local_node.index);
1370 ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *)"ip6-lookup");
1371 ASSERT(ip6_lookup_node);
1373 ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *)"ip6-rewrite");
1374 ASSERT(ip6_rewrite_node);
1376 ip6_rewrite_local_node = vlib_get_node_by_name (vm,
1377 (u8 *)"ip6-rewrite-local");
1378 ASSERT(ip6_rewrite_local_node);
1380 /* Add a disposition to ip6_lookup for the sr rewrite node */
1381 sm->ip6_lookup_sr_next_index =
1382 vlib_node_add_next (vm, ip6_lookup_node->index, sr_rewrite_node.index);
1384 /* Add a disposition to ip6_rewrite for the sr dst address hack node */
1385 sm->ip6_rewrite_sr_next_index =
1386 vlib_node_add_next (vm, ip6_rewrite_node->index,
1387 sr_fix_dst_addr_node.index);
1389 * Fix ip6-rewrite-local, sibling of the above. The sibling bitmap
1390 * isn't set up at this point, so we have to do it manually
1392 verify_next_index = vlib_node_add_next
1393 (vm, ip6_rewrite_local_node->index,
1394 sr_fix_dst_addr_node.index);
1396 ASSERT(sm->ip6_rewrite_sr_next_index == verify_next_index);
1398 OpenSSL_add_all_digests();
1400 sm->md = (void *) EVP_get_digestbyname ("sha1");
1401 sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
1406 VLIB_INIT_FUNCTION (sr_init);
1408 #define foreach_sr_local_next \
1409 _ (ERROR, "error-drop") \
1410 _ (IP6_LOOKUP, "ip6-lookup")
1413 #define _(s,n) SR_LOCAL_NEXT_##s,
1414 foreach_sr_local_next
1422 ip6_address_t src, dst;
1427 static char * sr_local_error_strings[] = {
1428 #define sr_error(n,s) s,
1429 #include "sr_error.def"
1434 #define sr_error(n,s) SR_LOCAL_ERROR_##n,
1435 #include "sr_error.def"
1440 u8 * format_sr_local_trace (u8 * s, va_list * args)
1442 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1443 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1444 sr_local_trace_t * t = va_arg (*args, sr_local_trace_t *);
1446 s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
1447 format_ip6_address, &t->src,
1448 format_ip6_address, &t->dst, t->length, t->next_index);
1450 s = format (s, "\n %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
1452 s = format (s, "\n popped SR header");
1458 /* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
1460 static int sr_validate_hmac (ip6_sr_main_t * sm, ip6_header_t * ip,
1461 ip6_sr_header_t * sr)
1467 ip6_address_t *addrp;
1469 ip6_sr_hmac_key_t * hmac_key;
1470 static u8 * signature;
1473 key_index = sr->hmac_key;
1475 /* No signature? Pass... */
1479 /* We don't know about this key? Fail... */
1480 if (key_index >= vec_len (sm->hmac_keys))
1483 vec_validate (signature, SHA256_DIGEST_LENGTH-1);
1485 hmac_key = sm->hmac_keys + key_index;
1487 vec_reset_length (keybuf);
1489 /* pkt ip6 src address */
1490 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
1491 memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
1494 vec_add2 (keybuf, copy_target, 1);
1495 copy_target[0] = sr->first_segment;
1497 /* octet w/ bit 0 = "clean" flag */
1498 vec_add2 (keybuf, copy_target, 1);
1500 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
1504 vec_add2 (keybuf, copy_target, 1);
1505 copy_target[0] = sr->hmac_key;
1507 first_segment = sr->first_segment;
1509 addrp = sr->segments;
1512 for (i = 0; i <= first_segment; i++)
1514 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
1515 memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
1520 clib_warning ("verify key index %d keybuf: %U", key_index,
1521 format_hex_bytes, keybuf, vec_len(keybuf));
1525 /* SHA1 is shorter than SHA-256 */
1526 memset (signature, 0, vec_len(signature));
1528 HMAC_CTX_init(sm->hmac_ctx);
1529 if (!HMAC_Init(sm->hmac_ctx, hmac_key->shared_secret,
1530 vec_len(hmac_key->shared_secret),sm->md))
1531 clib_warning ("barf1");
1532 if (!HMAC_Update(sm->hmac_ctx,keybuf,vec_len(keybuf)))
1533 clib_warning ("barf2");
1534 if (!HMAC_Final(sm->hmac_ctx,signature,&sig_len))
1535 clib_warning ("barf3");
1536 HMAC_CTX_cleanup(sm->hmac_ctx);
1539 clib_warning ("computed signature len %d, value %U", sig_len,
1540 format_hex_bytes, signature, vec_len(signature));
1542 /* Point at the SHA signature in the packet */
1545 clib_warning ("read signature %U", format_hex_bytes, addrp,
1546 SHA256_DIGEST_LENGTH);
1548 return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
1552 sr_local (vlib_main_t * vm,
1553 vlib_node_runtime_t * node,
1554 vlib_frame_t * from_frame)
1556 u32 n_left_from, next_index, * from, * to_next;
1557 ip6_sr_main_t * sm = &sr_main;
1558 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
1559 vlib_buffer_t *, ip6_header_t *,
1561 sr_local_cb = sm->sr_local_cb;
1563 from = vlib_frame_vector_args (from_frame);
1564 n_left_from = from_frame->n_vectors;
1566 next_index = node->cached_next_index;
1568 while (n_left_from > 0)
1572 vlib_get_next_frame (vm, node, next_index,
1573 to_next, n_left_to_next);
1575 while (n_left_from >= 4 && n_left_to_next >= 2)
1578 vlib_buffer_t * b0, * b1;
1579 ip6_header_t * ip0, *ip1;
1580 ip6_sr_header_t * sr0, *sr1;
1581 ip6_address_t * new_dst0, * new_dst1;
1582 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
1583 u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
1584 /* Prefetch next iteration. */
1586 vlib_buffer_t * p2, * p3;
1588 p2 = vlib_get_buffer (vm, from[2]);
1589 p3 = vlib_get_buffer (vm, from[3]);
1591 vlib_prefetch_buffer_header (p2, LOAD);
1592 vlib_prefetch_buffer_header (p3, LOAD);
1594 CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
1595 CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
1604 n_left_to_next -= 2;
1608 b0 = vlib_get_buffer (vm, bi0);
1609 ip0 = vlib_buffer_get_current (b0);
1610 sr0 = (ip6_sr_header_t *)(ip0+1);
1612 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
1614 next0 = SR_LOCAL_NEXT_ERROR;
1615 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
1619 /* Out of segments? Turf the packet */
1620 if (PREDICT_FALSE (sr0->segments_left == 0))
1622 next0 = SR_LOCAL_NEXT_ERROR;
1623 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
1627 if (PREDICT_FALSE(sm->validate_hmac))
1629 if (sr_validate_hmac (sm, ip0, sr0))
1631 next0 = SR_LOCAL_NEXT_ERROR;
1632 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
1637 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
1641 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
1643 if (PREDICT_FALSE (next0 & 0x80000000))
1645 next0 ^= 0xFFFFFFFF;
1646 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
1648 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
1654 segment_index0 = sr0->segments_left - 1;
1656 /* Rewrite the packet */
1657 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
1658 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1659 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1661 if (PREDICT_TRUE (sr0->segments_left > 0))
1663 sr0->segments_left -= 1;
1668 /* End of the path. Clean up the SR header, or not */
1669 if (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))
1671 u64 *copy_dst0, *copy_src0;
1674 * Copy the ip6 header right by the (real) length of the
1675 * sr header. Here's another place which assumes that
1676 * the sr header is the only extention header.
1679 ip0->protocol = sr0->protocol;
1680 vlib_buffer_advance (b0, (sr0->length+1)*8);
1682 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
1684 ip0->payload_length = clib_host_to_net_u16(new_l0);
1686 copy_src0 = (u64 *)ip0;
1687 copy_dst0 = copy_src0 + (sr0->length + 1);
1689 copy_dst0 [4] = copy_src0[4];
1690 copy_dst0 [3] = copy_src0[3];
1691 copy_dst0 [2] = copy_src0[2];
1692 copy_dst0 [1] = copy_src0[1];
1693 copy_dst0 [0] = copy_src0[0];
1699 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1701 sr_local_trace_t *tr = vlib_add_trace (vm, node,
1703 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1704 sizeof (tr->src.as_u8));
1705 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1706 sizeof (tr->dst.as_u8));
1707 tr->length = vlib_buffer_length_in_chain (vm, b0);
1708 tr->next_index = next0;
1709 tr->sr_valid = sr0 != 0;
1711 memcpy (tr->sr, sr0, sizeof (tr->sr));
1714 b1 = vlib_get_buffer (vm, bi1);
1715 ip1 = vlib_buffer_get_current (b1);
1716 sr1 = (ip6_sr_header_t *)(ip1+1);
1718 if (PREDICT_FALSE(sr1->type != ROUTING_HEADER_TYPE_SR))
1720 next1 = SR_LOCAL_NEXT_ERROR;
1721 b1->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
1725 /* Out of segments? Turf the packet */
1726 if (PREDICT_FALSE (sr1->segments_left == 0))
1728 next1 = SR_LOCAL_NEXT_ERROR;
1729 b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
1733 if (PREDICT_FALSE(sm->validate_hmac))
1735 if (sr_validate_hmac (sm, ip1, sr1))
1737 next1 = SR_LOCAL_NEXT_ERROR;
1738 b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
1743 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
1747 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
1749 if (PREDICT_FALSE (next1 & 0x80000000))
1751 next1 ^= 0xFFFFFFFF;
1752 if (PREDICT_FALSE(next1 == SR_LOCAL_NEXT_ERROR))
1754 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
1760 segment_index1 = sr1->segments_left - 1;
1762 /* Rewrite the packet */
1763 new_dst1 = (ip6_address_t *)(sr1->segments + segment_index1);
1764 ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
1765 ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
1767 if (PREDICT_TRUE (sr1->segments_left > 0))
1769 sr1->segments_left -= 1;
1774 /* End of the path. Clean up the SR header, or not */
1775 if (sr1->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))
1777 u64 *copy_dst1, *copy_src1;
1780 * Copy the ip6 header right by the (real) length of the
1781 * sr header. Here's another place which assumes that
1782 * the sr header is the only extention header.
1785 ip1->protocol = sr1->protocol;
1786 vlib_buffer_advance (b1, (sr1->length+1)*8);
1788 new_l1 = clib_net_to_host_u16(ip1->payload_length) -
1790 ip1->payload_length = clib_host_to_net_u16(new_l1);
1792 copy_src1 = (u64 *)ip1;
1793 copy_dst1 = copy_src1 + (sr1->length + 1);
1795 copy_dst1 [4] = copy_src1[4];
1796 copy_dst1 [3] = copy_src1[3];
1797 copy_dst1 [2] = copy_src1[2];
1798 copy_dst1 [1] = copy_src1[1];
1799 copy_dst1 [0] = copy_src1[0];
1805 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
1807 sr_local_trace_t *tr = vlib_add_trace (vm, node,
1809 memcpy (tr->src.as_u8, ip1->src_address.as_u8,
1810 sizeof (tr->src.as_u8));
1811 memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
1812 sizeof (tr->dst.as_u8));
1813 tr->length = vlib_buffer_length_in_chain (vm, b1);
1814 tr->next_index = next1;
1815 tr->sr_valid = sr1 != 0;
1817 memcpy (tr->sr, sr1, sizeof (tr->sr));
1820 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1821 to_next, n_left_to_next,
1822 bi0, bi1, next0, next1);
1825 while (n_left_from > 0 && n_left_to_next > 0)
1830 ip6_sr_header_t * sr0;
1831 ip6_address_t * new_dst0;
1832 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
1839 n_left_to_next -= 1;
1841 b0 = vlib_get_buffer (vm, bi0);
1842 ip0 = vlib_buffer_get_current (b0);
1843 sr0 = (ip6_sr_header_t *)(ip0+1);
1845 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
1847 next0 = SR_LOCAL_NEXT_ERROR;
1848 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
1852 /* Out of segments? Turf the packet */
1853 if (PREDICT_FALSE (sr0->segments_left == 0))
1855 next0 = SR_LOCAL_NEXT_ERROR;
1856 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
1860 if (PREDICT_FALSE(sm->validate_hmac))
1862 if (sr_validate_hmac (sm, ip0, sr0))
1864 next0 = SR_LOCAL_NEXT_ERROR;
1865 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
1870 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
1874 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
1876 if (PREDICT_FALSE (next0 & 0x80000000))
1878 next0 ^= 0xFFFFFFFF;
1879 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
1881 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
1887 segment_index0 = sr0->segments_left - 1;
1889 /* Rewrite the packet */
1890 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
1891 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1892 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1894 if (PREDICT_TRUE (sr0->segments_left > 0))
1896 sr0->segments_left -= 1;
1901 /* End of the path. Clean up the SR header, or not */
1902 if (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))
1904 u64 *copy_dst0, *copy_src0;
1907 * Copy the ip6 header right by the (real) length of the
1908 * sr header. Here's another place which assumes that
1909 * the sr header is the only extention header.
1912 ip0->protocol = sr0->protocol;
1913 vlib_buffer_advance (b0, (sr0->length+1)*8);
1915 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
1917 ip0->payload_length = clib_host_to_net_u16(new_l0);
1919 copy_src0 = (u64 *)ip0;
1920 copy_dst0 = copy_src0 + (sr0->length + 1);
1922 copy_dst0 [4] = copy_src0[4];
1923 copy_dst0 [3] = copy_src0[3];
1924 copy_dst0 [2] = copy_src0[2];
1925 copy_dst0 [1] = copy_src0[1];
1926 copy_dst0 [0] = copy_src0[0];
1932 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1934 sr_local_trace_t *tr = vlib_add_trace (vm, node,
1936 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
1937 sizeof (tr->src.as_u8));
1938 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
1939 sizeof (tr->dst.as_u8));
1940 tr->length = vlib_buffer_length_in_chain (vm, b0);
1941 tr->next_index = next0;
1942 tr->sr_valid = sr0 != 0;
1944 memcpy (tr->sr, sr0, sizeof (tr->sr));
1947 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1948 to_next, n_left_to_next,
1952 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1954 vlib_node_increment_counter (vm, sr_local_node.index,
1955 SR_LOCAL_ERROR_PKTS_PROCESSED,
1956 from_frame->n_vectors);
1957 return from_frame->n_vectors;
1960 VLIB_REGISTER_NODE (sr_local_node, static) = {
1961 .function = sr_local,
1963 /* Takes a vector of packets. */
1964 .vector_size = sizeof (u32),
1965 .format_trace = format_sr_local_trace,
1967 .runtime_data_bytes = 0,
1969 .n_errors = SR_LOCAL_N_ERROR,
1970 .error_strings = sr_local_error_strings,
1972 .n_next_nodes = SR_LOCAL_N_NEXT,
1974 #define _(s,n) [SR_LOCAL_NEXT_##s] = n,
1975 foreach_sr_local_next
1980 ip6_sr_main_t * sr_get_main (vlib_main_t * vm)
1982 vlib_call_init_function (vm, sr_init);
1983 ASSERT(sr_local_node.index);
1988 static clib_error_t *
1989 set_ip6_sr_rewrite_fn (vlib_main_t * vm,
1990 unformat_input_t * input,
1991 vlib_cli_command_t * cmd)
1994 ip6_main_t * im = &ip6_main;
1995 ip_lookup_main_t * lm = &im->lookup_main;
2000 ip_adjacency_t * adj;
2001 vnet_hw_interface_t * hi;
2003 ip6_sr_main_t * sm = &sr_main;
2004 vnet_main_t * vnm = vnet_get_main();
2006 if (!unformat (input, "%U", unformat_ip6_address, &a))
2007 return clib_error_return (0, "ip6 address missing in '%U'",
2008 format_unformat_error, input);
2010 if (unformat (input, "rx-table-id %d", &fib_id))
2012 p = hash_get (im->fib_index_by_table_id, fib_id);
2014 return clib_error_return (0, "fib-id %d not found");
2018 adj_index = ip6_fib_lookup_with_table (im, fib_index, &a);
2020 if (adj_index == lm->miss_adj_index)
2021 return clib_error_return (0, "no match for %U",
2022 format_ip6_address, &a);
2024 adj = ip_get_adjacency (lm, adj_index);
2026 if (adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
2027 return clib_error_return (0, "%U unresolved (not a rewrite adj)",
2028 format_ip6_address, &a);
2030 adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
2032 sw_if_index = adj->rewrite_header.sw_if_index;
2033 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2034 adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
2036 /* $$$$$ hack... steal the mcast group index */
2037 adj->mcast_group_index =
2038 vlib_node_add_next (vm, sr_fix_dst_addr_node.index, hi->output_node_index);
2043 VLIB_CLI_COMMAND (set_ip6_sr_rewrite, static) = {
2044 .path = "set ip6 sr rewrite",
2045 .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
2046 .function = set_ip6_sr_rewrite_fn,
2049 void vnet_register_sr_app_callback (void *cb)
2051 ip6_sr_main_t * sm = &sr_main;
2053 sm->sr_local_cb = cb;
2056 static clib_error_t *
2057 test_sr_hmac_validate_fn (vlib_main_t * vm,
2058 unformat_input_t * input,
2059 vlib_cli_command_t * cmd)
2061 ip6_sr_main_t * sm = &sr_main;
2063 if (unformat (input, "validate on"))
2064 sm->validate_hmac = 1;
2065 else if (unformat (input, "chunk-offset off"))
2066 sm->validate_hmac = 0;
2068 return clib_error_return (0, "expected validate on|off in '%U'",
2069 format_unformat_error, input);
2071 vlib_cli_output (vm, "hmac signature validation %s",
2077 VLIB_CLI_COMMAND (test_sr_hmac_validate, static) = {
2078 .path = "test sr hmac",
2079 .short_help = "test sr hmac validate [on|off]",
2080 .function = test_sr_hmac_validate_fn,
2083 i32 sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
2087 ip6_sr_hmac_key_t * key;
2091 /* Specific key in use? Fail. */
2092 if (key_id && vec_len (sm->hmac_keys) > key_id
2093 && sm->hmac_keys[key_id].shared_secret)
2097 key = find_or_add_shared_secret (sm, shared_secret, &index);
2098 ASSERT(index == key_id);
2104 if (key_id) /* delete by key ID */
2106 if (vec_len (sm->hmac_keys) <= key_id)
2109 key = sm->hmac_keys + key_id;
2111 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2112 vec_free (key->shared_secret);
2117 key = find_or_add_shared_secret (sm, shared_secret, &index);
2118 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2119 vec_free (key->shared_secret);
2124 static clib_error_t *
2125 sr_hmac_add_del_key_fn (vlib_main_t * vm,
2126 unformat_input_t * input,
2127 vlib_cli_command_t * cmd)
2129 ip6_sr_main_t * sm = &sr_main;
2133 u8 * shared_secret = 0;
2136 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2138 if (unformat (input, "del"))
2140 else if (unformat (input, "id %d", &key_id))
2142 else if (unformat (input, "key %s", &shared_secret))
2144 /* Do not include the trailing NULL byte. Guaranteed interop issue */
2145 _vec_len (shared_secret) -= 1;
2151 if (is_del == 0 && shared_secret == 0)
2152 return clib_error_return (0, "shared secret must be set to add a key");
2154 if (shared_secret == 0 && key_id_set == 0)
2155 return clib_error_return (0, "shared secret and key id both unset");
2157 rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
2159 vec_free (shared_secret);
2167 return clib_error_return (0, "sr_hmac_add_del_key returned %d",
2174 VLIB_CLI_COMMAND (sr_hmac, static) = {
2176 .short_help = "sr hmac [del] id <nn> key <str>",
2177 .function = sr_hmac_add_del_key_fn,
2181 static clib_error_t *
2182 show_sr_hmac_fn (vlib_main_t * vm,
2183 unformat_input_t * input,
2184 vlib_cli_command_t * cmd)
2186 ip6_sr_main_t * sm = &sr_main;
2189 for (i = 1; i < vec_len (sm->hmac_keys); i++)
2191 if (sm->hmac_keys[i].shared_secret)
2192 vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
2198 VLIB_CLI_COMMAND (show_sr_hmac, static) = {
2199 .path = "show sr hmac",
2200 .short_help = "show sr hmac",
2201 .function = show_sr_hmac_fn,
2204 static clib_error_t *
2205 test_sr_debug_fn (vlib_main_t * vm,
2206 unformat_input_t * input,
2207 vlib_cli_command_t * cmd)
2209 ip6_sr_main_t * sm = &sr_main;
2211 if (unformat (input, "on"))
2213 else if (unformat (input, "off"))
2216 return clib_error_return (0, "expected on|off in '%U'",
2217 format_unformat_error, input);
2219 vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
2224 VLIB_CLI_COMMAND (test_sr_debug, static) = {
2225 .path = "test sr debug",
2226 .short_help = "test sr debug on|off",
2227 .function = test_sr_debug_fn,