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 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") \
208 _(SR_REPLICATE,"sr-replicate")
211 #define _(s,n) SR_REWRITE_NEXT_##s,
212 foreach_sr_rewrite_next
218 ip6_address_t src, dst;
223 } sr_rewrite_trace_t;
225 static char * sr_rewrite_error_strings[] = {
226 #define sr_error(n,s) s,
227 #include "sr_error.def"
232 #define sr_error(n,s) SR_REWRITE_ERROR_##n,
233 #include "sr_error.def"
236 } sr_rewrite_error_t;
239 u8 * format_sr_rewrite_trace (u8 * s, va_list * args)
241 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
242 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
243 sr_rewrite_trace_t * t = va_arg (*args, sr_rewrite_trace_t *);
244 ip6_main_t * im = &ip6_main;
245 ip6_sr_main_t * sm = &sr_main;
246 ip6_sr_tunnel_t *tun = pool_elt_at_index (sm->tunnels, t->tunnel_index);
247 ip6_fib_t * rx_fib, * tx_fib;
249 rx_fib = find_ip6_fib_by_table_index_or_id (im, tun->rx_fib_index,
250 IP6_ROUTE_FLAG_FIB_INDEX);
252 tx_fib = find_ip6_fib_by_table_index_or_id (im, tun->tx_fib_index,
253 IP6_ROUTE_FLAG_FIB_INDEX);
256 (s, "SR-REWRITE: next %s ip6 src %U dst %U len %u\n"
257 " rx-fib-id %d tx-fib-id %d\n%U",
258 (t->next_index == SR_REWRITE_NEXT_SR_LOCAL)
259 ? "sr-local" : "ip6-lookup",
260 format_ip6_address, &t->src,
261 format_ip6_address, &t->dst, t->length,
262 rx_fib->table_id, tx_fib->table_id,
263 format_ip6_sr_header, t->sr, 0 /* print_hmac */);
268 sr_rewrite (vlib_main_t * vm,
269 vlib_node_runtime_t * node,
270 vlib_frame_t * from_frame)
272 u32 n_left_from, next_index, * from, * to_next;
273 ip6_main_t * im = &ip6_main;
274 ip_lookup_main_t * lm = &im->lookup_main;
275 ip6_sr_main_t * sm = &sr_main;
276 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
277 vlib_buffer_t *, ip6_header_t *,
279 sr_local_cb = sm->sr_local_cb;
281 from = vlib_frame_vector_args (from_frame);
282 n_left_from = from_frame->n_vectors;
284 next_index = node->cached_next_index;
286 while (n_left_from > 0)
290 vlib_get_next_frame (vm, node, next_index,
291 to_next, n_left_to_next);
293 /* Note 2x loop disabled */
294 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
297 vlib_buffer_t * b0, * b1;
298 ip6_header_t * ip0, * ip1;
299 ip_adjacency_t * adj0, * adj1;
300 ip6_sr_header_t * sr0, * sr1;
301 ip6_sr_tunnel_t * t0, *t1;
302 u64 * copy_src0, * copy_dst0;
303 u64 * copy_src1, * copy_dst1;
304 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
305 u32 next1 = SR_REWRITE_NEXT_IP6_LOOKUP;
309 /* Prefetch next iteration. */
311 vlib_buffer_t * p2, * p3;
313 p2 = vlib_get_buffer (vm, from[2]);
314 p3 = vlib_get_buffer (vm, from[3]);
316 vlib_prefetch_buffer_header (p2, LOAD);
317 vlib_prefetch_buffer_header (p3, LOAD);
329 b0 = vlib_get_buffer (vm, bi0);
330 b1 = vlib_get_buffer (vm, bi1);
333 * $$$ parse through header(s) to pick the point
334 * where we punch in the SR extention header
337 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
338 adj1 = ip_get_adjacency (lm, vnet_buffer(b1)->ip.adj_index[VLIB_TX]);
339 t0 = pool_elt_at_index (sm->tunnels,
340 adj0->rewrite_header.sw_if_index);
341 t1 = pool_elt_at_index (sm->tunnels,
342 adj1->rewrite_header.sw_if_index);
344 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
345 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
346 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
347 >= ((word) vec_len (t1->rewrite)) + b1->current_data);
349 vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
350 vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->tx_fib_index;
352 ip0 = vlib_buffer_get_current (b0);
353 ip1 = vlib_buffer_get_current (b1);
356 * SR-unaware service chaining case: pkt coming back from
357 * service has the original dst address, and will already
358 * have an SR header. If so, send it to sr-local
360 if (PREDICT_FALSE(ip0->protocol == 43))
362 vlib_buffer_advance (b0, sizeof(ip0));
363 sr0 = (ip6_sr_header_t *) (ip0+1);
364 new_l0 = clib_net_to_host_u16(ip0->payload_length);
365 next0 = SR_REWRITE_NEXT_SR_LOCAL;
369 copy_dst0 = (u64 *)(((u8 *)ip0) - vec_len (t0->rewrite));
370 copy_src0 = (u64 *) ip0;
373 * Copy data before the punch-in point left by the
374 * required amount. Assume (for the moment) that only
375 * the main packet header needs to be copied.
377 copy_dst0 [0] = copy_src0 [0];
378 copy_dst0 [1] = copy_src0 [1];
379 copy_dst0 [2] = copy_src0 [2];
380 copy_dst0 [3] = copy_src0 [3];
381 copy_dst0 [4] = copy_src0 [4];
382 vlib_buffer_advance (b0, - (word) vec_len(t0->rewrite));
383 ip0 = vlib_buffer_get_current (b0);
384 sr0 = (ip6_sr_header_t *) (ip0+1);
386 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
387 /* Fix the next header chain */
388 sr0->protocol = ip0->protocol;
389 ip0->protocol = 43; /* routing extension header */
390 new_l0 = clib_net_to_host_u16(ip0->payload_length) +
391 vec_len (t0->rewrite);
392 ip0->payload_length = clib_host_to_net_u16(new_l0);
393 /* Rewrite the ip6 dst address */
394 ip0->dst_address.as_u64[0] = t0->first_hop.as_u64[0];
395 ip0->dst_address.as_u64[1] = t0->first_hop.as_u64[1];
397 sr_fix_hmac (sm, ip0, sr0);
399 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
403 * Ignore "do not rewrite" shtik in this path
405 if (PREDICT_FALSE (next0 & 0x80000000))
408 if (PREDICT_FALSE(next0 == SR_REWRITE_NEXT_ERROR))
410 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
414 if (PREDICT_FALSE(ip1->protocol == 43))
416 vlib_buffer_advance (b1, sizeof(ip1));
417 sr1 = (ip6_sr_header_t *) (ip1+1);
418 new_l1 = clib_net_to_host_u16(ip1->payload_length);
419 next1 = SR_REWRITE_NEXT_SR_LOCAL;
423 copy_dst1 = (u64 *)(((u8 *)ip1) - vec_len (t1->rewrite));
424 copy_src1 = (u64 *) ip1;
426 copy_dst1 [0] = copy_src1 [0];
427 copy_dst1 [1] = copy_src1 [1];
428 copy_dst1 [2] = copy_src1 [2];
429 copy_dst1 [3] = copy_src1 [3];
430 copy_dst1 [4] = copy_src1 [4];
431 vlib_buffer_advance (b1, - (word) vec_len(t1->rewrite));
432 ip1 = vlib_buffer_get_current (b1);
433 sr1 = (ip6_sr_header_t *) (ip1+1);
434 clib_memcpy (sr1, t1->rewrite, vec_len (t1->rewrite));
435 sr1->protocol = ip1->protocol;
437 new_l1 = clib_net_to_host_u16(ip1->payload_length) +
438 vec_len (t1->rewrite);
439 ip1->payload_length = clib_host_to_net_u16(new_l1);
440 ip1->dst_address.as_u64[0] = t1->first_hop.as_u64[0];
441 ip1->dst_address.as_u64[1] = t1->first_hop.as_u64[1];
443 sr_fix_hmac (sm, ip1, sr1);
445 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
449 * Ignore "do not rewrite" shtik in this path
451 if (PREDICT_FALSE (next1 & 0x80000000))
454 if (PREDICT_FALSE(next1 == SR_REWRITE_NEXT_ERROR))
456 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
460 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
462 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
464 tr->tunnel_index = t0 - sm->tunnels;
465 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
466 sizeof (tr->src.as_u8));
467 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
468 sizeof (tr->dst.as_u8));
470 tr->next_index = next0;
471 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
473 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
475 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
477 tr->tunnel_index = t1 - sm->tunnels;
478 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
479 sizeof (tr->src.as_u8));
480 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
481 sizeof (tr->dst.as_u8));
483 tr->next_index = next1;
484 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
487 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
488 to_next, n_left_to_next,
489 bi0, bi1, next0, next1);
492 while (n_left_from > 0 && n_left_to_next > 0)
496 ip6_header_t * ip0 = 0;
497 ip_adjacency_t * adj0;
498 ip6_sr_header_t * sr0 = 0;
499 ip6_sr_tunnel_t * t0;
500 u64 * copy_src0, * copy_dst0;
501 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
511 b0 = vlib_get_buffer (vm, bi0);
514 * $$$ parse through header(s) to pick the point
515 * where we punch in the SR extention header
518 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
519 t0 = pool_elt_at_index (sm->tunnels,
520 adj0->rewrite_header.sw_if_index);
522 /* add a replication node */
523 if(PREDICT_FALSE(t0->policy_index != ~0))
525 vnet_buffer(b0)->ip.save_protocol = t0->policy_index;
526 next0=SR_REWRITE_NEXT_SR_REPLICATE;
530 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
531 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
533 vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
535 ip0 = vlib_buffer_get_current (b0);
538 * SR-unaware service chaining case: pkt coming back from
539 * service has the original dst address, and will already
540 * have an SR header. If so, send it to sr-local
542 if (PREDICT_FALSE(ip0->protocol == 43))
544 vlib_buffer_advance (b0, sizeof(ip0));
545 sr0 = (ip6_sr_header_t *) (ip0+1);
546 new_l0 = clib_net_to_host_u16(ip0->payload_length);
547 next0 = SR_REWRITE_NEXT_SR_LOCAL;
551 copy_dst0 = (u64 *)(((u8 *)ip0) - vec_len (t0->rewrite));
552 copy_src0 = (u64 *) ip0;
555 * Copy data before the punch-in point left by the
556 * required amount. Assume (for the moment) that only
557 * the main packet header needs to be copied.
559 copy_dst0 [0] = copy_src0 [0];
560 copy_dst0 [1] = copy_src0 [1];
561 copy_dst0 [2] = copy_src0 [2];
562 copy_dst0 [3] = copy_src0 [3];
563 copy_dst0 [4] = copy_src0 [4];
564 vlib_buffer_advance (b0, - (word) vec_len(t0->rewrite));
565 ip0 = vlib_buffer_get_current (b0);
566 sr0 = (ip6_sr_header_t *) (ip0+1);
568 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
569 /* Fix the next header chain */
570 sr0->protocol = ip0->protocol;
571 ip0->protocol = 43; /* routing extension header */
572 new_l0 = clib_net_to_host_u16(ip0->payload_length) +
573 vec_len (t0->rewrite);
574 ip0->payload_length = clib_host_to_net_u16(new_l0);
575 /* Rewrite the ip6 dst address */
576 ip0->dst_address.as_u64[0] = t0->first_hop.as_u64[0];
577 ip0->dst_address.as_u64[1] = t0->first_hop.as_u64[1];
579 sr_fix_hmac (sm, ip0, sr0);
581 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
585 * Ignore "do not rewrite" shtik in this path
587 if (PREDICT_FALSE (next0 & 0x80000000))
590 if (PREDICT_FALSE(next0 == SR_REWRITE_NEXT_ERROR))
592 node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
597 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
599 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
601 tr->tunnel_index = t0 - sm->tunnels;
604 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
605 sizeof (tr->src.as_u8));
606 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
607 sizeof (tr->dst.as_u8));
610 tr->next_index = next0;
611 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
614 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
615 to_next, n_left_to_next,
619 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
621 return from_frame->n_vectors;
624 VLIB_REGISTER_NODE (sr_rewrite_node) = {
625 .function = sr_rewrite,
626 .name = "sr-rewrite",
627 /* Takes a vector of packets. */
628 .vector_size = sizeof (u32),
629 .format_trace = format_sr_rewrite_trace,
630 .format_buffer = format_ip6_sr_header_with_length,
632 .n_errors = SR_REWRITE_N_ERROR,
633 .error_strings = sr_rewrite_error_strings,
635 .runtime_data_bytes = 0,
637 .n_next_nodes = SR_REWRITE_N_NEXT,
639 #define _(s,n) [SR_REWRITE_NEXT_##s] = n,
640 foreach_sr_rewrite_next
645 static int ip6_delete_route_no_next_hop (ip6_address_t *dst_address_arg,
646 u32 dst_address_length,
649 ip6_add_del_route_args_t a;
650 ip6_address_t dst_address;
652 ip6_main_t * im6 = &ip6_main;
653 BVT(clib_bihash_kv) kv, value;
655 fib = find_ip6_fib_by_table_index_or_id (im6, rx_table_id,
656 IP6_ROUTE_FLAG_TABLE_ID);
657 memset (&a, 0, sizeof (a));
658 a.flags |= IP4_ROUTE_FLAG_DEL;
659 a.dst_address_length = dst_address_length;
661 dst_address = *dst_address_arg;
663 ip6_address_mask (&dst_address,
664 &im6->fib_masks[dst_address_length]);
666 kv.key[0] = dst_address.as_u64[0];
667 kv.key[1] = dst_address.as_u64[1];
668 kv.key[2] = ((u64)((fib - im6->fibs))<<32) | dst_address_length;
670 if (BV(clib_bihash_search)(&im6->ip6_lookup_table, &kv, &value) < 0)
672 clib_warning ("%U/%d not in FIB",
673 format_ip6_address, &a.dst_address,
674 a.dst_address_length);
678 a.adj_index = value.value;
679 a.dst_address = dst_address;
681 ip6_add_del_route (im6, &a);
682 ip6_maybe_remap_adjacencies (im6, rx_table_id, IP6_ROUTE_FLAG_TABLE_ID);
686 static ip6_sr_hmac_key_t *
687 find_or_add_shared_secret (ip6_sr_main_t * sm, u8 * secret, u32 * indexp)
690 ip6_sr_hmac_key_t * key = 0;
693 p = hash_get_mem (sm->hmac_key_by_shared_secret, secret);
697 key = vec_elt_at_index (sm->hmac_keys, p[0]);
703 /* Specific key ID? */
704 if (indexp && *indexp)
706 vec_validate (sm->hmac_keys, *indexp);
707 key = sm->hmac_keys + *indexp;
711 for (i = 0; i < vec_len (sm->hmac_keys); i++)
713 if (sm->hmac_keys[i].shared_secret == 0)
714 key = sm->hmac_keys + i;
717 vec_validate (sm->hmac_keys, i);
718 key = sm->hmac_keys + i;
723 key->shared_secret = vec_dup (secret);
725 hash_set_mem (sm->hmac_key_by_shared_secret, key->shared_secret,
726 key - sm->hmac_keys);
729 *indexp = key - sm->hmac_keys;
734 int ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
736 ip6_main_t * im = &ip6_main;
737 ip_lookup_main_t * lm = &im->lookup_main;
738 ip6_sr_tunnel_key_t key;
741 ip6_sr_header_t * h = 0;
743 ip6_address_t * addrp, *this_address;
744 ip_adjacency_t adj, * ap, * add_adj = 0;
746 ip6_sr_main_t * sm = &sr_main;
748 u32 rx_fib_index, tx_fib_index;
749 ip6_add_del_route_args_t aa;
750 u32 hmac_key_index_u32;
751 u8 hmac_key_index = 0;
752 ip6_sr_policy_t * pt;
755 /* Make sure that the rx FIB exists */
756 p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
761 /* remember the FIB index */
764 /* Make sure that the supplied FIB exists */
765 p = hash_get (im->fib_index_by_table_id, a->tx_table_id);
770 /* remember the FIB index */
773 clib_memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
774 clib_memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
776 /* If the name exists, find the tunnel by name else... */
778 p = hash_get_mem(sm->tunnel_index_by_name, a->name);
780 p = hash_get_mem (sm->tunnel_index_by_key, &key);
788 /* Delete existing tunnel */
789 t = pool_elt_at_index (sm->tunnels, p[0]);
791 ip6_delete_route_no_next_hop (&t->key.dst, t->dst_mask_width,
793 vec_free (t->rewrite);
794 /* Remove tunnel from any policy if associated */
795 if (t->policy_index != ~0)
797 pt=pool_elt_at_index (sm->policies, t->policy_index);
798 for (i=0; i< vec_len (pt->tunnel_indices); i++)
800 if (pt->tunnel_indices[i] == t - sm->tunnels)
802 vec_delete (pt->tunnel_indices, 1, i);
806 clib_warning ("Tunnel index %d not found in policy_index %d",
807 t - sm->tunnels, pt - sm->policies);
809 /* If this is last tunnel in the policy, clean up the policy too */
810 if (vec_len (pt->tunnel_indices) == 0)
812 hash_unset_mem (sm->policy_index_by_policy_name, pt->name);
814 pool_put (sm->policies, pt);
818 /* Clean up the tunnel by name */
821 hash_unset_mem (sm->tunnel_index_by_name, t->name);
824 pool_put (sm->tunnels, t);
825 hp = hash_get_pair (sm->tunnel_index_by_key, &key);
826 key_copy = (void *)(hp->key);
827 hash_unset_mem (sm->tunnel_index_by_key, &key);
831 else /* create; tunnel already exists; complain */
836 /* delete; tunnel does not exist; complain */
841 /* create a new tunnel */
842 pool_get (sm->tunnels, t);
843 memset (t, 0, sizeof (*t));
844 t->policy_index = ~0;
846 clib_memcpy (&t->key, &key, sizeof (t->key));
847 t->dst_mask_width = a->dst_mask_width;
848 t->rx_fib_index = rx_fib_index;
849 t->tx_fib_index = tx_fib_index;
851 /* The first specified hop goes right into the dst address */
852 if (vec_len(a->segments))
854 t->first_hop = a->segments[0];
855 /* It won't feel nice if we do it twice */
856 vec_delete (a->segments, 1, 0);
858 else /* there must be at least one segment... */
862 * Create the sr header rewrite string
863 * We append the dst address to the set of next hops
864 * so the ultimate recipient can tell where the
865 * packet entered the SR domain
867 header_length = sizeof (*h) +
868 sizeof (ip6_address_t) * (vec_len (a->segments) + vec_len (a->tags));
870 if (a->shared_secret)
872 /* Allocate a new key slot if we don't find the secret key */
873 hmac_key_index_u32 = 0;
874 (void) find_or_add_shared_secret (sm, a->shared_secret,
875 &hmac_key_index_u32);
877 /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
878 if (hmac_key_index_u32 >= 256)
880 hmac_key_index = hmac_key_index_u32;
881 header_length += SHA256_DIGEST_LENGTH;
884 vec_validate (t->rewrite, header_length-1);
886 h = (ip6_sr_header_t *) t->rewrite;
888 h->protocol = 0xFF; /* we don't know yet */
890 h->length = (header_length/8) - 1;
891 h->type = ROUTING_HEADER_TYPE_SR;
892 h->segments_left = vec_len (a->segments);
893 h->first_segment = vec_len(a->segments) -1;
894 if (a->shared_secret)
895 h->hmac_key = hmac_key_index & 0xFF;
897 h->flags = a->flags_net_byte_order;
899 /* Paint on the segment list, in reverse */
900 addrp = h->segments + (vec_len (a->segments) - 1);
902 vec_foreach (this_address, a->segments)
904 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
908 /* Paint on the tag list, not reversed */
909 addrp = h->segments + vec_len(a->segments);
911 vec_foreach (this_address, a->tags)
913 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
917 key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
918 clib_memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
919 hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
921 memset(&adj, 0, sizeof (adj));
923 /* Create an adjacency and add to v6 fib */
924 adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
925 adj.lookup_next_index = sm->ip6_lookup_sr_next_index;
926 adj.explicit_fib_index = ~0;
928 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */,
932 * Stick the tunnel index into the rewrite header.
934 * Unfortunately, inserting an SR header according to the various
935 * RFC's requires parsing through the ip6 header, perhaps consing a
936 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
937 * normal reverse bcopy rewrite code.
939 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
942 ap->rewrite_header.sw_if_index = t - sm->tunnels;
944 vec_add1 (add_adj, ap[0]);
946 clib_memcpy (aa.dst_address.as_u8, a->dst_address, sizeof (aa.dst_address.as_u8));
947 aa.dst_address_length = a->dst_mask_width;
949 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
950 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
951 aa.table_index_or_table_id = rx_fib_index;
952 aa.add_adj = add_adj;
953 aa.adj_index = adj_index;
955 ip6_add_del_route (im, &aa);
960 p=hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
963 pt = pool_elt_at_index (sm->policies, p[0]);
965 else /* no policy, lets create one */
967 pool_get (sm->policies, pt);
968 memset (pt, 0, sizeof(*pt));
969 pt->name = format (0, "%s%c", a->policy_name, 0);
970 hash_set_mem (sm->policy_index_by_policy_name, pt->name, pt - sm->policies);
971 p=hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
973 vec_add1 (pt->tunnel_indices, t - sm->tunnels);
974 t->policy_index = p[0]; /* equiv. to (pt - sm->policies) */
979 t->name = format (0, "%s%c", a->name, 0);
980 hash_set_mem(sm->tunnel_index_by_name, t->name, t - sm->tunnels);
986 static clib_error_t *
987 sr_add_del_tunnel_command_fn (vlib_main_t * vm,
988 unformat_input_t * input,
989 vlib_cli_command_t * cmd)
992 ip6_address_t src_address;
993 int src_address_set = 0;
994 ip6_address_t dst_address;
996 int dst_address_set = 0;
998 u8 *shared_secret = 0;
1000 u8 *policy_name = 0;
1001 u32 rx_table_id = 0;
1002 u32 tx_table_id = 0;
1003 ip6_address_t * segments = 0;
1004 ip6_address_t * this_seg;
1005 ip6_address_t * tags = 0;
1006 ip6_address_t * this_tag;
1007 ip6_sr_add_del_tunnel_args_t _a, *a=&_a;
1008 ip6_address_t next_address, tag;
1012 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1014 if (unformat (input, "del"))
1016 else if (unformat (input, "rx-fib-id %d", &rx_table_id))
1018 else if (unformat (input, "tx-fib-id %d", &tx_table_id))
1020 else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
1021 src_address_set = 1;
1022 else if (unformat (input, "name %s", &name))
1024 else if (unformat (input, "policy %s", &policy_name))
1026 else if (unformat (input, "dst %U/%d",
1027 unformat_ip6_address, &dst_address,
1029 dst_address_set = 1;
1030 else if (unformat (input, "next %U", unformat_ip6_address,
1033 vec_add2 (segments, this_seg, 1);
1034 clib_memcpy (this_seg->as_u8, next_address.as_u8, sizeof (*this_seg));
1036 else if (unformat (input, "tag %U", unformat_ip6_address,
1039 vec_add2 (tags, this_tag, 1);
1040 clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
1042 else if (unformat (input, "clean"))
1043 flags |= IP6_SR_HEADER_FLAG_CLEANUP;
1044 else if (unformat (input, "protected"))
1045 flags |= IP6_SR_HEADER_FLAG_PROTECTED;
1046 else if (unformat (input, "key %s", &shared_secret))
1047 /* Do not include the trailing NULL byte. Guaranteed interop issue */
1048 _vec_len (shared_secret) -= 1;
1049 else if (unformat (input, "InPE %d", &pl_index))
1051 if (pl_index <= 0 || pl_index > 4)
1053 pl_index_range_error:
1054 return clib_error_return
1055 (0, "Policy List Element Index %d out of range (1-4)", pl_index);
1058 flags |= IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
1059 << ip6_sr_policy_list_shift_from_index (pl_index);
1061 else if (unformat (input, "EgPE %d", &pl_index))
1063 if (pl_index <= 0 || pl_index > 4)
1064 goto pl_index_range_error;
1065 flags |= IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
1066 << ip6_sr_policy_list_shift_from_index (pl_index);
1068 else if (unformat (input, "OrgSrc %d", &pl_index))
1070 if (pl_index <= 0 || pl_index > 4)
1071 goto pl_index_range_error;
1072 flags |= IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
1073 << ip6_sr_policy_list_shift_from_index (pl_index);
1079 if (!src_address_set)
1080 return clib_error_return (0, "src address required");
1082 if (!dst_address_set)
1083 return clib_error_return (0, "dst address required");
1086 return clib_error_return (0, "at least one sr segment required");
1088 memset (a, 0, sizeof (*a));
1089 a->src_address = &src_address;
1090 a->dst_address = &dst_address;
1091 a->dst_mask_width = dst_mask_width;
1092 a->segments = segments;
1094 a->flags_net_byte_order = clib_host_to_net_u16(flags);
1096 a->rx_table_id = rx_table_id;
1097 a->tx_table_id = tx_table_id;
1098 a->shared_secret = shared_secret;
1105 if (vec_len(policy_name))
1106 a->policy_name = policy_name;
1110 rv = ip6_sr_add_del_tunnel (a);
1112 vec_free (segments);
1114 vec_free (shared_secret);
1122 return clib_error_return (0, "SR tunnel src %U dst %U already exists",
1123 format_ip6_address, &src_address,
1124 format_ip6_address, &dst_address);
1127 return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
1128 format_ip6_address, &src_address,
1129 format_ip6_address, &dst_address);
1132 return clib_error_return (0, "FIB table %d does not exist", rx_table_id);
1135 return clib_error_return (0, "At least one segment is required");
1138 return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
1145 VLIB_CLI_COMMAND (sr_tunnel_command, static) = {
1146 .path = "sr tunnel",
1148 "sr tunnel [del] [name <name>] src <addr> dst <addr> [next <addr>] [cleanup] [reroute] [key %s] [policy <policy_name>",
1149 .function = sr_add_del_tunnel_command_fn,
1153 ip6_sr_tunnel_display (vlib_main_t * vm,
1154 ip6_sr_tunnel_t * t)
1156 ip6_main_t * im = &ip6_main;
1157 ip6_sr_main_t * sm = &sr_main;
1158 ip6_fib_t * rx_fib, * tx_fib;
1159 ip6_sr_policy_t * pt;
1161 rx_fib = find_ip6_fib_by_table_index_or_id (im, t->rx_fib_index,
1162 IP6_ROUTE_FLAG_FIB_INDEX);
1164 tx_fib = find_ip6_fib_by_table_index_or_id (im, t->tx_fib_index,
1165 IP6_ROUTE_FLAG_FIB_INDEX);
1168 vlib_cli_output (vm,"sr tunnel name: %s", (char *)t->name);
1170 vlib_cli_output (vm, "src %U dst %U first hop %U",
1171 format_ip6_address, &t->key.src,
1172 format_ip6_address, &t->key.dst,
1173 format_ip6_address, &t->first_hop);
1174 vlib_cli_output (vm, " rx-fib-id %d tx-fib-id %d",
1175 rx_fib->table_id, tx_fib->table_id);
1176 vlib_cli_output (vm, " sr: %U", format_ip6_sr_header, t->rewrite,
1177 0 /* print_hmac */);
1179 if (t->policy_index != ~0)
1181 pt=pool_elt_at_index(sm->policies, t->policy_index);
1182 vlib_cli_output (vm,"sr policy: %s", (char *)pt->name);
1184 vlib_cli_output (vm, "-------");
1189 static clib_error_t *
1190 show_sr_tunnel_fn (vlib_main_t * vm,
1191 unformat_input_t * input,
1192 vlib_cli_command_t * cmd)
1194 static ip6_sr_tunnel_t ** tunnels;
1195 ip6_sr_tunnel_t * t;
1196 ip6_sr_main_t * sm = &sr_main;
1201 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1203 if (unformat (input, "name %s", &name))
1205 p=hash_get_mem (sm->tunnel_index_by_name, name);
1207 vlib_cli_output (vm, "No SR tunnel with name: %s. Showing all.", name);
1213 vec_reset_length (tunnels);
1215 if(!p) /* Either name parm not passed or no tunnel with that name found, show all */
1217 pool_foreach (t, sm->tunnels,
1219 vec_add1 (tunnels, t);
1222 else /* Just show the one tunnel by name */
1223 vec_add1 (tunnels, &sm->tunnels[p[0]]);
1225 if (vec_len (tunnels) == 0)
1226 vlib_cli_output (vm, "No SR tunnels configured");
1228 for (i = 0; i < vec_len (tunnels); i++)
1231 ip6_sr_tunnel_display (vm, t);
1237 VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
1238 .path = "show sr tunnel",
1239 .short_help = "show sr tunnel [name <sr-tunnel-name>]",
1240 .function = show_sr_tunnel_fn,
1243 int ip6_sr_add_del_policy (ip6_sr_add_del_policy_args_t * a)
1245 ip6_sr_main_t * sm = &sr_main;
1247 ip6_sr_tunnel_t * t = 0;
1248 ip6_sr_policy_t * policy;
1249 u32 * tunnel_indices = 0;
1256 p=hash_get_mem (sm->policy_index_by_policy_name, a->name);
1258 return -6; /* policy name not found */
1260 policy = pool_elt_at_index(sm->policies, p[0]);
1262 vec_foreach_index (i, policy->tunnel_indices)
1264 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1265 t->policy_index = ~0;
1267 hash_unset_mem (sm->policy_index_by_policy_name, a->name);
1268 pool_put (sm->policies, policy);
1273 if (!vec_len(a->tunnel_names))
1274 return -3; /*tunnel name is required case */
1276 vec_reset_length (tunnel_indices);
1277 /* Check tunnel names, add tunnel_index to policy */
1278 for (i=0; i < vec_len (a->tunnel_names); i++)
1280 p = hash_get_mem (sm->tunnel_index_by_name, a->tunnel_names[i]);
1282 return -4; /* tunnel name not found case */
1284 t = pool_elt_at_index (sm->tunnels, p[0]);
1286 No need to check t==0. -3 condition above ensures name
1288 if (t->policy_index != ~0)
1289 return -5; /* tunnel name already associated with a policy */
1291 /* Add to tunnel indicies */
1292 vec_add1 (tunnel_indices, p[0]);
1295 /* Add policy to ip6_sr_main_t */
1296 pool_get (sm->policies, policy);
1297 policy->name = a->name;
1298 policy->tunnel_indices = tunnel_indices;
1299 hash_set_mem (sm->policy_index_by_policy_name, policy->name, policy - sm->policies);
1301 /* Yes, this could be construed as overkill but the last thing you should do is set
1302 the policy_index on the tunnel after everything is set in ip6_sr_main_t.
1303 If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop.
1305 for (i=0; i < vec_len(policy->tunnel_indices); i++)
1307 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1308 t->policy_index = policy - sm->policies;
1315 static clib_error_t *
1316 sr_add_del_policy_command_fn (vlib_main_t * vm,
1317 unformat_input_t * input,
1318 vlib_cli_command_t * cmd)
1321 u8 ** tunnel_names = 0;
1322 u8 * tunnel_name = 0;
1324 ip6_sr_add_del_policy_args_t _a, *a=&_a;
1327 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1329 if (unformat (input, "del"))
1331 else if (unformat (input, "name %s", &name))
1333 else if (unformat (input, "tunnel %s", &tunnel_name))
1337 vec_add1 (tunnel_names, tunnel_name);
1346 return clib_error_return (0, "name of SR policy required");
1349 memset(a, 0, sizeof(*a));
1353 a->tunnel_names = tunnel_names;
1355 rv = ip6_sr_add_del_policy (a);
1357 vec_free(tunnel_names);
1365 return clib_error_return (0, "tunnel name to associate to SR policy is required");
1368 return clib_error_return (0, "tunnel name not found");
1371 return clib_error_return (0, "tunnel already associated with policy");
1374 return clib_error_return (0, "policy name %s not found", name);
1377 return clib_error_return (0, "TODO: deleting policy name %s", name);
1380 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d", rv);
1386 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1387 .path = "sr policy",
1389 "sr policy [del] name <policy-name> tunnel <sr-tunnel-name> [tunnel <sr-tunnel-name>]*",
1390 .function = sr_add_del_policy_command_fn,
1393 static clib_error_t *
1394 show_sr_policy_fn (vlib_main_t * vm,
1395 unformat_input_t * input,
1396 vlib_cli_command_t * cmd)
1398 static ip6_sr_policy_t ** policies;
1399 ip6_sr_policy_t * policy;
1400 ip6_sr_tunnel_t * t;
1401 ip6_sr_main_t * sm = &sr_main;
1406 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1408 if (unformat (input, "name %s", &name))
1410 p=hash_get_mem (sm->policy_index_by_policy_name, name);
1412 vlib_cli_output (vm, "policy with name %s not found. Showing all.", name);
1418 vec_reset_length (policies);
1420 if(!p) /* Either name parm not passed or no policy with that name found, show all */
1422 pool_foreach (policy, sm->policies,
1424 vec_add1 (policies, policy);
1427 else /* Just show the one policy by name and a summary of tunnel names */
1429 policy = pool_elt_at_index(sm->policies, p[0]);
1430 vec_add1 (policies, policy);
1433 if (vec_len (policies) == 0)
1434 vlib_cli_output (vm, "No SR policies configured");
1436 for (i = 0; i < vec_len (policies); i++)
1438 policy = policies [i];
1441 vlib_cli_output (vm,"SR policy name: %s", (char *)policy->name);
1442 for(j = 0; j < vec_len (policy->tunnel_indices); j++)
1444 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[j]);
1445 ip6_sr_tunnel_display (vm, t);
1453 VLIB_CLI_COMMAND (show_sr_policy_command, static) = {
1454 .path = "show sr policy",
1455 .short_help = "show sr policy [name <sr-policy-name>]",
1456 .function = show_sr_policy_fn,
1459 int ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a)
1462 ip6_main_t * im = &ip6_main;
1463 ip_lookup_main_t * lm = &im->lookup_main;
1464 ip6_sr_tunnel_t * t;
1465 ip_adjacency_t adj, * ap, * add_adj = 0;
1467 ip6_sr_main_t * sm = &sr_main;
1468 ip6_add_del_route_args_t aa;
1469 ip6_sr_policy_t * pt;
1473 /* clean up the adjacency */
1474 p = hash_get_mem (sm->policy_index_by_multicast_address, a->multicast_address);
1478 /* Get our policy by policy_name */
1479 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1485 pt=pool_elt_at_index (sm->policies, p[0]);
1488 Get the first tunnel associated with policy populate the fib adjacency.
1489 From there, since this tunnel will have it's policy_index != ~0 it will
1490 be the trigger in the dual_loop to pull up the policy and make a copy-rewrite
1491 for each tunnel in the policy
1494 t = pool_elt_at_index (sm->tunnels, pt->tunnel_indices[0]);
1496 /* Construct a FIB entry for multicast using the rx/tx fib from the first tunnel */
1497 memset(&adj, 0, sizeof (adj));
1499 /* Create an adjacency and add to v6 fib */
1500 adj.lookup_next_index = sm->ip6_lookup_sr_replicate_index;
1501 adj.explicit_fib_index = ~0;
1503 ap = ip_add_adjacency (lm, &adj, 1 /* one adj */,
1507 * Stick the tunnel index into the rewrite header.
1509 * Unfortunately, inserting an SR header according to the various
1510 * RFC's requires parsing through the ip6 header, perhaps consing a
1511 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1512 * normal reverse bcopy rewrite code.
1514 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1517 ap->rewrite_header.sw_if_index = t - sm->tunnels;
1519 vec_add1 (add_adj, ap[0]);
1521 memcpy (aa.dst_address.as_u8, a->multicast_address, sizeof (aa.dst_address.as_u8));
1522 aa.dst_address_length = 128;
1524 aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1525 aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1526 aa.table_index_or_table_id = t->rx_fib_index;
1527 aa.add_adj = add_adj;
1528 aa.adj_index = adj_index;
1530 ip6_add_del_route (im, &aa);
1533 u8 * mcast_copy = 0;
1534 mcast_copy = vec_new (ip6_address_t, 1);
1535 memcpy (mcast_copy, a->multicast_address, sizeof (ip6_address_t));
1539 hash_unset_mem (sm->policy_index_by_multicast_address, mcast_copy);
1540 vec_free (mcast_copy);
1545 hash_set_mem (sm->policy_index_by_multicast_address, mcast_copy, pt - sm->policies);
1551 static clib_error_t *
1552 sr_add_del_multicast_map_command_fn (vlib_main_t * vm,
1553 unformat_input_t * input,
1554 vlib_cli_command_t * cmd)
1557 ip6_address_t multicast_address;
1558 u8 * policy_name = 0;
1559 int multicast_address_set = 0;
1560 ip6_sr_add_del_multicastmap_args_t _a, *a=&_a;
1563 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1565 if (unformat (input, "del"))
1567 else if (unformat (input, "address %U", unformat_ip6_address, &multicast_address))
1568 multicast_address_set = 1;
1569 else if (unformat (input, "sr-policy %s", &policy_name))
1575 if (!is_del && !policy_name)
1576 return clib_error_return (0, "name of sr policy required");
1578 if (!multicast_address_set)
1579 return clib_error_return (0, "multicast address required");
1581 memset(a, 0, sizeof(*a));
1584 a->multicast_address = &multicast_address;
1585 a->policy_name = policy_name;
1587 rv = ip6_sr_add_del_multicastmap (a);
1594 return clib_error_return (0, "no policy with name: %s", policy_name);
1597 return clib_error_return (0, "multicast map someting ");
1600 return clib_error_return (0, "tunnel name to associate to SR policy is required");
1603 return clib_error_return (0, "TODO: deleting policy name %s", policy_name);
1606 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d", rv);
1614 VLIB_CLI_COMMAND (sr_multicast_map_command, static) = {
1615 .path = "sr multicast-map",
1617 "sr multicast-map address <multicast-ip6-address> sr-policy <sr-policy-name> [del]",
1618 .function = sr_add_del_multicast_map_command_fn,
1621 static clib_error_t *
1622 show_sr_multicast_map_fn (vlib_main_t * vm,
1623 unformat_input_t * input,
1624 vlib_cli_command_t * cmd)
1626 ip6_sr_main_t * sm = &sr_main;
1629 ip6_address_t multicast_address;
1630 ip6_sr_policy_t * pt ;
1632 /* pull all entries from the hash table into vector for display */
1634 hash_foreach_mem (key, value, sm->policy_index_by_multicast_address,
1637 vlib_cli_output (vm, "no multicast maps configured");
1640 multicast_address = *((ip6_address_t *)key);
1641 pt = pool_elt_at_index (sm->policies, value);
1644 vlib_cli_output (vm, "address: %U policy: %s",
1645 format_ip6_address, &multicast_address,
1649 vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d",
1650 format_ip6_address, &multicast_address,
1660 VLIB_CLI_COMMAND (show_sr_multicast_map_command, static) = {
1661 .path = "show sr multicast-map",
1662 .short_help = "show sr multicast-map",
1663 .function = show_sr_multicast_map_fn,
1667 #define foreach_sr_fix_dst_addr_next \
1668 _(DROP, "error-drop")
1671 #define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
1672 foreach_sr_fix_dst_addr_next
1674 SR_FIX_DST_ADDR_N_NEXT,
1675 } sr_fix_dst_addr_next_t;
1677 static char * sr_fix_dst_error_strings[] = {
1678 #define sr_fix_dst_error(n,s) s,
1679 #include "sr_fix_dst_error.def"
1680 #undef sr_fix_dst_error
1684 #define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
1685 #include "sr_fix_dst_error.def"
1686 #undef sr_fix_dst_error
1688 } sr_fix_dst_error_t;
1691 ip6_address_t src, dst;
1695 } sr_fix_addr_trace_t;
1697 u8 * format_sr_fix_addr_trace (u8 * s, va_list * args)
1699 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1700 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1701 sr_fix_addr_trace_t * t = va_arg (*args, sr_fix_addr_trace_t *);
1702 vnet_hw_interface_t * hi = 0;
1703 ip_adjacency_t * adj;
1704 ip6_main_t * im = &ip6_main;
1705 ip_lookup_main_t * lm = &im->lookup_main;
1706 vnet_main_t * vnm = vnet_get_main();
1708 if (t->adj_index != ~0)
1710 adj = ip_get_adjacency (lm, t->adj_index);
1711 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
1714 s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
1715 (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
1716 ? "drop" : "output",
1717 format_ip6_address, &t->src,
1718 format_ip6_address, &t->dst);
1719 if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
1721 s = format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
1722 s = format (s, " output via %s", hi ? (char *)(hi->name)
1729 sr_fix_dst_addr (vlib_main_t * vm,
1730 vlib_node_runtime_t * node,
1731 vlib_frame_t * from_frame)
1733 u32 n_left_from, next_index, * from, * to_next;
1734 ip6_main_t * im = &ip6_main;
1735 ip_lookup_main_t * lm = &im->lookup_main;
1737 from = vlib_frame_vector_args (from_frame);
1738 n_left_from = from_frame->n_vectors;
1740 next_index = node->cached_next_index;
1742 while (n_left_from > 0)
1746 vlib_get_next_frame (vm, node, next_index,
1747 to_next, n_left_to_next);
1750 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
1753 __attribute__((unused)) vlib_buffer_t * b0, * b1;
1754 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1755 u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
1757 /* Prefetch next iteration. */
1759 vlib_buffer_t * p2, * p3;
1761 p2 = vlib_get_buffer (vm, from[2]);
1762 p3 = vlib_get_buffer (vm, from[3]);
1764 vlib_prefetch_buffer_header (p2, LOAD);
1765 vlib_prefetch_buffer_header (p3, LOAD);
1774 n_left_to_next -= 2;
1777 b0 = vlib_get_buffer (vm, bi0);
1778 b1 = vlib_get_buffer (vm, bi1);
1781 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
1782 to_next, n_left_to_next,
1783 bi0, bi1, next0, next1);
1787 while (n_left_from > 0 && n_left_to_next > 0)
1792 ip_adjacency_t * adj0;
1793 ip6_sr_header_t * sr0;
1794 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
1795 ip6_address_t *new_dst0;
1796 ethernet_header_t * eh0;
1803 n_left_to_next -= 1;
1805 b0 = vlib_get_buffer (vm, bi0);
1807 adj0 = ip_get_adjacency (lm, vnet_buffer(b0)->ip.adj_index[VLIB_TX]);
1808 next0 = adj0->mcast_group_index;
1810 /* We should be pointing at an Ethernet header... */
1811 eh0 = vlib_buffer_get_current (b0);
1812 ip0 = (ip6_header_t *)(eh0+1);
1813 sr0 = (ip6_sr_header_t *) (ip0+1);
1815 /* We'd better find an SR header... */
1816 if (PREDICT_FALSE(ip0->protocol != 43))
1818 b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
1824 * We get here from sr_rewrite or sr_local, with
1825 * sr->segments_left pointing at the (copy of the original) dst
1826 * address. Use it, then increment sr0->segments_left.
1829 /* Out of segments? Turf the packet */
1830 if (PREDICT_FALSE (sr0->segments_left == 0))
1832 b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
1837 * Rewrite the packet with the original dst address
1838 * We assume that the last segment (in processing order) contains
1839 * the original dst address. The list is reversed, so sr0->segments
1840 * contains the original dst address.
1842 new_dst0 = sr0->segments;
1843 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
1844 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
1849 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1851 sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
1853 t->next_index = next0;
1856 if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
1858 t->adj_index = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
1859 clib_memcpy (t->src.as_u8, ip0->src_address.as_u8,
1860 sizeof (t->src.as_u8));
1861 clib_memcpy (t->dst.as_u8, ip0->dst_address.as_u8,
1862 sizeof (t->dst.as_u8));
1863 clib_memcpy (t->sr, sr0, sizeof (t->sr));
1867 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1868 to_next, n_left_to_next,
1872 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1874 return from_frame->n_vectors;
1878 VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
1879 .function = sr_fix_dst_addr,
1880 .name = "sr-fix-dst-addr",
1881 /* Takes a vector of packets. */
1882 .vector_size = sizeof (u32),
1883 .format_trace = format_sr_fix_addr_trace,
1884 .format_buffer = format_ip6_sr_header_with_length,
1886 .runtime_data_bytes = 0,
1888 .n_errors = SR_FIX_DST_N_ERROR,
1889 .error_strings = sr_fix_dst_error_strings,
1891 .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
1893 #define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
1894 foreach_sr_fix_dst_addr_next
1899 static clib_error_t * sr_init (vlib_main_t * vm)
1901 ip6_sr_main_t * sm = &sr_main;
1902 clib_error_t * error = 0;
1903 vlib_node_t * ip6_lookup_node, * ip6_rewrite_node;
1904 vlib_node_t * ip6_rewrite_local_node;
1905 u32 verify_next_index;
1907 if ((error = vlib_call_init_function (vm, ip_main_init)))
1910 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
1914 sm->vnet_main = vnet_get_main();
1916 vec_validate (sm->hmac_keys, 0);
1917 sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
1919 sm->tunnel_index_by_key =
1920 hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
1922 sm->tunnel_index_by_name =
1923 hash_create_string (0, sizeof (uword));
1925 sm->policy_index_by_policy_name =
1926 hash_create_string(0, sizeof (uword));
1928 sm->policy_index_by_multicast_address =
1929 hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
1931 sm->hmac_key_by_shared_secret = hash_create_string (0, sizeof(uword));
1933 ip6_register_protocol (43, sr_local_node.index);
1935 ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *)"ip6-lookup");
1936 ASSERT(ip6_lookup_node);
1938 ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *)"ip6-rewrite");
1939 ASSERT(ip6_rewrite_node);
1941 ip6_rewrite_local_node = vlib_get_node_by_name (vm,
1942 (u8 *)"ip6-rewrite-local");
1943 ASSERT(ip6_rewrite_local_node);
1945 /* Add a disposition to ip6_lookup for the sr rewrite node */
1946 sm->ip6_lookup_sr_next_index =
1947 vlib_node_add_next (vm, ip6_lookup_node->index, sr_rewrite_node.index);
1949 /* Add a disposition to sr_replicate for the sr multicast replicate node */
1950 sm->ip6_lookup_sr_replicate_index =
1951 vlib_node_add_next (vm, ip6_lookup_node->index, sr_replicate_node.index);
1953 /* Add a disposition to ip6_rewrite for the sr dst address hack node */
1954 sm->ip6_rewrite_sr_next_index =
1955 vlib_node_add_next (vm, ip6_rewrite_node->index,
1956 sr_fix_dst_addr_node.index);
1958 * Fix ip6-rewrite-local, sibling of the above. The sibling bitmap
1959 * isn't set up at this point, so we have to do it manually
1961 verify_next_index = vlib_node_add_next
1962 (vm, ip6_rewrite_local_node->index,
1963 sr_fix_dst_addr_node.index);
1965 ASSERT(sm->ip6_rewrite_sr_next_index == verify_next_index);
1967 OpenSSL_add_all_digests();
1969 sm->md = (void *) EVP_get_digestbyname ("sha1");
1970 sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
1975 VLIB_INIT_FUNCTION (sr_init);
1977 #define foreach_sr_local_next \
1978 _ (ERROR, "error-drop") \
1979 _ (IP6_LOOKUP, "ip6-lookup")
1982 #define _(s,n) SR_LOCAL_NEXT_##s,
1983 foreach_sr_local_next
1991 ip6_address_t src, dst;
1996 static char * sr_local_error_strings[] = {
1997 #define sr_error(n,s) s,
1998 #include "sr_error.def"
2003 #define sr_error(n,s) SR_LOCAL_ERROR_##n,
2004 #include "sr_error.def"
2009 u8 * format_sr_local_trace (u8 * s, va_list * args)
2011 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2012 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2013 sr_local_trace_t * t = va_arg (*args, sr_local_trace_t *);
2015 s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
2016 format_ip6_address, &t->src,
2017 format_ip6_address, &t->dst, t->length, t->next_index);
2019 s = format (s, "\n %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */);
2021 s = format (s, "\n popped SR header");
2027 /* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
2029 static int sr_validate_hmac (ip6_sr_main_t * sm, ip6_header_t * ip,
2030 ip6_sr_header_t * sr)
2036 ip6_address_t *addrp;
2038 ip6_sr_hmac_key_t * hmac_key;
2039 static u8 * signature;
2042 key_index = sr->hmac_key;
2044 /* No signature? Pass... */
2048 /* We don't know about this key? Fail... */
2049 if (key_index >= vec_len (sm->hmac_keys))
2052 vec_validate (signature, SHA256_DIGEST_LENGTH-1);
2054 hmac_key = sm->hmac_keys + key_index;
2056 vec_reset_length (keybuf);
2058 /* pkt ip6 src address */
2059 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2060 clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
2063 vec_add2 (keybuf, copy_target, 1);
2064 copy_target[0] = sr->first_segment;
2066 /* octet w/ bit 0 = "clean" flag */
2067 vec_add2 (keybuf, copy_target, 1);
2069 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
2073 vec_add2 (keybuf, copy_target, 1);
2074 copy_target[0] = sr->hmac_key;
2076 first_segment = sr->first_segment;
2078 addrp = sr->segments;
2081 for (i = 0; i <= first_segment; i++)
2083 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2084 clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
2089 clib_warning ("verify key index %d keybuf: %U", key_index,
2090 format_hex_bytes, keybuf, vec_len(keybuf));
2094 /* SHA1 is shorter than SHA-256 */
2095 memset (signature, 0, vec_len(signature));
2097 HMAC_CTX_init(sm->hmac_ctx);
2098 if (!HMAC_Init(sm->hmac_ctx, hmac_key->shared_secret,
2099 vec_len(hmac_key->shared_secret),sm->md))
2100 clib_warning ("barf1");
2101 if (!HMAC_Update(sm->hmac_ctx,keybuf,vec_len(keybuf)))
2102 clib_warning ("barf2");
2103 if (!HMAC_Final(sm->hmac_ctx,signature,&sig_len))
2104 clib_warning ("barf3");
2105 HMAC_CTX_cleanup(sm->hmac_ctx);
2108 clib_warning ("computed signature len %d, value %U", sig_len,
2109 format_hex_bytes, signature, vec_len(signature));
2111 /* Point at the SHA signature in the packet */
2114 clib_warning ("read signature %U", format_hex_bytes, addrp,
2115 SHA256_DIGEST_LENGTH);
2117 return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
2121 sr_local (vlib_main_t * vm,
2122 vlib_node_runtime_t * node,
2123 vlib_frame_t * from_frame)
2125 u32 n_left_from, next_index, * from, * to_next;
2126 ip6_sr_main_t * sm = &sr_main;
2127 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
2128 vlib_buffer_t *, ip6_header_t *,
2130 sr_local_cb = sm->sr_local_cb;
2132 from = vlib_frame_vector_args (from_frame);
2133 n_left_from = from_frame->n_vectors;
2135 next_index = node->cached_next_index;
2137 while (n_left_from > 0)
2141 vlib_get_next_frame (vm, node, next_index,
2142 to_next, n_left_to_next);
2144 while (n_left_from >= 4 && n_left_to_next >= 2)
2147 vlib_buffer_t * b0, * b1;
2148 ip6_header_t * ip0, *ip1;
2149 ip6_sr_header_t * sr0, *sr1;
2150 ip6_address_t * new_dst0, * new_dst1;
2151 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2152 u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
2153 /* Prefetch next iteration. */
2155 vlib_buffer_t * p2, * p3;
2157 p2 = vlib_get_buffer (vm, from[2]);
2158 p3 = vlib_get_buffer (vm, from[3]);
2160 vlib_prefetch_buffer_header (p2, LOAD);
2161 vlib_prefetch_buffer_header (p3, LOAD);
2163 CLIB_PREFETCH (p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
2164 CLIB_PREFETCH (p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
2173 n_left_to_next -= 2;
2177 b0 = vlib_get_buffer (vm, bi0);
2178 ip0 = vlib_buffer_get_current (b0);
2179 sr0 = (ip6_sr_header_t *)(ip0+1);
2181 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
2183 next0 = SR_LOCAL_NEXT_ERROR;
2184 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2188 /* Out of segments? Turf the packet */
2189 if (PREDICT_FALSE (sr0->segments_left == 0))
2191 next0 = SR_LOCAL_NEXT_ERROR;
2192 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2196 if (PREDICT_FALSE(sm->validate_hmac))
2198 if (sr_validate_hmac (sm, ip0, sr0))
2200 next0 = SR_LOCAL_NEXT_ERROR;
2201 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2206 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
2210 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2212 if (PREDICT_FALSE (next0 & 0x80000000))
2214 next0 ^= 0xFFFFFFFF;
2215 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
2217 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2223 segment_index0 = sr0->segments_left - 1;
2225 /* Rewrite the packet */
2226 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
2227 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2228 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2230 if (PREDICT_TRUE (sr0->segments_left > 0))
2231 sr0->segments_left -= 1;
2234 /* End of the path. Clean up the SR header, or not */
2236 (sr0->segments_left == 0 &&
2237 (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2239 u64 *copy_dst0, *copy_src0;
2242 * Copy the ip6 header right by the (real) length of the
2243 * sr header. Here's another place which assumes that
2244 * the sr header is the only extention header.
2247 ip0->protocol = sr0->protocol;
2248 vlib_buffer_advance (b0, (sr0->length+1)*8);
2250 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
2252 ip0->payload_length = clib_host_to_net_u16(new_l0);
2254 copy_src0 = (u64 *)ip0;
2255 copy_dst0 = copy_src0 + (sr0->length + 1);
2257 copy_dst0 [4] = copy_src0[4];
2258 copy_dst0 [3] = copy_src0[3];
2259 copy_dst0 [2] = copy_src0[2];
2260 copy_dst0 [1] = copy_src0[1];
2261 copy_dst0 [0] = copy_src0[0];
2267 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2269 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2271 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2272 sizeof (tr->src.as_u8));
2273 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2274 sizeof (tr->dst.as_u8));
2275 tr->length = vlib_buffer_length_in_chain (vm, b0);
2276 tr->next_index = next0;
2277 tr->sr_valid = sr0 != 0;
2279 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2282 b1 = vlib_get_buffer (vm, bi1);
2283 ip1 = vlib_buffer_get_current (b1);
2284 sr1 = (ip6_sr_header_t *)(ip1+1);
2286 if (PREDICT_FALSE(sr1->type != ROUTING_HEADER_TYPE_SR))
2288 next1 = SR_LOCAL_NEXT_ERROR;
2289 b1->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2293 /* Out of segments? Turf the packet */
2294 if (PREDICT_FALSE (sr1->segments_left == 0))
2296 next1 = SR_LOCAL_NEXT_ERROR;
2297 b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2301 if (PREDICT_FALSE(sm->validate_hmac))
2303 if (sr_validate_hmac (sm, ip1, sr1))
2305 next1 = SR_LOCAL_NEXT_ERROR;
2306 b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2311 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
2315 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2317 if (PREDICT_FALSE (next1 & 0x80000000))
2319 next1 ^= 0xFFFFFFFF;
2320 if (PREDICT_FALSE(next1 == SR_LOCAL_NEXT_ERROR))
2322 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2328 segment_index1 = sr1->segments_left - 1;
2330 /* Rewrite the packet */
2331 new_dst1 = (ip6_address_t *)(sr1->segments + segment_index1);
2332 ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
2333 ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
2335 if (PREDICT_TRUE (sr1->segments_left > 0))
2336 sr1->segments_left -= 1;
2339 /* End of the path. Clean up the SR header, or not */
2341 (sr1->segments_left == 0 &&
2342 (sr1->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2344 u64 *copy_dst1, *copy_src1;
2347 * Copy the ip6 header right by the (real) length of the
2348 * sr header. Here's another place which assumes that
2349 * the sr header is the only extention header.
2352 ip1->protocol = sr1->protocol;
2353 vlib_buffer_advance (b1, (sr1->length+1)*8);
2355 new_l1 = clib_net_to_host_u16(ip1->payload_length) -
2357 ip1->payload_length = clib_host_to_net_u16(new_l1);
2359 copy_src1 = (u64 *)ip1;
2360 copy_dst1 = copy_src1 + (sr1->length + 1);
2362 copy_dst1 [4] = copy_src1[4];
2363 copy_dst1 [3] = copy_src1[3];
2364 copy_dst1 [2] = copy_src1[2];
2365 copy_dst1 [1] = copy_src1[1];
2366 copy_dst1 [0] = copy_src1[0];
2372 if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
2374 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2376 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2377 sizeof (tr->src.as_u8));
2378 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2379 sizeof (tr->dst.as_u8));
2380 tr->length = vlib_buffer_length_in_chain (vm, b1);
2381 tr->next_index = next1;
2382 tr->sr_valid = sr1 != 0;
2384 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
2387 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2388 to_next, n_left_to_next,
2389 bi0, bi1, next0, next1);
2392 while (n_left_from > 0 && n_left_to_next > 0)
2396 ip6_header_t * ip0 = 0;
2397 ip6_sr_header_t * sr0;
2398 ip6_address_t * new_dst0;
2399 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2406 n_left_to_next -= 1;
2408 b0 = vlib_get_buffer (vm, bi0);
2409 ip0 = vlib_buffer_get_current (b0);
2410 sr0 = (ip6_sr_header_t *)(ip0+1);
2412 if (PREDICT_FALSE(sr0->type != ROUTING_HEADER_TYPE_SR))
2414 next0 = SR_LOCAL_NEXT_ERROR;
2415 b0->error = node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2419 /* Out of segments? Turf the packet */
2420 if (PREDICT_FALSE (sr0->segments_left == 0))
2422 next0 = SR_LOCAL_NEXT_ERROR;
2423 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2427 if (PREDICT_FALSE(sm->validate_hmac))
2429 if (sr_validate_hmac (sm, ip0, sr0))
2431 next0 = SR_LOCAL_NEXT_ERROR;
2432 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2437 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
2441 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2443 if (PREDICT_FALSE (next0 & 0x80000000))
2445 next0 ^= 0xFFFFFFFF;
2446 if (PREDICT_FALSE(next0 == SR_LOCAL_NEXT_ERROR))
2448 node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2454 segment_index0 = sr0->segments_left - 1;
2456 /* Rewrite the packet */
2457 new_dst0 = (ip6_address_t *)(sr0->segments + segment_index0);
2458 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2459 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2461 if (PREDICT_TRUE (sr0->segments_left > 0))
2462 sr0->segments_left -= 1;
2465 /* End of the path. Clean up the SR header, or not */
2467 (sr0->segments_left == 0 &&
2468 (sr0->flags & clib_host_to_net_u16(IP6_SR_HEADER_FLAG_CLEANUP))))
2470 u64 *copy_dst0, *copy_src0;
2473 * Copy the ip6 header right by the (real) length of the
2474 * sr header. Here's another place which assumes that
2475 * the sr header is the only extention header.
2478 ip0->protocol = sr0->protocol;
2479 vlib_buffer_advance (b0, (sr0->length+1)*8);
2481 new_l0 = clib_net_to_host_u16(ip0->payload_length) -
2483 ip0->payload_length = clib_host_to_net_u16(new_l0);
2485 copy_src0 = (u64 *)ip0;
2486 copy_dst0 = copy_src0 + (sr0->length + 1);
2488 copy_dst0 [4] = copy_src0[4];
2489 copy_dst0 [3] = copy_src0[3];
2490 copy_dst0 [2] = copy_src0[2];
2491 copy_dst0 [1] = copy_src0[1];
2492 copy_dst0 [0] = copy_src0[0];
2498 if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2500 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2502 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2503 sizeof (tr->src.as_u8));
2504 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2505 sizeof (tr->dst.as_u8));
2506 tr->length = vlib_buffer_length_in_chain (vm, b0);
2507 tr->next_index = next0;
2508 tr->sr_valid = sr0 != 0;
2510 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2513 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2514 to_next, n_left_to_next,
2518 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2520 vlib_node_increment_counter (vm, sr_local_node.index,
2521 SR_LOCAL_ERROR_PKTS_PROCESSED,
2522 from_frame->n_vectors);
2523 return from_frame->n_vectors;
2526 VLIB_REGISTER_NODE (sr_local_node, static) = {
2527 .function = sr_local,
2529 /* Takes a vector of packets. */
2530 .vector_size = sizeof (u32),
2531 .format_trace = format_sr_local_trace,
2533 .runtime_data_bytes = 0,
2535 .n_errors = SR_LOCAL_N_ERROR,
2536 .error_strings = sr_local_error_strings,
2538 .n_next_nodes = SR_LOCAL_N_NEXT,
2540 #define _(s,n) [SR_LOCAL_NEXT_##s] = n,
2541 foreach_sr_local_next
2546 ip6_sr_main_t * sr_get_main (vlib_main_t * vm)
2548 vlib_call_init_function (vm, sr_init);
2549 ASSERT(sr_local_node.index);
2554 static clib_error_t *
2555 set_ip6_sr_rewrite_fn (vlib_main_t * vm,
2556 unformat_input_t * input,
2557 vlib_cli_command_t * cmd)
2560 ip6_main_t * im = &ip6_main;
2561 ip_lookup_main_t * lm = &im->lookup_main;
2566 ip_adjacency_t * adj;
2567 vnet_hw_interface_t * hi;
2569 ip6_sr_main_t * sm = &sr_main;
2570 vnet_main_t * vnm = vnet_get_main();
2572 if (!unformat (input, "%U", unformat_ip6_address, &a))
2573 return clib_error_return (0, "ip6 address missing in '%U'",
2574 format_unformat_error, input);
2576 if (unformat (input, "rx-table-id %d", &fib_id))
2578 p = hash_get (im->fib_index_by_table_id, fib_id);
2580 return clib_error_return (0, "fib-id %d not found");
2584 adj_index = ip6_fib_lookup_with_table (im, fib_index, &a);
2586 if (adj_index == lm->miss_adj_index)
2587 return clib_error_return (0, "no match for %U",
2588 format_ip6_address, &a);
2590 adj = ip_get_adjacency (lm, adj_index);
2592 if (adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
2593 return clib_error_return (0, "%U unresolved (not a rewrite adj)",
2594 format_ip6_address, &a);
2596 adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
2598 sw_if_index = adj->rewrite_header.sw_if_index;
2599 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2600 adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
2602 /* $$$$$ hack... steal the mcast group index */
2603 adj->mcast_group_index =
2604 vlib_node_add_next (vm, sr_fix_dst_addr_node.index, hi->output_node_index);
2609 VLIB_CLI_COMMAND (set_ip6_sr_rewrite, static) = {
2610 .path = "set ip6 sr rewrite",
2611 .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
2612 .function = set_ip6_sr_rewrite_fn,
2615 void vnet_register_sr_app_callback (void *cb)
2617 ip6_sr_main_t * sm = &sr_main;
2619 sm->sr_local_cb = cb;
2622 static clib_error_t *
2623 test_sr_hmac_validate_fn (vlib_main_t * vm,
2624 unformat_input_t * input,
2625 vlib_cli_command_t * cmd)
2627 ip6_sr_main_t * sm = &sr_main;
2629 if (unformat (input, "validate on"))
2630 sm->validate_hmac = 1;
2631 else if (unformat (input, "chunk-offset off"))
2632 sm->validate_hmac = 0;
2634 return clib_error_return (0, "expected validate on|off in '%U'",
2635 format_unformat_error, input);
2637 vlib_cli_output (vm, "hmac signature validation %s",
2643 VLIB_CLI_COMMAND (test_sr_hmac_validate, static) = {
2644 .path = "test sr hmac",
2645 .short_help = "test sr hmac validate [on|off]",
2646 .function = test_sr_hmac_validate_fn,
2649 i32 sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
2653 ip6_sr_hmac_key_t * key;
2657 /* Specific key in use? Fail. */
2658 if (key_id && vec_len (sm->hmac_keys) > key_id
2659 && sm->hmac_keys[key_id].shared_secret)
2663 key = find_or_add_shared_secret (sm, shared_secret, &index);
2664 ASSERT(index == key_id);
2670 if (key_id) /* delete by key ID */
2672 if (vec_len (sm->hmac_keys) <= key_id)
2675 key = sm->hmac_keys + key_id;
2677 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2678 vec_free (key->shared_secret);
2683 key = find_or_add_shared_secret (sm, shared_secret, &index);
2684 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
2685 vec_free (key->shared_secret);
2690 static clib_error_t *
2691 sr_hmac_add_del_key_fn (vlib_main_t * vm,
2692 unformat_input_t * input,
2693 vlib_cli_command_t * cmd)
2695 ip6_sr_main_t * sm = &sr_main;
2699 u8 * shared_secret = 0;
2702 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2704 if (unformat (input, "del"))
2706 else if (unformat (input, "id %d", &key_id))
2708 else if (unformat (input, "key %s", &shared_secret))
2710 /* Do not include the trailing NULL byte. Guaranteed interop issue */
2711 _vec_len (shared_secret) -= 1;
2717 if (is_del == 0 && shared_secret == 0)
2718 return clib_error_return (0, "shared secret must be set to add a key");
2720 if (shared_secret == 0 && key_id_set == 0)
2721 return clib_error_return (0, "shared secret and key id both unset");
2723 rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
2725 vec_free (shared_secret);
2733 return clib_error_return (0, "sr_hmac_add_del_key returned %d",
2740 VLIB_CLI_COMMAND (sr_hmac, static) = {
2742 .short_help = "sr hmac [del] id <nn> key <str>",
2743 .function = sr_hmac_add_del_key_fn,
2747 static clib_error_t *
2748 show_sr_hmac_fn (vlib_main_t * vm,
2749 unformat_input_t * input,
2750 vlib_cli_command_t * cmd)
2752 ip6_sr_main_t * sm = &sr_main;
2755 for (i = 1; i < vec_len (sm->hmac_keys); i++)
2757 if (sm->hmac_keys[i].shared_secret)
2758 vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
2764 VLIB_CLI_COMMAND (show_sr_hmac, static) = {
2765 .path = "show sr hmac",
2766 .short_help = "show sr hmac",
2767 .function = show_sr_hmac_fn,
2770 static clib_error_t *
2771 test_sr_debug_fn (vlib_main_t * vm,
2772 unformat_input_t * input,
2773 vlib_cli_command_t * cmd)
2775 ip6_sr_main_t * sm = &sr_main;
2777 if (unformat (input, "on"))
2779 else if (unformat (input, "off"))
2782 return clib_error_return (0, "expected on|off in '%U'",
2783 format_unformat_error, input);
2785 vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
2790 VLIB_CLI_COMMAND (test_sr_debug, static) = {
2791 .path = "test sr debug",
2792 .short_help = "test sr debug on|off",
2793 .function = test_sr_debug_fn,