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