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