VPP-303 - Documentation changes for vnet/vnet/sr
[vpp.git] / vnet / vnet / sr / sr.c
1 /*
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
18 /**
19  * @file
20  * @brief Segment Routing main functions
21  *
22  */
23 #include <vnet/vnet.h>
24 #include <vnet/sr/sr.h>
25
26 #include <openssl/hmac.h>
27
28 ip6_sr_main_t sr_main;
29 static vlib_node_registration_t sr_local_node;
30
31 /**
32  * @brief Use passed HMAC key in ip6_sr_header_t in OpenSSL HMAC routines
33  *
34  * @param sm ip6_sr_main_t *
35  * @param ip ip6_header_t *
36  * @param sr ip6_sr_header_t *
37  */
38 void
39 sr_fix_hmac (ip6_sr_main_t * sm, ip6_header_t * ip, ip6_sr_header_t * sr)
40 {
41   u32 key_index;
42   static u8 *keybuf;
43   u8 *copy_target;
44   int first_segment;
45   ip6_address_t *addrp;
46   int i;
47   ip6_sr_hmac_key_t *hmac_key;
48   u32 sig_len;
49
50   key_index = sr->hmac_key;
51
52   /* No signature? Pass... */
53   if (key_index == 0)
54     return;
55
56   /* We don't know about this key? Fail... */
57   if (key_index >= vec_len (sm->hmac_keys))
58     return;
59
60   hmac_key = sm->hmac_keys + key_index;
61
62   vec_reset_length (keybuf);
63
64   /* pkt ip6 src address */
65   vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
66   clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
67
68   /* first segment */
69   vec_add2 (keybuf, copy_target, 1);
70   copy_target[0] = sr->first_segment;
71
72   /* octet w/ bit 0 = "clean" flag */
73   vec_add2 (keybuf, copy_target, 1);
74   copy_target[0]
75     = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
76     ? 0x80 : 0;
77
78   /* hmac key id */
79   vec_add2 (keybuf, copy_target, 1);
80   copy_target[0] = sr->hmac_key;
81
82   first_segment = sr->first_segment;
83
84   addrp = sr->segments;
85
86   /* segments */
87   for (i = 0; i <= first_segment; i++)
88     {
89       vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
90       clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
91       addrp++;
92     }
93
94   addrp++;
95
96   HMAC_CTX_init (sm->hmac_ctx);
97   if (!HMAC_Init (sm->hmac_ctx, hmac_key->shared_secret,
98                   vec_len (hmac_key->shared_secret), sm->md))
99     clib_warning ("barf1");
100   if (!HMAC_Update (sm->hmac_ctx, keybuf, vec_len (keybuf)))
101     clib_warning ("barf2");
102   if (!HMAC_Final (sm->hmac_ctx, (unsigned char *) addrp, &sig_len))
103     clib_warning ("barf3");
104   HMAC_CTX_cleanup (sm->hmac_ctx);
105 }
106
107 /**
108  * @brief Format function for decoding various SR flags
109  *
110  * @param s u8 * - formatted string
111  * @param args va_list * - u16 flags
112  *
113  * @return formatted output string u8 *
114  */
115 u8 *
116 format_ip6_sr_header_flags (u8 * s, va_list * args)
117 {
118   u16 flags = (u16) va_arg (*args, int);
119   u8 pl_flag;
120   int bswap_needed = va_arg (*args, int);
121   int i;
122
123   if (bswap_needed)
124     flags = clib_host_to_net_u16 (flags);
125
126   if (flags & IP6_SR_HEADER_FLAG_CLEANUP)
127     s = format (s, "cleanup ");
128
129   if (flags & IP6_SR_HEADER_FLAG_PROTECTED)
130     s = format (s, "reroute ");
131
132   s = format (s, "pl: ");
133   for (i = 1; i <= 4; i++)
134     {
135       pl_flag = ip6_sr_policy_list_flags (flags, i);
136       s = format (s, "[%d] ", i);
137
138       switch (pl_flag)
139         {
140         case IP6_SR_HEADER_FLAG_PL_ELT_NOT_PRESENT:
141           s = format (s, "NotPr ");
142           break;
143         case IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE:
144           s = format (s, "InPE ");
145           break;
146         case IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE:
147           s = format (s, "EgPE ");
148           break;
149
150         case IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR:
151           s = format (s, "OrgSrc ");
152           break;
153         }
154     }
155   return s;
156 }
157
158 /**
159  * @brief Format function for decoding ip6_sr_header_t
160  *
161  * @param s u8 * - formatted string
162  * @param args va_list * - ip6_sr_header_t
163  *
164  * @return formatted output string u8 *
165  */
166 u8 *
167 format_ip6_sr_header (u8 * s, va_list * args)
168 {
169   ip6_sr_header_t *h = va_arg (*args, ip6_sr_header_t *);
170   ip6_address_t placeholder_addr =
171     { {254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
172        254, 254}
173   };
174   int print_hmac = va_arg (*args, int);
175   int i, pl_index, max_segs;
176   int flags_host_byte_order = clib_net_to_host_u16 (h->flags);
177
178   s = format (s, "next proto %d, len %d, type %d",
179               h->protocol, (h->length << 3) + 8, h->type);
180   s = format (s, "\n      segs left %d, first_segment %d, hmac key %d",
181               h->segments_left, h->first_segment, h->hmac_key);
182   s = format (s, "\n      flags %U", format_ip6_sr_header_flags,
183               flags_host_byte_order, 0 /* bswap needed */ );
184
185   /*
186    * Header length is in 8-byte units (minus one), so
187    * divide by 2 to ascertain the number of ip6 addresses in the
188    * segment list
189    */
190   max_segs = (h->length >> 1);
191
192   if (!print_hmac && h->hmac_key)
193     max_segs -= 2;
194
195   s = format (s, "\n  Segments (in processing order):");
196
197   for (i = h->first_segment; i >= 1; i--)
198     s = format (s, "\n  %U", format_ip6_address, h->segments + i);
199   if (ip6_address_is_equal (&placeholder_addr, h->segments))
200     s = format (s, "\n  (empty placeholder)");
201   else
202     s = format (s, "\n  %U", format_ip6_address, h->segments);
203
204   s = format (s, "\n  Policy List:");
205
206   pl_index = 1;                 /* to match the RFC text */
207   for (i = (h->first_segment + 1); i < max_segs; i++, pl_index++)
208     {
209       char *tag;
210       char *tags[] = { " ", "InPE: ", "EgPE: ", "OrgSrc: " };
211
212       tag = tags[0];
213       if (pl_index >= 1 && pl_index <= 4)
214         {
215           int this_pl_flag = ip6_sr_policy_list_flags
216             (flags_host_byte_order, pl_index);
217           tag = tags[this_pl_flag];
218         }
219
220       s = format (s, "\n  %s%U", tag, format_ip6_address, h->segments + i);
221     }
222
223   return s;
224 }
225
226 /**
227  * @brief Format function for decoding ip6_sr_header_t with length
228  *
229  * @param s u8 * - formatted string
230  * @param args va_list * - ip6_header_t + ip6_sr_header_t
231  *
232  * @return formatted output string u8 *
233  */
234 u8 *
235 format_ip6_sr_header_with_length (u8 * s, va_list * args)
236 {
237   ip6_header_t *h = va_arg (*args, ip6_header_t *);
238   u32 max_header_bytes = va_arg (*args, u32);
239   uword header_bytes;
240
241   header_bytes = sizeof (h[0]) + sizeof (ip6_sr_header_t);
242   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
243     return format (s, "ip6_sr header truncated");
244
245   s = format (s, "IP6: %U\n", format_ip6_header, h, max_header_bytes);
246   s =
247     format (s, "SR: %U\n", format_ip6_sr_header, (ip6_sr_header_t *) (h + 1),
248             0 /* print_hmac */ , max_header_bytes);
249   return s;
250 }
251
252 /**
253  * @brief Defined valid next nodes
254  * @note Cannot call replicate yet without DPDK
255 */
256 #if DPDK > 0
257 #define foreach_sr_rewrite_next                 \
258 _(ERROR, "error-drop")                          \
259 _(IP6_LOOKUP, "ip6-lookup")                     \
260 _(SR_LOCAL, "sr-local")                         \
261 _(SR_REPLICATE,"sr-replicate")
262 #else
263 #define foreach_sr_rewrite_next                 \
264 _(ERROR, "error-drop")                          \
265 _(IP6_LOOKUP, "ip6-lookup")                     \
266 _(SR_LOCAL, "sr-local")
267 #endif /* DPDK */
268
269 /**
270  * @brief Struct for defined valid next nodes
271 */
272 typedef enum
273 {
274 #define _(s,n) SR_REWRITE_NEXT_##s,
275   foreach_sr_rewrite_next
276 #undef _
277     SR_REWRITE_N_NEXT,
278 } sr_rewrite_next_t;
279
280 /**
281  * @brief Struct for data for SR rewrite packet trace
282  */
283 typedef struct
284 {
285   ip6_address_t src, dst;
286   u16 length;
287   u32 next_index;
288   u32 tunnel_index;
289   u8 sr[256];
290 } sr_rewrite_trace_t;
291
292 /**
293  * @brief Error strings for SR rewrite
294  */
295 static char *sr_rewrite_error_strings[] = {
296 #define sr_error(n,s) s,
297 #include "sr_error.def"
298 #undef sr_error
299 };
300
301 /**
302  * @brief Struct for SR rewrite error strings
303  */
304 typedef enum
305 {
306 #define sr_error(n,s) SR_REWRITE_ERROR_##n,
307 #include "sr_error.def"
308 #undef sr_error
309   SR_REWRITE_N_ERROR,
310 } sr_rewrite_error_t;
311
312
313 /**
314  * @brief Format function for SR rewrite trace.
315  */
316 u8 *
317 format_sr_rewrite_trace (u8 * s, va_list * args)
318 {
319   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
320   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
321   sr_rewrite_trace_t *t = va_arg (*args, sr_rewrite_trace_t *);
322   ip6_main_t *im = &ip6_main;
323   ip6_sr_main_t *sm = &sr_main;
324   ip6_sr_tunnel_t *tun = pool_elt_at_index (sm->tunnels, t->tunnel_index);
325   ip6_fib_t *rx_fib, *tx_fib;
326
327   rx_fib = find_ip6_fib_by_table_index_or_id (im, tun->rx_fib_index,
328                                               IP6_ROUTE_FLAG_FIB_INDEX);
329
330   tx_fib = find_ip6_fib_by_table_index_or_id (im, tun->tx_fib_index,
331                                               IP6_ROUTE_FLAG_FIB_INDEX);
332
333   s = format
334     (s, "SR-REWRITE: next %s ip6 src %U dst %U len %u\n"
335      "           rx-fib-id %d tx-fib-id %d\n%U",
336      (t->next_index == SR_REWRITE_NEXT_SR_LOCAL)
337      ? "sr-local" : "ip6-lookup",
338      format_ip6_address, &t->src,
339      format_ip6_address, &t->dst, t->length,
340      rx_fib->table_id, tx_fib->table_id,
341      format_ip6_sr_header, t->sr, 0 /* print_hmac */ );
342   return s;
343 }
344
345 /**
346  * @brief Main processing dual-loop for Segment Routing Rewrite
347  * @node sr-rewrite
348  *
349  * @param vm vlib_main_t *
350  * @param node vlib_node_runtime_t *
351  * @param from_frame vlib_frame_t *
352  *
353  * @return from_frame->n_vectors uword
354  */
355 static uword
356 sr_rewrite (vlib_main_t * vm,
357             vlib_node_runtime_t * node, vlib_frame_t * from_frame)
358 {
359   u32 n_left_from, next_index, *from, *to_next;
360   ip6_main_t *im = &ip6_main;
361   ip_lookup_main_t *lm = &im->lookup_main;
362   ip6_sr_main_t *sm = &sr_main;
363   u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
364                       vlib_buffer_t *, ip6_header_t *, ip6_sr_header_t *);
365   sr_local_cb = sm->sr_local_cb;
366
367   from = vlib_frame_vector_args (from_frame);
368   n_left_from = from_frame->n_vectors;
369
370   next_index = node->cached_next_index;
371
372   while (n_left_from > 0)
373     {
374       u32 n_left_to_next;
375
376       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
377
378       /* Note 2x loop disabled */
379       while (0 && n_left_from >= 4 && n_left_to_next >= 2)
380         {
381           u32 bi0, bi1;
382           vlib_buffer_t *b0, *b1;
383           ip6_header_t *ip0, *ip1;
384           ip_adjacency_t *adj0, *adj1;
385           ip6_sr_header_t *sr0, *sr1;
386           ip6_sr_tunnel_t *t0, *t1;
387           u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
388           u32 next1 = SR_REWRITE_NEXT_IP6_LOOKUP;
389           u16 new_l0 = 0;
390           u16 new_l1 = 0;
391
392           /* Prefetch next iteration. */
393           {
394             vlib_buffer_t *p2, *p3;
395
396             p2 = vlib_get_buffer (vm, from[2]);
397             p3 = vlib_get_buffer (vm, from[3]);
398
399             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
415           /*
416            * $$$ parse through header(s) to pick the point
417            * where we punch in the SR extention header
418            */
419
420           adj0 =
421             ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
422           adj1 =
423             ip_get_adjacency (lm, vnet_buffer (b1)->ip.adj_index[VLIB_TX]);
424           t0 =
425             pool_elt_at_index (sm->tunnels, adj0->rewrite_header.sw_if_index);
426           t1 =
427             pool_elt_at_index (sm->tunnels, adj1->rewrite_header.sw_if_index);
428
429           ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
430                   >= ((word) vec_len (t0->rewrite)) + b0->current_data);
431           ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
432                   >= ((word) vec_len (t1->rewrite)) + b1->current_data);
433
434           vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
435           vnet_buffer (b1)->sw_if_index[VLIB_TX] = t1->tx_fib_index;
436
437           ip0 = vlib_buffer_get_current (b0);
438           ip1 = vlib_buffer_get_current (b1);
439
440           /*
441            * SR-unaware service chaining case: pkt coming back from
442            * service has the original dst address, and will already
443            * have an SR header. If so, send it to sr-local
444            */
445           if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE))
446             {
447               vlib_buffer_advance (b0, sizeof (ip0));
448               sr0 = (ip6_sr_header_t *) (ip0 + 1);
449               new_l0 = clib_net_to_host_u16 (ip0->payload_length);
450               next0 = SR_REWRITE_NEXT_SR_LOCAL;
451             }
452           else
453             {
454               /*
455                * Copy data before the punch-in point left by the
456                * required amount. Assume (for the moment) that only
457                * the main packet header needs to be copied.
458                */
459               clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
460                            ip0, sizeof (ip6_header_t));
461               vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
462               ip0 = vlib_buffer_get_current (b0);
463               sr0 = (ip6_sr_header_t *) (ip0 + 1);
464               /* $$$ tune */
465               clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
466
467               /* Fix the next header chain */
468               sr0->protocol = ip0->protocol;
469               ip0->protocol = IPPROTO_IPV6_ROUTE;       /* routing extension header */
470               new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
471                 vec_len (t0->rewrite);
472               ip0->payload_length = clib_host_to_net_u16 (new_l0);
473
474               /* Copy dst address into the DA slot in the segment list */
475               clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
476                            sizeof (ip6_address_t));
477               /* Rewrite the ip6 dst address with the first hop */
478               clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
479                            sizeof (ip6_address_t));
480
481               sr_fix_hmac (sm, ip0, sr0);
482
483               next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
484                 next0;
485
486               /*
487                * Ignore "do not rewrite" shtik in this path
488                */
489               if (PREDICT_FALSE (next0 & 0x80000000))
490                 {
491                   next0 ^= 0xFFFFFFFF;
492                   if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
493                     b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
494                 }
495             }
496
497           if (PREDICT_FALSE (ip1->protocol == IPPROTO_IPV6_ROUTE))
498             {
499               vlib_buffer_advance (b1, sizeof (ip1));
500               sr1 = (ip6_sr_header_t *) (ip1 + 1);
501               new_l1 = clib_net_to_host_u16 (ip1->payload_length);
502               next1 = SR_REWRITE_NEXT_SR_LOCAL;
503             }
504           else
505             {
506               clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
507                            ip0, sizeof (ip6_header_t));
508               vlib_buffer_advance (b1, -(word) vec_len (t1->rewrite));
509               ip1 = vlib_buffer_get_current (b1);
510               sr1 = (ip6_sr_header_t *) (ip1 + 1);
511               clib_memcpy (sr1, t1->rewrite, vec_len (t1->rewrite));
512
513               sr1->protocol = ip1->protocol;
514               ip1->protocol = IPPROTO_IPV6_ROUTE;
515               new_l1 = clib_net_to_host_u16 (ip1->payload_length) +
516                 vec_len (t1->rewrite);
517               ip1->payload_length = clib_host_to_net_u16 (new_l1);
518
519               /* Copy dst address into the DA slot in the segment list */
520               clib_memcpy (sr1->segments, ip1->dst_address.as_u64,
521                            sizeof (ip6_address_t));
522               /* Rewrite the ip6 dst address with the first hop */
523               clib_memcpy (ip1->dst_address.as_u64, t1->first_hop.as_u64,
524                            sizeof (ip6_address_t));
525
526               sr_fix_hmac (sm, ip1, sr1);
527
528               next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) :
529                 next1;
530
531               /*
532                * Ignore "do not rewrite" shtik in this path
533                */
534               if (PREDICT_FALSE (next1 & 0x80000000))
535                 {
536                   next1 ^= 0xFFFFFFFF;
537                   if (PREDICT_FALSE (next1 == SR_REWRITE_NEXT_ERROR))
538                     b1->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
539                 }
540             }
541
542           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
543             {
544               sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
545                                                        b0, sizeof (*tr));
546               tr->tunnel_index = t0 - sm->tunnels;
547               clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
548                            sizeof (tr->src.as_u8));
549               clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
550                            sizeof (tr->dst.as_u8));
551               tr->length = new_l0;
552               tr->next_index = next0;
553               clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
554             }
555           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
556             {
557               sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
558                                                        b1, sizeof (*tr));
559               tr->tunnel_index = t1 - sm->tunnels;
560               clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
561                            sizeof (tr->src.as_u8));
562               clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
563                            sizeof (tr->dst.as_u8));
564               tr->length = new_l1;
565               tr->next_index = next1;
566               clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
567             }
568
569           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
570                                            to_next, n_left_to_next,
571                                            bi0, bi1, next0, next1);
572         }
573
574       while (n_left_from > 0 && n_left_to_next > 0)
575         {
576           u32 bi0;
577           vlib_buffer_t *b0;
578           ip6_header_t *ip0 = 0;
579           ip_adjacency_t *adj0;
580           ip6_sr_header_t *sr0 = 0;
581           ip6_sr_tunnel_t *t0;
582           u32 next0 = SR_REWRITE_NEXT_IP6_LOOKUP;
583           u16 new_l0 = 0;
584
585           bi0 = from[0];
586           to_next[0] = bi0;
587           from += 1;
588           to_next += 1;
589           n_left_from -= 1;
590           n_left_to_next -= 1;
591
592           b0 = vlib_get_buffer (vm, bi0);
593
594           /*
595            * $$$ parse through header(s) to pick the point
596            * where we punch in the SR extention header
597            */
598
599           adj0 =
600             ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
601           t0 =
602             pool_elt_at_index (sm->tunnels, adj0->rewrite_header.sw_if_index);
603
604 #if DPDK > 0                    /* Cannot call replication node yet without DPDK */
605           /* add a replication node */
606           if (PREDICT_FALSE (t0->policy_index != ~0))
607             {
608               vnet_buffer (b0)->ip.save_protocol = t0->policy_index;
609               next0 = SR_REWRITE_NEXT_SR_REPLICATE;
610               goto trace0;
611             }
612 #endif /* DPDK */
613
614           ASSERT (VLIB_BUFFER_PRE_DATA_SIZE
615                   >= ((word) vec_len (t0->rewrite)) + b0->current_data);
616
617           vnet_buffer (b0)->sw_if_index[VLIB_TX] = t0->tx_fib_index;
618
619           ip0 = vlib_buffer_get_current (b0);
620
621           /*
622            * SR-unaware service chaining case: pkt coming back from
623            * service has the original dst address, and will already
624            * have an SR header. If so, send it to sr-local
625            */
626           if (PREDICT_FALSE (ip0->protocol == IPPROTO_IPV6_ROUTE))
627             {
628               vlib_buffer_advance (b0, sizeof (ip0));
629               sr0 = (ip6_sr_header_t *) (ip0 + 1);
630               new_l0 = clib_net_to_host_u16 (ip0->payload_length);
631               next0 = SR_REWRITE_NEXT_SR_LOCAL;
632             }
633           else
634             {
635               /*
636                * Copy data before the punch-in point left by the
637                * required amount. Assume (for the moment) that only
638                * the main packet header needs to be copied.
639                */
640               clib_memcpy (((u8 *) ip0) - vec_len (t0->rewrite),
641                            ip0, sizeof (ip6_header_t));
642               vlib_buffer_advance (b0, -(word) vec_len (t0->rewrite));
643               ip0 = vlib_buffer_get_current (b0);
644               sr0 = (ip6_sr_header_t *) (ip0 + 1);
645               /* $$$ tune */
646               clib_memcpy (sr0, t0->rewrite, vec_len (t0->rewrite));
647
648               /* Fix the next header chain */
649               sr0->protocol = ip0->protocol;
650               ip0->protocol = IPPROTO_IPV6_ROUTE;       /* routing extension header */
651               new_l0 = clib_net_to_host_u16 (ip0->payload_length) +
652                 vec_len (t0->rewrite);
653               ip0->payload_length = clib_host_to_net_u16 (new_l0);
654
655               /* Copy dst address into the DA slot in the segment list */
656               clib_memcpy (sr0->segments, ip0->dst_address.as_u64,
657                            sizeof (ip6_address_t));
658               /* Rewrite the ip6 dst address with the first hop */
659               clib_memcpy (ip0->dst_address.as_u64, t0->first_hop.as_u64,
660                            sizeof (ip6_address_t));
661
662               sr_fix_hmac (sm, ip0, sr0);
663
664               next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) :
665                 next0;
666
667               /*
668                * Ignore "do not rewrite" shtik in this path
669                */
670               if (PREDICT_FALSE (next0 & 0x80000000))
671                 {
672                   next0 ^= 0xFFFFFFFF;
673                   if (PREDICT_FALSE (next0 == SR_REWRITE_NEXT_ERROR))
674                     b0->error = node->errors[SR_REWRITE_ERROR_APP_CALLBACK];
675                 }
676             }
677
678 #if DPDK > 0                    /* Cannot run replicate without DPDK and only replicate uses this label */
679         trace0:
680 #endif /* DPDK */
681           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
682             {
683               sr_rewrite_trace_t *tr = vlib_add_trace (vm, node,
684                                                        b0, sizeof (*tr));
685               tr->tunnel_index = t0 - sm->tunnels;
686               if (ip0)
687                 {
688                   memcpy (tr->src.as_u8, ip0->src_address.as_u8,
689                           sizeof (tr->src.as_u8));
690                   memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
691                           sizeof (tr->dst.as_u8));
692                 }
693               tr->length = new_l0;
694               tr->next_index = next0;
695               clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
696             }
697
698           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
699                                            to_next, n_left_to_next,
700                                            bi0, next0);
701         }
702
703       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
704     }
705   return from_frame->n_vectors;
706 }
707
708 /* *INDENT-OFF* */
709 VLIB_REGISTER_NODE (sr_rewrite_node) = {
710   .function = sr_rewrite,
711   .name = "sr-rewrite",
712   /* Takes a vector of packets. */
713   .vector_size = sizeof (u32),
714   .format_trace = format_sr_rewrite_trace,
715   .format_buffer = format_ip6_sr_header_with_length,
716
717   .n_errors = SR_REWRITE_N_ERROR,
718   .error_strings = sr_rewrite_error_strings,
719
720   .runtime_data_bytes = 0,
721
722   .n_next_nodes = SR_REWRITE_N_NEXT,
723   .next_nodes = {
724 #define _(s,n) [SR_REWRITE_NEXT_##s] = n,
725     foreach_sr_rewrite_next
726 #undef _
727   },
728 };
729 /* *INDENT-ON* */
730
731 VLIB_NODE_FUNCTION_MULTIARCH (sr_rewrite_node, sr_rewrite)
732      static int ip6_delete_route_no_next_hop (ip6_address_t * dst_address_arg,
733                                               u32 dst_address_length,
734                                               u32 rx_table_id)
735 {
736   ip6_add_del_route_args_t a;
737   ip6_address_t dst_address;
738   ip6_fib_t *fib;
739   ip6_main_t *im6 = &ip6_main;
740   BVT (clib_bihash_kv) kv, value;
741
742   fib = find_ip6_fib_by_table_index_or_id (im6, rx_table_id,
743                                            IP6_ROUTE_FLAG_TABLE_ID);
744   memset (&a, 0, sizeof (a));
745   a.flags |= IP4_ROUTE_FLAG_DEL;
746   a.dst_address_length = dst_address_length;
747
748   dst_address = *dst_address_arg;
749
750   ip6_address_mask (&dst_address, &im6->fib_masks[dst_address_length]);
751
752   kv.key[0] = dst_address.as_u64[0];
753   kv.key[1] = dst_address.as_u64[1];
754   kv.key[2] = ((u64) ((fib - im6->fibs)) << 32) | dst_address_length;
755
756   if (BV (clib_bihash_search) (&im6->ip6_lookup_table, &kv, &value) < 0)
757     {
758       clib_warning ("%U/%d not in FIB",
759                     format_ip6_address, &a.dst_address, a.dst_address_length);
760       return -10;
761     }
762
763   a.adj_index = value.value;
764   a.dst_address = dst_address;
765
766   ip6_add_del_route (im6, &a);
767   ip6_maybe_remap_adjacencies (im6, rx_table_id, IP6_ROUTE_FLAG_TABLE_ID);
768   return 0;
769 }
770
771 /**
772  * @brief Find or add if not found - HMAC shared secret
773  *
774  * @param sm ip6_sr_main_t *
775  * @param secret u8 *
776  * @param indexp u32 *
777  *
778  * @return ip6_sr_hmac_key_t *
779  */
780 static ip6_sr_hmac_key_t *
781 find_or_add_shared_secret (ip6_sr_main_t * sm, u8 * secret, u32 * indexp)
782 {
783   uword *p;
784   ip6_sr_hmac_key_t *key = 0;
785   int i;
786
787   p = hash_get_mem (sm->hmac_key_by_shared_secret, secret);
788
789   if (p)
790     {
791       key = vec_elt_at_index (sm->hmac_keys, p[0]);
792       if (indexp)
793         *indexp = p[0];
794       return (key);
795     }
796
797   /* Specific key ID? */
798   if (indexp && *indexp)
799     {
800       vec_validate (sm->hmac_keys, *indexp);
801       key = sm->hmac_keys + *indexp;
802     }
803   else
804     {
805       for (i = 0; i < vec_len (sm->hmac_keys); i++)
806         {
807           if (sm->hmac_keys[i].shared_secret == 0)
808             {
809               key = sm->hmac_keys + i;
810               goto found;
811             }
812         }
813       vec_validate (sm->hmac_keys, i);
814       key = sm->hmac_keys + i;
815     found:
816       ;
817     }
818
819   key->shared_secret = vec_dup (secret);
820
821   hash_set_mem (sm->hmac_key_by_shared_secret, key->shared_secret,
822                 key - sm->hmac_keys);
823
824   if (indexp)
825     *indexp = key - sm->hmac_keys;
826   return (key);
827 }
828
829 /**
830  * @brief Add or Delete a Segment Routing tunnel.
831  *
832  * @param a ip6_sr_add_del_tunnel_args_t *
833  *
834  * @return retval int
835  */
836 int
837 ip6_sr_add_del_tunnel (ip6_sr_add_del_tunnel_args_t * a)
838 {
839   ip6_main_t *im = &ip6_main;
840   ip_lookup_main_t *lm = &im->lookup_main;
841   ip6_sr_tunnel_key_t key;
842   ip6_sr_tunnel_t *t;
843   uword *p, *n;
844   ip6_sr_header_t *h = 0;
845   u32 header_length;
846   ip6_address_t *addrp, *this_address;
847   ip_adjacency_t adj, *ap, *add_adj = 0;
848   u32 adj_index;
849   ip6_sr_main_t *sm = &sr_main;
850   u8 *key_copy;
851   u32 rx_fib_index, tx_fib_index;
852   ip6_add_del_route_args_t aa;
853   u32 hmac_key_index_u32;
854   u8 hmac_key_index = 0;
855   ip6_sr_policy_t *pt;
856   int i;
857
858   /* Make sure that the rx FIB exists */
859   p = hash_get (im->fib_index_by_table_id, a->rx_table_id);
860
861   if (p == 0)
862     return -3;
863
864   /* remember the FIB index */
865   rx_fib_index = p[0];
866
867   /* Make sure that the supplied FIB exists */
868   p = hash_get (im->fib_index_by_table_id, a->tx_table_id);
869
870   if (p == 0)
871     return -4;
872
873   /* remember the FIB index */
874   tx_fib_index = p[0];
875
876   clib_memcpy (key.src.as_u8, a->src_address->as_u8, sizeof (key.src));
877   clib_memcpy (key.dst.as_u8, a->dst_address->as_u8, sizeof (key.dst));
878
879   /* When adding a tunnel:
880    * - If a "name" is given, it must not exist.
881    * - The "key" is always checked, and must not exist.
882    * When deleting a tunnel:
883    * - If the "name" is given, and it exists, then use it.
884    * - If the "name" is not given, use the "key".
885    * - If the "name" and the "key" are given, then both must point to the same
886    *   thing.
887    */
888
889   /* Lookup the key */
890   p = hash_get_mem (sm->tunnel_index_by_key, &key);
891
892   /* If the name is given, look it up */
893   if (a->name)
894     n = hash_get_mem (sm->tunnel_index_by_name, a->name);
895   else
896     n = 0;
897
898   /* validate key/name parameters */
899   if (!a->is_del)               /* adding a tunnel */
900     {
901       if (a->name && n)         /* name given & exists already */
902         return -1;
903       if (p)                    /* key exists already */
904         return -1;
905     }
906   else                          /* deleting a tunnel */
907     {
908       if (!p)                   /* key doesn't exist */
909         return -2;
910       if (a->name && !n)        /* name given & it doesn't exist */
911         return -2;
912
913       if (n)                    /* name given & found */
914         {
915           if (n[0] != p[0])     /* name and key do not point to the same thing */
916             return -2;
917         }
918     }
919
920
921   if (a->is_del)                /* delete the tunnel */
922     {
923       hash_pair_t *hp;
924
925       /* Delete existing tunnel */
926       t = pool_elt_at_index (sm->tunnels, p[0]);
927
928       ip6_delete_route_no_next_hop (&t->key.dst, t->dst_mask_width,
929                                     a->rx_table_id);
930       vec_free (t->rewrite);
931       /* Remove tunnel from any policy if associated */
932       if (t->policy_index != ~0)
933         {
934           pt = pool_elt_at_index (sm->policies, t->policy_index);
935           for (i = 0; i < vec_len (pt->tunnel_indices); i++)
936             {
937               if (pt->tunnel_indices[i] == t - sm->tunnels)
938                 {
939                   vec_delete (pt->tunnel_indices, 1, i);
940                   goto found;
941                 }
942             }
943           clib_warning ("Tunnel index %d not found in policy_index %d",
944                         t - sm->tunnels, pt - sm->policies);
945         found:
946           /* If this is last tunnel in the  policy, clean up the policy too */
947           if (vec_len (pt->tunnel_indices) == 0)
948             {
949               hash_unset_mem (sm->policy_index_by_policy_name, pt->name);
950               vec_free (pt->name);
951               pool_put (sm->policies, pt);
952             }
953         }
954
955       /* Clean up the tunnel by name */
956       if (t->name)
957         {
958           hash_unset_mem (sm->tunnel_index_by_name, t->name);
959           vec_free (t->name);
960         }
961       pool_put (sm->tunnels, t);
962       hp = hash_get_pair (sm->tunnel_index_by_key, &key);
963       key_copy = (void *) (hp->key);
964       hash_unset_mem (sm->tunnel_index_by_key, &key);
965       vec_free (key_copy);
966       return 0;
967     }
968
969   /* create a new tunnel */
970   pool_get (sm->tunnels, t);
971   memset (t, 0, sizeof (*t));
972   t->policy_index = ~0;
973
974   clib_memcpy (&t->key, &key, sizeof (t->key));
975   t->dst_mask_width = a->dst_mask_width;
976   t->rx_fib_index = rx_fib_index;
977   t->tx_fib_index = tx_fib_index;
978
979   if (!vec_len (a->segments))
980     /* there must be at least one segment... */
981     return -4;
982
983   /* The first specified hop goes right into the dst address */
984   clib_memcpy (&t->first_hop, &a->segments[0], sizeof (ip6_address_t));
985
986   /*
987    * Create the sr header rewrite string
988    * The list of segments needs an extra slot for the ultimate destination
989    * which is taken from the packet we add the SRH to.
990    */
991   header_length = sizeof (*h) +
992     sizeof (ip6_address_t) * (vec_len (a->segments) + 1 + vec_len (a->tags));
993
994   if (a->shared_secret)
995     {
996       /* Allocate a new key slot if we don't find the secret key */
997       hmac_key_index_u32 = 0;
998       (void) find_or_add_shared_secret (sm, a->shared_secret,
999                                         &hmac_key_index_u32);
1000
1001       /* Hey Vinz Clortho: Gozzer is pissed.. you're out of keys! */
1002       if (hmac_key_index_u32 >= 256)
1003         return -5;
1004       hmac_key_index = hmac_key_index_u32;
1005       header_length += SHA256_DIGEST_LENGTH;
1006     }
1007
1008   vec_validate (t->rewrite, header_length - 1);
1009
1010   h = (ip6_sr_header_t *) t->rewrite;
1011
1012   h->protocol = 0xFF;           /* we don't know yet */
1013
1014   h->length = (header_length / 8) - 1;
1015   h->type = ROUTING_HEADER_TYPE_SR;
1016
1017   /* first_segment and segments_left need to have the index of the last
1018    * element in the list; a->segments has one element less than ends up
1019    * in the header (it does not have the DA in it), so vec_len(a->segments)
1020    * is the value we want.
1021    */
1022   h->first_segment = h->segments_left = vec_len (a->segments);
1023
1024   if (a->shared_secret)
1025     h->hmac_key = hmac_key_index & 0xFF;
1026
1027   h->flags = a->flags_net_byte_order;
1028
1029   /* Paint on the segment list, in reverse.
1030    * This is offset by one to leave room at the start for the ultimate
1031    * destination.
1032    */
1033   addrp = h->segments + vec_len (a->segments);
1034
1035   vec_foreach (this_address, a->segments)
1036   {
1037     clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
1038     addrp--;
1039   }
1040
1041   /*
1042    * Since the ultimate destination address is not yet known, set that slot
1043    * to a value we will instantly recognize as bogus.
1044    */
1045   memset (h->segments, 0xfe, sizeof (ip6_address_t));
1046
1047   /* Paint on the tag list, not reversed */
1048   addrp = h->segments + vec_len (a->segments);
1049
1050   vec_foreach (this_address, a->tags)
1051   {
1052     clib_memcpy (addrp->as_u8, this_address->as_u8, sizeof (ip6_address_t));
1053     addrp++;
1054   }
1055
1056   key_copy = vec_new (ip6_sr_tunnel_key_t, 1);
1057   clib_memcpy (key_copy, &key, sizeof (ip6_sr_tunnel_key_t));
1058   hash_set_mem (sm->tunnel_index_by_key, key_copy, t - sm->tunnels);
1059
1060   memset (&adj, 0, sizeof (adj));
1061
1062   /* Create an adjacency and add to v6 fib */
1063   adj.lookup_next_index = sm->ip6_lookup_sr_next_index;
1064   adj.explicit_fib_index = ~0;
1065
1066   ap = ip_add_adjacency (lm, &adj, 1 /* one adj */ ,
1067                          &adj_index);
1068
1069   /*
1070    * Stick the tunnel index into the rewrite header.
1071    *
1072    * Unfortunately, inserting an SR header according to the various
1073    * RFC's requires parsing through the ip6 header, perhaps consing a
1074    * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1075    * normal reverse bcopy rewrite code.
1076    *
1077    * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1078    * at some point...
1079    */
1080   ap->rewrite_header.sw_if_index = t - sm->tunnels;
1081
1082   vec_add1 (add_adj, ap[0]);
1083
1084   clib_memcpy (aa.dst_address.as_u8, a->dst_address,
1085                sizeof (aa.dst_address.as_u8));
1086   aa.dst_address_length = a->dst_mask_width;
1087
1088   aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1089   aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1090   aa.table_index_or_table_id = rx_fib_index;
1091   aa.add_adj = add_adj;
1092   aa.adj_index = adj_index;
1093   aa.n_add_adj = 1;
1094   ip6_add_del_route (im, &aa);
1095   vec_free (add_adj);
1096
1097   if (a->policy_name)
1098     {
1099       p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1100       if (p)
1101         {
1102           pt = pool_elt_at_index (sm->policies, p[0]);
1103         }
1104       else                      /* no policy, lets create one */
1105         {
1106           pool_get (sm->policies, pt);
1107           memset (pt, 0, sizeof (*pt));
1108           pt->name = format (0, "%s%c", a->policy_name, 0);
1109           hash_set_mem (sm->policy_index_by_policy_name, pt->name,
1110                         pt - sm->policies);
1111           p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1112         }
1113       vec_add1 (pt->tunnel_indices, t - sm->tunnels);
1114       if (p == 0)
1115         clib_warning ("p is NULL!");
1116       t->policy_index = p ? p[0] : ~0;  /* equiv. to (pt - sm->policies) */
1117     }
1118
1119   if (a->name)
1120     {
1121       t->name = format (0, "%s%c", a->name, 0);
1122       hash_set_mem (sm->tunnel_index_by_name, t->name, t - sm->tunnels);
1123     }
1124
1125   return 0;
1126 }
1127
1128 /**
1129  * @brief CLI parser for Add or Delete a Segment Routing tunnel.
1130  *
1131  * @param vm vlib_main_t *
1132  * @param input unformat_input_t *
1133  * @param cmd vlib_cli_command_t *
1134  *
1135  * @return error clib_error_t *
1136  */
1137 static clib_error_t *
1138 sr_add_del_tunnel_command_fn (vlib_main_t * vm,
1139                               unformat_input_t * input,
1140                               vlib_cli_command_t * cmd)
1141 {
1142   int is_del = 0;
1143   ip6_address_t src_address;
1144   int src_address_set = 0;
1145   ip6_address_t dst_address;
1146   u32 dst_mask_width;
1147   int dst_address_set = 0;
1148   u16 flags = 0;
1149   u8 *shared_secret = 0;
1150   u8 *name = 0;
1151   u8 *policy_name = 0;
1152   u32 rx_table_id = 0;
1153   u32 tx_table_id = 0;
1154   ip6_address_t *segments = 0;
1155   ip6_address_t *this_seg;
1156   ip6_address_t *tags = 0;
1157   ip6_address_t *this_tag;
1158   ip6_sr_add_del_tunnel_args_t _a, *a = &_a;
1159   ip6_address_t next_address, tag;
1160   int pl_index;
1161   int rv;
1162
1163   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1164     {
1165       if (unformat (input, "del"))
1166         is_del = 1;
1167       else if (unformat (input, "rx-fib-id %d", &rx_table_id))
1168         ;
1169       else if (unformat (input, "tx-fib-id %d", &tx_table_id))
1170         ;
1171       else if (unformat (input, "src %U", unformat_ip6_address, &src_address))
1172         src_address_set = 1;
1173       else if (unformat (input, "name %s", &name))
1174         ;
1175       else if (unformat (input, "policy %s", &policy_name))
1176         ;
1177       else if (unformat (input, "dst %U/%d",
1178                          unformat_ip6_address, &dst_address, &dst_mask_width))
1179         dst_address_set = 1;
1180       else if (unformat (input, "next %U", unformat_ip6_address,
1181                          &next_address))
1182         {
1183           vec_add2 (segments, this_seg, 1);
1184           clib_memcpy (this_seg->as_u8, next_address.as_u8,
1185                        sizeof (*this_seg));
1186         }
1187       else if (unformat (input, "tag %U", unformat_ip6_address, &tag))
1188         {
1189           vec_add2 (tags, this_tag, 1);
1190           clib_memcpy (this_tag->as_u8, tag.as_u8, sizeof (*this_tag));
1191         }
1192       else if (unformat (input, "clean"))
1193         flags |= IP6_SR_HEADER_FLAG_CLEANUP;
1194       else if (unformat (input, "protected"))
1195         flags |= IP6_SR_HEADER_FLAG_PROTECTED;
1196       else if (unformat (input, "key %s", &shared_secret))
1197         /* Do not include the trailing NULL byte. Guaranteed interop issue */
1198         _vec_len (shared_secret) -= 1;
1199       else if (unformat (input, "InPE %d", &pl_index))
1200         {
1201           if (pl_index <= 0 || pl_index > 4)
1202             {
1203             pl_index_range_error:
1204               return clib_error_return
1205                 (0, "Policy List Element Index %d out of range (1-4)",
1206                  pl_index);
1207
1208             }
1209           flags |= IP6_SR_HEADER_FLAG_PL_ELT_INGRESS_PE
1210             << ip6_sr_policy_list_shift_from_index (pl_index);
1211         }
1212       else if (unformat (input, "EgPE %d", &pl_index))
1213         {
1214           if (pl_index <= 0 || pl_index > 4)
1215             goto pl_index_range_error;
1216           flags |= IP6_SR_HEADER_FLAG_PL_ELT_EGRESS_PE
1217             << ip6_sr_policy_list_shift_from_index (pl_index);
1218         }
1219       else if (unformat (input, "OrgSrc %d", &pl_index))
1220         {
1221           if (pl_index <= 0 || pl_index > 4)
1222             goto pl_index_range_error;
1223           flags |= IP6_SR_HEADER_FLAG_PL_ELT_ORIG_SRC_ADDR
1224             << ip6_sr_policy_list_shift_from_index (pl_index);
1225         }
1226       else
1227         break;
1228     }
1229
1230   if (!src_address_set)
1231     return clib_error_return (0, "src address required");
1232
1233   if (!dst_address_set)
1234     return clib_error_return (0, "dst address required");
1235
1236   if (!segments)
1237     return clib_error_return (0, "at least one sr segment required");
1238
1239   memset (a, 0, sizeof (*a));
1240   a->src_address = &src_address;
1241   a->dst_address = &dst_address;
1242   a->dst_mask_width = dst_mask_width;
1243   a->segments = segments;
1244   a->tags = tags;
1245   a->flags_net_byte_order = clib_host_to_net_u16 (flags);
1246   a->is_del = is_del;
1247   a->rx_table_id = rx_table_id;
1248   a->tx_table_id = tx_table_id;
1249   a->shared_secret = shared_secret;
1250
1251   if (vec_len (name))
1252     a->name = name;
1253   else
1254     a->name = 0;
1255
1256   if (vec_len (policy_name))
1257     a->policy_name = policy_name;
1258   else
1259     a->policy_name = 0;
1260
1261   rv = ip6_sr_add_del_tunnel (a);
1262
1263   vec_free (segments);
1264   vec_free (tags);
1265   vec_free (shared_secret);
1266
1267   switch (rv)
1268     {
1269     case 0:
1270       break;
1271
1272     case -1:
1273       return clib_error_return (0, "SR tunnel src %U dst %U already exists",
1274                                 format_ip6_address, &src_address,
1275                                 format_ip6_address, &dst_address);
1276
1277     case -2:
1278       return clib_error_return (0, "SR tunnel src %U dst %U does not exist",
1279                                 format_ip6_address, &src_address,
1280                                 format_ip6_address, &dst_address);
1281
1282     case -3:
1283       return clib_error_return (0, "FIB table %d does not exist",
1284                                 rx_table_id);
1285
1286     case -4:
1287       return clib_error_return (0, "At least one segment is required");
1288
1289     default:
1290       return clib_error_return (0, "BUG: ip6_sr_add_del_tunnel returns %d",
1291                                 rv);
1292     }
1293
1294   return 0;
1295 }
1296
1297 /* *INDENT-OFF* */
1298 VLIB_CLI_COMMAND (sr_tunnel_command, static) = {
1299     .path = "sr tunnel",
1300     .short_help =
1301       "sr tunnel [del] [name <name>] src <addr> dst <addr> [next <addr>] "
1302       "[clean] [reroute] [key <secret>] [policy <policy_name>]"
1303       "[rx-fib-id <fib_id>] [tx-fib-id <fib_id>]",
1304     .function = sr_add_del_tunnel_command_fn,
1305 };
1306 /* *INDENT-ON* */
1307
1308 /**
1309  * @brief Display Segment Routing tunnel
1310  *
1311  * @param vm vlib_main_t *
1312  * @param t ip6_sr_tunnel_t *
1313  *
1314  */
1315 void
1316 ip6_sr_tunnel_display (vlib_main_t * vm, ip6_sr_tunnel_t * t)
1317 {
1318   ip6_main_t *im = &ip6_main;
1319   ip6_sr_main_t *sm = &sr_main;
1320   ip6_fib_t *rx_fib, *tx_fib;
1321   ip6_sr_policy_t *pt;
1322
1323   rx_fib = find_ip6_fib_by_table_index_or_id (im, t->rx_fib_index,
1324                                               IP6_ROUTE_FLAG_FIB_INDEX);
1325
1326   tx_fib = find_ip6_fib_by_table_index_or_id (im, t->tx_fib_index,
1327                                               IP6_ROUTE_FLAG_FIB_INDEX);
1328
1329   if (t->name)
1330     vlib_cli_output (vm, "sr tunnel name: %s", (char *) t->name);
1331
1332   vlib_cli_output (vm, "src %U dst %U first hop %U",
1333                    format_ip6_address, &t->key.src,
1334                    format_ip6_address, &t->key.dst,
1335                    format_ip6_address, &t->first_hop);
1336   vlib_cli_output (vm, "    rx-fib-id %d tx-fib-id %d",
1337                    rx_fib->table_id, tx_fib->table_id);
1338   vlib_cli_output (vm, "  sr: %U", format_ip6_sr_header, t->rewrite,
1339                    0 /* print_hmac */ );
1340
1341   if (t->policy_index != ~0)
1342     {
1343       pt = pool_elt_at_index (sm->policies, t->policy_index);
1344       vlib_cli_output (vm, "sr policy: %s", (char *) pt->name);
1345     }
1346   vlib_cli_output (vm, "-------");
1347
1348   return;
1349 }
1350
1351 /**
1352  * @brief CLI Parser for Display Segment Routing tunnel
1353  *
1354  * @param vm vlib_main_t *
1355  * @param input unformat_input_t *
1356  * @param cmd vlib_cli_command_t *
1357  *
1358  * @return error clib_error_t *
1359  */
1360 static clib_error_t *
1361 show_sr_tunnel_fn (vlib_main_t * vm,
1362                    unformat_input_t * input, vlib_cli_command_t * cmd)
1363 {
1364   static ip6_sr_tunnel_t **tunnels;
1365   ip6_sr_tunnel_t *t;
1366   ip6_sr_main_t *sm = &sr_main;
1367   int i;
1368   uword *p = 0;
1369   u8 *name = 0;
1370
1371   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1372     {
1373       if (unformat (input, "name %s", &name))
1374         {
1375           p = hash_get_mem (sm->tunnel_index_by_name, name);
1376           if (!p)
1377             vlib_cli_output (vm, "No SR tunnel with name: %s. Showing all.",
1378                              name);
1379         }
1380       else
1381         break;
1382     }
1383
1384   vec_reset_length (tunnels);
1385
1386   if (!p)                       /* Either name parm not passed or no tunnel with that name found, show all */
1387     {
1388       /* *INDENT-OFF* */
1389   pool_foreach (t, sm->tunnels,
1390   ({
1391     vec_add1 (tunnels, t);
1392   }));
1393   /* *INDENT-ON* */
1394     }
1395   else                          /* Just show the one tunnel by name */
1396     vec_add1 (tunnels, &sm->tunnels[p[0]]);
1397
1398   if (vec_len (tunnels) == 0)
1399     vlib_cli_output (vm, "No SR tunnels configured");
1400
1401   for (i = 0; i < vec_len (tunnels); i++)
1402     {
1403       t = tunnels[i];
1404       ip6_sr_tunnel_display (vm, t);
1405     }
1406
1407   return 0;
1408 }
1409
1410 /* *INDENT-OFF* */
1411 VLIB_CLI_COMMAND (show_sr_tunnel_command, static) = {
1412     .path = "show sr tunnel",
1413     .short_help = "show sr tunnel [name <sr-tunnel-name>]",
1414     .function = show_sr_tunnel_fn,
1415 };
1416 /* *INDENT-ON* */
1417
1418 /**
1419  * @brief Add or Delete a Segment Routing policy
1420  *
1421  * @param a ip6_sr_add_del_policy_args_t *
1422  *
1423  * @return retval int
1424  */
1425 int
1426 ip6_sr_add_del_policy (ip6_sr_add_del_policy_args_t * a)
1427 {
1428   ip6_sr_main_t *sm = &sr_main;
1429   uword *p;
1430   ip6_sr_tunnel_t *t = 0;
1431   ip6_sr_policy_t *policy;
1432   u32 *tunnel_indices = 0;
1433   int i;
1434
1435
1436
1437   if (a->is_del)
1438     {
1439       p = hash_get_mem (sm->policy_index_by_policy_name, a->name);
1440       if (!p)
1441         return -6;              /* policy name not found */
1442
1443       policy = pool_elt_at_index (sm->policies, p[0]);
1444
1445       vec_foreach_index (i, policy->tunnel_indices)
1446       {
1447         t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1448         t->policy_index = ~0;
1449       }
1450       hash_unset_mem (sm->policy_index_by_policy_name, a->name);
1451       pool_put (sm->policies, policy);
1452       return 0;
1453     }
1454
1455
1456   if (!vec_len (a->tunnel_names))
1457     return -3;                  /*tunnel name is required case */
1458
1459   vec_reset_length (tunnel_indices);
1460   /* Check tunnel names, add tunnel_index to policy */
1461   for (i = 0; i < vec_len (a->tunnel_names); i++)
1462     {
1463       p = hash_get_mem (sm->tunnel_index_by_name, a->tunnel_names[i]);
1464       if (!p)
1465         return -4;              /* tunnel name not found case */
1466
1467       t = pool_elt_at_index (sm->tunnels, p[0]);
1468       /*
1469          No need to check t==0. -3 condition above ensures name
1470        */
1471       if (t->policy_index != ~0)
1472         return -5;              /* tunnel name already associated with a policy */
1473
1474       /* Add to tunnel indicies */
1475       vec_add1 (tunnel_indices, p[0]);
1476     }
1477
1478   /* Add policy to ip6_sr_main_t */
1479   pool_get (sm->policies, policy);
1480   policy->name = a->name;
1481   policy->tunnel_indices = tunnel_indices;
1482   hash_set_mem (sm->policy_index_by_policy_name, policy->name,
1483                 policy - sm->policies);
1484
1485   /* Yes, this could be construed as overkill but the last thing you should do is set
1486      the policy_index on the tunnel after everything is set in ip6_sr_main_t.
1487      If this is deemed overly cautious, could set this in the vec_len(tunnel_names) loop.
1488    */
1489   for (i = 0; i < vec_len (policy->tunnel_indices); i++)
1490     {
1491       t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[i]);
1492       t->policy_index = policy - sm->policies;
1493     }
1494
1495   return 0;
1496 }
1497
1498 /**
1499  * @brief CLI Parser for Add or Delete a Segment Routing policy
1500  *
1501  * @param vm vlib_main_t *
1502  * @param input unformat_input_t *
1503  * @param cmd vlib_cli_command_t *
1504  *
1505  * @return error clib_error_t *
1506  */
1507 static clib_error_t *
1508 sr_add_del_policy_command_fn (vlib_main_t * vm,
1509                               unformat_input_t * input,
1510                               vlib_cli_command_t * cmd)
1511 {
1512   int is_del = 0;
1513   u8 **tunnel_names = 0;
1514   u8 *tunnel_name = 0;
1515   u8 *name = 0;
1516   ip6_sr_add_del_policy_args_t _a, *a = &_a;
1517   int rv;
1518
1519   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1520     {
1521       if (unformat (input, "del"))
1522         is_del = 1;
1523       else if (unformat (input, "name %s", &name))
1524         ;
1525       else if (unformat (input, "tunnel %s", &tunnel_name))
1526         {
1527           if (tunnel_name)
1528             {
1529               vec_add1 (tunnel_names, tunnel_name);
1530               tunnel_name = 0;
1531             }
1532         }
1533       else
1534         break;
1535     }
1536
1537   if (!name)
1538     return clib_error_return (0, "name of SR policy required");
1539
1540
1541   memset (a, 0, sizeof (*a));
1542
1543   a->is_del = is_del;
1544   a->name = name;
1545   a->tunnel_names = tunnel_names;
1546
1547   rv = ip6_sr_add_del_policy (a);
1548
1549   vec_free (tunnel_names);
1550
1551   switch (rv)
1552     {
1553     case 0:
1554       break;
1555
1556     case -3:
1557       return clib_error_return (0,
1558                                 "tunnel name to associate to SR policy is required");
1559
1560     case -4:
1561       return clib_error_return (0, "tunnel name not found");
1562
1563     case -5:
1564       return clib_error_return (0, "tunnel already associated with policy");
1565
1566     case -6:
1567       return clib_error_return (0, "policy name %s not found", name);
1568
1569     case -7:
1570       return clib_error_return (0, "TODO: deleting policy name %s", name);
1571
1572     default:
1573       return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1574                                 rv);
1575
1576     }
1577   return 0;
1578 }
1579
1580 /* *INDENT-OFF* */
1581 VLIB_CLI_COMMAND (sr_policy_command, static) = {
1582     .path = "sr policy",
1583     .short_help =
1584     "sr policy [del] name <policy-name> tunnel <sr-tunnel-name> [tunnel <sr-tunnel-name>]*",
1585     .function = sr_add_del_policy_command_fn,
1586 };
1587 /* *INDENT-ON* */
1588
1589 /**
1590  * @brief CLI Parser for Displaying Segment Routing policy
1591  *
1592  * @param vm vlib_main_t *
1593  * @param input unformat_input_t *
1594  * @param cmd vlib_cli_command_t *
1595  *
1596  * @return error clib_error_t *
1597  */
1598 static clib_error_t *
1599 show_sr_policy_fn (vlib_main_t * vm,
1600                    unformat_input_t * input, vlib_cli_command_t * cmd)
1601 {
1602   static ip6_sr_policy_t **policies;
1603   ip6_sr_policy_t *policy;
1604   ip6_sr_tunnel_t *t;
1605   ip6_sr_main_t *sm = &sr_main;
1606   int i, j;
1607   uword *p = 0;
1608   u8 *name = 0;
1609
1610   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1611     {
1612       if (unformat (input, "name %s", &name))
1613         {
1614           p = hash_get_mem (sm->policy_index_by_policy_name, name);
1615           if (!p)
1616             vlib_cli_output (vm,
1617                              "policy with name %s not found. Showing all.",
1618                              name);
1619         }
1620       else
1621         break;
1622     }
1623
1624   vec_reset_length (policies);
1625
1626   if (!p)                       /* Either name parm not passed or no policy with that name found, show all */
1627     {
1628       /* *INDENT-OFF* */
1629   pool_foreach (policy, sm->policies,
1630   ({
1631     vec_add1 (policies, policy);
1632   }));
1633   /* *INDENT-ON* */
1634     }
1635   else                          /* Just show the one policy by name and a summary of tunnel names */
1636     {
1637       policy = pool_elt_at_index (sm->policies, p[0]);
1638       vec_add1 (policies, policy);
1639     }
1640
1641   if (vec_len (policies) == 0)
1642     vlib_cli_output (vm, "No SR policies configured");
1643
1644   for (i = 0; i < vec_len (policies); i++)
1645     {
1646       policy = policies[i];
1647
1648       if (policy->name)
1649         vlib_cli_output (vm, "SR policy name: %s", (char *) policy->name);
1650       for (j = 0; j < vec_len (policy->tunnel_indices); j++)
1651         {
1652           t = pool_elt_at_index (sm->tunnels, policy->tunnel_indices[j]);
1653           ip6_sr_tunnel_display (vm, t);
1654         }
1655     }
1656
1657   return 0;
1658
1659 }
1660
1661 /* *INDENT-OFF* */
1662 VLIB_CLI_COMMAND (show_sr_policy_command, static) = {
1663     .path = "show sr policy",
1664     .short_help = "show sr policy [name <sr-policy-name>]",
1665     .function = show_sr_policy_fn,
1666 };
1667 /* *INDENT-ON* */
1668
1669 /**
1670  * @brief Add or Delete a mapping of IP6 multicast address
1671  * to Segment Routing policy.
1672  *
1673  * @param a ip6_sr_add_del_multicastmap_args_t *
1674  *
1675  * @return retval int
1676  */
1677 int
1678 ip6_sr_add_del_multicastmap (ip6_sr_add_del_multicastmap_args_t * a)
1679 {
1680   uword *p;
1681   ip6_main_t *im = &ip6_main;
1682   ip_lookup_main_t *lm = &im->lookup_main;
1683   ip6_sr_tunnel_t *t;
1684   ip_adjacency_t adj, *ap, *add_adj = 0;
1685   u32 adj_index;
1686   ip6_sr_main_t *sm = &sr_main;
1687   ip6_add_del_route_args_t aa;
1688   ip6_sr_policy_t *pt;
1689
1690   if (a->is_del)
1691     {
1692       /* clean up the adjacency */
1693       p =
1694         hash_get_mem (sm->policy_index_by_multicast_address,
1695                       a->multicast_address);
1696     }
1697   else
1698     {
1699       /* Get our policy by policy_name */
1700       p = hash_get_mem (sm->policy_index_by_policy_name, a->policy_name);
1701
1702     }
1703   if (!p)
1704     return -1;
1705
1706   pt = pool_elt_at_index (sm->policies, p[0]);
1707
1708   /*
1709      Get the first tunnel associated with policy populate the fib adjacency.
1710      From there, since this tunnel will have it's policy_index != ~0 it will
1711      be the trigger in the dual_loop to pull up the policy and make a copy-rewrite
1712      for each tunnel in the policy
1713    */
1714
1715   t = pool_elt_at_index (sm->tunnels, pt->tunnel_indices[0]);
1716
1717   /* Construct a FIB entry for multicast using the rx/tx fib from the first tunnel */
1718   memset (&adj, 0, sizeof (adj));
1719
1720   /* Create an adjacency and add to v6 fib */
1721   adj.lookup_next_index = sm->ip6_lookup_sr_replicate_index;
1722   adj.explicit_fib_index = ~0;
1723
1724   ap = ip_add_adjacency (lm, &adj, 1 /* one adj */ ,
1725                          &adj_index);
1726
1727   /*
1728    * Stick the tunnel index into the rewrite header.
1729    *
1730    * Unfortunately, inserting an SR header according to the various
1731    * RFC's requires parsing through the ip6 header, perhaps consing a
1732    * buffer onto the head of the vlib_buffer_t, etc. We don't use the
1733    * normal reverse bcopy rewrite code.
1734    *
1735    * We don't handle ugly RFC-related cases yet, but I'm sure PL will complain
1736    * at some point...
1737    */
1738   ap->rewrite_header.sw_if_index = t - sm->tunnels;
1739
1740   vec_add1 (add_adj, ap[0]);
1741
1742   memcpy (aa.dst_address.as_u8, a->multicast_address,
1743           sizeof (aa.dst_address.as_u8));
1744   aa.dst_address_length = 128;
1745
1746   aa.flags = (a->is_del ? IP6_ROUTE_FLAG_DEL : IP6_ROUTE_FLAG_ADD);
1747   aa.flags |= IP6_ROUTE_FLAG_FIB_INDEX;
1748   aa.table_index_or_table_id = t->rx_fib_index;
1749   aa.add_adj = add_adj;
1750   aa.adj_index = adj_index;
1751   aa.n_add_adj = 1;
1752   ip6_add_del_route (im, &aa);
1753   vec_free (add_adj);
1754
1755   u8 *mcast_copy = 0;
1756   mcast_copy = vec_new (ip6_address_t, 1);
1757   memcpy (mcast_copy, a->multicast_address, sizeof (ip6_address_t));
1758
1759   if (a->is_del)
1760     {
1761       hash_unset_mem (sm->policy_index_by_multicast_address, mcast_copy);
1762       vec_free (mcast_copy);
1763       return 0;
1764     }
1765   /* else */
1766
1767   hash_set_mem (sm->policy_index_by_multicast_address, mcast_copy,
1768                 pt - sm->policies);
1769
1770
1771   return 0;
1772 }
1773
1774 /**
1775  * @brief CLI Parser for Adding or Delete a mapping of IP6 multicast address
1776  * to Segment Routing policy.
1777  *
1778  * @param vm vlib_main_t *
1779  * @param input unformat_input_t *
1780  * @param cmd vlib_cli_command_t *
1781  *
1782  * @return error clib_error_t *
1783  */
1784 static clib_error_t *
1785 sr_add_del_multicast_map_command_fn (vlib_main_t * vm,
1786                                      unformat_input_t * input,
1787                                      vlib_cli_command_t * cmd)
1788 {
1789   int is_del = 0;
1790   ip6_address_t multicast_address;
1791   u8 *policy_name = 0;
1792   int multicast_address_set = 0;
1793   ip6_sr_add_del_multicastmap_args_t _a, *a = &_a;
1794   int rv;
1795
1796   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1797     {
1798       if (unformat (input, "del"))
1799         is_del = 1;
1800       else
1801         if (unformat
1802             (input, "address %U", unformat_ip6_address, &multicast_address))
1803         multicast_address_set = 1;
1804       else if (unformat (input, "sr-policy %s", &policy_name))
1805         ;
1806       else
1807         break;
1808     }
1809
1810   if (!is_del && !policy_name)
1811     return clib_error_return (0, "name of sr policy required");
1812
1813   if (!multicast_address_set)
1814     return clib_error_return (0, "multicast address required");
1815
1816   memset (a, 0, sizeof (*a));
1817
1818   a->is_del = is_del;
1819   a->multicast_address = &multicast_address;
1820   a->policy_name = policy_name;
1821
1822 #if DPDK > 0                    /*Cannot call replicate or configure multicast map yet without DPDK */
1823   rv = ip6_sr_add_del_multicastmap (a);
1824 #else
1825   return clib_error_return (0,
1826                             "cannot use multicast replicate spray case without DPDK installed");
1827 #endif /* DPDK */
1828
1829   switch (rv)
1830     {
1831     case 0:
1832       break;
1833     case -1:
1834       return clib_error_return (0, "no policy with name: %s", policy_name);
1835
1836     case -2:
1837       return clib_error_return (0, "multicast map someting ");
1838
1839     case -3:
1840       return clib_error_return (0,
1841                                 "tunnel name to associate to SR policy is required");
1842
1843     case -7:
1844       return clib_error_return (0, "TODO: deleting policy name %s",
1845                                 policy_name);
1846
1847     default:
1848       return clib_error_return (0, "BUG: ip6_sr_add_del_policy returns %d",
1849                                 rv);
1850
1851     }
1852   return 0;
1853
1854 }
1855
1856
1857 /* *INDENT-OFF* */
1858 VLIB_CLI_COMMAND (sr_multicast_map_command, static) = {
1859     .path = "sr multicast-map",
1860     .short_help =
1861     "sr multicast-map address <multicast-ip6-address> sr-policy <sr-policy-name> [del]",
1862     .function = sr_add_del_multicast_map_command_fn,
1863 };
1864 /* *INDENT-ON* */
1865
1866 /**
1867  * @brief CLI Parser for Displaying a mapping of IP6 multicast address
1868  * to Segment Routing policy.
1869  *
1870  * @param vm vlib_main_t *
1871  * @param input unformat_input_t *
1872  * @param cmd vlib_cli_command_t *
1873  *
1874  * @return error clib_error_t *
1875  */
1876 static clib_error_t *
1877 show_sr_multicast_map_fn (vlib_main_t * vm,
1878                           unformat_input_t * input, vlib_cli_command_t * cmd)
1879 {
1880   ip6_sr_main_t *sm = &sr_main;
1881   u8 *key = 0;
1882   u32 value;
1883   ip6_address_t multicast_address;
1884   ip6_sr_policy_t *pt;
1885
1886   /* pull all entries from the hash table into vector for display */
1887
1888   /* *INDENT-OFF* */
1889   hash_foreach_mem (key, value, sm->policy_index_by_multicast_address,
1890   ({
1891     if (!key)
1892         vlib_cli_output (vm, "no multicast maps configured");
1893     else
1894       {
1895         multicast_address = *((ip6_address_t *)key);
1896         pt = pool_elt_at_index (sm->policies, value);
1897         if (pt)
1898           {
1899             vlib_cli_output (vm, "address: %U policy: %s",
1900                              format_ip6_address, &multicast_address,
1901                              pt->name);
1902           }
1903         else
1904           vlib_cli_output (vm, "BUG: policy not found for address: %U with policy index %d",
1905                              format_ip6_address, &multicast_address,
1906                              value);
1907
1908       }
1909
1910   }));
1911   /* *INDENT-ON* */
1912
1913   return 0;
1914 }
1915
1916 /* *INDENT-OFF* */
1917 VLIB_CLI_COMMAND (show_sr_multicast_map_command, static) = {
1918     .path = "show sr multicast-map",
1919     .short_help = "show sr multicast-map",
1920     .function = show_sr_multicast_map_fn,
1921 };
1922 /* *INDENT-ON* */
1923
1924
1925 #define foreach_sr_fix_dst_addr_next            \
1926 _(DROP, "error-drop")
1927
1928 /**
1929  * @brief Struct for valid next-nodes for SR fix destination address node
1930  */
1931 typedef enum
1932 {
1933 #define _(s,n) SR_FIX_DST_ADDR_NEXT_##s,
1934   foreach_sr_fix_dst_addr_next
1935 #undef _
1936     SR_FIX_DST_ADDR_N_NEXT,
1937 } sr_fix_dst_addr_next_t;
1938
1939 /**
1940  * @brief Error strings for SR Fix Destination rewrite
1941  */
1942 static char *sr_fix_dst_error_strings[] = {
1943 #define sr_fix_dst_error(n,s) s,
1944 #include "sr_fix_dst_error.def"
1945 #undef sr_fix_dst_error
1946 };
1947
1948 /**
1949  * @brief Struct for errors for SR Fix Destination rewrite
1950  */
1951 typedef enum
1952 {
1953 #define sr_fix_dst_error(n,s) SR_FIX_DST_ERROR_##n,
1954 #include "sr_fix_dst_error.def"
1955 #undef sr_fix_dst_error
1956   SR_FIX_DST_N_ERROR,
1957 } sr_fix_dst_error_t;
1958
1959 /**
1960  * @brief Information for fix address trace
1961  */
1962 typedef struct
1963 {
1964   ip6_address_t src, dst;
1965   u32 next_index;
1966   u32 adj_index;
1967   u8 sr[256];
1968 } sr_fix_addr_trace_t;
1969
1970 /**
1971  * @brief Formatter for fix address trace
1972  */
1973 u8 *
1974 format_sr_fix_addr_trace (u8 * s, va_list * args)
1975 {
1976   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1977   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1978   sr_fix_addr_trace_t *t = va_arg (*args, sr_fix_addr_trace_t *);
1979   vnet_hw_interface_t *hi = 0;
1980   ip_adjacency_t *adj;
1981   ip6_main_t *im = &ip6_main;
1982   ip_lookup_main_t *lm = &im->lookup_main;
1983   vnet_main_t *vnm = vnet_get_main ();
1984
1985   if (t->adj_index != ~0)
1986     {
1987       adj = ip_get_adjacency (lm, t->adj_index);
1988       hi = vnet_get_sup_hw_interface (vnm, adj->rewrite_header.sw_if_index);
1989     }
1990
1991   s = format (s, "SR-FIX_ADDR: next %s ip6 src %U dst %U\n",
1992               (t->next_index == SR_FIX_DST_ADDR_NEXT_DROP)
1993               ? "drop" : "output",
1994               format_ip6_address, &t->src, format_ip6_address, &t->dst);
1995   if (t->next_index != SR_FIX_DST_ADDR_NEXT_DROP)
1996     {
1997       s =
1998         format (s, "%U\n", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
1999       s =
2000         format (s, "   output via %s",
2001                 hi ? (char *) (hi->name) : "Invalid adj");
2002     }
2003   return s;
2004 }
2005
2006 /**
2007  * @brief Fix SR destination address - dual-loop
2008  *
2009  * @node sr-fix-dst-addr
2010  * @param vm vlib_main_t *
2011  * @param node vlib_node_runtime_t *
2012  * @param from_frame vlib_frame_t *
2013  *
2014  * @return from_frame->n_vectors uword
2015  */
2016 static uword
2017 sr_fix_dst_addr (vlib_main_t * vm,
2018                  vlib_node_runtime_t * node, vlib_frame_t * from_frame)
2019 {
2020   u32 n_left_from, next_index, *from, *to_next;
2021   ip6_main_t *im = &ip6_main;
2022   ip_lookup_main_t *lm = &im->lookup_main;
2023
2024   from = vlib_frame_vector_args (from_frame);
2025   n_left_from = from_frame->n_vectors;
2026
2027   next_index = node->cached_next_index;
2028
2029   while (n_left_from > 0)
2030     {
2031       u32 n_left_to_next;
2032
2033       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2034
2035 #if 0
2036       while (0 && n_left_from >= 4 && n_left_to_next >= 2)
2037         {
2038           u32 bi0, bi1;
2039           __attribute__ ((unused)) vlib_buffer_t *b0, *b1;
2040           u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
2041           u32 next1 = SR_FIX_DST_ADDR_NEXT_DROP;
2042
2043           /* Prefetch next iteration. */
2044           {
2045             vlib_buffer_t *p2, *p3;
2046
2047             p2 = vlib_get_buffer (vm, from[2]);
2048             p3 = vlib_get_buffer (vm, from[3]);
2049
2050             vlib_prefetch_buffer_header (p2, LOAD);
2051             vlib_prefetch_buffer_header (p3, LOAD);
2052           }
2053
2054           bi0 = from[0];
2055           bi1 = from[1];
2056           to_next[0] = bi0;
2057           to_next[1] = bi1;
2058           from += 2;
2059           to_next += 2;
2060           n_left_to_next -= 2;
2061           n_left_from -= 2;
2062
2063           b0 = vlib_get_buffer (vm, bi0);
2064           b1 = vlib_get_buffer (vm, bi1);
2065
2066
2067           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2068                                            to_next, n_left_to_next,
2069                                            bi0, bi1, next0, next1);
2070         }
2071 #endif
2072
2073       while (n_left_from > 0 && n_left_to_next > 0)
2074         {
2075           u32 bi0;
2076           vlib_buffer_t *b0;
2077           ip6_header_t *ip0;
2078           ip_adjacency_t *adj0;
2079           ip6_sr_header_t *sr0;
2080           u32 next0 = SR_FIX_DST_ADDR_NEXT_DROP;
2081           ip6_address_t *new_dst0;
2082           ethernet_header_t *eh0;
2083
2084           bi0 = from[0];
2085           to_next[0] = bi0;
2086           from += 1;
2087           to_next += 1;
2088           n_left_from -= 1;
2089           n_left_to_next -= 1;
2090
2091           b0 = vlib_get_buffer (vm, bi0);
2092
2093           adj0 =
2094             ip_get_adjacency (lm, vnet_buffer (b0)->ip.adj_index[VLIB_TX]);
2095           next0 = adj0->mcast_group_index;
2096
2097           /* We should be pointing at an Ethernet header... */
2098           eh0 = vlib_buffer_get_current (b0);
2099           ip0 = (ip6_header_t *) (eh0 + 1);
2100           sr0 = (ip6_sr_header_t *) (ip0 + 1);
2101
2102           /* We'd better find an SR header... */
2103           if (PREDICT_FALSE (ip0->protocol != IPPROTO_IPV6_ROUTE))
2104             {
2105               b0->error = node->errors[SR_FIX_DST_ERROR_NO_SR_HEADER];
2106               goto do_trace0;
2107             }
2108           else
2109             {
2110               /*
2111                * We get here from sr_rewrite or sr_local, with
2112                * sr->segments_left pointing at the (copy of the original) dst
2113                * address. Use it, then increment sr0->segments_left.
2114                */
2115
2116               /* Out of segments? Turf the packet */
2117               if (PREDICT_FALSE (sr0->segments_left == 0))
2118                 {
2119                   b0->error = node->errors[SR_FIX_DST_ERROR_NO_MORE_SEGMENTS];
2120                   goto do_trace0;
2121                 }
2122
2123               /*
2124                * Rewrite the packet with the original dst address
2125                * We assume that the last segment (in processing order) contains
2126                * the original dst address. The list is reversed, so sr0->segments
2127                * contains the original dst address.
2128                */
2129               new_dst0 = sr0->segments;
2130               ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2131               ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2132             }
2133
2134         do_trace0:
2135
2136           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2137             {
2138               sr_fix_addr_trace_t *t = vlib_add_trace (vm, node,
2139                                                        b0, sizeof (*t));
2140               t->next_index = next0;
2141               t->adj_index = ~0;
2142
2143               if (next0 != SR_FIX_DST_ADDR_NEXT_DROP)
2144                 {
2145                   t->adj_index = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
2146                   clib_memcpy (t->src.as_u8, ip0->src_address.as_u8,
2147                                sizeof (t->src.as_u8));
2148                   clib_memcpy (t->dst.as_u8, ip0->dst_address.as_u8,
2149                                sizeof (t->dst.as_u8));
2150                   clib_memcpy (t->sr, sr0, sizeof (t->sr));
2151                 }
2152             }
2153
2154           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2155                                            to_next, n_left_to_next,
2156                                            bi0, next0);
2157         }
2158
2159       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2160     }
2161   return from_frame->n_vectors;
2162 }
2163
2164
2165 /* *INDENT-OFF* */
2166 VLIB_REGISTER_NODE (sr_fix_dst_addr_node) = {
2167   .function = sr_fix_dst_addr,
2168   .name = "sr-fix-dst-addr",
2169   /* Takes a vector of packets. */
2170   .vector_size = sizeof (u32),
2171   .format_trace = format_sr_fix_addr_trace,
2172   .format_buffer = format_ip6_sr_header_with_length,
2173
2174   .runtime_data_bytes = 0,
2175
2176   .n_errors = SR_FIX_DST_N_ERROR,
2177   .error_strings = sr_fix_dst_error_strings,
2178
2179   .n_next_nodes = SR_FIX_DST_ADDR_N_NEXT,
2180   .next_nodes = {
2181 #define _(s,n) [SR_FIX_DST_ADDR_NEXT_##s] = n,
2182     foreach_sr_fix_dst_addr_next
2183 #undef _
2184   },
2185 };
2186 /* *INDENT-ON* */
2187
2188 VLIB_NODE_FUNCTION_MULTIARCH (sr_fix_dst_addr_node, sr_fix_dst_addr)
2189      static clib_error_t *sr_init (vlib_main_t * vm)
2190 {
2191   ip6_sr_main_t *sm = &sr_main;
2192   clib_error_t *error = 0;
2193   vlib_node_t *ip6_lookup_node, *ip6_rewrite_node;
2194
2195   if ((error = vlib_call_init_function (vm, ip_main_init)))
2196     return error;
2197
2198   if ((error = vlib_call_init_function (vm, ip6_lookup_init)))
2199     return error;
2200
2201   sm->vlib_main = vm;
2202   sm->vnet_main = vnet_get_main ();
2203
2204   vec_validate (sm->hmac_keys, 0);
2205   sm->hmac_keys[0].shared_secret = (u8 *) 0xdeadbeef;
2206
2207   sm->tunnel_index_by_key =
2208     hash_create_mem (0, sizeof (ip6_sr_tunnel_key_t), sizeof (uword));
2209
2210   sm->tunnel_index_by_name = hash_create_string (0, sizeof (uword));
2211
2212   sm->policy_index_by_policy_name = hash_create_string (0, sizeof (uword));
2213
2214   sm->policy_index_by_multicast_address =
2215     hash_create_mem (0, sizeof (ip6_address_t), sizeof (uword));
2216
2217   sm->hmac_key_by_shared_secret = hash_create_string (0, sizeof (uword));
2218
2219   ip6_register_protocol (IPPROTO_IPV6_ROUTE, sr_local_node.index);
2220
2221   ip6_lookup_node = vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
2222   ASSERT (ip6_lookup_node);
2223
2224   ip6_rewrite_node = vlib_get_node_by_name (vm, (u8 *) "ip6-rewrite");
2225   ASSERT (ip6_rewrite_node);
2226
2227   /* Add a disposition to ip6_lookup for the sr rewrite node */
2228   sm->ip6_lookup_sr_next_index =
2229     vlib_node_add_next (vm, ip6_lookup_node->index, sr_rewrite_node.index);
2230
2231 #if DPDK > 0                    /* Cannot run replicate without DPDK */
2232   /* Add a disposition to sr_replicate for the sr multicast replicate node */
2233   sm->ip6_lookup_sr_replicate_index =
2234     vlib_node_add_next (vm, ip6_lookup_node->index, sr_replicate_node.index);
2235 #endif /* DPDK */
2236
2237   /* Add a disposition to ip6_rewrite for the sr dst address hack node */
2238   sm->ip6_rewrite_sr_next_index =
2239     vlib_node_add_next (vm, ip6_rewrite_node->index,
2240                         sr_fix_dst_addr_node.index);
2241
2242   OpenSSL_add_all_digests ();
2243
2244   sm->md = (void *) EVP_get_digestbyname ("sha1");
2245   sm->hmac_ctx = clib_mem_alloc (sizeof (HMAC_CTX));
2246
2247   return error;
2248 }
2249
2250 VLIB_INIT_FUNCTION (sr_init);
2251
2252 /**
2253  * @brief Definition of next-nodes for SR local
2254  */
2255 #define foreach_sr_local_next                   \
2256   _ (ERROR, "error-drop")                       \
2257   _ (IP6_LOOKUP, "ip6-lookup")
2258
2259 /**
2260  * @brief Struct for definition of next-nodes for SR local
2261  */
2262 typedef enum
2263 {
2264 #define _(s,n) SR_LOCAL_NEXT_##s,
2265   foreach_sr_local_next
2266 #undef _
2267     SR_LOCAL_N_NEXT,
2268 } sr_local_next_t;
2269
2270 /**
2271  * @brief Struct for packet trace of SR local
2272  */
2273 typedef struct
2274 {
2275   u8 next_index;
2276   u8 sr_valid;
2277   ip6_address_t src, dst;
2278   u16 length;
2279   u8 sr[256];
2280 } sr_local_trace_t;
2281
2282 /**
2283  * @brief Definition of SR local error-strings
2284  */
2285 static char *sr_local_error_strings[] = {
2286 #define sr_error(n,s) s,
2287 #include "sr_error.def"
2288 #undef sr_error
2289 };
2290
2291 /**
2292  * @brief Struct for definition of SR local error-strings
2293  */
2294 typedef enum
2295 {
2296 #define sr_error(n,s) SR_LOCAL_ERROR_##n,
2297 #include "sr_error.def"
2298 #undef sr_error
2299   SR_LOCAL_N_ERROR,
2300 } sr_local_error_t;
2301
2302 /**
2303  * @brief Format SR local trace
2304  *
2305  * @param s u8 *
2306  * @param args va_list *
2307  *
2308  * @return s u8 *
2309  */
2310 u8 *
2311 format_sr_local_trace (u8 * s, va_list * args)
2312 {
2313   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2314   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2315   sr_local_trace_t *t = va_arg (*args, sr_local_trace_t *);
2316
2317   s = format (s, "SR-LOCAL: src %U dst %U len %u next_index %d",
2318               format_ip6_address, &t->src,
2319               format_ip6_address, &t->dst, t->length, t->next_index);
2320   if (t->sr_valid)
2321     s =
2322       format (s, "\n  %U", format_ip6_sr_header, t->sr, 1 /* print_hmac */ );
2323   else
2324     s = format (s, "\n  popped SR header");
2325
2326   return s;
2327 }
2328
2329
2330 /* $$$$ fixme: smp, don't copy data, cache input, output (maybe) */
2331 /**
2332  * @brief Validate the SR HMAC
2333  *
2334  * @param sm ip6_sr_main_t *
2335  * @param ip ip6_header_t *
2336  * @param sr ip6_sr_header_t *
2337  *
2338  * @return retval int
2339  */
2340 static int
2341 sr_validate_hmac (ip6_sr_main_t * sm, ip6_header_t * ip, ip6_sr_header_t * sr)
2342 {
2343   u32 key_index;
2344   static u8 *keybuf;
2345   u8 *copy_target;
2346   int first_segment;
2347   ip6_address_t *addrp;
2348   int i;
2349   ip6_sr_hmac_key_t *hmac_key;
2350   static u8 *signature;
2351   u32 sig_len;
2352
2353   key_index = sr->hmac_key;
2354
2355   /* No signature? Pass... */
2356   if (key_index == 0)
2357     return 0;
2358
2359   /* We don't know about this key? Fail... */
2360   if (key_index >= vec_len (sm->hmac_keys))
2361     return 1;
2362
2363   vec_validate (signature, SHA256_DIGEST_LENGTH - 1);
2364
2365   hmac_key = sm->hmac_keys + key_index;
2366
2367   vec_reset_length (keybuf);
2368
2369   /* pkt ip6 src address */
2370   vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2371   clib_memcpy (copy_target, ip->src_address.as_u8, sizeof (ip6_address_t));
2372
2373   /* last segment */
2374   vec_add2 (keybuf, copy_target, 1);
2375   copy_target[0] = sr->first_segment;
2376
2377   /* octet w/ bit 0 = "clean" flag */
2378   vec_add2 (keybuf, copy_target, 1);
2379   copy_target[0]
2380     = (sr->flags & clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))
2381     ? 0x80 : 0;
2382
2383   /* hmac key id */
2384   vec_add2 (keybuf, copy_target, 1);
2385   copy_target[0] = sr->hmac_key;
2386
2387   first_segment = sr->first_segment;
2388
2389   addrp = sr->segments;
2390
2391   /* segments */
2392   for (i = 0; i <= first_segment; i++)
2393     {
2394       vec_add2 (keybuf, copy_target, sizeof (ip6_address_t));
2395       clib_memcpy (copy_target, addrp->as_u8, sizeof (ip6_address_t));
2396       addrp++;
2397     }
2398
2399   if (sm->is_debug)
2400     clib_warning ("verify key index %d keybuf: %U", key_index,
2401                   format_hex_bytes, keybuf, vec_len (keybuf));
2402
2403   /* shared secret */
2404
2405   /* SHA1 is shorter than SHA-256 */
2406   memset (signature, 0, vec_len (signature));
2407
2408   HMAC_CTX_init (sm->hmac_ctx);
2409   if (!HMAC_Init (sm->hmac_ctx, hmac_key->shared_secret,
2410                   vec_len (hmac_key->shared_secret), sm->md))
2411     clib_warning ("barf1");
2412   if (!HMAC_Update (sm->hmac_ctx, keybuf, vec_len (keybuf)))
2413     clib_warning ("barf2");
2414   if (!HMAC_Final (sm->hmac_ctx, signature, &sig_len))
2415     clib_warning ("barf3");
2416   HMAC_CTX_cleanup (sm->hmac_ctx);
2417
2418   if (sm->is_debug)
2419     clib_warning ("computed signature len %d, value %U", sig_len,
2420                   format_hex_bytes, signature, vec_len (signature));
2421
2422   /* Point at the SHA signature in the packet */
2423   addrp++;
2424   if (sm->is_debug)
2425     clib_warning ("read signature %U", format_hex_bytes, addrp,
2426                   SHA256_DIGEST_LENGTH);
2427
2428   return memcmp (signature, addrp, SHA256_DIGEST_LENGTH);
2429 }
2430
2431 /**
2432  * @brief SR local node
2433  * @node sr-local
2434  *
2435  * @param vm vlib_main_t *
2436  * @param node vlib_node_runtime_t *
2437  * @param from_frame vlib_frame_t *
2438  *
2439  * @return from_frame->n_vectors uword
2440  */
2441 static uword
2442 sr_local (vlib_main_t * vm,
2443           vlib_node_runtime_t * node, vlib_frame_t * from_frame)
2444 {
2445   u32 n_left_from, next_index, *from, *to_next;
2446   ip6_sr_main_t *sm = &sr_main;
2447   u32 (*sr_local_cb) (vlib_main_t *, vlib_node_runtime_t *,
2448                       vlib_buffer_t *, ip6_header_t *, ip6_sr_header_t *);
2449   sr_local_cb = sm->sr_local_cb;
2450
2451   from = vlib_frame_vector_args (from_frame);
2452   n_left_from = from_frame->n_vectors;
2453
2454   next_index = node->cached_next_index;
2455
2456   while (n_left_from > 0)
2457     {
2458       u32 n_left_to_next;
2459
2460       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
2461
2462       while (n_left_from >= 4 && n_left_to_next >= 2)
2463         {
2464           u32 bi0, bi1;
2465           vlib_buffer_t *b0, *b1;
2466           ip6_header_t *ip0, *ip1;
2467           ip6_sr_header_t *sr0, *sr1;
2468           ip6_address_t *new_dst0, *new_dst1;
2469           u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2470           u32 next1 = SR_LOCAL_NEXT_IP6_LOOKUP;
2471           /* Prefetch next iteration. */
2472           {
2473             vlib_buffer_t *p2, *p3;
2474
2475             p2 = vlib_get_buffer (vm, from[2]);
2476             p3 = vlib_get_buffer (vm, from[3]);
2477
2478             vlib_prefetch_buffer_header (p2, LOAD);
2479             vlib_prefetch_buffer_header (p3, LOAD);
2480
2481             CLIB_PREFETCH (p2->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2482             CLIB_PREFETCH (p3->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
2483           }
2484
2485           bi0 = from[0];
2486           bi1 = from[1];
2487           to_next[0] = bi0;
2488           to_next[1] = bi1;
2489           from += 2;
2490           to_next += 2;
2491           n_left_to_next -= 2;
2492           n_left_from -= 2;
2493
2494
2495           b0 = vlib_get_buffer (vm, bi0);
2496           ip0 = vlib_buffer_get_current (b0);
2497           sr0 = (ip6_sr_header_t *) (ip0 + 1);
2498
2499           if (PREDICT_FALSE (sr0->type != ROUTING_HEADER_TYPE_SR))
2500             {
2501               next0 = SR_LOCAL_NEXT_ERROR;
2502               b0->error =
2503                 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2504               goto do_trace0;
2505             }
2506
2507           /* Out of segments? Turf the packet */
2508           if (PREDICT_FALSE (sr0->segments_left == 0))
2509             {
2510               next0 = SR_LOCAL_NEXT_ERROR;
2511               b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2512               goto do_trace0;
2513             }
2514
2515           if (PREDICT_FALSE (sm->validate_hmac))
2516             {
2517               if (sr_validate_hmac (sm, ip0, sr0))
2518                 {
2519                   next0 = SR_LOCAL_NEXT_ERROR;
2520                   b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2521                   goto do_trace0;
2522                 }
2523             }
2524
2525           next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
2526
2527           /*
2528            * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2529            */
2530           if (PREDICT_FALSE (next0 & 0x80000000))
2531             {
2532               next0 ^= 0xFFFFFFFF;
2533               if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2534                 b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2535             }
2536           else
2537             {
2538               u32 segment_index0;
2539
2540               segment_index0 = sr0->segments_left - 1;
2541
2542               /* Rewrite the packet */
2543               new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2544               ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2545               ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2546
2547               if (PREDICT_TRUE (sr0->segments_left > 0))
2548                 sr0->segments_left -= 1;
2549             }
2550
2551           /* End of the path. Clean up the SR header, or not */
2552           if (PREDICT_FALSE
2553               (sr0->segments_left == 0 &&
2554                (sr0->flags &
2555                 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2556             {
2557               u64 *copy_dst0, *copy_src0;
2558               u16 new_l0;
2559               /*
2560                * Copy the ip6 header right by the (real) length of the
2561                * sr header. Here's another place which assumes that
2562                * the sr header is the only extention header.
2563                */
2564
2565               ip0->protocol = sr0->protocol;
2566               vlib_buffer_advance (b0, (sr0->length + 1) * 8);
2567
2568               new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2569                 (sr0->length + 1) * 8;
2570               ip0->payload_length = clib_host_to_net_u16 (new_l0);
2571
2572               copy_src0 = (u64 *) ip0;
2573               copy_dst0 = copy_src0 + (sr0->length + 1);
2574
2575               copy_dst0[4] = copy_src0[4];
2576               copy_dst0[3] = copy_src0[3];
2577               copy_dst0[2] = copy_src0[2];
2578               copy_dst0[1] = copy_src0[1];
2579               copy_dst0[0] = copy_src0[0];
2580
2581               sr0 = 0;
2582             }
2583
2584         do_trace0:
2585           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2586             {
2587               sr_local_trace_t *tr = vlib_add_trace (vm, node,
2588                                                      b0, sizeof (*tr));
2589               clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2590                            sizeof (tr->src.as_u8));
2591               clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2592                            sizeof (tr->dst.as_u8));
2593               tr->length = vlib_buffer_length_in_chain (vm, b0);
2594               tr->next_index = next0;
2595               tr->sr_valid = sr0 != 0;
2596               if (tr->sr_valid)
2597                 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2598             }
2599
2600           b1 = vlib_get_buffer (vm, bi1);
2601           ip1 = vlib_buffer_get_current (b1);
2602           sr1 = (ip6_sr_header_t *) (ip1 + 1);
2603
2604           if (PREDICT_FALSE (sr1->type != ROUTING_HEADER_TYPE_SR))
2605             {
2606               next1 = SR_LOCAL_NEXT_ERROR;
2607               b1->error =
2608                 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2609               goto do_trace1;
2610             }
2611
2612           /* Out of segments? Turf the packet */
2613           if (PREDICT_FALSE (sr1->segments_left == 0))
2614             {
2615               next1 = SR_LOCAL_NEXT_ERROR;
2616               b1->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2617               goto do_trace1;
2618             }
2619
2620           if (PREDICT_FALSE (sm->validate_hmac))
2621             {
2622               if (sr_validate_hmac (sm, ip1, sr1))
2623                 {
2624                   next1 = SR_LOCAL_NEXT_ERROR;
2625                   b1->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2626                   goto do_trace1;
2627                 }
2628             }
2629
2630           next1 = sr_local_cb ? sr_local_cb (vm, node, b1, ip1, sr1) : next1;
2631
2632           /*
2633            * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2634            */
2635           if (PREDICT_FALSE (next1 & 0x80000000))
2636             {
2637               next1 ^= 0xFFFFFFFF;
2638               if (PREDICT_FALSE (next1 == SR_LOCAL_NEXT_ERROR))
2639                 b1->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2640             }
2641           else
2642             {
2643               u32 segment_index1;
2644
2645               segment_index1 = sr1->segments_left - 1;
2646
2647               /* Rewrite the packet */
2648               new_dst1 = (ip6_address_t *) (sr1->segments + segment_index1);
2649               ip1->dst_address.as_u64[0] = new_dst1->as_u64[0];
2650               ip1->dst_address.as_u64[1] = new_dst1->as_u64[1];
2651
2652               if (PREDICT_TRUE (sr1->segments_left > 0))
2653                 sr1->segments_left -= 1;
2654             }
2655
2656           /* End of the path. Clean up the SR header, or not */
2657           if (PREDICT_FALSE
2658               (sr1->segments_left == 0 &&
2659                (sr1->flags &
2660                 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2661             {
2662               u64 *copy_dst1, *copy_src1;
2663               u16 new_l1;
2664               /*
2665                * Copy the ip6 header right by the (real) length of the
2666                * sr header. Here's another place which assumes that
2667                * the sr header is the only extention header.
2668                */
2669
2670               ip1->protocol = sr1->protocol;
2671               vlib_buffer_advance (b1, (sr1->length + 1) * 8);
2672
2673               new_l1 = clib_net_to_host_u16 (ip1->payload_length) -
2674                 (sr1->length + 1) * 8;
2675               ip1->payload_length = clib_host_to_net_u16 (new_l1);
2676
2677               copy_src1 = (u64 *) ip1;
2678               copy_dst1 = copy_src1 + (sr1->length + 1);
2679
2680               copy_dst1[4] = copy_src1[4];
2681               copy_dst1[3] = copy_src1[3];
2682               copy_dst1[2] = copy_src1[2];
2683               copy_dst1[1] = copy_src1[1];
2684               copy_dst1[0] = copy_src1[0];
2685
2686               sr1 = 0;
2687             }
2688
2689         do_trace1:
2690           if (PREDICT_FALSE (b1->flags & VLIB_BUFFER_IS_TRACED))
2691             {
2692               sr_local_trace_t *tr = vlib_add_trace (vm, node,
2693                                                      b1, sizeof (*tr));
2694               clib_memcpy (tr->src.as_u8, ip1->src_address.as_u8,
2695                            sizeof (tr->src.as_u8));
2696               clib_memcpy (tr->dst.as_u8, ip1->dst_address.as_u8,
2697                            sizeof (tr->dst.as_u8));
2698               tr->length = vlib_buffer_length_in_chain (vm, b1);
2699               tr->next_index = next1;
2700               tr->sr_valid = sr1 != 0;
2701               if (tr->sr_valid)
2702                 clib_memcpy (tr->sr, sr1, sizeof (tr->sr));
2703             }
2704
2705           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
2706                                            to_next, n_left_to_next,
2707                                            bi0, bi1, next0, next1);
2708         }
2709
2710       while (n_left_from > 0 && n_left_to_next > 0)
2711         {
2712           u32 bi0;
2713           vlib_buffer_t *b0;
2714           ip6_header_t *ip0 = 0;
2715           ip6_sr_header_t *sr0;
2716           ip6_address_t *new_dst0;
2717           u32 next0 = SR_LOCAL_NEXT_IP6_LOOKUP;
2718
2719           bi0 = from[0];
2720           to_next[0] = bi0;
2721           from += 1;
2722           to_next += 1;
2723           n_left_from -= 1;
2724           n_left_to_next -= 1;
2725
2726           b0 = vlib_get_buffer (vm, bi0);
2727           ip0 = vlib_buffer_get_current (b0);
2728           sr0 = (ip6_sr_header_t *) (ip0 + 1);
2729
2730           if (PREDICT_FALSE (sr0->type != ROUTING_HEADER_TYPE_SR))
2731             {
2732               next0 = SR_LOCAL_NEXT_ERROR;
2733               b0->error =
2734                 node->errors[SR_LOCAL_ERROR_BAD_ROUTING_HEADER_TYPE];
2735               goto do_trace;
2736             }
2737
2738           /* Out of segments? Turf the packet */
2739           if (PREDICT_FALSE (sr0->segments_left == 0))
2740             {
2741               next0 = SR_LOCAL_NEXT_ERROR;
2742               b0->error = node->errors[SR_LOCAL_ERROR_NO_MORE_SEGMENTS];
2743               goto do_trace;
2744             }
2745
2746           if (PREDICT_FALSE (sm->validate_hmac))
2747             {
2748               if (sr_validate_hmac (sm, ip0, sr0))
2749                 {
2750                   next0 = SR_LOCAL_NEXT_ERROR;
2751                   b0->error = node->errors[SR_LOCAL_ERROR_HMAC_INVALID];
2752                   goto do_trace;
2753                 }
2754             }
2755
2756           next0 = sr_local_cb ? sr_local_cb (vm, node, b0, ip0, sr0) : next0;
2757
2758           /*
2759            * To suppress rewrite, return ~SR_LOCAL_NEXT_xxx
2760            */
2761           if (PREDICT_FALSE (next0 & 0x80000000))
2762             {
2763               next0 ^= 0xFFFFFFFF;
2764               if (PREDICT_FALSE (next0 == SR_LOCAL_NEXT_ERROR))
2765                 b0->error = node->errors[SR_LOCAL_ERROR_APP_CALLBACK];
2766             }
2767           else
2768             {
2769               u32 segment_index0;
2770
2771               segment_index0 = sr0->segments_left - 1;
2772
2773               /* Rewrite the packet */
2774               new_dst0 = (ip6_address_t *) (sr0->segments + segment_index0);
2775               ip0->dst_address.as_u64[0] = new_dst0->as_u64[0];
2776               ip0->dst_address.as_u64[1] = new_dst0->as_u64[1];
2777
2778               if (PREDICT_TRUE (sr0->segments_left > 0))
2779                 sr0->segments_left -= 1;
2780             }
2781
2782           /* End of the path. Clean up the SR header, or not */
2783           if (PREDICT_FALSE
2784               (sr0->segments_left == 0 &&
2785                (sr0->flags &
2786                 clib_host_to_net_u16 (IP6_SR_HEADER_FLAG_CLEANUP))))
2787             {
2788               u64 *copy_dst0, *copy_src0;
2789               u16 new_l0;
2790               /*
2791                * Copy the ip6 header right by the (real) length of the
2792                * sr header. Here's another place which assumes that
2793                * the sr header is the only extention header.
2794                */
2795
2796               ip0->protocol = sr0->protocol;
2797               vlib_buffer_advance (b0, (sr0->length + 1) * 8);
2798
2799               new_l0 = clib_net_to_host_u16 (ip0->payload_length) -
2800                 (sr0->length + 1) * 8;
2801               ip0->payload_length = clib_host_to_net_u16 (new_l0);
2802
2803               copy_src0 = (u64 *) ip0;
2804               copy_dst0 = copy_src0 + (sr0->length + 1);
2805
2806               copy_dst0[4] = copy_src0[4];
2807               copy_dst0[3] = copy_src0[3];
2808               copy_dst0[2] = copy_src0[2];
2809               copy_dst0[1] = copy_src0[1];
2810               copy_dst0[0] = copy_src0[0];
2811
2812               sr0 = 0;
2813             }
2814
2815         do_trace:
2816           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
2817             {
2818               sr_local_trace_t *tr = vlib_add_trace (vm, node,
2819                                                      b0, sizeof (*tr));
2820               clib_memcpy (tr->src.as_u8, ip0->src_address.as_u8,
2821                            sizeof (tr->src.as_u8));
2822               clib_memcpy (tr->dst.as_u8, ip0->dst_address.as_u8,
2823                            sizeof (tr->dst.as_u8));
2824               tr->length = vlib_buffer_length_in_chain (vm, b0);
2825               tr->next_index = next0;
2826               tr->sr_valid = sr0 != 0;
2827               if (tr->sr_valid)
2828                 clib_memcpy (tr->sr, sr0, sizeof (tr->sr));
2829             }
2830
2831           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
2832                                            to_next, n_left_to_next,
2833                                            bi0, next0);
2834         }
2835
2836       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
2837     }
2838   vlib_node_increment_counter (vm, sr_local_node.index,
2839                                SR_LOCAL_ERROR_PKTS_PROCESSED,
2840                                from_frame->n_vectors);
2841   return from_frame->n_vectors;
2842 }
2843
2844 /* *INDENT-OFF* */
2845 VLIB_REGISTER_NODE (sr_local_node, static) = {
2846   .function = sr_local,
2847   .name = "sr-local",
2848   /* Takes a vector of packets. */
2849   .vector_size = sizeof (u32),
2850   .format_trace = format_sr_local_trace,
2851
2852   .runtime_data_bytes = 0,
2853
2854   .n_errors = SR_LOCAL_N_ERROR,
2855   .error_strings = sr_local_error_strings,
2856
2857   .n_next_nodes = SR_LOCAL_N_NEXT,
2858   .next_nodes = {
2859 #define _(s,n) [SR_LOCAL_NEXT_##s] = n,
2860     foreach_sr_local_next
2861 #undef _
2862   },
2863 };
2864 /* *INDENT-ON* */
2865
2866 VLIB_NODE_FUNCTION_MULTIARCH (sr_local_node, sr_local)
2867      ip6_sr_main_t *sr_get_main (vlib_main_t * vm)
2868 {
2869   vlib_call_init_function (vm, sr_init);
2870   ASSERT (sr_local_node.index);
2871   return &sr_main;
2872 }
2873
2874 /**
2875  * @brief CLI parser for SR fix destination rewrite node
2876  *
2877  * @param vm vlib_main_t *
2878  * @param input unformat_input_t *
2879  * @param cmd vlib_cli_command_t *
2880  *
2881  * @return error clib_error_t *
2882  */
2883 static clib_error_t *
2884 set_ip6_sr_rewrite_fn (vlib_main_t * vm,
2885                        unformat_input_t * input, vlib_cli_command_t * cmd)
2886 {
2887   ip6_address_t a;
2888   ip6_main_t *im = &ip6_main;
2889   ip_lookup_main_t *lm = &im->lookup_main;
2890   u32 fib_index = 0;
2891   u32 fib_id = 0;
2892   u32 adj_index;
2893   uword *p;
2894   ip_adjacency_t *adj;
2895   vnet_hw_interface_t *hi;
2896   u32 sw_if_index;
2897   ip6_sr_main_t *sm = &sr_main;
2898   vnet_main_t *vnm = vnet_get_main ();
2899
2900   if (!unformat (input, "%U", unformat_ip6_address, &a))
2901     return clib_error_return (0, "ip6 address missing in '%U'",
2902                               format_unformat_error, input);
2903
2904   if (unformat (input, "rx-table-id %d", &fib_id))
2905     {
2906       p = hash_get (im->fib_index_by_table_id, fib_id);
2907       if (p == 0)
2908         return clib_error_return (0, "fib-id %d not found");
2909       fib_index = p[0];
2910     }
2911
2912   adj_index = ip6_fib_lookup_with_table (im, fib_index, &a);
2913
2914   if (adj_index == lm->miss_adj_index)
2915     return clib_error_return (0, "no match for %U", format_ip6_address, &a);
2916
2917   adj = ip_get_adjacency (lm, adj_index);
2918
2919   if (adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
2920     return clib_error_return (0, "%U unresolved (not a rewrite adj)",
2921                               format_ip6_address, &a);
2922
2923   adj->rewrite_header.next_index = sm->ip6_rewrite_sr_next_index;
2924
2925   sw_if_index = adj->rewrite_header.sw_if_index;
2926   hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
2927   adj->rewrite_header.node_index = sr_fix_dst_addr_node.index;
2928
2929   /* $$$$$ hack... steal the mcast group index */
2930   adj->mcast_group_index =
2931     vlib_node_add_next (vm, sr_fix_dst_addr_node.index,
2932                         hi->output_node_index);
2933
2934   return 0;
2935 }
2936
2937 /* *INDENT-OFF* */
2938 VLIB_CLI_COMMAND (set_ip6_sr_rewrite, static) = {
2939     .path = "set ip6 sr rewrite",
2940     .short_help = "set ip6 sr rewrite <ip6-address> [fib-id <id>]",
2941     .function = set_ip6_sr_rewrite_fn,
2942 };
2943 /* *INDENT-ON* */
2944
2945 /**
2946  * @brief Register a callback routine to set next0 in sr_local
2947  *
2948  * @param cb void *
2949  */
2950 void
2951 vnet_register_sr_app_callback (void *cb)
2952 {
2953   ip6_sr_main_t *sm = &sr_main;
2954
2955   sm->sr_local_cb = cb;
2956 }
2957
2958 /**
2959  * @brief Test routine for validation of HMAC
2960  */
2961 static clib_error_t *
2962 test_sr_hmac_validate_fn (vlib_main_t * vm,
2963                           unformat_input_t * input, vlib_cli_command_t * cmd)
2964 {
2965   ip6_sr_main_t *sm = &sr_main;
2966
2967   if (unformat (input, "validate on"))
2968     sm->validate_hmac = 1;
2969   else if (unformat (input, "chunk-offset off"))
2970     sm->validate_hmac = 0;
2971   else
2972     return clib_error_return (0, "expected validate on|off in '%U'",
2973                               format_unformat_error, input);
2974
2975   vlib_cli_output (vm, "hmac signature validation %s",
2976                    sm->validate_hmac ? "on" : "off");
2977   return 0;
2978 }
2979
2980 /* *INDENT-OFF* */
2981 VLIB_CLI_COMMAND (test_sr_hmac_validate, static) = {
2982     .path = "test sr hmac",
2983     .short_help = "test sr hmac validate [on|off]",
2984     .function = test_sr_hmac_validate_fn,
2985 };
2986 /* *INDENT-ON* */
2987
2988 /**
2989  * @brief Add or Delete HMAC key
2990  *
2991  * @param sm ip6_sr_main_t *
2992  * @param key_id u32
2993  * @param shared_secret u8 *
2994  * @param is_del u8
2995  *
2996  * @return retval i32
2997  */
2998 // $$$ fixme shouldn't return i32
2999 i32
3000 sr_hmac_add_del_key (ip6_sr_main_t * sm, u32 key_id, u8 * shared_secret,
3001                      u8 is_del)
3002 {
3003   u32 index;
3004   ip6_sr_hmac_key_t *key;
3005
3006   if (is_del == 0)
3007     {
3008       /* Specific key in use? Fail. */
3009       if (key_id && vec_len (sm->hmac_keys) > key_id
3010           && sm->hmac_keys[key_id].shared_secret)
3011         return -2;
3012
3013       index = key_id;
3014       key = find_or_add_shared_secret (sm, shared_secret, &index);
3015       ASSERT (index == key_id);
3016       return 0;
3017     }
3018
3019   /* delete */
3020
3021   if (key_id)                   /* delete by key ID */
3022     {
3023       if (vec_len (sm->hmac_keys) <= key_id)
3024         return -3;
3025
3026       key = sm->hmac_keys + key_id;
3027
3028       hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
3029       vec_free (key->shared_secret);
3030       return 0;
3031     }
3032
3033   index = 0;
3034   key = find_or_add_shared_secret (sm, shared_secret, &index);
3035   hash_unset_mem (sm->hmac_key_by_shared_secret, key->shared_secret);
3036   vec_free (key->shared_secret);
3037   return 0;
3038 }
3039
3040
3041 static clib_error_t *
3042 sr_hmac_add_del_key_fn (vlib_main_t * vm,
3043                         unformat_input_t * input, vlib_cli_command_t * cmd)
3044 {
3045   ip6_sr_main_t *sm = &sr_main;
3046   u8 is_del = 0;
3047   u32 key_id = 0;
3048   u8 key_id_set = 0;
3049   u8 *shared_secret = 0;
3050   i32 rv;
3051
3052   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
3053     {
3054       if (unformat (input, "del"))
3055         is_del = 1;
3056       else if (unformat (input, "id %d", &key_id))
3057         key_id_set = 1;
3058       else if (unformat (input, "key %s", &shared_secret))
3059         {
3060           /* Do not include the trailing NULL byte. Guaranteed interop issue */
3061           _vec_len (shared_secret) -= 1;
3062         }
3063       else
3064         break;
3065     }
3066
3067   if (is_del == 0 && shared_secret == 0)
3068     return clib_error_return (0, "shared secret must be set to add a key");
3069
3070   if (shared_secret == 0 && key_id_set == 0)
3071     return clib_error_return (0, "shared secret and key id both unset");
3072
3073   rv = sr_hmac_add_del_key (sm, key_id, shared_secret, is_del);
3074
3075   vec_free (shared_secret);
3076
3077   switch (rv)
3078     {
3079     case 0:
3080       break;
3081
3082     default:
3083       return clib_error_return (0, "sr_hmac_add_del_key returned %d", rv);
3084     }
3085
3086   return 0;
3087 }
3088
3089 /* *INDENT-OFF* */
3090 VLIB_CLI_COMMAND (sr_hmac, static) = {
3091     .path = "sr hmac",
3092     .short_help = "sr hmac [del] id <nn> key <str>",
3093     .function = sr_hmac_add_del_key_fn,
3094 };
3095 /* *INDENT-ON* */
3096
3097 /**
3098  * @brief CLI parser for show HMAC key shared secrets
3099  *
3100  * @param vm vlib_main_t *
3101  * @param input unformat_input_t *
3102  * @param cmd vlib_cli_command_t *
3103  *
3104  * @return error clib_error_t *
3105  */
3106 static clib_error_t *
3107 show_sr_hmac_fn (vlib_main_t * vm,
3108                  unformat_input_t * input, vlib_cli_command_t * cmd)
3109 {
3110   ip6_sr_main_t *sm = &sr_main;
3111   int i;
3112
3113   for (i = 1; i < vec_len (sm->hmac_keys); i++)
3114     {
3115       if (sm->hmac_keys[i].shared_secret)
3116         vlib_cli_output (vm, "[%d]: %v", i, sm->hmac_keys[i].shared_secret);
3117     }
3118
3119   return 0;
3120 }
3121
3122 /* *INDENT-OFF* */
3123 VLIB_CLI_COMMAND (show_sr_hmac, static) = {
3124     .path = "show sr hmac",
3125     .short_help = "show sr hmac",
3126     .function = show_sr_hmac_fn,
3127 };
3128 /* *INDENT-ON* */
3129
3130 /**
3131  * @brief Test for SR debug flag
3132  *
3133  * @param vm vlib_main_t *
3134  * @param input unformat_input_t *
3135  * @param cmd vlib_cli_command_t *
3136  *
3137  * @return error clib_error_t *
3138  */
3139 static clib_error_t *
3140 test_sr_debug_fn (vlib_main_t * vm,
3141                   unformat_input_t * input, vlib_cli_command_t * cmd)
3142 {
3143   ip6_sr_main_t *sm = &sr_main;
3144
3145   if (unformat (input, "on"))
3146     sm->is_debug = 1;
3147   else if (unformat (input, "off"))
3148     sm->is_debug = 0;
3149   else
3150     return clib_error_return (0, "expected on|off in '%U'",
3151                               format_unformat_error, input);
3152
3153   vlib_cli_output (vm, "debug trace now %s", sm->is_debug ? "on" : "off");
3154
3155   return 0;
3156 }
3157
3158 /* *INDENT-OFF* */
3159 VLIB_CLI_COMMAND (test_sr_debug, static) = {
3160     .path = "test sr debug",
3161     .short_help = "test sr debug on|off",
3162     .function = test_sr_debug_fn,
3163 };
3164 /* *INDENT-ON* */
3165
3166 /*
3167  * fd.io coding-style-patch-verification: ON
3168  *
3169  * Local Variables:
3170  * eval: (c-set-style "gnu")
3171  * End:
3172  */