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