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