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