blob: 5d0275d992a991621d98a850e37a5d0fc9d5091b [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * sr.c: ipv6 segment routing
3 *
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:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 */
17
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -070018/**
19 * @file
20 * @brief Segment Routing main functions
21 *
22 */
Ed Warnickecb9cada2015-12-08 15:45:58 -070023#include <vnet/vnet.h>
24#include <vnet/sr/sr.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010025#include <vnet/fib/ip6_fib.h>
26#include <vnet/dpo/dpo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070027
28#include <openssl/hmac.h>
29
30ip6_sr_main_t sr_main;
31static vlib_node_registration_t sr_local_node;
32
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -070033/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +010034 * @brief Dynamically added SR DPO type
35 */
36static dpo_type_t sr_dpo_type;
37
38/**
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -070039 * @brief Use passed HMAC key in ip6_sr_header_t in OpenSSL HMAC routines
40 *
41 * @param sm ip6_sr_main_t *
42 * @param ip ip6_header_t *
43 * @param sr ip6_sr_header_t *
44 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -070045void
46sr_fix_hmac (ip6_sr_main_t * sm, ip6_header_t * ip, ip6_sr_header_t * sr)
Ed Warnickecb9cada2015-12-08 15:45:58 -070047{
48 u32 key_index;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -070049 static u8 *keybuf;
50 u8 *copy_target;
Ed Warnickecb9cada2015-12-08 15:45:58 -070051 int first_segment;
52 ip6_address_t *addrp;
53 int i;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -070054 ip6_sr_hmac_key_t *hmac_key;
Ed Warnickecb9cada2015-12-08 15:45:58 -070055 u32 sig_len;
56
57 key_index = sr->hmac_key;
58
59 /* No signature? Pass... */
60 if (key_index == 0)
61 return;
62
63 /* We don't know about this key? Fail... */
64 if (key_index >= vec_len (sm->hmac_keys))
65 return;
66
67 hmac_key = sm->hmac_keys + key_index;
68
69 vec_reset_length (keybuf);
70
71 /* pkt ip6 src address */
72 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
Damjan Marionf1213b82016-03-13 02:22:06 +010073 clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -070074
75 /* first segment */
76 vec_add2 (keybuf, copy_target, 1);
77 copy_target[0] = sr->first_segment;
78
79 /* octet w/ bit 0 = "clean" flag */
80 vec_add2 (keybuf, copy_target, 1);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -070081 copy_target[0]
82 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
Ed Warnickecb9cada2015-12-08 15:45:58 -070083 ? 0x80 : 0;
84
85 /* hmac key id */
86 vec_add2 (keybuf, copy_target, 1);
87 copy_target[0] = sr->hmac_key;
88
89 first_segment = sr->first_segment;
90
91 addrp = sr->segments;
92
93 /* segments */
94 for (i = 0; i <= first_segment; i++)
95 {
96 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
Damjan Marionf1213b82016-03-13 02:22:06 +010097 clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -070098 addrp++;
99 }
100
101 addrp++;
102
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700103 HMAC_CTX_init (sm->hmac_ctx);
104 if (!HMAC_Init (sm->hmac_ctx, hmac_key->shared_secret,
105 vec_len (hmac_key->shared_secret), sm->md))
106 clib_warning ("barf1");
107 if (!HMAC_Update (sm->hmac_ctx, keybuf, vec_len (keybuf)))
108 clib_warning ("barf2");
109 if (!HMAC_Final (sm->hmac_ctx, (unsigned char *) addrp, &sig_len))
110 clib_warning ("barf3");
111 HMAC_CTX_cleanup (sm->hmac_ctx);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700112}
113
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700114/**
115 * @brief Format function for decoding various SR flags
116 *
117 * @param s u8 * - formatted string
118 * @param args va_list * - u16 flags
119 *
120 * @return formatted output string u8 *
121 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700122u8 *
123format_ip6_sr_header_flags (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700124{
125 u16 flags = (u16) va_arg (*args, int);
126 u8 pl_flag;
127 int bswap_needed = va_arg (*args, int);
128 int i;
129
130 if (bswap_needed)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700131 flags = clib_host_to_net_u16 (flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132
133 if (flags & IP6_SR_HEADER_FLAG_CLEANUP)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700134 s = format (s, "cleanup ");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135
136 if (flags & IP6_SR_HEADER_FLAG_PROTECTED)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700137 s = format (s, "reroute ");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
139 s = format (s, "pl: ");
140 for (i = 1; i <= 4; i++)
141 {
142 pl_flag = ip6_sr_policy_list_flags (flags, i);
143 s = format (s, "[%d] ", i);
144
145 switch (pl_flag)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700146 {
147 case IP6_SR_HEADER_FLAG_PL_ELT_NOT_PRESENT:
148 s = format (s, "NotPr ");
149 break;
150 case IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE:
151 s = format (s, "InPE ");
152 break;
153 case IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE:
154 s = format (s, "EgPE ");
155 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700157 case IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR:
158 s = format (s, "OrgSrc ");
159 break;
160 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161 }
162 return s;
163}
164
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700165/**
166 * @brief Format function for decoding ip6_sr_header_t
167 *
168 * @param s u8 * - formatted string
169 * @param args va_list * - ip6_sr_header_t
170 *
171 * @return formatted output string u8 *
172 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700173u8 *
174format_ip6_sr_header (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700175{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700176 ip6_sr_header_t *h = va_arg (*args, ip6_sr_header_t *);
177 ip6_address_t placeholder_addr =
178 { {254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
179 254, 254}
180 };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181 int print_hmac = va_arg (*args, int);
182 int i, pl_index, max_segs;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700183 int flags_host_byte_order = clib_net_to_host_u16 (h->flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184
185 s = format (s, "next proto %d, len %d, type %d",
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700186 h->protocol, (h->length << 3) + 8, h->type);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 s = format (s, "\n segs left %d, first_segment %d, hmac key %d",
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700188 h->segments_left, h->first_segment, h->hmac_key);
189 s = format (s, "\n flags %U", format_ip6_sr_header_flags,
190 flags_host_byte_order, 0 /* bswap needed */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191
Damjan Marion607de1a2016-08-16 22:53:54 +0200192 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 * Header length is in 8-byte units (minus one), so
194 * divide by 2 to ascertain the number of ip6 addresses in the
195 * segment list
196 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700197 max_segs = (h->length >> 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198
199 if (!print_hmac && h->hmac_key)
200 max_segs -= 2;
201
202 s = format (s, "\n Segments (in processing order):");
203
Calvined9b7572016-07-04 16:30:50 -0400204 for (i = h->first_segment; i >= 1; i--)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 s = format (s, "\n %U", format_ip6_address, h->segments + i);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700206 if (ip6_address_is_equal (&placeholder_addr, h->segments))
207 s = format (s, "\n (empty placeholder)");
Calvined9b7572016-07-04 16:30:50 -0400208 else
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700209 s = format (s, "\n %U", format_ip6_address, h->segments);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
211 s = format (s, "\n Policy List:");
212
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700213 pl_index = 1; /* to match the RFC text */
214 for (i = (h->first_segment + 1); i < max_segs; i++, pl_index++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700216 char *tag;
217 char *tags[] = { " ", "InPE: ", "EgPE: ", "OrgSrc: " };
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218
219 tag = tags[0];
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700220 if (pl_index >= 1 && pl_index <= 4)
221 {
222 int this_pl_flag = ip6_sr_policy_list_flags
223 (flags_host_byte_order, pl_index);
224 tag = tags[this_pl_flag];
225 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226
227 s = format (s, "\n %s%U", tag, format_ip6_address, h->segments + i);
228 }
229
230 return s;
231}
232
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700233/**
234 * @brief Format function for decoding ip6_sr_header_t with length
235 *
236 * @param s u8 * - formatted string
237 * @param args va_list * - ip6_header_t + ip6_sr_header_t
238 *
239 * @return formatted output string u8 *
240 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700241u8 *
242format_ip6_sr_header_with_length (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700244 ip6_header_t *h = va_arg (*args, ip6_header_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 u32 max_header_bytes = va_arg (*args, u32);
246 uword header_bytes;
247
248 header_bytes = sizeof (h[0]) + sizeof (ip6_sr_header_t);
249 if (max_header_bytes != 0 && header_bytes > max_header_bytes)
250 return format (s, "ip6_sr header truncated");
251
252 s = format (s, "IP6: %U\n", format_ip6_header, h, max_header_bytes);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700253 s =
254 format (s, "SR: %U\n", format_ip6_sr_header, (ip6_sr_header_t *) (h + 1),
255 0 /* print_hmac */ , max_header_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256 return s;
257}
258
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700259/**
260 * @brief Defined valid next nodes
261 * @note Cannot call replicate yet without DPDK
262*/
263#if DPDK > 0
Ed Warnickecb9cada2015-12-08 15:45:58 -0700264#define foreach_sr_rewrite_next \
265_(ERROR, "error-drop") \
266_(IP6_LOOKUP, "ip6-lookup") \
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700267_(SR_LOCAL, "sr-local") \
268_(SR_REPLICATE,"sr-replicate")
Keith Burns (alagalah)21c33bb2016-05-02 13:13:46 -0700269#else
270#define foreach_sr_rewrite_next \
271_(ERROR, "error-drop") \
272_(IP6_LOOKUP, "ip6-lookup") \
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700273_(SR_LOCAL, "sr-local")
Keith Burns (alagalah)21c33bb2016-05-02 13:13:46 -0700274#endif /* DPDK */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700276/**
277 * @brief Struct for defined valid next nodes
278*/
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700279typedef enum
280{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281#define _(s,n) SR_REWRITE_NEXT_##s,
282 foreach_sr_rewrite_next
283#undef _
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700284 SR_REWRITE_N_NEXT,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285} sr_rewrite_next_t;
286
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700287/**
288 * @brief Struct for data for SR rewrite packet trace
289 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700290typedef struct
291{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292 ip6_address_t src, dst;
293 u16 length;
294 u32 next_index;
295 u32 tunnel_index;
296 u8 sr[256];
297} sr_rewrite_trace_t;
298
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700299/**
300 * @brief Error strings for SR rewrite
301 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700302static char *sr_rewrite_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303#define sr_error(n,s) s,
304#include "sr_error.def"
305#undef sr_error
306};
307
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700308/**
309 * @brief Struct for SR rewrite error strings
310 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700311typedef enum
312{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700313#define sr_error(n,s) SR_REWRITE_ERROR_##n,
314#include "sr_error.def"
315#undef sr_error
316 SR_REWRITE_N_ERROR,
317} sr_rewrite_error_t;
318
319
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700320/**
321 * @brief Format function for SR rewrite trace.
322 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700323u8 *
324format_sr_rewrite_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325{
326 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
327 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700328 sr_rewrite_trace_t *t = va_arg (*args, sr_rewrite_trace_t *);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700329 ip6_sr_main_t *sm = &sr_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 ip6_sr_tunnel_t *tun = pool_elt_at_index (sm->tunnels, t->tunnel_index);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700331 ip6_fib_t *rx_fib, *tx_fib;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100333 rx_fib = ip6_fib_get (tun->rx_fib_index);
334 tx_fib = ip6_fib_get (tun->tx_fib_index);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700335
336 s = format
337 (s, "SR-REWRITE: next %s ip6 src %U dst %U len %u\n"
338 " rx-fib-id %d tx-fib-id %d\n%U",
339 (t->next_index == SR_REWRITE_NEXT_SR_LOCAL)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340 ? "sr-local" : "ip6-lookup",
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700341 format_ip6_address, &t->src,
342 format_ip6_address, &t->dst, t->length,
343 rx_fib->table_id, tx_fib->table_id,
344 format_ip6_sr_header, t->sr, 0 /* print_hmac */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345 return s;
346}
347
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700348/**
349 * @brief Main processing dual-loop for Segment Routing Rewrite
350 * @node sr-rewrite
351 *
352 * @param vm vlib_main_t *
353 * @param node vlib_node_runtime_t *
354 * @param from_frame vlib_frame_t *
355 *
356 * @return from_frame->n_vectors uword
357 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358static uword
359sr_rewrite (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700360 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700362 u32 n_left_from, next_index, *from, *to_next;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700363 ip6_sr_main_t *sm = &sr_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700365 vlib_buffer_t *, ip6_header_t *, ip6_sr_header_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366 sr_local_cb = sm->sr_local_cb;
367
368 from = vlib_frame_vector_args (from_frame);
369 n_left_from = from_frame->n_vectors;
370
371 next_index = node->cached_next_index;
372
373 while (n_left_from > 0)
374 {
375 u32 n_left_to_next;
376
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700377 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700379 /* Note 2x loop disabled */
380 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381 {
382 u32 bi0, bi1;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700383 vlib_buffer_t *b0, *b1;
384 ip6_header_t *ip0, *ip1;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700385 ip6_sr_header_t *sr0, *sr1;
386 ip6_sr_tunnel_t *t0, *t1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
388 u32 next1 = SR_REWRITE_NEXT_IP6_LOOKUP;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700389 u16 new_l0 = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700390 u16 new_l1 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391
392 /* Prefetch next iteration. */
393 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700394 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395
396 p2 = vlib_get_buffer (vm, from[2]);
397 p3 = vlib_get_buffer (vm, from[3]);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700398
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399 vlib_prefetch_buffer_header (p2, LOAD);
400 vlib_prefetch_buffer_header (p3, LOAD);
401 }
402
403 bi0 = from[0];
404 bi1 = from[1];
405 to_next[0] = bi0;
406 to_next[1] = bi1;
407 from += 2;
408 to_next += 2;
409 n_left_to_next -= 2;
410 n_left_from -= 2;
411
412 b0 = vlib_get_buffer (vm, bi0);
413 b1 = vlib_get_buffer (vm, bi1);
414
Damjan Marion607de1a2016-08-16 22:53:54 +0200415 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700416 * $$$ parse through header(s) to pick the point
417 * where we punch in the SR extention header
418 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700419 t0 =
Shwethab78292e2016-09-13 11:51:00 +0100420 pool_elt_at_index (sm->tunnels,
421 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700422 t1 =
Shwethab78292e2016-09-13 11:51:00 +0100423 pool_elt_at_index (sm->tunnels,
424 vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700426 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
427 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
428 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
429 >= ((word) vec_len (t1->rewrite)) + b1->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700431 vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
432 vnet_buffer (b1)->sw_if_index[VLIB_TX] = t1->tx_fib_index;
Chris Luke4b8b7182016-05-25 14:39:47 -0400433
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700434 ip0 = vlib_buffer_get_current (b0);
435 ip1 = vlib_buffer_get_current (b1);
Shwethab78292e2016-09-13 11:51:00 +0100436#if DPDK > 0 /* Cannot call replication node yet without DPDK */
437 /* add a replication node */
438 if (PREDICT_FALSE (t0->policy_index != ~0))
439 {
440 vnet_buffer (b0)->ip.save_protocol = t0->policy_index;
441 next0 = SR_REWRITE_NEXT_SR_REPLICATE;
442 sr0 = (ip6_sr_header_t *) (t0->rewrite);
443 goto processnext;
444 }
445#endif /* DPDK */
Chris Luke4b8b7182016-05-25 14:39:47 -0400446
Damjan Marion607de1a2016-08-16 22:53:54 +0200447 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700448 * SR-unaware service chaining case: pkt coming back from
449 * service has the original dst address, and will already
Damjan Marion607de1a2016-08-16 22:53:54 +0200450 * have an SR header. If so, send it to sr-local
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700451 */
452 if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE))
453 {
454 vlib_buffer_advance (b0, sizeof (ip0));
455 sr0 = (ip6_sr_header_t *) (ip0 + 1);
456 new_l0 = clib_net_to_host_u16 (ip0->payload_length);
457 next0 = SR_REWRITE_NEXT_SR_LOCAL;
458 }
459 else
460 {
Shwethab78292e2016-09-13 11:51:00 +0100461 u32 len_bytes = sizeof (ip6_header_t);
462 u8 next_hdr = ip0->protocol;
463
464 /* HBH must immediately follow ipv6 header */
465 if (PREDICT_FALSE
466 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
467 {
468 ip6_hop_by_hop_ext_t *ext_hdr =
469 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
470 len_bytes +=
471 ip6_ext_header_len ((ip6_ext_header_t *) ext_hdr);
472 /* Ignoring the sr_local for now, if RH follows HBH here */
473 next_hdr = ext_hdr->next_hdr;
474 ext_hdr->next_hdr = IPPROTO_IPV6_ROUTE;
475 }
476 else
477 {
478 ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
479 }
Damjan Marion607de1a2016-08-16 22:53:54 +0200480 /*
481 * Copy data before the punch-in point left by the
482 * required amount. Assume (for the moment) that only
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700483 * the main packet header needs to be copied.
484 */
485 clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
Shwethab78292e2016-09-13 11:51:00 +0100486 ip0, len_bytes);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700487 vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
488 ip0 = vlib_buffer_get_current (b0);
Shwethab78292e2016-09-13 11:51:00 +0100489 sr0 = (ip6_sr_header_t *) ((u8 *) ip0 + len_bytes);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700490 /* $$$ tune */
491 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700492
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700493 /* Fix the next header chain */
Shwethab78292e2016-09-13 11:51:00 +0100494 sr0->protocol = next_hdr;
495
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700496 new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
497 vec_len (t0->rewrite);
498 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700500 /* Copy dst address into the DA slot in the segment list */
501 clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
502 sizeof (ip6_address_t));
503 /* Rewrite the ip6 dst address with the first hop */
504 clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
505 sizeof (ip6_address_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700507 sr_fix_hmac (sm, ip0, sr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700509 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
510 next0;
Chris Luke4b8b7182016-05-25 14:39:47 -0400511
Damjan Marion607de1a2016-08-16 22:53:54 +0200512 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700513 * Ignore "do not rewrite" shtik in this path
514 */
515 if (PREDICT_FALSE (next0 & 0x80000000))
516 {
517 next0 ^= 0xFFFFFFFF;
518 if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
519 b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
520 }
521 }
Shwethab78292e2016-09-13 11:51:00 +0100522#if DPDK > 0 /* Cannot call replication node yet without DPDK */
523 processnext:
524 /* add a replication node */
525 if (PREDICT_FALSE (t1->policy_index != ~0))
526 {
527 vnet_buffer (b1)->ip.save_protocol = t1->policy_index;
528 next1 = SR_REWRITE_NEXT_SR_REPLICATE;
529 sr1 = (ip6_sr_header_t *) (t1->rewrite);
530 goto trace00;
531 }
532#endif /* DPDK */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700533 if (PREDICT_FALSE (ip1->protocol == IPPROTO_IPV6_ROUTE))
534 {
535 vlib_buffer_advance (b1, sizeof (ip1));
536 sr1 = (ip6_sr_header_t *) (ip1 + 1);
537 new_l1 = clib_net_to_host_u16 (ip1->payload_length);
538 next1 = SR_REWRITE_NEXT_SR_LOCAL;
539 }
540 else
541 {
Shwethab78292e2016-09-13 11:51:00 +0100542 u32 len_bytes = sizeof (ip6_header_t);
543 u8 next_hdr = ip1->protocol;
544
545 /* HBH must immediately follow ipv6 header */
546 if (PREDICT_FALSE
547 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
548 {
549 ip6_hop_by_hop_ext_t *ext_hdr =
550 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip1);
551 len_bytes +=
552 ip6_ext_header_len ((ip6_ext_header_t *) ext_hdr);
553 /* Ignoring the sr_local for now, if RH follows HBH here */
554 next_hdr = ext_hdr->next_hdr;
555 ext_hdr->next_hdr = IPPROTO_IPV6_ROUTE;
556 }
557 else
558 {
559 ip1->protocol = IPPROTO_IPV6_ROUTE;
560 }
561 /*
562 * Copy data before the punch-in point left by the
563 * required amount. Assume (for the moment) that only
564 * the main packet header needs to be copied.
565 */
566 clib_memcpy (((u8 *) ip1) - vec_len (t1->rewrite),
567 ip1, len_bytes);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700568 vlib_buffer_advance (b1, -(word) vec_len (t1->rewrite));
569 ip1 = vlib_buffer_get_current (b1);
Shwethab78292e2016-09-13 11:51:00 +0100570 sr1 = (ip6_sr_header_t *) ((u8 *) ip1 + len_bytes);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700571 clib_memcpy (sr1, t1->rewrite, vec_len (t1->rewrite));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700572
Shwethab78292e2016-09-13 11:51:00 +0100573 sr1->protocol = next_hdr;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700574 new_l1 = clib_net_to_host_u16 (ip1->payload_length) +
575 vec_len (t1->rewrite);
576 ip1->payload_length = clib_host_to_net_u16 (new_l1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700577
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700578 /* Copy dst address into the DA slot in the segment list */
579 clib_memcpy (sr1->segments, ip1->dst_address.as_u64,
580 sizeof (ip6_address_t));
581 /* Rewrite the ip6 dst address with the first hop */
582 clib_memcpy (ip1->dst_address.as_u64, t1->first_hop.as_u64,
583 sizeof (ip6_address_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700584
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700585 sr_fix_hmac (sm, ip1, sr1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700586
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700587 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
588 next1;
589
Damjan Marion607de1a2016-08-16 22:53:54 +0200590 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700591 * Ignore "do not rewrite" shtik in this path
592 */
593 if (PREDICT_FALSE (next1 & 0x80000000))
594 {
595 next1 ^= 0xFFFFFFFF;
596 if (PREDICT_FALSE (next1 == SR_REWRITE_NEXT_ERROR))
597 b1->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
598 }
599 }
Shwethab78292e2016-09-13 11:51:00 +0100600#if DPDK > 0 /* Cannot run replicate without DPDK and only replicate uses this label */
601 trace00:
602#endif /* DPDK */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700603
604 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
605 {
606 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
607 b0, sizeof (*tr));
608 tr->tunnel_index = t0 - sm->tunnels;
609 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
610 sizeof (tr->src.as_u8));
611 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
612 sizeof (tr->dst.as_u8));
613 tr->length = new_l0;
614 tr->next_index = next0;
Shwethab78292e2016-09-13 11:51:00 +0100615 if (sr0)
616 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700617 }
618 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
619 {
620 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
621 b1, sizeof (*tr));
622 tr->tunnel_index = t1 - sm->tunnels;
623 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
624 sizeof (tr->src.as_u8));
625 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
626 sizeof (tr->dst.as_u8));
627 tr->length = new_l1;
628 tr->next_index = next1;
Shwethab78292e2016-09-13 11:51:00 +0100629 if (sr1)
630 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700631 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
633 to_next, n_left_to_next,
634 bi0, bi1, next0, next1);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700635 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700636
637 while (n_left_from > 0 && n_left_to_next > 0)
638 {
639 u32 bi0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700640 vlib_buffer_t *b0;
641 ip6_header_t *ip0 = 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700642 ip6_sr_header_t *sr0 = 0;
643 ip6_sr_tunnel_t *t0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644 u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700645 u16 new_l0 = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646
647 bi0 = from[0];
648 to_next[0] = bi0;
649 from += 1;
650 to_next += 1;
651 n_left_from -= 1;
652 n_left_to_next -= 1;
653
654 b0 = vlib_get_buffer (vm, bi0);
655
Shwethab78292e2016-09-13 11:51:00 +0100656
Damjan Marion607de1a2016-08-16 22:53:54 +0200657 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700658 * $$$ parse through header(s) to pick the point
659 * where we punch in the SR extention header
660 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700661 t0 =
Shwethab78292e2016-09-13 11:51:00 +0100662 pool_elt_at_index (sm->tunnels,
663 vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700664#if DPDK > 0 /* Cannot call replication node yet without DPDK */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700665 /* add a replication node */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700666 if (PREDICT_FALSE (t0->policy_index != ~0))
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700667 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700668 vnet_buffer (b0)->ip.save_protocol = t0->policy_index;
669 next0 = SR_REWRITE_NEXT_SR_REPLICATE;
Shwethab78292e2016-09-13 11:51:00 +0100670 sr0 = (ip6_sr_header_t *) (t0->rewrite);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700671 goto trace0;
672 }
Keith Burns (alagalah)21c33bb2016-05-02 13:13:46 -0700673#endif /* DPDK */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700674
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700675 ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
676 >= ((word) vec_len (t0->rewrite)) + b0->current_data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700678 vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700679
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700680 ip0 = vlib_buffer_get_current (b0);
Chris Luke4b8b7182016-05-25 14:39:47 -0400681
Damjan Marion607de1a2016-08-16 22:53:54 +0200682 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700683 * SR-unaware service chaining case: pkt coming back from
684 * service has the original dst address, and will already
Damjan Marion607de1a2016-08-16 22:53:54 +0200685 * have an SR header. If so, send it to sr-local
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700686 */
687 if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE))
688 {
689 vlib_buffer_advance (b0, sizeof (ip0));
690 sr0 = (ip6_sr_header_t *) (ip0 + 1);
691 new_l0 = clib_net_to_host_u16 (ip0->payload_length);
692 next0 = SR_REWRITE_NEXT_SR_LOCAL;
693 }
694 else
695 {
Shwethab78292e2016-09-13 11:51:00 +0100696 u32 len_bytes = sizeof (ip6_header_t);
697 u8 next_hdr = ip0->protocol;
698
699 /* HBH must immediately follow ipv6 header */
700 if (PREDICT_FALSE
701 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
702 {
703 ip6_hop_by_hop_ext_t *ext_hdr =
704 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
705 len_bytes +=
706 ip6_ext_header_len ((ip6_ext_header_t *) ext_hdr);
707 next_hdr = ext_hdr->next_hdr;
708 ext_hdr->next_hdr = IPPROTO_IPV6_ROUTE;
709 /* Ignoring the sr_local for now, if RH follows HBH here */
710 }
711 else
712 {
713 ip0->protocol = IPPROTO_IPV6_ROUTE; /* routing extension header */
714 }
Damjan Marion607de1a2016-08-16 22:53:54 +0200715 /*
716 * Copy data before the punch-in point left by the
717 * required amount. Assume (for the moment) that only
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700718 * the main packet header needs to be copied.
719 */
720 clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
Shwethab78292e2016-09-13 11:51:00 +0100721 ip0, len_bytes);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700722 vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
723 ip0 = vlib_buffer_get_current (b0);
Shwethab78292e2016-09-13 11:51:00 +0100724 sr0 = (ip6_sr_header_t *) ((u8 *) ip0 + len_bytes);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700725 /* $$$ tune */
726 clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
Chris Luke4b8b7182016-05-25 14:39:47 -0400727
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700728 /* Fix the next header chain */
Shwethab78292e2016-09-13 11:51:00 +0100729 sr0->protocol = next_hdr;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700730 new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
731 vec_len (t0->rewrite);
732 ip0->payload_length = clib_host_to_net_u16 (new_l0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700734 /* Copy dst address into the DA slot in the segment list */
735 clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
736 sizeof (ip6_address_t));
737 /* Rewrite the ip6 dst address with the first hop */
738 clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
739 sizeof (ip6_address_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700741 sr_fix_hmac (sm, ip0, sr0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700743 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
744 next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745
Damjan Marion607de1a2016-08-16 22:53:54 +0200746 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700747 * Ignore "do not rewrite" shtik in this path
748 */
749 if (PREDICT_FALSE (next0 & 0x80000000))
750 {
751 next0 ^= 0xFFFFFFFF;
752 if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
753 b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
754 }
755 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700756#if DPDK > 0 /* Cannot run replicate without DPDK and only replicate uses this label */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700757 trace0:
Keith Burns (alagalah)21c33bb2016-05-02 13:13:46 -0700758#endif /* DPDK */
Shwethab78292e2016-09-13 11:51:00 +0100759
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700760 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
761 {
762 sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
763 b0, sizeof (*tr));
764 tr->tunnel_index = t0 - sm->tunnels;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700765 if (ip0)
766 {
767 memcpy (tr->src.as_u8, ip0->src_address.as_u8,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700768 sizeof (tr->src.as_u8));
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700769 memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700770 sizeof (tr->dst.as_u8));
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700771 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700772 tr->length = new_l0;
773 tr->next_index = next0;
Shwethab78292e2016-09-13 11:51:00 +0100774 if (sr0)
775 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700776 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700777 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
778 to_next, n_left_to_next,
779 bi0, next0);
780 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700781 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
782 }
783 return from_frame->n_vectors;
784}
785
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700786/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787VLIB_REGISTER_NODE (sr_rewrite_node) = {
788 .function = sr_rewrite,
789 .name = "sr-rewrite",
790 /* Takes a vector of packets. */
791 .vector_size = sizeof (u32),
792 .format_trace = format_sr_rewrite_trace,
793 .format_buffer = format_ip6_sr_header_with_length,
794
795 .n_errors = SR_REWRITE_N_ERROR,
796 .error_strings = sr_rewrite_error_strings,
797
798 .runtime_data_bytes = 0,
799
800 .n_next_nodes = SR_REWRITE_N_NEXT,
801 .next_nodes = {
802#define _(s,n) [SR_REWRITE_NEXT_##s] = n,
803 foreach_sr_rewrite_next
804#undef _
805 },
806};
807
Damjan Marion1c80e832016-05-11 23:07:18 +0200808VLIB_NODE_FUNCTION_MULTIARCH (sr_rewrite_node, sr_rewrite)
Damjan Marione33b9e02016-10-17 12:51:18 +0200809/* *INDENT-ON* */
810
811static int
812ip6_delete_route_no_next_hop (ip6_address_t * dst_address_arg,
813 u32 dst_address_length, u32 rx_table_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700814{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100815 fib_prefix_t pfx = {
816 .fp_len = dst_address_length,
817 .fp_proto = FIB_PROTOCOL_IP6,
818 .fp_addr = {
819 .ip6 = *dst_address_arg,
820 }
821 };
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700822
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100823 fib_table_entry_delete (fib_table_id_find_fib_index (FIB_PROTOCOL_IP6,
824 rx_table_id),
825 &pfx, FIB_SOURCE_SR);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700826
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827 return 0;
828}
829
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700830/**
831 * @brief Find or add if not found - HMAC shared secret
832 *
833 * @param sm ip6_sr_main_t *
834 * @param secret u8 *
835 * @param indexp u32 *
836 *
837 * @return ip6_sr_hmac_key_t *
838 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700839static ip6_sr_hmac_key_t *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700840find_or_add_shared_secret (ip6_sr_main_t * sm, u8 * secret, u32 * indexp)
841{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700842 uword *p;
843 ip6_sr_hmac_key_t *key = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700844 int i;
845
846 p = hash_get_mem (sm->hmac_key_by_shared_secret, secret);
847
848 if (p)
849 {
850 key = vec_elt_at_index (sm->hmac_keys, p[0]);
851 if (indexp)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700852 *indexp = p[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700853 return (key);
854 }
855
856 /* Specific key ID? */
857 if (indexp && *indexp)
858 {
859 vec_validate (sm->hmac_keys, *indexp);
860 key = sm->hmac_keys + *indexp;
861 }
862 else
863 {
864 for (i = 0; i < vec_len (sm->hmac_keys); i++)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700865 {
866 if (sm->hmac_keys[i].shared_secret == 0)
867 {
868 key = sm->hmac_keys + i;
869 goto found;
870 }
871 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872 vec_validate (sm->hmac_keys, i);
873 key = sm->hmac_keys + i;
874 found:
875 ;
876 }
877
878 key->shared_secret = vec_dup (secret);
879
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700880 hash_set_mem (sm->hmac_key_by_shared_secret, key->shared_secret,
881 key - sm->hmac_keys);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700882
883 if (indexp)
884 *indexp = key - sm->hmac_keys;
885 return (key);
886}
887
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -0700888/**
889 * @brief Add or Delete a Segment Routing tunnel.
890 *
891 * @param a ip6_sr_add_del_tunnel_args_t *
892 *
893 * @return retval int
894 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700895int
896ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700897{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700898 ip6_main_t *im = &ip6_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700899 ip6_sr_tunnel_key_t key;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700900 ip6_sr_tunnel_t *t;
901 uword *p, *n;
902 ip6_sr_header_t *h = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903 u32 header_length;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700904 ip6_address_t *addrp, *this_address;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700905 ip6_sr_main_t *sm = &sr_main;
906 u8 *key_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907 u32 rx_fib_index, tx_fib_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700908 u32 hmac_key_index_u32;
909 u8 hmac_key_index = 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700910 ip6_sr_policy_t *pt;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700911 int i;
Neale Ranns948e00f2016-10-20 13:39:34 +0100912 dpo_id_t dpo = DPO_INVALID;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700913
914 /* Make sure that the rx FIB exists */
915 p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700916
Ed Warnickecb9cada2015-12-08 15:45:58 -0700917 if (p == 0)
918 return -3;
919
920 /* remember the FIB index */
921 rx_fib_index = p[0];
922
923 /* Make sure that the supplied FIB exists */
924 p = hash_get (im->fib_index_by_table_id, a->tx_table_id);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700925
Ed Warnickecb9cada2015-12-08 15:45:58 -0700926 if (p == 0)
927 return -4;
928
929 /* remember the FIB index */
930 tx_fib_index = p[0];
931
Damjan Marionf1213b82016-03-13 02:22:06 +0100932 clib_memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
933 clib_memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700934
Chris Lukee5443602016-06-02 11:00:41 -0400935 /* When adding a tunnel:
936 * - If a "name" is given, it must not exist.
937 * - The "key" is always checked, and must not exist.
938 * When deleting a tunnel:
939 * - If the "name" is given, and it exists, then use it.
940 * - If the "name" is not given, use the "key".
941 * - If the "name" and the "key" are given, then both must point to the same
942 * thing.
943 */
944
945 /* Lookup the key */
946 p = hash_get_mem (sm->tunnel_index_by_key, &key);
947
948 /* If the name is given, look it up */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -0700949 if (a->name)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700950 n = hash_get_mem (sm->tunnel_index_by_name, a->name);
Chris Lukee5443602016-06-02 11:00:41 -0400951 else
952 n = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953
Chris Lukee5443602016-06-02 11:00:41 -0400954 /* validate key/name parameters */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700955 if (!a->is_del) /* adding a tunnel */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700957 if (a->name && n) /* name given & exists already */
958 return -1;
959 if (p) /* key exists already */
960 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700962 else /* deleting a tunnel */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700964 if (!p) /* key doesn't exist */
965 return -2;
966 if (a->name && !n) /* name given & it doesn't exist */
967 return -2;
Chris Lukee5443602016-06-02 11:00:41 -0400968
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700969 if (n) /* name given & found */
970 {
971 if (n[0] != p[0]) /* name and key do not point to the same thing */
972 return -2;
973 }
Chris Lukee5443602016-06-02 11:00:41 -0400974 }
975
976
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700977 if (a->is_del) /* delete the tunnel */
Chris Lukee5443602016-06-02 11:00:41 -0400978 {
979 hash_pair_t *hp;
980
981 /* Delete existing tunnel */
982 t = pool_elt_at_index (sm->tunnels, p[0]);
983
984 ip6_delete_route_no_next_hop (&t->key.dst, t->dst_mask_width,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700985 a->rx_table_id);
Chris Lukee5443602016-06-02 11:00:41 -0400986 vec_free (t->rewrite);
987 /* Remove tunnel from any policy if associated */
988 if (t->policy_index != ~0)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -0700989 {
990 pt = pool_elt_at_index (sm->policies, t->policy_index);
991 for (i = 0; i < vec_len (pt->tunnel_indices); i++)
992 {
993 if (pt->tunnel_indices[i] == t - sm->tunnels)
994 {
995 vec_delete (pt->tunnel_indices, 1, i);
996 goto found;
997 }
998 }
999 clib_warning ("Tunnel index %d not found in policy_index %d",
1000 t - sm->tunnels, pt - sm->policies);
1001 found:
1002 /* If this is last tunnel in the policy, clean up the policy too */
1003 if (vec_len (pt->tunnel_indices) == 0)
1004 {
1005 hash_unset_mem (sm->policy_index_by_policy_name, pt->name);
1006 vec_free (pt->name);
1007 pool_put (sm->policies, pt);
1008 }
1009 }
Chris Lukee5443602016-06-02 11:00:41 -04001010
1011 /* Clean up the tunnel by name */
1012 if (t->name)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001013 {
1014 hash_unset_mem (sm->tunnel_index_by_name, t->name);
1015 vec_free (t->name);
1016 }
Chris Lukee5443602016-06-02 11:00:41 -04001017 pool_put (sm->tunnels, t);
1018 hp = hash_get_pair (sm->tunnel_index_by_key, &key);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001019 key_copy = (void *) (hp->key);
Chris Lukee5443602016-06-02 11:00:41 -04001020 hash_unset_mem (sm->tunnel_index_by_key, &key);
1021 vec_free (key_copy);
1022 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023 }
1024
1025 /* create a new tunnel */
1026 pool_get (sm->tunnels, t);
1027 memset (t, 0, sizeof (*t));
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001028 t->policy_index = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029
Damjan Marionf1213b82016-03-13 02:22:06 +01001030 clib_memcpy (&t->key, &key, sizeof (t->key));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031 t->dst_mask_width = a->dst_mask_width;
1032 t->rx_fib_index = rx_fib_index;
1033 t->tx_fib_index = tx_fib_index;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001034
Chris Luke4b8b7182016-05-25 14:39:47 -04001035 if (!vec_len (a->segments))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001036 /* there must be at least one segment... */
1037 return -4;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001038
Chris Luke4b8b7182016-05-25 14:39:47 -04001039 /* The first specified hop goes right into the dst address */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001040 clib_memcpy (&t->first_hop, &a->segments[0], sizeof (ip6_address_t));
Chris Luke4b8b7182016-05-25 14:39:47 -04001041
Damjan Marion607de1a2016-08-16 22:53:54 +02001042 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001043 * Create the sr header rewrite string
Chris Luke4b8b7182016-05-25 14:39:47 -04001044 * The list of segments needs an extra slot for the ultimate destination
1045 * which is taken from the packet we add the SRH to.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001047 header_length = sizeof (*h) +
Chris Luke4b8b7182016-05-25 14:39:47 -04001048 sizeof (ip6_address_t) * (vec_len (a->segments) + 1 + vec_len (a->tags));
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001049
Ed Warnickecb9cada2015-12-08 15:45:58 -07001050 if (a->shared_secret)
1051 {
1052 /* Allocate a new key slot if we don't find the secret key */
1053 hmac_key_index_u32 = 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001054 (void) find_or_add_shared_secret (sm, a->shared_secret,
1055 &hmac_key_index_u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001056
1057 /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
1058 if (hmac_key_index_u32 >= 256)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001059 return -5;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001060 hmac_key_index = hmac_key_index_u32;
1061 header_length += SHA256_DIGEST_LENGTH;
1062 }
1063
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001064 vec_validate (t->rewrite, header_length - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001065
1066 h = (ip6_sr_header_t *) t->rewrite;
1067
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001068 h->protocol = 0xFF; /* we don't know yet */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001070 h->length = (header_length / 8) - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071 h->type = ROUTING_HEADER_TYPE_SR;
Chris Luke4b8b7182016-05-25 14:39:47 -04001072
1073 /* first_segment and segments_left need to have the index of the last
1074 * element in the list; a->segments has one element less than ends up
1075 * in the header (it does not have the DA in it), so vec_len(a->segments)
1076 * is the value we want.
1077 */
1078 h->first_segment = h->segments_left = vec_len (a->segments);
1079
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080 if (a->shared_secret)
1081 h->hmac_key = hmac_key_index & 0xFF;
1082
1083 h->flags = a->flags_net_byte_order;
1084
Chris Luke4b8b7182016-05-25 14:39:47 -04001085 /* Paint on the segment list, in reverse.
1086 * This is offset by one to leave room at the start for the ultimate
1087 * destination.
1088 */
1089 addrp = h->segments + vec_len (a->segments);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001090
1091 vec_foreach (this_address, a->segments)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001092 {
1093 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
1094 addrp--;
1095 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096
Chris Luke4b8b7182016-05-25 14:39:47 -04001097 /*
1098 * Since the ultimate destination address is not yet known, set that slot
1099 * to a value we will instantly recognize as bogus.
1100 */
1101 memset (h->segments, 0xfe, sizeof (ip6_address_t));
1102
Ed Warnickecb9cada2015-12-08 15:45:58 -07001103 /* Paint on the tag list, not reversed */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001104 addrp = h->segments + vec_len (a->segments);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001105
1106 vec_foreach (this_address, a->tags)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001107 {
1108 clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
1109 addrp++;
1110 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001111
1112 key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
Damjan Marionf1213b82016-03-13 02:22:06 +01001113 clib_memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001114 hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
1115
Damjan Marion607de1a2016-08-16 22:53:54 +02001116 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -07001117 * Stick the tunnel index into the rewrite header.
Damjan Marion607de1a2016-08-16 22:53:54 +02001118 *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119 * Unfortunately, inserting an SR header according to the various
1120 * RFC's requires parsing through the ip6 header, perhaps consing a
1121 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1122 * normal reverse bcopy rewrite code.
Damjan Marion607de1a2016-08-16 22:53:54 +02001123 *
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1125 * at some point...
1126 */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001127 dpo_set (&dpo, sr_dpo_type, DPO_PROTO_IP6, t - sm->tunnels);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001128
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001129 fib_prefix_t pfx = {
1130 .fp_proto = FIB_PROTOCOL_IP6,
1131 .fp_len = a->dst_mask_width,
1132 .fp_addr = {
1133 .ip6 = *a->dst_address,
1134 }
1135 };
1136 fib_table_entry_special_dpo_add (rx_fib_index,
1137 &pfx,
1138 FIB_SOURCE_SR,
1139 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
1140 dpo_reset (&dpo);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001142 if (a->policy_name)
1143 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001144 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001145 if (p)
1146 {
1147 pt = pool_elt_at_index (sm->policies, p[0]);
1148 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001149 else /* no policy, lets create one */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001150 {
1151 pool_get (sm->policies, pt);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001152 memset (pt, 0, sizeof (*pt));
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001153 pt->name = format (0, "%s%c", a->policy_name, 0);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001154 hash_set_mem (sm->policy_index_by_policy_name, pt->name,
1155 pt - sm->policies);
1156 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001157 }
1158 vec_add1 (pt->tunnel_indices, t - sm->tunnels);
Dave Barachf9c231e2016-08-05 10:10:18 -04001159 if (p == 0)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001160 clib_warning ("p is NULL!");
1161 t->policy_index = p ? p[0] : ~0; /* equiv. to (pt - sm->policies) */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001162 }
1163
1164 if (a->name)
1165 {
1166 t->name = format (0, "%s%c", a->name, 0);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001167 hash_set_mem (sm->tunnel_index_by_name, t->name, t - sm->tunnels);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001168 }
1169
Ed Warnickecb9cada2015-12-08 15:45:58 -07001170 return 0;
1171}
1172
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001173/**
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001174 * @brief no-op lock function.
1175 * The lifetime of the SR entry is managed by the control plane
1176 */
1177static void
1178sr_dpo_lock (dpo_id_t * dpo)
1179{
1180}
1181
1182/**
1183 * @brief no-op unlock function.
1184 * The lifetime of the SR entry is managed by the control plane
1185 */
1186static void
1187sr_dpo_unlock (dpo_id_t * dpo)
1188{
1189}
1190
1191u8 *
1192format_sr_dpo (u8 * s, va_list * args)
1193{
1194 index_t index = va_arg (*args, index_t);
1195 CLIB_UNUSED (u32 indent) = va_arg (*args, u32);
1196
1197 return (format (s, "SR: tunnel:[%d]", index));
1198}
1199
1200const static dpo_vft_t sr_vft = {
1201 .dv_lock = sr_dpo_lock,
1202 .dv_unlock = sr_dpo_unlock,
1203 .dv_format = format_sr_dpo,
1204};
1205
1206const static char *const sr_ip6_nodes[] = {
1207 "sr-rewrite",
1208 NULL,
1209};
1210
1211const static char *const *const sr_nodes[DPO_PROTO_NUM] = {
1212 [DPO_PROTO_IP6] = sr_ip6_nodes,
1213};
1214
1215/**
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001216 * @brief CLI parser for Add or Delete a Segment Routing tunnel.
1217 *
1218 * @param vm vlib_main_t *
1219 * @param input unformat_input_t *
1220 * @param cmd vlib_cli_command_t *
1221 *
1222 * @return error clib_error_t *
1223 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001224static clib_error_t *
1225sr_add_del_tunnel_command_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001226 unformat_input_t * input,
1227 vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228{
1229 int is_del = 0;
1230 ip6_address_t src_address;
1231 int src_address_set = 0;
1232 ip6_address_t dst_address;
1233 u32 dst_mask_width;
1234 int dst_address_set = 0;
1235 u16 flags = 0;
1236 u8 *shared_secret = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001237 u8 *name = 0;
1238 u8 *policy_name = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001239 u32 rx_table_id = 0;
1240 u32 tx_table_id = 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001241 ip6_address_t *segments = 0;
1242 ip6_address_t *this_seg;
1243 ip6_address_t *tags = 0;
1244 ip6_address_t *this_tag;
1245 ip6_sr_add_del_tunnel_args_t _a, *a = &_a;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001246 ip6_address_t next_address, tag;
1247 int pl_index;
1248 int rv;
1249
1250 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1251 {
1252 if (unformat (input, "del"))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001253 is_del = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001254 else if (unformat (input, "rx-fib-id %d", &rx_table_id))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001255 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001256 else if (unformat (input, "tx-fib-id %d", &tx_table_id))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001257 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001258 else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001259 src_address_set = 1;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001260 else if (unformat (input, "name %s", &name))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001261 ;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001262 else if (unformat (input, "policy %s", &policy_name))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001263 ;
1264 else if (unformat (input, "dst %U/%d",
1265 unformat_ip6_address, &dst_address, &dst_mask_width))
1266 dst_address_set = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267 else if (unformat (input, "next %U", unformat_ip6_address,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001268 &next_address))
1269 {
1270 vec_add2 (segments, this_seg, 1);
1271 clib_memcpy (this_seg->as_u8, next_address.as_u8,
1272 sizeof (*this_seg));
1273 }
1274 else if (unformat (input, "tag %U", unformat_ip6_address, &tag))
1275 {
1276 vec_add2 (tags, this_tag, 1);
1277 clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
1278 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001279 else if (unformat (input, "clean"))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001280 flags |= IP6_SR_HEADER_FLAG_CLEANUP;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001281 else if (unformat (input, "protected"))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001282 flags |= IP6_SR_HEADER_FLAG_PROTECTED;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001283 else if (unformat (input, "key %s", &shared_secret))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001284 /* Do not include the trailing NULL byte. Guaranteed interop issue */
1285 _vec_len (shared_secret) -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286 else if (unformat (input, "InPE %d", &pl_index))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001287 {
1288 if (pl_index <= 0 || pl_index > 4)
1289 {
1290 pl_index_range_error:
1291 return clib_error_return
1292 (0, "Policy List Element Index %d out of range (1-4)",
1293 pl_index);
1294
1295 }
1296 flags |= IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
1297 << ip6_sr_policy_list_shift_from_index (pl_index);
1298 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001299 else if (unformat (input, "EgPE %d", &pl_index))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001300 {
1301 if (pl_index <= 0 || pl_index > 4)
1302 goto pl_index_range_error;
1303 flags |= IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
1304 << ip6_sr_policy_list_shift_from_index (pl_index);
1305 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306 else if (unformat (input, "OrgSrc %d", &pl_index))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001307 {
1308 if (pl_index <= 0 || pl_index > 4)
1309 goto pl_index_range_error;
1310 flags |= IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
1311 << ip6_sr_policy_list_shift_from_index (pl_index);
1312 }
1313 else
1314 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001315 }
1316
1317 if (!src_address_set)
1318 return clib_error_return (0, "src address required");
1319
1320 if (!dst_address_set)
1321 return clib_error_return (0, "dst address required");
1322
1323 if (!segments)
1324 return clib_error_return (0, "at least one sr segment required");
1325
1326 memset (a, 0, sizeof (*a));
1327 a->src_address = &src_address;
1328 a->dst_address = &dst_address;
1329 a->dst_mask_width = dst_mask_width;
1330 a->segments = segments;
1331 a->tags = tags;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001332 a->flags_net_byte_order = clib_host_to_net_u16 (flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001333 a->is_del = is_del;
1334 a->rx_table_id = rx_table_id;
1335 a->tx_table_id = tx_table_id;
1336 a->shared_secret = shared_secret;
1337
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001338 if (vec_len (name))
1339 a->name = name;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001340 else
1341 a->name = 0;
1342
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001343 if (vec_len (policy_name))
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001344 a->policy_name = policy_name;
1345 else
1346 a->policy_name = 0;
1347
Ed Warnickecb9cada2015-12-08 15:45:58 -07001348 rv = ip6_sr_add_del_tunnel (a);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001349
Ed Warnickecb9cada2015-12-08 15:45:58 -07001350 vec_free (segments);
1351 vec_free (tags);
1352 vec_free (shared_secret);
1353
1354 switch (rv)
1355 {
1356 case 0:
1357 break;
1358
1359 case -1:
1360 return clib_error_return (0, "SR tunnel src %U dst %U already exists",
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001361 format_ip6_address, &src_address,
1362 format_ip6_address, &dst_address);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001363
1364 case -2:
1365 return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001366 format_ip6_address, &src_address,
1367 format_ip6_address, &dst_address);
1368
Ed Warnickecb9cada2015-12-08 15:45:58 -07001369 case -3:
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001370 return clib_error_return (0, "FIB table %d does not exist",
1371 rx_table_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372
1373 case -4:
1374 return clib_error_return (0, "At least one segment is required");
1375
1376 default:
1377 return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001378 rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001379 }
1380
1381 return 0;
1382}
1383
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001384/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001385VLIB_CLI_COMMAND (sr_tunnel_command, static) = {
1386 .path = "sr tunnel",
Damjan Marion607de1a2016-08-16 22:53:54 +02001387 .short_help =
Chris Lukee5443602016-06-02 11:00:41 -04001388 "sr tunnel [del] [name <name>] src <addr> dst <addr> [next <addr>] "
1389 "[clean] [reroute] [key <secret>] [policy <policy_name>]"
1390 "[rx-fib-id <fib_id>] [tx-fib-id <fib_id>]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001391 .function = sr_add_del_tunnel_command_fn,
1392};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001393/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001395/**
1396 * @brief Display Segment Routing tunnel
1397 *
1398 * @param vm vlib_main_t *
1399 * @param t ip6_sr_tunnel_t *
1400 *
1401 */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001402void
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001403ip6_sr_tunnel_display (vlib_main_t * vm, ip6_sr_tunnel_t * t)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001404{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001405 ip6_sr_main_t *sm = &sr_main;
1406 ip6_fib_t *rx_fib, *tx_fib;
1407 ip6_sr_policy_t *pt;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001408
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001409 rx_fib = ip6_fib_get (t->rx_fib_index);
1410 tx_fib = ip6_fib_get (t->tx_fib_index);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001411
1412 if (t->name)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001413 vlib_cli_output (vm, "sr tunnel name: %s", (char *) t->name);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001414
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001415 vlib_cli_output (vm, "src %U dst %U first hop %U",
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001416 format_ip6_address, &t->key.src,
1417 format_ip6_address, &t->key.dst,
1418 format_ip6_address, &t->first_hop);
1419 vlib_cli_output (vm, " rx-fib-id %d tx-fib-id %d",
1420 rx_fib->table_id, tx_fib->table_id);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001421 vlib_cli_output (vm, " sr: %U", format_ip6_sr_header, t->rewrite,
1422 0 /* print_hmac */ );
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001423
1424 if (t->policy_index != ~0)
1425 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001426 pt = pool_elt_at_index (sm->policies, t->policy_index);
1427 vlib_cli_output (vm, "sr policy: %s", (char *) pt->name);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001428 }
1429 vlib_cli_output (vm, "-------");
1430
1431 return;
1432}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001433
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001434/**
1435 * @brief CLI Parser for Display Segment Routing tunnel
1436 *
1437 * @param vm vlib_main_t *
1438 * @param input unformat_input_t *
1439 * @param cmd vlib_cli_command_t *
1440 *
1441 * @return error clib_error_t *
1442 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001443static clib_error_t *
1444show_sr_tunnel_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001445 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001446{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001447 static ip6_sr_tunnel_t **tunnels;
1448 ip6_sr_tunnel_t *t;
1449 ip6_sr_main_t *sm = &sr_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001450 int i;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001451 uword *p = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001452 u8 *name = 0;
1453
1454 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1455 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001456 if (unformat (input, "name %s", &name))
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001457 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001458 p = hash_get_mem (sm->tunnel_index_by_name, name);
1459 if (!p)
1460 vlib_cli_output (vm, "No SR tunnel with name: %s. Showing all.",
1461 name);
1462 }
1463 else
1464 break;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001465 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001466
1467 vec_reset_length (tunnels);
1468
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001469 if (!p) /* Either name parm not passed or no tunnel with that name found, show all */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001470 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001471 /* *INDENT-OFF* */
Damjan Marion607de1a2016-08-16 22:53:54 +02001472 pool_foreach (t, sm->tunnels,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001473 ({
1474 vec_add1 (tunnels, t);
1475 }));
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001476 /* *INDENT-ON* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001477 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001478 else /* Just show the one tunnel by name */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001479 vec_add1 (tunnels, &sm->tunnels[p[0]]);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001480
1481 if (vec_len (tunnels) == 0)
1482 vlib_cli_output (vm, "No SR tunnels configured");
1483
1484 for (i = 0; i < vec_len (tunnels); i++)
1485 {
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001486 t = tunnels[i];
1487 ip6_sr_tunnel_display (vm, t);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001488 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001489
Ed Warnickecb9cada2015-12-08 15:45:58 -07001490 return 0;
1491}
1492
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001493/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001494VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
1495 .path = "show sr tunnel",
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001496 .short_help = "show sr tunnel [name <sr-tunnel-name>]",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001497 .function = show_sr_tunnel_fn,
1498};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001499/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001500
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001501/**
1502 * @brief Add or Delete a Segment Routing policy
1503 *
1504 * @param a ip6_sr_add_del_policy_args_t *
1505 *
1506 * @return retval int
1507 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001508int
1509ip6_sr_add_del_policy (ip6_sr_add_del_policy_args_t * a)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001510{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001511 ip6_sr_main_t *sm = &sr_main;
1512 uword *p;
1513 ip6_sr_tunnel_t *t = 0;
1514 ip6_sr_policy_t *policy;
1515 u32 *tunnel_indices = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001516 int i;
1517
1518
1519
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001520 if (a->is_del)
1521 {
1522 p = hash_get_mem (sm->policy_index_by_policy_name, a->name);
1523 if (!p)
1524 return -6; /* policy name not found */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001525
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001526 policy = pool_elt_at_index (sm->policies, p[0]);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001527
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001528 vec_foreach_index (i, policy->tunnel_indices)
1529 {
1530 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1531 t->policy_index = ~0;
1532 }
1533 hash_unset_mem (sm->policy_index_by_policy_name, a->name);
1534 pool_put (sm->policies, policy);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001535 return 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001536 }
1537
1538
1539 if (!vec_len (a->tunnel_names))
1540 return -3; /*tunnel name is required case */
1541
1542 vec_reset_length (tunnel_indices);
1543 /* Check tunnel names, add tunnel_index to policy */
1544 for (i = 0; i < vec_len (a->tunnel_names); i++)
1545 {
1546 p = hash_get_mem (sm->tunnel_index_by_name, a->tunnel_names[i]);
1547 if (!p)
1548 return -4; /* tunnel name not found case */
1549
1550 t = pool_elt_at_index (sm->tunnels, p[0]);
1551 /*
1552 No need to check t==0. -3 condition above ensures name
1553 */
1554 if (t->policy_index != ~0)
1555 return -5; /* tunnel name already associated with a policy */
1556
1557 /* Add to tunnel indicies */
1558 vec_add1 (tunnel_indices, p[0]);
1559 }
1560
1561 /* Add policy to ip6_sr_main_t */
1562 pool_get (sm->policies, policy);
1563 policy->name = a->name;
1564 policy->tunnel_indices = tunnel_indices;
1565 hash_set_mem (sm->policy_index_by_policy_name, policy->name,
1566 policy - sm->policies);
1567
1568 /* Yes, this could be construed as overkill but the last thing you should do is set
Damjan Marion607de1a2016-08-16 22:53:54 +02001569 the policy_index on the tunnel after everything is set in ip6_sr_main_t.
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001570 If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop.
1571 */
1572 for (i = 0; i < vec_len (policy->tunnel_indices); i++)
1573 {
1574 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1575 t->policy_index = policy - sm->policies;
1576 }
1577
1578 return 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001579}
1580
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001581/**
1582 * @brief CLI Parser for Add or Delete a Segment Routing policy
1583 *
1584 * @param vm vlib_main_t *
1585 * @param input unformat_input_t *
1586 * @param cmd vlib_cli_command_t *
1587 *
1588 * @return error clib_error_t *
1589 */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001590static clib_error_t *
1591sr_add_del_policy_command_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001592 unformat_input_t * input,
1593 vlib_cli_command_t * cmd)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001594{
1595 int is_del = 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001596 u8 **tunnel_names = 0;
1597 u8 *tunnel_name = 0;
1598 u8 *name = 0;
1599 ip6_sr_add_del_policy_args_t _a, *a = &_a;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001600 int rv;
1601
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001602 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001603 {
1604 if (unformat (input, "del"))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001605 is_del = 1;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001606 else if (unformat (input, "name %s", &name))
1607 ;
1608 else if (unformat (input, "tunnel %s", &tunnel_name))
1609 {
1610 if (tunnel_name)
1611 {
1612 vec_add1 (tunnel_names, tunnel_name);
1613 tunnel_name = 0;
1614 }
1615 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001616 else
1617 break;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001618 }
1619
1620 if (!name)
1621 return clib_error_return (0, "name of SR policy required");
1622
1623
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001624 memset (a, 0, sizeof (*a));
1625
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001626 a->is_del = is_del;
1627 a->name = name;
1628 a->tunnel_names = tunnel_names;
1629
1630 rv = ip6_sr_add_del_policy (a);
1631
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001632 vec_free (tunnel_names);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001633
1634 switch (rv)
1635 {
1636 case 0:
1637 break;
1638
1639 case -3:
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001640 return clib_error_return (0,
1641 "tunnel name to associate to SR policy is required");
1642
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001643 case -4:
1644 return clib_error_return (0, "tunnel name not found");
1645
1646 case -5:
1647 return clib_error_return (0, "tunnel already associated with policy");
1648
1649 case -6:
1650 return clib_error_return (0, "policy name %s not found", name);
1651
1652 case -7:
1653 return clib_error_return (0, "TODO: deleting policy name %s", name);
1654
1655 default:
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001656 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1657 rv);
1658
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001659 }
1660 return 0;
1661}
1662
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001663/* *INDENT-OFF* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001664VLIB_CLI_COMMAND (sr_policy_command, static) = {
1665 .path = "sr policy",
Damjan Marion607de1a2016-08-16 22:53:54 +02001666 .short_help =
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001667 "sr policy [del] name <policy-name> tunnel <sr-tunnel-name> [tunnel <sr-tunnel-name>]*",
1668 .function = sr_add_del_policy_command_fn,
1669};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001670/* *INDENT-ON* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001671
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001672/**
1673 * @brief CLI Parser for Displaying Segment Routing policy
1674 *
1675 * @param vm vlib_main_t *
1676 * @param input unformat_input_t *
1677 * @param cmd vlib_cli_command_t *
1678 *
1679 * @return error clib_error_t *
1680 */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001681static clib_error_t *
1682show_sr_policy_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001683 unformat_input_t * input, vlib_cli_command_t * cmd)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001684{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001685 static ip6_sr_policy_t **policies;
1686 ip6_sr_policy_t *policy;
1687 ip6_sr_tunnel_t *t;
1688 ip6_sr_main_t *sm = &sr_main;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001689 int i, j;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001690 uword *p = 0;
1691 u8 *name = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001692
1693 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1694 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001695 if (unformat (input, "name %s", &name))
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001696 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001697 p = hash_get_mem (sm->policy_index_by_policy_name, name);
1698 if (!p)
1699 vlib_cli_output (vm,
1700 "policy with name %s not found. Showing all.",
1701 name);
1702 }
1703 else
1704 break;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001705 }
1706
1707 vec_reset_length (policies);
1708
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001709 if (!p) /* Either name parm not passed or no policy with that name found, show all */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001710 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001711 /* *INDENT-OFF* */
Damjan Marion607de1a2016-08-16 22:53:54 +02001712 pool_foreach (policy, sm->policies,
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001713 ({
1714 vec_add1 (policies, policy);
1715 }));
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001716 /* *INDENT-ON* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001717 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001718 else /* Just show the one policy by name and a summary of tunnel names */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001719 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001720 policy = pool_elt_at_index (sm->policies, p[0]);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001721 vec_add1 (policies, policy);
1722 }
1723
1724 if (vec_len (policies) == 0)
1725 vlib_cli_output (vm, "No SR policies configured");
1726
1727 for (i = 0; i < vec_len (policies); i++)
1728 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001729 policy = policies[i];
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001730
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001731 if (policy->name)
1732 vlib_cli_output (vm, "SR policy name: %s", (char *) policy->name);
1733 for (j = 0; j < vec_len (policy->tunnel_indices); j++)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001734 {
1735 t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[j]);
1736 ip6_sr_tunnel_display (vm, t);
1737 }
1738 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001739
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001740 return 0;
1741
1742}
1743
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001744/* *INDENT-OFF* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001745VLIB_CLI_COMMAND (show_sr_policy_command, static) = {
1746 .path = "show sr policy",
1747 .short_help = "show sr policy [name <sr-policy-name>]",
1748 .function = show_sr_policy_fn,
1749};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001750/* *INDENT-ON* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001751
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001752/**
1753 * @brief Add or Delete a mapping of IP6 multicast address
1754 * to Segment Routing policy.
1755 *
1756 * @param a ip6_sr_add_del_multicastmap_args_t *
1757 *
1758 * @return retval int
1759 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001760int
1761ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001762{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001763 uword *p;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001764 ip6_sr_tunnel_t *t;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001765 ip6_sr_main_t *sm = &sr_main;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001766 ip6_sr_policy_t *pt;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001767
1768 if (a->is_del)
1769 {
1770 /* clean up the adjacency */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001771 p =
1772 hash_get_mem (sm->policy_index_by_multicast_address,
1773 a->multicast_address);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001774 }
1775 else
1776 {
1777 /* Get our policy by policy_name */
1778 p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1779
1780 }
1781 if (!p)
1782 return -1;
1783
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001784 pt = pool_elt_at_index (sm->policies, p[0]);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001785
Damjan Marion607de1a2016-08-16 22:53:54 +02001786 /*
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001787 Get the first tunnel associated with policy populate the fib adjacency.
1788 From there, since this tunnel will have it's policy_index != ~0 it will
1789 be the trigger in the dual_loop to pull up the policy and make a copy-rewrite
1790 for each tunnel in the policy
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001791 */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001792
1793 t = pool_elt_at_index (sm->tunnels, pt->tunnel_indices[0]);
1794
Damjan Marion607de1a2016-08-16 22:53:54 +02001795 /*
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001796 * Stick the tunnel index into the rewrite header.
Damjan Marion607de1a2016-08-16 22:53:54 +02001797 *
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001798 * Unfortunately, inserting an SR header according to the various
1799 * RFC's requires parsing through the ip6 header, perhaps consing a
1800 * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1801 * normal reverse bcopy rewrite code.
Damjan Marion607de1a2016-08-16 22:53:54 +02001802 *
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001803 * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1804 * at some point...
1805 */
Neale Ranns948e00f2016-10-20 13:39:34 +01001806 dpo_id_t dpo = DPO_INVALID;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001807
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001808 dpo_set (&dpo, sr_dpo_type, DPO_PROTO_IP6, t - sm->tunnels);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001809
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001810 /* Construct a FIB entry for multicast using the rx/tx fib from the first tunnel */
1811 fib_prefix_t pfx = {
1812 .fp_proto = FIB_PROTOCOL_IP6,
1813 .fp_len = 128,
1814 .fp_addr = {
1815 .ip6 = *a->multicast_address,
1816 }
1817 };
1818 fib_table_entry_special_dpo_add (t->rx_fib_index,
1819 &pfx,
1820 FIB_SOURCE_SR,
1821 FIB_ENTRY_FLAG_EXCLUSIVE, &dpo);
1822 dpo_reset (&dpo);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001823
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001824 u8 *mcast_copy = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001825 mcast_copy = vec_new (ip6_address_t, 1);
1826 memcpy (mcast_copy, a->multicast_address, sizeof (ip6_address_t));
1827
1828 if (a->is_del)
1829 {
1830 hash_unset_mem (sm->policy_index_by_multicast_address, mcast_copy);
1831 vec_free (mcast_copy);
1832 return 0;
1833 }
1834 /* else */
1835
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001836 hash_set_mem (sm->policy_index_by_multicast_address, mcast_copy,
1837 pt - sm->policies);
1838
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001839
1840 return 0;
1841}
1842
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001843/**
1844 * @brief CLI Parser for Adding or Delete a mapping of IP6 multicast address
1845 * to Segment Routing policy.
1846 *
1847 * @param vm vlib_main_t *
1848 * @param input unformat_input_t *
1849 * @param cmd vlib_cli_command_t *
1850 *
1851 * @return error clib_error_t *
1852 */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001853static clib_error_t *
1854sr_add_del_multicast_map_command_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001855 unformat_input_t * input,
1856 vlib_cli_command_t * cmd)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001857{
1858 int is_del = 0;
1859 ip6_address_t multicast_address;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001860 u8 *policy_name = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001861 int multicast_address_set = 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001862 ip6_sr_add_del_multicastmap_args_t _a, *a = &_a;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001863 int rv;
1864
1865 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1866 {
1867 if (unformat (input, "del"))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001868 is_del = 1;
1869 else
1870 if (unformat
1871 (input, "address %U", unformat_ip6_address, &multicast_address))
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001872 multicast_address_set = 1;
1873 else if (unformat (input, "sr-policy %s", &policy_name))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001874 ;
1875 else
1876 break;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001877 }
1878
1879 if (!is_del && !policy_name)
1880 return clib_error_return (0, "name of sr policy required");
1881
1882 if (!multicast_address_set)
1883 return clib_error_return (0, "multicast address required");
1884
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001885 memset (a, 0, sizeof (*a));
1886
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001887 a->is_del = is_del;
1888 a->multicast_address = &multicast_address;
1889 a->policy_name = policy_name;
1890
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001891#if DPDK > 0 /*Cannot call replicate or configure multicast map yet without DPDK */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001892 rv = ip6_sr_add_del_multicastmap (a);
Keith Burns (alagalah)21c33bb2016-05-02 13:13:46 -07001893#else
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001894 return clib_error_return (0,
1895 "cannot use multicast replicate spray case without DPDK installed");
Keith Burns (alagalah)21c33bb2016-05-02 13:13:46 -07001896#endif /* DPDK */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001897
1898 switch (rv)
1899 {
1900 case 0:
1901 break;
1902 case -1:
1903 return clib_error_return (0, "no policy with name: %s", policy_name);
1904
1905 case -2:
1906 return clib_error_return (0, "multicast map someting ");
1907
1908 case -3:
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001909 return clib_error_return (0,
1910 "tunnel name to associate to SR policy is required");
1911
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001912 case -7:
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001913 return clib_error_return (0, "TODO: deleting policy name %s",
1914 policy_name);
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001915
1916 default:
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001917 return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1918 rv);
1919
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001920 }
1921 return 0;
1922
1923}
1924
1925
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001926/* *INDENT-OFF* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001927VLIB_CLI_COMMAND (sr_multicast_map_command, static) = {
1928 .path = "sr multicast-map",
Damjan Marion607de1a2016-08-16 22:53:54 +02001929 .short_help =
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001930 "sr multicast-map address <multicast-ip6-address> sr-policy <sr-policy-name> [del]",
1931 .function = sr_add_del_multicast_map_command_fn,
1932};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001933/* *INDENT-ON* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001934
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001935/**
1936 * @brief CLI Parser for Displaying a mapping of IP6 multicast address
1937 * to Segment Routing policy.
1938 *
1939 * @param vm vlib_main_t *
1940 * @param input unformat_input_t *
1941 * @param cmd vlib_cli_command_t *
1942 *
1943 * @return error clib_error_t *
1944 */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001945static clib_error_t *
1946show_sr_multicast_map_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001947 unformat_input_t * input, vlib_cli_command_t * cmd)
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001948{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001949 ip6_sr_main_t *sm = &sr_main;
1950 u8 *key = 0;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001951 u32 value;
1952 ip6_address_t multicast_address;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001953 ip6_sr_policy_t *pt;
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001954
1955 /* pull all entries from the hash table into vector for display */
1956
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001957 /* *INDENT-OFF* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001958 hash_foreach_mem (key, value, sm->policy_index_by_multicast_address,
1959 ({
1960 if (!key)
1961 vlib_cli_output (vm, "no multicast maps configured");
Damjan Marion607de1a2016-08-16 22:53:54 +02001962 else
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001963 {
1964 multicast_address = *((ip6_address_t *)key);
1965 pt = pool_elt_at_index (sm->policies, value);
1966 if (pt)
1967 {
Damjan Marion607de1a2016-08-16 22:53:54 +02001968 vlib_cli_output (vm, "address: %U policy: %s",
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001969 format_ip6_address, &multicast_address,
1970 pt->name);
1971 }
1972 else
Damjan Marion607de1a2016-08-16 22:53:54 +02001973 vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d",
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001974 format_ip6_address, &multicast_address,
1975 value);
Damjan Marion607de1a2016-08-16 22:53:54 +02001976
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001977 }
1978
1979 }));
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001980 /* *INDENT-ON* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001981
1982 return 0;
1983}
1984
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001985/* *INDENT-OFF* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001986VLIB_CLI_COMMAND (show_sr_multicast_map_command, static) = {
1987 .path = "show sr multicast-map",
1988 .short_help = "show sr multicast-map",
1989 .function = show_sr_multicast_map_fn,
1990};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07001991/* *INDENT-ON* */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07001992
1993
Ed Warnickecb9cada2015-12-08 15:45:58 -07001994#define foreach_sr_fix_dst_addr_next \
1995_(DROP, "error-drop")
1996
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07001997/**
1998 * @brief Struct for valid next-nodes for SR fix destination address node
1999 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002000typedef enum
2001{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002002#define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002003 foreach_sr_fix_dst_addr_next
Ed Warnickecb9cada2015-12-08 15:45:58 -07002004#undef _
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002005 SR_FIX_DST_ADDR_N_NEXT,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002006} sr_fix_dst_addr_next_t;
2007
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002008/**
2009 * @brief Error strings for SR Fix Destination rewrite
2010 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002011static char *sr_fix_dst_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002012#define sr_fix_dst_error(n,s) s,
2013#include "sr_fix_dst_error.def"
2014#undef sr_fix_dst_error
2015};
2016
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002017/**
2018 * @brief Struct for errors for SR Fix Destination rewrite
2019 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002020typedef enum
2021{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002022#define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
2023#include "sr_fix_dst_error.def"
2024#undef sr_fix_dst_error
2025 SR_FIX_DST_N_ERROR,
2026} sr_fix_dst_error_t;
2027
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002028/**
2029 * @brief Information for fix address trace
2030 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002031typedef struct
2032{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002033 ip6_address_t src, dst;
2034 u32 next_index;
2035 u32 adj_index;
2036 u8 sr[256];
2037} sr_fix_addr_trace_t;
2038
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002039/**
2040 * @brief Formatter for fix address trace
2041 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002042u8 *
2043format_sr_fix_addr_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002044{
2045 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2046 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002047 sr_fix_addr_trace_t *t = va_arg (*args, sr_fix_addr_trace_t *);
2048 vnet_hw_interface_t *hi = 0;
2049 ip_adjacency_t *adj;
2050 ip6_main_t *im = &ip6_main;
2051 ip_lookup_main_t *lm = &im->lookup_main;
2052 vnet_main_t *vnm = vnet_get_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07002053
2054 if (t->adj_index != ~0)
2055 {
2056 adj = ip_get_adjacency (lm, t->adj_index);
2057 hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
2058 }
2059
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002060 s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
2061 (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
2062 ? "drop" : "output",
2063 format_ip6_address, &t->src, format_ip6_address, &t->dst);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002064 if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
2065 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002066 s =
2067 format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
2068 s =
2069 format (s, " output via %s",
2070 hi ? (char *) (hi->name) : "Invalid adj");
Ed Warnickecb9cada2015-12-08 15:45:58 -07002071 }
2072 return s;
2073}
2074
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002075/**
2076 * @brief Fix SR destination address - dual-loop
2077 *
2078 * @node sr-fix-dst-addr
2079 * @param vm vlib_main_t *
2080 * @param node vlib_node_runtime_t *
2081 * @param from_frame vlib_frame_t *
2082 *
2083 * @return from_frame->n_vectors uword
2084 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002085static uword
2086sr_fix_dst_addr (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002087 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002088{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002089 u32 n_left_from, next_index, *from, *to_next;
2090 ip6_main_t *im = &ip6_main;
2091 ip_lookup_main_t *lm = &im->lookup_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002092
2093 from = vlib_frame_vector_args (from_frame);
2094 n_left_from = from_frame->n_vectors;
2095
2096 next_index = node->cached_next_index;
2097
2098 while (n_left_from > 0)
2099 {
2100 u32 n_left_to_next;
2101
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002102 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002103
2104#if 0
2105 while (0 && n_left_from >= 4 && n_left_to_next >= 2)
2106 {
2107 u32 bi0, bi1;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002108 __attribute__ ((unused)) vlib_buffer_t *b0, *b1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002109 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
2110 u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
2111
2112 /* Prefetch next iteration. */
2113 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002114 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002115
2116 p2 = vlib_get_buffer (vm, from[2]);
2117 p3 = vlib_get_buffer (vm, from[3]);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002118
Ed Warnickecb9cada2015-12-08 15:45:58 -07002119 vlib_prefetch_buffer_header (p2, LOAD);
2120 vlib_prefetch_buffer_header (p3, LOAD);
2121 }
2122
2123 bi0 = from[0];
2124 bi1 = from[1];
2125 to_next[0] = bi0;
2126 to_next[1] = bi1;
2127 from += 2;
2128 to_next += 2;
2129 n_left_to_next -= 2;
2130 n_left_from -= 2;
2131
2132 b0 = vlib_get_buffer (vm, bi0);
2133 b1 = vlib_get_buffer (vm, bi1);
2134
2135
2136 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2137 to_next, n_left_to_next,
2138 bi0, bi1, next0, next1);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002139 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002140#endif
2141
2142 while (n_left_from > 0 && n_left_to_next > 0)
2143 {
2144 u32 bi0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002145 vlib_buffer_t *b0;
2146 ip6_header_t *ip0;
2147 ip_adjacency_t *adj0;
2148 ip6_sr_header_t *sr0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002149 u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002150 ip6_address_t *new_dst0;
2151 ethernet_header_t *eh0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002152
2153 bi0 = from[0];
2154 to_next[0] = bi0;
2155 from += 1;
2156 to_next += 1;
2157 n_left_from -= 1;
2158 n_left_to_next -= 1;
2159
2160 b0 = vlib_get_buffer (vm, bi0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002161
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002162 adj0 =
2163 ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2164 next0 = adj0->mcast_group_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002165
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002166 /* We should be pointing at an Ethernet header... */
2167 eh0 = vlib_buffer_get_current (b0);
2168 ip0 = (ip6_header_t *) (eh0 + 1);
2169 sr0 = (ip6_sr_header_t *) (ip0 + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002170
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002171 /* We'd better find an SR header... */
2172 if (PREDICT_FALSE (ip0->protocol != IPPROTO_IPV6_ROUTE))
2173 {
2174 b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
2175 goto do_trace0;
2176 }
2177 else
2178 {
Damjan Marion607de1a2016-08-16 22:53:54 +02002179 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002180 * We get here from sr_rewrite or sr_local, with
2181 * sr->segments_left pointing at the (copy of the original) dst
2182 * address. Use it, then increment sr0->segments_left.
2183 */
2184
2185 /* Out of segments? Turf the packet */
2186 if (PREDICT_FALSE (sr0->segments_left == 0))
2187 {
2188 b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
2189 goto do_trace0;
2190 }
2191
Damjan Marion607de1a2016-08-16 22:53:54 +02002192 /*
2193 * Rewrite the packet with the original dst address
2194 * We assume that the last segment (in processing order) contains
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002195 * the original dst address. The list is reversed, so sr0->segments
2196 * contains the original dst address.
2197 */
2198 new_dst0 = sr0->segments;
2199 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2200 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2201 }
2202
2203 do_trace0:
2204
2205 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2206 {
2207 sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
2208 b0, sizeof (*t));
2209 t->next_index = next0;
2210 t->adj_index = ~0;
2211
2212 if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
2213 {
2214 t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2215 clib_memcpy (t->src.as_u8, ip0->src_address.as_u8,
2216 sizeof (t->src.as_u8));
2217 clib_memcpy (t->dst.as_u8, ip0->dst_address.as_u8,
2218 sizeof (t->dst.as_u8));
2219 clib_memcpy (t->sr, sr0, sizeof (t->sr));
2220 }
2221 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002222
2223 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2224 to_next, n_left_to_next,
2225 bi0, next0);
2226 }
2227
2228 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2229 }
2230 return from_frame->n_vectors;
2231}
2232
2233
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002234/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002235VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
2236 .function = sr_fix_dst_addr,
2237 .name = "sr-fix-dst-addr",
2238 /* Takes a vector of packets. */
2239 .vector_size = sizeof (u32),
2240 .format_trace = format_sr_fix_addr_trace,
2241 .format_buffer = format_ip6_sr_header_with_length,
2242
2243 .runtime_data_bytes = 0,
2244
2245 .n_errors = SR_FIX_DST_N_ERROR,
2246 .error_strings = sr_fix_dst_error_strings,
2247
2248 .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
2249 .next_nodes = {
2250#define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
2251 foreach_sr_fix_dst_addr_next
2252#undef _
2253 },
2254};
2255
Damjan Marion1c80e832016-05-11 23:07:18 +02002256VLIB_NODE_FUNCTION_MULTIARCH (sr_fix_dst_addr_node, sr_fix_dst_addr)
Damjan Marione33b9e02016-10-17 12:51:18 +02002257/* *INDENT-ON* */
2258
2259static clib_error_t *
2260sr_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002261{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002262 ip6_sr_main_t *sm = &sr_main;
2263 clib_error_t *error = 0;
2264 vlib_node_t *ip6_lookup_node, *ip6_rewrite_node;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002265
2266 if ((error = vlib_call_init_function (vm, ip_main_init)))
2267 return error;
2268
2269 if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
2270 return error;
2271
2272 sm->vlib_main = vm;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002273 sm->vnet_main = vnet_get_main ();
2274
Ed Warnickecb9cada2015-12-08 15:45:58 -07002275 vec_validate (sm->hmac_keys, 0);
2276 sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
2277
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002278 sm->tunnel_index_by_key =
Ed Warnickecb9cada2015-12-08 15:45:58 -07002279 hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
2280
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002281 sm->tunnel_index_by_name = hash_create_string (0, sizeof (uword));
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07002282
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002283 sm->policy_index_by_policy_name = hash_create_string (0, sizeof (uword));
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07002284
2285 sm->policy_index_by_multicast_address =
2286 hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
2287
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002288 sm->hmac_key_by_shared_secret = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002289
Chris Luke4b8b7182016-05-25 14:39:47 -04002290 ip6_register_protocol (IPPROTO_IPV6_ROUTE, sr_local_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002291
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002292 ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
2293 ASSERT (ip6_lookup_node);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002294
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002295 ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
2296 ASSERT (ip6_rewrite_node);
2297
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002298#if DPDK > 0 /* Cannot run replicate without DPDK */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07002299 /* Add a disposition to sr_replicate for the sr multicast replicate node */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002300 sm->ip6_lookup_sr_replicate_index =
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07002301 vlib_node_add_next (vm, ip6_lookup_node->index, sr_replicate_node.index);
Keith Burns (alagalah)21c33bb2016-05-02 13:13:46 -07002302#endif /* DPDK */
Keith Burns (alagalah)52fc44d2016-03-25 09:38:50 -07002303
Ed Warnickecb9cada2015-12-08 15:45:58 -07002304 /* Add a disposition to ip6_rewrite for the sr dst address hack node */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002305 sm->ip6_rewrite_sr_next_index =
2306 vlib_node_add_next (vm, ip6_rewrite_node->index,
2307 sr_fix_dst_addr_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002308
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002309 OpenSSL_add_all_digests ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07002310
2311 sm->md = (void *) EVP_get_digestbyname ("sha1");
2312 sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
2313
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002314 sr_dpo_type = dpo_register_new_type (&sr_vft, sr_nodes);
2315
Ed Warnickecb9cada2015-12-08 15:45:58 -07002316 return error;
2317}
2318
2319VLIB_INIT_FUNCTION (sr_init);
2320
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002321/**
2322 * @brief Definition of next-nodes for SR local
2323 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002324#define foreach_sr_local_next \
2325 _ (ERROR, "error-drop") \
2326 _ (IP6_LOOKUP, "ip6-lookup")
2327
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002328/**
2329 * @brief Struct for definition of next-nodes for SR local
2330 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002331typedef enum
2332{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002333#define _(s,n) SR_LOCAL_NEXT_##s,
2334 foreach_sr_local_next
2335#undef _
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002336 SR_LOCAL_N_NEXT,
Ed Warnickecb9cada2015-12-08 15:45:58 -07002337} sr_local_next_t;
2338
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002339/**
2340 * @brief Struct for packet trace of SR local
2341 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002342typedef struct
2343{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002344 u8 next_index;
2345 u8 sr_valid;
2346 ip6_address_t src, dst;
2347 u16 length;
2348 u8 sr[256];
2349} sr_local_trace_t;
2350
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002351/**
2352 * @brief Definition of SR local error-strings
2353 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002354static char *sr_local_error_strings[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -07002355#define sr_error(n,s) s,
2356#include "sr_error.def"
2357#undef sr_error
2358};
2359
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002360/**
2361 * @brief Struct for definition of SR local error-strings
2362 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002363typedef enum
2364{
Ed Warnickecb9cada2015-12-08 15:45:58 -07002365#define sr_error(n,s) SR_LOCAL_ERROR_##n,
2366#include "sr_error.def"
2367#undef sr_error
2368 SR_LOCAL_N_ERROR,
2369} sr_local_error_t;
2370
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002371/**
2372 * @brief Format SR local trace
2373 *
2374 * @param s u8 *
2375 * @param args va_list *
2376 *
2377 * @return s u8 *
2378 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002379u8 *
2380format_sr_local_trace (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002381{
2382 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2383 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002384 sr_local_trace_t *t = va_arg (*args, sr_local_trace_t *);
2385
2386 s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
2387 format_ip6_address, &t->src,
2388 format_ip6_address, &t->dst, t->length, t->next_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002389 if (t->sr_valid)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002390 s =
2391 format (s, "\n %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07002392 else
2393 s = format (s, "\n popped SR header");
2394
2395 return s;
2396}
2397
2398
2399/* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002400/**
2401 * @brief Validate the SR HMAC
2402 *
2403 * @param sm ip6_sr_main_t *
2404 * @param ip ip6_header_t *
2405 * @param sr ip6_sr_header_t *
2406 *
2407 * @return retval int
2408 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002409static int
2410sr_validate_hmac (ip6_sr_main_t * sm, ip6_header_t * ip, ip6_sr_header_t * sr)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002411{
2412 u32 key_index;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002413 static u8 *keybuf;
2414 u8 *copy_target;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002415 int first_segment;
2416 ip6_address_t *addrp;
2417 int i;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002418 ip6_sr_hmac_key_t *hmac_key;
2419 static u8 *signature;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002420 u32 sig_len;
2421
2422 key_index = sr->hmac_key;
2423
2424 /* No signature? Pass... */
2425 if (key_index == 0)
2426 return 0;
2427
2428 /* We don't know about this key? Fail... */
2429 if (key_index >= vec_len (sm->hmac_keys))
2430 return 1;
2431
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002432 vec_validate (signature, SHA256_DIGEST_LENGTH - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002433
2434 hmac_key = sm->hmac_keys + key_index;
2435
2436 vec_reset_length (keybuf);
2437
2438 /* pkt ip6 src address */
2439 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
Damjan Marionf1213b82016-03-13 02:22:06 +01002440 clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002441
2442 /* last segment */
2443 vec_add2 (keybuf, copy_target, 1);
2444 copy_target[0] = sr->first_segment;
2445
2446 /* octet w/ bit 0 = "clean" flag */
2447 vec_add2 (keybuf, copy_target, 1);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002448 copy_target[0]
2449 = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
Ed Warnickecb9cada2015-12-08 15:45:58 -07002450 ? 0x80 : 0;
2451
2452 /* hmac key id */
2453 vec_add2 (keybuf, copy_target, 1);
2454 copy_target[0] = sr->hmac_key;
2455
2456 first_segment = sr->first_segment;
2457
2458 addrp = sr->segments;
2459
2460 /* segments */
2461 for (i = 0; i <= first_segment; i++)
2462 {
2463 vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
Damjan Marionf1213b82016-03-13 02:22:06 +01002464 clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002465 addrp++;
2466 }
2467
2468 if (sm->is_debug)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002469 clib_warning ("verify key index %d keybuf: %U", key_index,
2470 format_hex_bytes, keybuf, vec_len (keybuf));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002471
2472 /* shared secret */
2473
2474 /* SHA1 is shorter than SHA-256 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002475 memset (signature, 0, vec_len (signature));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002476
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002477 HMAC_CTX_init (sm->hmac_ctx);
2478 if (!HMAC_Init (sm->hmac_ctx, hmac_key->shared_secret,
2479 vec_len (hmac_key->shared_secret), sm->md))
2480 clib_warning ("barf1");
2481 if (!HMAC_Update (sm->hmac_ctx, keybuf, vec_len (keybuf)))
2482 clib_warning ("barf2");
2483 if (!HMAC_Final (sm->hmac_ctx, signature, &sig_len))
2484 clib_warning ("barf3");
2485 HMAC_CTX_cleanup (sm->hmac_ctx);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002486
2487 if (sm->is_debug)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002488 clib_warning ("computed signature len %d, value %U", sig_len,
2489 format_hex_bytes, signature, vec_len (signature));
Ed Warnickecb9cada2015-12-08 15:45:58 -07002490
2491 /* Point at the SHA signature in the packet */
2492 addrp++;
2493 if (sm->is_debug)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002494 clib_warning ("read signature %U", format_hex_bytes, addrp,
2495 SHA256_DIGEST_LENGTH);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002496
2497 return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
2498}
2499
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07002500/**
2501 * @brief SR local node
2502 * @node sr-local
2503 *
2504 * @param vm vlib_main_t *
2505 * @param node vlib_node_runtime_t *
2506 * @param from_frame vlib_frame_t *
2507 *
2508 * @return from_frame->n_vectors uword
2509 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002510static uword
2511sr_local (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002512 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07002513{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002514 u32 n_left_from, next_index, *from, *to_next;
2515 ip6_sr_main_t *sm = &sr_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002516 u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002517 vlib_buffer_t *, ip6_header_t *, ip6_sr_header_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002518 sr_local_cb = sm->sr_local_cb;
2519
2520 from = vlib_frame_vector_args (from_frame);
2521 n_left_from = from_frame->n_vectors;
2522
2523 next_index = node->cached_next_index;
2524
2525 while (n_left_from > 0)
2526 {
2527 u32 n_left_to_next;
2528
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002529 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002530
2531 while (n_left_from >= 4 && n_left_to_next >= 2)
2532 {
2533 u32 bi0, bi1;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002534 vlib_buffer_t *b0, *b1;
2535 ip6_header_t *ip0, *ip1;
2536 ip6_sr_header_t *sr0, *sr1;
2537 ip6_address_t *new_dst0, *new_dst1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002538 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2539 u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
Shwethab78292e2016-09-13 11:51:00 +01002540
Ed Warnickecb9cada2015-12-08 15:45:58 -07002541 /* Prefetch next iteration. */
2542 {
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002543 vlib_buffer_t *p2, *p3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002544
2545 p2 = vlib_get_buffer (vm, from[2]);
2546 p3 = vlib_get_buffer (vm, from[3]);
2547
2548 vlib_prefetch_buffer_header (p2, LOAD);
2549 vlib_prefetch_buffer_header (p3, LOAD);
2550
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002551 CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2552 CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002553 }
2554
2555 bi0 = from[0];
2556 bi1 = from[1];
2557 to_next[0] = bi0;
2558 to_next[1] = bi1;
2559 from += 2;
2560 to_next += 2;
2561 n_left_to_next -= 2;
2562 n_left_from -= 2;
2563
2564
2565 b0 = vlib_get_buffer (vm, bi0);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002566 ip0 = vlib_buffer_get_current (b0);
2567 sr0 = (ip6_sr_header_t *) (ip0 + 1);
Shwethab78292e2016-09-13 11:51:00 +01002568 if (PREDICT_FALSE
2569 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
2570 {
2571 ip6_hop_by_hop_ext_t *ext_hdr =
2572 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
2573 sr0 =
2574 (ip6_sr_header_t *) ip6_ext_next_header ((ip6_ext_header_t *)
2575 ext_hdr);
2576 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002577
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002578 if (PREDICT_FALSE (sr0->type != ROUTING_HEADER_TYPE_SR))
2579 {
2580 next0 = SR_LOCAL_NEXT_ERROR;
2581 b0->error =
2582 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2583 goto do_trace0;
2584 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002585
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002586 /* Out of segments? Turf the packet */
2587 if (PREDICT_FALSE (sr0->segments_left == 0))
2588 {
2589 next0 = SR_LOCAL_NEXT_ERROR;
2590 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2591 goto do_trace0;
2592 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002593
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002594 if (PREDICT_FALSE (sm->validate_hmac))
2595 {
2596 if (sr_validate_hmac (sm, ip0, sr0))
2597 {
2598 next0 = SR_LOCAL_NEXT_ERROR;
2599 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2600 goto do_trace0;
2601 }
2602 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002603
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002604 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002605
Damjan Marion607de1a2016-08-16 22:53:54 +02002606 /*
2607 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002608 */
2609 if (PREDICT_FALSE (next0 & 0x80000000))
2610 {
2611 next0 ^= 0xFFFFFFFF;
2612 if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2613 b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2614 }
2615 else
2616 {
2617 u32 segment_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002618
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002619 segment_index0 = sr0->segments_left - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002620
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002621 /* Rewrite the packet */
2622 new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2623 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2624 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002625
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002626 if (PREDICT_TRUE (sr0->segments_left > 0))
2627 sr0->segments_left -= 1;
2628 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002629
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002630 /* End of the path. Clean up the SR header, or not */
2631 if (PREDICT_FALSE
2632 (sr0->segments_left == 0 &&
2633 (sr0->flags &
2634 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2635 {
2636 u64 *copy_dst0, *copy_src0;
2637 u16 new_l0;
Shwethab78292e2016-09-13 11:51:00 +01002638 u32 copy_len_u64s0 = 0;
2639 int i;
2640
Damjan Marion607de1a2016-08-16 22:53:54 +02002641 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002642 * Copy the ip6 header right by the (real) length of the
Shwethab78292e2016-09-13 11:51:00 +01002643 * sr header.
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002644 */
Shwethab78292e2016-09-13 11:51:00 +01002645 if (PREDICT_FALSE
2646 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
2647 {
2648 ip6_hop_by_hop_ext_t *ext_hdr =
2649 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
2650 copy_len_u64s0 =
2651 (((ip6_ext_header_t *) ext_hdr)->n_data_u64s) + 1;
2652 ext_hdr->next_hdr = sr0->protocol;
2653 }
2654 else
2655 {
2656 ip0->protocol = sr0->protocol;
2657 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002658 vlib_buffer_advance (b0, (sr0->length + 1) * 8);
2659
2660 new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2661 (sr0->length + 1) * 8;
2662 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2663
2664 copy_src0 = (u64 *) ip0;
2665 copy_dst0 = copy_src0 + (sr0->length + 1);
2666
Shwethab78292e2016-09-13 11:51:00 +01002667 copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
2668 copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
2669 copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
2670 copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
2671 copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
2672
2673 for (i = copy_len_u64s0 - 1; i >= 0; i--)
2674 {
2675 copy_dst0[i] = copy_src0[i];
2676 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002677
2678 sr0 = 0;
2679 }
2680
2681 do_trace0:
2682 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2683 {
2684 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2685 b0, sizeof (*tr));
2686 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2687 sizeof (tr->src.as_u8));
2688 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2689 sizeof (tr->dst.as_u8));
2690 tr->length = vlib_buffer_length_in_chain (vm, b0);
2691 tr->next_index = next0;
2692 tr->sr_valid = sr0 != 0;
2693 if (tr->sr_valid)
2694 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2695 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002696
2697 b1 = vlib_get_buffer (vm, bi1);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002698 ip1 = vlib_buffer_get_current (b1);
2699 sr1 = (ip6_sr_header_t *) (ip1 + 1);
Shwethab78292e2016-09-13 11:51:00 +01002700 if (PREDICT_FALSE
2701 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
2702 {
2703
2704 ip6_hop_by_hop_ext_t *ext_hdr =
2705 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip1);
2706 sr1 =
2707 (ip6_sr_header_t *) ip6_ext_next_header ((ip6_ext_header_t *)
2708 ext_hdr);
2709 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002710
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002711 if (PREDICT_FALSE (sr1->type != ROUTING_HEADER_TYPE_SR))
2712 {
2713 next1 = SR_LOCAL_NEXT_ERROR;
2714 b1->error =
2715 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2716 goto do_trace1;
2717 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002718
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002719 /* Out of segments? Turf the packet */
2720 if (PREDICT_FALSE (sr1->segments_left == 0))
2721 {
2722 next1 = SR_LOCAL_NEXT_ERROR;
2723 b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2724 goto do_trace1;
2725 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002726
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002727 if (PREDICT_FALSE (sm->validate_hmac))
2728 {
2729 if (sr_validate_hmac (sm, ip1, sr1))
2730 {
2731 next1 = SR_LOCAL_NEXT_ERROR;
2732 b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2733 goto do_trace1;
2734 }
2735 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002736
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002737 next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) : next1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002738
Damjan Marion607de1a2016-08-16 22:53:54 +02002739 /*
2740 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002741 */
2742 if (PREDICT_FALSE (next1 & 0x80000000))
2743 {
2744 next1 ^= 0xFFFFFFFF;
2745 if (PREDICT_FALSE (next1 == SR_LOCAL_NEXT_ERROR))
2746 b1->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2747 }
2748 else
2749 {
2750 u32 segment_index1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002751
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002752 segment_index1 = sr1->segments_left - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002753
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002754 /* Rewrite the packet */
2755 new_dst1 = (ip6_address_t *) (sr1->segments + segment_index1);
2756 ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
2757 ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002758
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002759 if (PREDICT_TRUE (sr1->segments_left > 0))
2760 sr1->segments_left -= 1;
2761 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002762
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002763 /* End of the path. Clean up the SR header, or not */
2764 if (PREDICT_FALSE
2765 (sr1->segments_left == 0 &&
2766 (sr1->flags &
2767 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2768 {
2769 u64 *copy_dst1, *copy_src1;
2770 u16 new_l1;
Shwethab78292e2016-09-13 11:51:00 +01002771 u32 copy_len_u64s1 = 0;
2772 int i;
2773
Damjan Marion607de1a2016-08-16 22:53:54 +02002774 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002775 * Copy the ip6 header right by the (real) length of the
Shwethab78292e2016-09-13 11:51:00 +01002776 * sr header.
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002777 */
Shwethab78292e2016-09-13 11:51:00 +01002778 if (PREDICT_FALSE
2779 (ip1->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
2780 {
2781 ip6_hop_by_hop_ext_t *ext_hdr =
2782 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip1);
2783 copy_len_u64s1 =
2784 (((ip6_ext_header_t *) ext_hdr)->n_data_u64s) + 1;
2785 ext_hdr->next_hdr = sr1->protocol;
2786 }
2787 else
2788 {
2789 ip1->protocol = sr1->protocol;
2790 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002791 vlib_buffer_advance (b1, (sr1->length + 1) * 8);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002792
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002793 new_l1 = clib_net_to_host_u16 (ip1->payload_length) -
2794 (sr1->length + 1) * 8;
2795 ip1->payload_length = clib_host_to_net_u16 (new_l1);
2796
2797 copy_src1 = (u64 *) ip1;
2798 copy_dst1 = copy_src1 + (sr1->length + 1);
2799
Shwethab78292e2016-09-13 11:51:00 +01002800 copy_dst1[4 + copy_len_u64s1] = copy_src1[4 + copy_len_u64s1];
2801 copy_dst1[3 + copy_len_u64s1] = copy_src1[3 + copy_len_u64s1];
2802 copy_dst1[2 + copy_len_u64s1] = copy_src1[2 + copy_len_u64s1];
2803 copy_dst1[1 + copy_len_u64s1] = copy_src1[1 + copy_len_u64s1];
2804 copy_dst1[0 + copy_len_u64s1] = copy_src1[0 + copy_len_u64s1];
2805
2806 for (i = copy_len_u64s1 - 1; i >= 0; i--)
2807 {
2808 copy_dst1[i] = copy_src1[i];
2809 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002810
2811 sr1 = 0;
2812 }
2813
2814 do_trace1:
2815 if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2816 {
2817 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2818 b1, sizeof (*tr));
2819 clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2820 sizeof (tr->src.as_u8));
2821 clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2822 sizeof (tr->dst.as_u8));
2823 tr->length = vlib_buffer_length_in_chain (vm, b1);
2824 tr->next_index = next1;
2825 tr->sr_valid = sr1 != 0;
2826 if (tr->sr_valid)
2827 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
2828 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002829
2830 vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2831 to_next, n_left_to_next,
2832 bi0, bi1, next0, next1);
2833 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002834
Ed Warnickecb9cada2015-12-08 15:45:58 -07002835 while (n_left_from > 0 && n_left_to_next > 0)
2836 {
2837 u32 bi0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002838 vlib_buffer_t *b0;
2839 ip6_header_t *ip0 = 0;
2840 ip6_sr_header_t *sr0;
2841 ip6_address_t *new_dst0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002842 u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2843
2844 bi0 = from[0];
2845 to_next[0] = bi0;
2846 from += 1;
2847 to_next += 1;
2848 n_left_from -= 1;
2849 n_left_to_next -= 1;
2850
2851 b0 = vlib_get_buffer (vm, bi0);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002852 ip0 = vlib_buffer_get_current (b0);
2853 sr0 = (ip6_sr_header_t *) (ip0 + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002854
Shwethab78292e2016-09-13 11:51:00 +01002855 if (PREDICT_FALSE
2856 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
2857 {
2858 ip6_hop_by_hop_ext_t *ext_hdr =
2859 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
2860 sr0 =
2861 (ip6_sr_header_t *) ip6_ext_next_header ((ip6_ext_header_t *)
2862 ext_hdr);
2863 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002864 if (PREDICT_FALSE (sr0->type != ROUTING_HEADER_TYPE_SR))
2865 {
2866 next0 = SR_LOCAL_NEXT_ERROR;
2867 b0->error =
2868 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2869 goto do_trace;
2870 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002871
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002872 /* Out of segments? Turf the packet */
2873 if (PREDICT_FALSE (sr0->segments_left == 0))
2874 {
2875 next0 = SR_LOCAL_NEXT_ERROR;
2876 b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2877 goto do_trace;
2878 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002879
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002880 if (PREDICT_FALSE (sm->validate_hmac))
2881 {
2882 if (sr_validate_hmac (sm, ip0, sr0))
2883 {
2884 next0 = SR_LOCAL_NEXT_ERROR;
2885 b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2886 goto do_trace;
2887 }
2888 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002889
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002890 next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002891
Damjan Marion607de1a2016-08-16 22:53:54 +02002892 /*
2893 * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002894 */
2895 if (PREDICT_FALSE (next0 & 0x80000000))
2896 {
2897 next0 ^= 0xFFFFFFFF;
2898 if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2899 b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2900 }
2901 else
2902 {
2903 u32 segment_index0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002904
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002905 segment_index0 = sr0->segments_left - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07002906
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002907 /* Rewrite the packet */
2908 new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2909 ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2910 ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
Ed Warnickecb9cada2015-12-08 15:45:58 -07002911
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002912 if (PREDICT_TRUE (sr0->segments_left > 0))
2913 sr0->segments_left -= 1;
2914 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002915
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002916 /* End of the path. Clean up the SR header, or not */
2917 if (PREDICT_FALSE
2918 (sr0->segments_left == 0 &&
2919 (sr0->flags &
2920 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2921 {
2922 u64 *copy_dst0, *copy_src0;
2923 u16 new_l0;
Shwethab78292e2016-09-13 11:51:00 +01002924 u32 copy_len_u64s0 = 0;
2925 int i;
2926
Damjan Marion607de1a2016-08-16 22:53:54 +02002927 /*
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002928 * Copy the ip6 header right by the (real) length of the
Shwethab78292e2016-09-13 11:51:00 +01002929 * sr header.
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002930 */
Shwethab78292e2016-09-13 11:51:00 +01002931 if (PREDICT_FALSE
2932 (ip0->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS))
2933 {
2934 ip6_hop_by_hop_ext_t *ext_hdr =
2935 (ip6_hop_by_hop_ext_t *) ip6_next_header (ip0);
2936 copy_len_u64s0 =
2937 (((ip6_ext_header_t *) ext_hdr)->n_data_u64s) + 1;
2938 ext_hdr->next_hdr = sr0->protocol;
2939 }
2940 else
2941 {
2942 ip0->protocol = sr0->protocol;
2943 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002944
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002945 vlib_buffer_advance (b0, (sr0->length + 1) * 8);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002946
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002947 new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2948 (sr0->length + 1) * 8;
2949 ip0->payload_length = clib_host_to_net_u16 (new_l0);
2950
2951 copy_src0 = (u64 *) ip0;
2952 copy_dst0 = copy_src0 + (sr0->length + 1);
Shwethab78292e2016-09-13 11:51:00 +01002953 copy_dst0[4 + copy_len_u64s0] = copy_src0[4 + copy_len_u64s0];
2954 copy_dst0[3 + copy_len_u64s0] = copy_src0[3 + copy_len_u64s0];
2955 copy_dst0[2 + copy_len_u64s0] = copy_src0[2 + copy_len_u64s0];
2956 copy_dst0[1 + copy_len_u64s0] = copy_src0[1 + copy_len_u64s0];
2957 copy_dst0[0 + copy_len_u64s0] = copy_src0[0 + copy_len_u64s0];
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002958
Shwethab78292e2016-09-13 11:51:00 +01002959 for (i = copy_len_u64s0 - 1; i >= 0; i--)
2960 {
2961 copy_dst0[i] = copy_src0[i];
2962 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002963
2964 sr0 = 0;
2965 }
2966
2967 do_trace:
2968 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2969 {
2970 sr_local_trace_t *tr = vlib_add_trace (vm, node,
2971 b0, sizeof (*tr));
2972 clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2973 sizeof (tr->src.as_u8));
2974 clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2975 sizeof (tr->dst.as_u8));
2976 tr->length = vlib_buffer_length_in_chain (vm, b0);
2977 tr->next_index = next0;
2978 tr->sr_valid = sr0 != 0;
2979 if (tr->sr_valid)
2980 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2981 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07002982
2983 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2984 to_next, n_left_to_next,
2985 bi0, next0);
2986 }
2987
2988 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2989 }
2990 vlib_node_increment_counter (vm, sr_local_node.index,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002991 SR_LOCAL_ERROR_PKTS_PROCESSED,
2992 from_frame->n_vectors);
Ed Warnickecb9cada2015-12-08 15:45:58 -07002993 return from_frame->n_vectors;
2994}
2995
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07002996/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07002997VLIB_REGISTER_NODE (sr_local_node, static) = {
2998 .function = sr_local,
2999 .name = "sr-local",
3000 /* Takes a vector of packets. */
3001 .vector_size = sizeof (u32),
3002 .format_trace = format_sr_local_trace,
3003
3004 .runtime_data_bytes = 0,
3005
3006 .n_errors = SR_LOCAL_N_ERROR,
3007 .error_strings = sr_local_error_strings,
3008
3009 .n_next_nodes = SR_LOCAL_N_NEXT,
3010 .next_nodes = {
3011#define _(s,n) [SR_LOCAL_NEXT_##s] = n,
3012 foreach_sr_local_next
3013#undef _
3014 },
3015};
3016
Damjan Marion1c80e832016-05-11 23:07:18 +02003017VLIB_NODE_FUNCTION_MULTIARCH (sr_local_node, sr_local)
Damjan Marione33b9e02016-10-17 12:51:18 +02003018/* *INDENT-ON* */
3019
3020ip6_sr_main_t *
3021sr_get_main (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003022{
3023 vlib_call_init_function (vm, sr_init);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003024 ASSERT (sr_local_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003025 return &sr_main;
3026}
3027
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07003028/**
3029 * @brief CLI parser for SR fix destination rewrite node
3030 *
3031 * @param vm vlib_main_t *
3032 * @param input unformat_input_t *
3033 * @param cmd vlib_cli_command_t *
3034 *
3035 * @return error clib_error_t *
3036 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003037static clib_error_t *
3038set_ip6_sr_rewrite_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003039 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003040{
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003041 fib_prefix_t pfx = {
3042 .fp_proto = FIB_PROTOCOL_IP6,
3043 .fp_len = 128,
3044 };
Ed Warnickecb9cada2015-12-08 15:45:58 -07003045 u32 fib_index = 0;
3046 u32 fib_id = 0;
3047 u32 adj_index;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003048 ip_adjacency_t *adj;
3049 vnet_hw_interface_t *hi;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003050 u32 sw_if_index;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003051 ip6_sr_main_t *sm = &sr_main;
3052 vnet_main_t *vnm = vnet_get_main ();
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003053 fib_node_index_t fei;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003054
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003055 if (!unformat (input, "%U", unformat_ip6_address, &pfx.fp_addr.ip6))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003056 return clib_error_return (0, "ip6 address missing in '%U'",
3057 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003058
3059 if (unformat (input, "rx-table-id %d", &fib_id))
3060 {
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003061 fib_index = fib_table_id_find_fib_index (FIB_PROTOCOL_IP6, fib_id);
3062 if (fib_index == ~0)
3063 return clib_error_return (0, "fib-id %d not found", fib_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003064 }
3065
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003066 fei = fib_table_lookup_exact_match (fib_index, &pfx);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003067
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003068 if (FIB_NODE_INDEX_INVALID == fei)
3069 return clib_error_return (0, "no match for %U",
3070 format_ip6_address, &pfx.fp_addr.ip6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003071
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003072 adj_index = fib_entry_get_adj_for_source (fei, FIB_SOURCE_SR);
3073
3074 if (ADJ_INDEX_INVALID == adj_index)
3075 return clib_error_return (0, "%U not SR sourced",
3076 format_ip6_address, &pfx.fp_addr.ip6);
3077
3078 adj = adj_get (adj_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003079
3080 if (adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
3081 return clib_error_return (0, "%U unresolved (not a rewrite adj)",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003082 format_ip6_address, &pfx.fp_addr.ip6);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003083
3084 adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
3085
3086 sw_if_index = adj->rewrite_header.sw_if_index;
3087 hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
3088 adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
3089
3090 /* $$$$$ hack... steal the mcast group index */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003091 adj->mcast_group_index =
3092 vlib_node_add_next (vm, sr_fix_dst_addr_node.index,
3093 hi->output_node_index);
3094
Ed Warnickecb9cada2015-12-08 15:45:58 -07003095 return 0;
3096}
3097
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003098/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003099VLIB_CLI_COMMAND (set_ip6_sr_rewrite, static) = {
3100 .path = "set ip6 sr rewrite",
3101 .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
3102 .function = set_ip6_sr_rewrite_fn,
3103};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003104/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003105
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07003106/**
3107 * @brief Register a callback routine to set next0 in sr_local
3108 *
3109 * @param cb void *
3110 */
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003111void
3112vnet_register_sr_app_callback (void *cb)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003113{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003114 ip6_sr_main_t *sm = &sr_main;
3115
Ed Warnickecb9cada2015-12-08 15:45:58 -07003116 sm->sr_local_cb = cb;
3117}
3118
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07003119/**
3120 * @brief Test routine for validation of HMAC
3121 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003122static clib_error_t *
3123test_sr_hmac_validate_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003124 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003125{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003126 ip6_sr_main_t *sm = &sr_main;
3127
Ed Warnickecb9cada2015-12-08 15:45:58 -07003128 if (unformat (input, "validate on"))
3129 sm->validate_hmac = 1;
3130 else if (unformat (input, "chunk-offset off"))
3131 sm->validate_hmac = 0;
3132 else
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003133 return clib_error_return (0, "expected validate on|off in '%U'",
3134 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003135
3136 vlib_cli_output (vm, "hmac signature validation %s",
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003137 sm->validate_hmac ? "on" : "off");
Ed Warnickecb9cada2015-12-08 15:45:58 -07003138 return 0;
3139}
3140
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003141/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003142VLIB_CLI_COMMAND (test_sr_hmac_validate, static) = {
3143 .path = "test sr hmac",
3144 .short_help = "test sr hmac validate [on|off]",
3145 .function = test_sr_hmac_validate_fn,
3146};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003147/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003148
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07003149/**
3150 * @brief Add or Delete HMAC key
3151 *
3152 * @param sm ip6_sr_main_t *
3153 * @param key_id u32
3154 * @param shared_secret u8 *
3155 * @param is_del u8
3156 *
3157 * @return retval i32
3158 */
3159// $$$ fixme shouldn't return i32
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003160i32
3161sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
3162 u8 is_del)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003163{
3164 u32 index;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003165 ip6_sr_hmac_key_t *key;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003166
3167 if (is_del == 0)
3168 {
3169 /* Specific key in use? Fail. */
3170 if (key_id && vec_len (sm->hmac_keys) > key_id
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003171 && sm->hmac_keys[key_id].shared_secret)
3172 return -2;
3173
Ed Warnickecb9cada2015-12-08 15:45:58 -07003174 index = key_id;
3175 key = find_or_add_shared_secret (sm, shared_secret, &index);
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003176 ASSERT (index == key_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003177 return 0;
3178 }
3179
3180 /* delete */
3181
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003182 if (key_id) /* delete by key ID */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003183 {
3184 if (vec_len (sm->hmac_keys) <= key_id)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003185 return -3;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003186
3187 key = sm->hmac_keys + key_id;
3188
3189 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
3190 vec_free (key->shared_secret);
3191 return 0;
3192 }
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003193
Ed Warnickecb9cada2015-12-08 15:45:58 -07003194 index = 0;
3195 key = find_or_add_shared_secret (sm, shared_secret, &index);
3196 hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
3197 vec_free (key->shared_secret);
3198 return 0;
3199}
3200
3201
3202static clib_error_t *
3203sr_hmac_add_del_key_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003204 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003205{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003206 ip6_sr_main_t *sm = &sr_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003207 u8 is_del = 0;
3208 u32 key_id = 0;
3209 u8 key_id_set = 0;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003210 u8 *shared_secret = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003211 i32 rv;
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003212
Ed Warnickecb9cada2015-12-08 15:45:58 -07003213 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3214 {
3215 if (unformat (input, "del"))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003216 is_del = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003217 else if (unformat (input, "id %d", &key_id))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003218 key_id_set = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003219 else if (unformat (input, "key %s", &shared_secret))
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003220 {
3221 /* Do not include the trailing NULL byte. Guaranteed interop issue */
3222 _vec_len (shared_secret) -= 1;
3223 }
3224 else
3225 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003226 }
3227
3228 if (is_del == 0 && shared_secret == 0)
3229 return clib_error_return (0, "shared secret must be set to add a key");
3230
3231 if (shared_secret == 0 && key_id_set == 0)
3232 return clib_error_return (0, "shared secret and key id both unset");
3233
3234 rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
3235
3236 vec_free (shared_secret);
3237
3238 switch (rv)
3239 {
3240 case 0:
3241 break;
3242
3243 default:
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003244 return clib_error_return (0, "sr_hmac_add_del_key returned %d", rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003245 }
3246
3247 return 0;
3248}
3249
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003250/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003251VLIB_CLI_COMMAND (sr_hmac, static) = {
3252 .path = "sr hmac",
3253 .short_help = "sr hmac [del] id <nn> key <str>",
3254 .function = sr_hmac_add_del_key_fn,
3255};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003256/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003257
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07003258/**
3259 * @brief CLI parser for show HMAC key shared secrets
3260 *
3261 * @param vm vlib_main_t *
3262 * @param input unformat_input_t *
3263 * @param cmd vlib_cli_command_t *
3264 *
3265 * @return error clib_error_t *
3266 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003267static clib_error_t *
3268show_sr_hmac_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003269 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003270{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003271 ip6_sr_main_t *sm = &sr_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07003272 int i;
3273
3274 for (i = 1; i < vec_len (sm->hmac_keys); i++)
3275 {
3276 if (sm->hmac_keys[i].shared_secret)
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003277 vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003278 }
3279
3280 return 0;
3281}
3282
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003283/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003284VLIB_CLI_COMMAND (show_sr_hmac, static) = {
3285 .path = "show sr hmac",
Damjan Marion607de1a2016-08-16 22:53:54 +02003286 .short_help = "show sr hmac",
Ed Warnickecb9cada2015-12-08 15:45:58 -07003287 .function = show_sr_hmac_fn,
3288};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003289/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003290
Keith Burns (alagalah)7214cf12016-08-08 15:56:50 -07003291/**
3292 * @brief Test for SR debug flag
3293 *
3294 * @param vm vlib_main_t *
3295 * @param input unformat_input_t *
3296 * @param cmd vlib_cli_command_t *
3297 *
3298 * @return error clib_error_t *
3299 */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003300static clib_error_t *
3301test_sr_debug_fn (vlib_main_t * vm,
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003302 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07003303{
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003304 ip6_sr_main_t *sm = &sr_main;
3305
Ed Warnickecb9cada2015-12-08 15:45:58 -07003306 if (unformat (input, "on"))
3307 sm->is_debug = 1;
3308 else if (unformat (input, "off"))
3309 sm->is_debug = 0;
3310 else
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003311 return clib_error_return (0, "expected on|off in '%U'",
3312 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07003313
3314 vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
3315
3316 return 0;
3317}
3318
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003319/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07003320VLIB_CLI_COMMAND (test_sr_debug, static) = {
3321 .path = "test sr debug",
3322 .short_help = "test sr debug on|off",
3323 .function = test_sr_debug_fn,
3324};
Keith Burns (alagalah)06c5ffd2016-08-06 08:32:45 -07003325/* *INDENT-ON* */
3326
3327/*
3328 * fd.io coding-style-patch-verification: ON
3329 *
3330 * Local Variables:
3331 * eval: (c-set-style "gnu")
3332 * End:
3333 */