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