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