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