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