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