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