Add ILA plugin
[vpp.git] / plugins / ila-plugin / ila / ila.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <ila/ila.h>
17 #include <vnet/plugin/plugin.h>
18
19 static ila_main_t ila_main;
20
21 #define ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
22 #define ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE (32<<20)
23
24 #define foreach_ila_error \
25  _(NONE, "valid ILA packets")
26
27 typedef enum {
28 #define _(sym,str) ILA_ERROR_##sym,
29   foreach_ila_error
30 #undef _
31     ILA_N_ERROR,
32 } ila_error_t;
33
34 static char *ila_error_strings[] = {
35 #define _(sym,string) string,
36   foreach_ila_error
37 #undef _
38 };
39
40 typedef enum {
41   ILA_ILA2SIR_NEXT_IP6_REWRITE,
42   ILA_ILA2SIR_NEXT_DROP,
43   ILA_ILA2SIR_N_NEXT,
44 } ila_ila2sir_next_t;
45
46 typedef struct {
47   u32 ila_index;
48   ip6_address_t initial_dst;
49   u32 adj_index;
50 } ila_ila2sir_trace_t;
51
52 static ila_entry_t ila_default_entry = {
53   .csum_mode = ILA_CSUM_MODE_NO_ACTION,
54   .type = ILA_TYPE_IID,
55 };
56
57 u8 *
58 format_half_ip6_address (u8 * s, va_list * va)
59 {
60   u64 v = clib_net_to_host_u64 (va_arg (*va, u64));
61
62   return format (s, "%04x:%04x:%04x:%04x",
63                  v >> 48, (v >> 32) & 0xffff, (v >> 16) & 0xffff, v & 0xffff);
64
65 }
66
67 static u8 *
68 format_csum_mode (u8 * s, va_list * va)
69 {
70   ila_csum_mode_t csum_mode = va_arg (*va, ila_csum_mode_t);
71   char *txt;
72
73   switch (csum_mode)
74     {
75 #define _(i,n,st) \
76   case ILA_CSUM_MODE_##i: \
77     txt = st; \
78     break;
79       ila_csum_foreach_type
80 #undef _
81     default:
82       txt = "(unknown)";
83       break;
84     }
85   return format (s, txt);
86 }
87
88 u8 *
89 format_ila_type (u8 * s, va_list * args)
90 {
91   ila_type_t t = va_arg (*args, ila_type_t);
92 #define _(i,n,st) \
93   if (t == ILA_TYPE_##i) \
94     return format(s, st);
95   ila_foreach_type
96 #undef _
97     return format (s, "invalid type");
98 }
99
100 static u8 *
101 format_ila_entry (u8 * s, va_list * va)
102 {
103   vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
104   ila_entry_t *e = va_arg (*va, ila_entry_t *);
105
106   if (!e)
107     {
108       return format (s, "%-15s%=40s%=40s%+16s%+18s", "Type", "SIR Address",
109                      "ILA Address", "Adjacency Index", "Checksum Mode");
110
111     }
112   else if (vnm)
113     {
114       if (e->ila_adj_index == ~0)
115         {
116           return format (s, "%-15U%=40U%=40U%16s%18U",
117                          format_ila_type, e->type,
118                          format_ip6_address, &e->sir_address,
119                          format_ip6_address, &e->ila_address,
120                          "n/a", format_csum_mode, e->csum_mode);
121         }
122       else
123         {
124           return format (s, "%-15U%=40U%=40U%16d%18U",
125                          format_ila_type, e->type,
126                          format_ip6_address, &e->sir_address,
127                          format_ip6_address, &e->ila_address,
128                          e->ila_adj_index, format_csum_mode, e->csum_mode);
129         }
130     }
131
132   return NULL;
133 }
134
135 u8 *
136 format_ila_ila2sir_trace (u8 * s, va_list * args)
137 {
138   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
139   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
140   ila_ila2sir_trace_t *t = va_arg (*args, ila_ila2sir_trace_t *);
141   return format (s,
142                  "ILA -> SIR adj index: %d entry index: %d initial_dst: %U",
143                  t->adj_index, t->ila_index, format_ip6_address,
144                  &t->initial_dst);
145 }
146
147 static uword
148 unformat_ila_type (unformat_input_t * input, va_list * args)
149 {
150   ila_type_t *result = va_arg (*args, ila_type_t *);
151 #define _(i,n,s) \
152   if (unformat(input, s)) \
153       { \
154         *result = ILA_TYPE_##i; \
155         return 1;\
156       }
157
158   ila_foreach_type
159 #undef _
160     return 0;
161 }
162
163 static uword
164 unformat_ila_csum_mode (unformat_input_t * input, va_list * args)
165 {
166   ila_csum_mode_t *result = va_arg (*args, ila_csum_mode_t *);
167   if (unformat (input, "none") || unformat (input, "no-action"))
168     {
169       *result = ILA_CSUM_MODE_NO_ACTION;
170       return 1;
171     }
172   if (unformat (input, "neutral-map"))
173     {
174       *result = ILA_CSUM_MODE_NEUTRAL_MAP;
175       return 1;
176     }
177   if (unformat (input, "adjust-transport"))
178     {
179       *result = ILA_CSUM_MODE_ADJUST_TRANSPORT;
180       return 1;
181     }
182   return 0;
183 }
184
185 static uword
186 unformat_half_ip6_address (unformat_input_t * input, va_list * args)
187 {
188   u64 *result = va_arg (*args, u64 *);
189   u32 a[4];
190
191   if (!unformat (input, "%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3]))
192     return 0;
193
194   if (a[0] > 0xFFFF || a[1] > 0xFFFF || a[2] > 0xFFFF || a[3] > 0xFFFF)
195     return 0;
196
197   *result = clib_host_to_net_u64 ((((u64) a[0]) << 48) |
198                                   (((u64) a[1]) << 32) |
199                                   (((u64) a[2]) << 16) | (((u64) a[3])));
200
201   return 1;
202 }
203
204 static vlib_node_registration_t ila_ila2sir_node;
205
206 static uword
207 ila_ila2sir (vlib_main_t * vm,
208              vlib_node_runtime_t * node, vlib_frame_t * frame)
209 {
210   ip6_main_t *im = &ip6_main;
211   ip_lookup_main_t *lm = &im->lookup_main;
212   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
213   ila_main_t *ilm = &ila_main;
214
215   from = vlib_frame_vector_args (frame);
216   n_left_from = frame->n_vectors;
217   next_index = node->cached_next_index;
218
219   while (n_left_from > 0)
220     {
221       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
222
223       while (n_left_from >= 4 && n_left_to_next >= 2)
224         {
225           u32 pi0, pi1;
226           vlib_buffer_t *p0, *p1;
227           ip_adjacency_t *adj0, *adj1;
228           ila_entry_t *ie0, *ie1;
229           ip6_header_t *ip60, *ip61;
230           ila_adj_data_t *ad0, *ad1;
231
232           {
233             vlib_buffer_t *p2, *p3;
234
235             p2 = vlib_get_buffer (vm, from[2]);
236             p3 = vlib_get_buffer (vm, from[3]);
237
238             vlib_prefetch_buffer_header (p2, LOAD);
239             vlib_prefetch_buffer_header (p3, LOAD);
240             CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD);
241             CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD);
242           }
243
244           pi0 = to_next[0] = from[0];
245           pi1 = to_next[1] = from[1];
246           from += 2;
247           n_left_from -= 2;
248           to_next += 2;
249           n_left_to_next -= 2;
250
251           p0 = vlib_get_buffer (vm, pi0);
252           p1 = vlib_get_buffer (vm, pi1);
253           ip60 = vlib_buffer_get_current (p0);
254           ip61 = vlib_buffer_get_current (p1);
255           adj0 =
256             ip_get_adjacency (lm, vnet_buffer (p0)->ip.adj_index[VLIB_TX]);
257           adj1 =
258             ip_get_adjacency (lm, vnet_buffer (p1)->ip.adj_index[VLIB_TX]);
259           ad0 = (ila_adj_data_t *) & adj0->opaque;
260           ad1 = (ila_adj_data_t *) & adj1->opaque;
261           ie0 = pool_elt_at_index (ilm->entries, ad0->entry_index);
262           ie1 = pool_elt_at_index (ilm->entries, ad1->entry_index);
263
264           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
265             {
266               ila_ila2sir_trace_t *tr =
267                 vlib_add_trace (vm, node, p0, sizeof (*tr));
268               tr->ila_index = ie0 ? (ie0 - ilm->entries) : ~0;
269               tr->initial_dst = ip60->dst_address;
270               tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
271             }
272
273           if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
274             {
275               ila_ila2sir_trace_t *tr =
276                 vlib_add_trace (vm, node, p1, sizeof (*tr));
277               tr->ila_index = ie1 ? (ie1 - ilm->entries) : ~0;
278               tr->initial_dst = ip61->dst_address;
279               tr->adj_index = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
280             }
281
282           ip60->dst_address.as_u64[0] = ie0->sir_address.as_u64[0];
283           ip60->dst_address.as_u64[1] = ie0->sir_address.as_u64[1];
284           ip61->dst_address.as_u64[0] = ie1->sir_address.as_u64[0];
285           ip61->dst_address.as_u64[1] = ie1->sir_address.as_u64[1];
286
287           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_adj_index;
288           vnet_buffer (p1)->ip.adj_index[VLIB_TX] = ie1->ila_adj_index;
289
290           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
291                                            n_left_to_next, pi0, pi1,
292                                            ILA_ILA2SIR_NEXT_IP6_REWRITE,
293                                            ILA_ILA2SIR_NEXT_IP6_REWRITE);
294         }
295
296       /* Single loop */
297       while (n_left_from > 0 && n_left_to_next > 0)
298         {
299           u32 pi0;
300           vlib_buffer_t *p0;
301           ip_adjacency_t *adj0;
302           ila_adj_data_t *ad0;
303           ila_entry_t *ie0;
304           ip6_header_t *ip60;
305
306           pi0 = to_next[0] = from[0];
307           from += 1;
308           n_left_from -= 1;
309           to_next += 1;
310           n_left_to_next -= 1;
311
312           p0 = vlib_get_buffer (vm, pi0);
313           ip60 = vlib_buffer_get_current (p0);
314           adj0 =
315             ip_get_adjacency (lm, vnet_buffer (p0)->ip.adj_index[VLIB_TX]);
316           ad0 = (ila_adj_data_t *) & adj0->opaque;
317           ie0 = pool_elt_at_index (ilm->entries, ad0->entry_index);
318
319           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
320             {
321               ila_ila2sir_trace_t *tr =
322                 vlib_add_trace (vm, node, p0, sizeof (*tr));
323               tr->ila_index = ie0 ? (ie0 - ilm->entries) : ~0;
324               tr->initial_dst = ip60->dst_address;
325               tr->adj_index = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
326             }
327
328           ip60->dst_address.as_u64[0] = ie0->sir_address.as_u64[0];
329           ip60->dst_address.as_u64[1] = ie0->sir_address.as_u64[1];
330           vnet_buffer (p0)->ip.adj_index[VLIB_TX] = ie0->ila_adj_index;
331
332           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
333                                            n_left_to_next, pi0,
334                                            ILA_ILA2SIR_NEXT_IP6_REWRITE);
335         }
336       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
337     }
338
339   return frame->n_vectors;
340 }
341
342 VLIB_REGISTER_NODE (ila_ila2sir_node, static) =
343 {
344   .function = ila_ila2sir,.name = "ila-to-sir",.vector_size =
345     sizeof (u32),.format_trace = format_ila_ila2sir_trace,.n_errors =
346     ILA_N_ERROR,.error_strings = ila_error_strings,.n_next_nodes =
347     ILA_ILA2SIR_N_NEXT,.next_nodes =
348   {
349   [ILA_ILA2SIR_NEXT_IP6_REWRITE] = "ip6-rewrite",
350       [ILA_ILA2SIR_NEXT_DROP] = "error-drop"}
351 ,};
352
353 typedef enum
354 {
355   ILA_SIR2ILA_NEXT_DROP,
356   ILA_SIR2ILA_N_NEXT,
357 } ila_sir2ila_next_t;
358
359 typedef struct
360 {
361   u32 ila_index;
362   ip6_address_t initial_dst;
363 } ila_sir2ila_trace_t;
364
365 u8 *
366 format_ila_sir2ila_trace (u8 * s, va_list * args)
367 {
368   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
369   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
370   ila_sir2ila_trace_t *t = va_arg (*args, ila_sir2ila_trace_t *);
371
372   return format (s, "SIR -> ILA entry index: %d initial_dst: %U",
373                  t->ila_index, format_ip6_address, &t->initial_dst);
374 }
375
376 static vlib_node_registration_t ila_sir2ila_node;
377
378 static uword
379 ila_sir2ila (vlib_main_t * vm,
380              vlib_node_runtime_t * node, vlib_frame_t * frame)
381 {
382   ip6_main_t *im = &ip6_main;
383   ip_lookup_main_t *lm = &im->lookup_main;
384   ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
385   u32 n_left_from, *from, next_index, *to_next, n_left_to_next;
386   ila_main_t *ilm = &ila_main;
387
388   from = vlib_frame_vector_args (frame);
389   n_left_from = frame->n_vectors;
390   next_index = node->cached_next_index;
391
392   while (n_left_from > 0)
393     {
394       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
395
396       while (n_left_from >= 4 && n_left_to_next >= 2)
397         {
398           u32 pi0, pi1;
399           vlib_buffer_t *p0, *p1;
400           ip6_header_t *ip60, *ip61;
401           u32 next0 = ILA_SIR2ILA_NEXT_DROP;
402           u32 next1 = ILA_SIR2ILA_NEXT_DROP;
403           BVT (clib_bihash_kv) kv0, value0;
404           BVT (clib_bihash_kv) kv1, value1;
405           ila_entry_t *ie0 = &ila_default_entry;
406           ila_entry_t *ie1 = &ila_default_entry;
407
408           {
409             vlib_buffer_t *p2, *p3;
410
411             p2 = vlib_get_buffer (vm, from[2]);
412             p3 = vlib_get_buffer (vm, from[3]);
413
414             vlib_prefetch_buffer_header (p2, LOAD);
415             vlib_prefetch_buffer_header (p3, LOAD);
416             CLIB_PREFETCH (p2->data, sizeof (ip6_header_t), LOAD);
417             CLIB_PREFETCH (p3->data, sizeof (ip6_header_t), LOAD);
418           }
419
420           pi0 = to_next[0] = from[0];
421           pi1 = to_next[1] = from[1];
422           from += 2;
423           n_left_from -= 2;
424           to_next += 2;
425           n_left_to_next -= 2;
426
427           p0 = vlib_get_buffer (vm, pi0);
428           p1 = vlib_get_buffer (vm, pi1);
429           ip60 = vlib_buffer_get_current (p0);
430           ip61 = vlib_buffer_get_current (p1);
431           kv0.key[0] = ip60->dst_address.as_u64[0];
432           kv0.key[1] = ip60->dst_address.as_u64[1];
433           kv0.key[2] = 0;
434           kv1.key[0] = ip61->dst_address.as_u64[0];
435           kv1.key[1] = ip61->dst_address.as_u64[1];
436           kv1.key[2] = 0;
437
438           if ((BV (clib_bihash_search)
439                (&ilm->id_to_entry_table, &kv0, &value0)) == 0)
440             ie0 = &ilm->entries[value0.value];
441
442           if ((BV (clib_bihash_search)
443                (&ilm->id_to_entry_table, &kv1, &value1)) == 0)
444             ie1 = &ilm->entries[value1.value];
445
446           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
447             {
448               ila_sir2ila_trace_t *tr =
449                 vlib_add_trace (vm, node, p0, sizeof (*tr));
450               tr->ila_index =
451                 (ie0 != &ila_default_entry) ? (ie0 - ilm->entries) : ~0;
452               tr->initial_dst = ip60->dst_address;
453             }
454
455           if (PREDICT_FALSE (p1->flags & VLIB_BUFFER_IS_TRACED))
456             {
457               ila_sir2ila_trace_t *tr =
458                 vlib_add_trace (vm, node, p1, sizeof (*tr));
459               tr->ila_index =
460                 (ie1 != &ila_default_entry) ? (ie1 - ilm->entries) : ~0;
461               tr->initial_dst = ip61->dst_address;
462             }
463
464           ip60->dst_address.as_u64[0] = ie0->ila_address.as_u64[0];
465           ip60->dst_address.as_u64[1] = ie0->ila_address.as_u64[1];
466           ip61->dst_address.as_u64[0] = ie1->ila_address.as_u64[0];
467           ip61->dst_address.as_u64[1] = ie1->ila_address.as_u64[1];
468
469           vnet_get_config_data (&cm->config_main,
470                                 &p0->current_config_index, &next0, 0);
471
472           vnet_get_config_data (&cm->config_main,
473                                 &p1->current_config_index, &next1, 0);
474
475           vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
476                                            n_left_to_next, pi0, pi1, next0,
477                                            next1);
478         }
479
480       /* Single loop */
481       while (n_left_from > 0 && n_left_to_next > 0)
482         {
483           u32 pi0;
484           vlib_buffer_t *p0;
485           ip6_header_t *ip60;
486           u32 next0 = ILA_SIR2ILA_NEXT_DROP;
487           BVT (clib_bihash_kv) kv0, value0;
488           ila_entry_t *ie0 = &ila_default_entry;
489
490           pi0 = to_next[0] = from[0];
491           from += 1;
492           n_left_from -= 1;
493           to_next += 1;
494           n_left_to_next -= 1;
495
496           p0 = vlib_get_buffer (vm, pi0);
497           ip60 = vlib_buffer_get_current (p0);
498           kv0.key[0] = ip60->dst_address.as_u64[0];
499           kv0.key[1] = ip60->dst_address.as_u64[1];
500           kv0.key[2] = 0;
501
502           if ((BV (clib_bihash_search)
503                (&ilm->id_to_entry_table, &kv0, &value0)) == 0)
504             ie0 = &ilm->entries[value0.value];
505
506           if (PREDICT_FALSE (p0->flags & VLIB_BUFFER_IS_TRACED))
507             {
508               ila_sir2ila_trace_t *tr =
509                 vlib_add_trace (vm, node, p0, sizeof (*tr));
510               tr->ila_index =
511                 (ie0 != &ila_default_entry) ? (ie0 - ilm->entries) : ~0;
512               tr->initial_dst = ip60->dst_address;
513             }
514
515           //This operation should do everything for any type (except vnid4 obviously)
516           ip60->dst_address.as_u64[0] = ie0->ila_address.as_u64[0];
517           ip60->dst_address.as_u64[1] = ie0->ila_address.as_u64[1];
518
519           vnet_get_config_data (&cm->config_main,
520                                 &p0->current_config_index, &next0, 0);
521
522           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
523                                            n_left_to_next, pi0, next0);
524         }
525       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
526     }
527
528   return frame->n_vectors;
529 }
530
531 VLIB_REGISTER_NODE (ila_sir2ila_node, static) =
532 {
533   .function = ila_sir2ila,.name = "sir-to-ila",.vector_size =
534     sizeof (u32),.format_trace = format_ila_sir2ila_trace,.n_errors =
535     ILA_N_ERROR,.error_strings = ila_error_strings,.n_next_nodes =
536     ILA_SIR2ILA_N_NEXT,.next_nodes =
537   {
538   [ILA_SIR2ILA_NEXT_DROP] = "error-drop"}
539 ,};
540
541 VNET_IP6_UNICAST_FEATURE_INIT (ila_sir2ila, static) =
542 {
543   .node_name = "sir-to-ila",.runs_before =
544   {
545 "ip6-lookup", 0},.feature_index = &ila_main.ila_sir2ila_feature_index,};
546
547 int
548 ila_add_del_entry (ila_add_del_entry_args_t * args)
549 {
550   ila_main_t *ilm = &ila_main;
551   ip6_main_t *im6 = &ip6_main;
552   BVT (clib_bihash_kv) kv, value;
553
554   //Sanity check
555   if (args->type == ILA_TYPE_IID || args->type == ILA_TYPE_LUID)
556     {
557       if ((args->sir_address.as_u8[8] >> 5) != args->type)
558         {
559           clib_warning ("Incorrect SIR address (ILA type mismatch %d %d)",
560                         args->sir_address.as_u8[8] >> 1, args->type);
561           return -1;
562         }
563       if (args->sir_address.as_u8[8] & 0x10)
564         {
565           clib_warning ("Checksum bit should not be set in SIR address");
566           return -1;
567         }
568     }
569   else if (args->type == ILA_TYPE_VNIDM)
570     {
571       if (args->sir_address.as_u8[0] != 0xff ||
572           (args->sir_address.as_u8[1] & 0xf0) != 0xf0)
573         {
574           clib_warning ("SIR multicast address must start with fff");
575           return -1;
576         }
577       if (args->sir_address.as_u16[1] || args->sir_address.as_u16[2] ||
578           args->sir_address.as_u16[3] || args->sir_address.as_u16[4] ||
579           args->sir_address.as_u16[5] || (args->sir_address.as_u8[12] & 0xf0))
580         {
581           clib_warning ("SIR multicast address must start with fff");
582           return -1;
583         }
584     }
585
586   if (!args->is_del)
587     {
588       ila_entry_t *e;
589       pool_get (ilm->entries, e);
590       e->type = args->type;
591       e->sir_address = args->sir_address;
592       e->ila_adj_index = args->local_adj_index;
593       e->csum_mode = args->csum_mode;
594
595       //Construct ILA address
596       switch (e->type)
597         {
598         case ILA_TYPE_IID:
599           e->ila_address = e->sir_address;
600           break;
601         case ILA_TYPE_LUID:
602           e->ila_address.as_u64[0] = args->locator;
603           e->ila_address.as_u64[1] = args->sir_address.as_u64[1];
604           break;
605         case ILA_TYPE_VNID6:
606           e->ila_address.as_u64[0] = args->locator;
607           e->ila_address.as_u8[8] = (ILA_TYPE_VNID6 << 1);
608           e->ila_address.as_u32[2] |= args->vnid;
609           e->ila_address.as_u32[3] = args->sir_address.as_u32[3];
610           break;
611         case ILA_TYPE_VNIDM:
612           e->ila_address.as_u64[0] = args->locator;
613           e->ila_address.as_u8[8] = (ILA_TYPE_VNIDM << 1);
614           e->ila_address.as_u32[2] |= args->vnid;
615           e->ila_address.as_u32[3] = args->sir_address.as_u32[3];
616           e->ila_address.as_u8[12] |= args->sir_address.as_u8[2] << 4;
617           break;
618         case ILA_TYPE_VNID4:
619           clib_warning ("ILA type '%U' is not supported", format_ila_type,
620                         e->type);
621           return -1;
622         }
623
624       //Modify ILA checksum if necessary
625       if (e->csum_mode == ILA_CSUM_MODE_NEUTRAL_MAP)
626         {
627           ip_csum_t csum = e->ila_address.as_u16[7];
628           int i;
629           for (i = 0; i < 4; i++)
630             {
631               csum = ip_csum_sub_even (csum, e->sir_address.as_u32[i]);
632               csum = ip_csum_add_even (csum, e->ila_address.as_u32[i]);
633             }
634           csum = ip_csum_add_even (csum, clib_host_to_net_u16 (0x1000));
635           e->ila_address.as_u16[7] = ip_csum_fold (csum);
636           e->ila_address.as_u8[8] |= 0x10;
637         }
638
639       //Create entry with the sir address
640       kv.key[0] = e->sir_address.as_u64[0];
641       kv.key[1] = e->sir_address.as_u64[1];
642       kv.key[2] = 0;
643       kv.value = e - ilm->entries;
644       BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv,
645                                 1 /* is_add */ );
646
647       if (e->ila_adj_index != ~0)
648         {
649           //This is a local entry - let's create a local adjacency
650           ip_adjacency_t adj;
651           ip6_add_del_route_args_t route_args;
652           ila_adj_data_t *ad;
653
654           //Adjacency
655           memset (&adj, 0, sizeof (adj));
656           adj.explicit_fib_index = ~0;
657           adj.lookup_next_index = ilm->ip6_lookup_next_index;
658           ad = (ila_adj_data_t *) & adj.opaque;
659           ad->entry_index = e - ilm->entries;
660
661           //Route
662           memset (&route_args, 0, sizeof (route_args));
663           route_args.table_index_or_table_id = 0;
664           route_args.flags = IP6_ROUTE_FLAG_ADD;
665           route_args.dst_address = e->ila_address;
666           route_args.dst_address_length = 128;
667           route_args.adj_index = ~0;
668           route_args.add_adj = &adj;
669           route_args.n_add_adj = 1;
670
671           ip6_add_del_route (im6, &route_args);
672         }
673     }
674   else
675     {
676       ila_entry_t *e;
677       kv.key[0] = args->sir_address.as_u64[0];
678       kv.key[1] = args->sir_address.as_u64[1];
679       kv.key[2] = 0;
680
681       if ((BV (clib_bihash_search) (&ilm->id_to_entry_table, &kv, &value) <
682            0))
683         {
684           return -1;
685         }
686
687       e = &ilm->entries[value.value];
688
689       if (e->ila_adj_index != ~0)
690         {
691           //Delete that route - Associated adjacency will be deleted too
692           ip6_add_del_route_args_t route_args;
693           memset (&route_args, 0, sizeof (route_args));
694           route_args.table_index_or_table_id = 0;
695           route_args.flags = IP6_ROUTE_FLAG_DEL;
696           route_args.dst_address = e->ila_address;
697           route_args.dst_address_length = 128;
698           route_args.adj_index = ~0;
699           route_args.add_adj = NULL;
700           route_args.n_add_adj = 0;
701
702           ip6_add_del_route (im6, &route_args);
703         }
704
705       BV (clib_bihash_add_del) (&ilm->id_to_entry_table, &kv,
706                                 0 /* is_add */ );
707       pool_put (ilm->entries, e);
708     }
709   return 0;
710 }
711
712 int
713 ila_interface (u32 sw_if_index, u8 disable)
714 {
715   vlib_main_t *vm = vlib_get_main ();
716   ila_main_t *ilm = &ila_main;
717   ip6_main_t *im = &ip6_main;
718   ip_lookup_main_t *lm = &im->lookup_main;
719   ip_config_main_t *cm = &lm->rx_config_mains[VNET_UNICAST];
720   vnet_config_main_t *vcm = &cm->config_main;
721   u32 ci, feature_index;
722
723   vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
724   ci = cm->config_index_by_sw_if_index[sw_if_index];
725   feature_index = ilm->ila_sir2ila_feature_index;
726
727   ci = ((disable) ? vnet_config_del_feature : vnet_config_add_feature)
728     (vm, vcm, ci, feature_index,
729      /* config data */ 0,
730      /* # bytes of config data */ 0);
731
732   cm->config_index_by_sw_if_index[sw_if_index] = ci;
733   return 0;
734 }
735
736 clib_error_t *
737 vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
738                       int from_early_init)
739 {
740   clib_error_t *error = 0;
741
742   return error;
743 }
744
745 clib_error_t *
746 ila_init (vlib_main_t * vm)
747 {
748   ila_main_t *ilm = &ila_main;
749   ilm->entries = NULL;
750
751   ASSERT (sizeof (ila_adj_data_t) < IP_ADJACENCY_OPAQUE_SZ);
752
753   ilm->lookup_table_nbuckets = ILA_TABLE_DEFAULT_HASH_NUM_BUCKETS;
754   ilm->lookup_table_nbuckets = 1 << max_log2 (ilm->lookup_table_nbuckets);
755   ilm->lookup_table_size = ILA_TABLE_DEFAULT_HASH_MEMORY_SIZE;
756
757   BV (clib_bihash_init) (&ilm->id_to_entry_table,
758                          "ila id to entry index table",
759                          ilm->lookup_table_nbuckets, ilm->lookup_table_size);
760
761   vlib_node_t *ip6_lookup_node =
762     vlib_get_node_by_name (vm, (u8 *) "ip6-lookup");
763
764   ilm->ip6_lookup_next_index =
765     vlib_node_add_next (vm, ip6_lookup_node->index, ila_ila2sir_node.index);
766   return NULL;
767 }
768
769 VLIB_INIT_FUNCTION (ila_init);
770
771 static clib_error_t *
772 ila_entry_command_fn (vlib_main_t * vm,
773                       unformat_input_t * input, vlib_cli_command_t * cmd)
774 {
775   unformat_input_t _line_input, *line_input = &_line_input;
776   ila_add_del_entry_args_t args = { 0 };
777   ip6_address_t next_hop;
778   u8 next_hop_set = 0;
779   ip6_main_t *im6 = &ip6_main;
780   int ret;
781
782   args.type = ILA_TYPE_IID;
783   args.csum_mode = ILA_CSUM_MODE_NO_ACTION;
784   args.local_adj_index = ~0;
785
786   if (!unformat_user (input, unformat_line_input, line_input))
787     return 0;
788
789   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
790     {
791       if (unformat (line_input, "type %U", unformat_ila_type, &args.type))
792         ;
793       else
794         if (unformat
795             (line_input, "sir-address %U", unformat_ip6_address,
796              &args.sir_address))
797         ;
798       else
799         if (unformat
800             (line_input, "locator %U", unformat_half_ip6_address,
801              &args.locator))
802         ;
803       else if (unformat (line_input, "adj-index %u", &args.local_adj_index))
804         ;
805       else
806         if (unformat
807             (line_input, "csum-mode %U", unformat_ila_csum_mode,
808              &args.csum_mode))
809         ;
810       else if (unformat (line_input, "vnid %x", &args.vnid))
811         ;
812       else
813         if (unformat
814             (line_input, "next-hop %U", unformat_ip6_address, &next_hop))
815         next_hop_set = 1;
816       else if (unformat (line_input, "del"))
817         args.is_del = 1;
818       else
819         return clib_error_return (0, "parse error: '%U'",
820                                   format_unformat_error, line_input);
821     }
822
823   unformat_free (line_input);
824
825   if (next_hop_set)
826     {
827       if (args.local_adj_index != ~0)
828         return clib_error_return (0,
829                                   "Specified both next hop and adjacency index");
830
831       u32 ai = ip6_get_route (im6, 0, 0, &next_hop, 128);
832       if (ai == 0)
833         return clib_error_return (0, "No route to next-hop %U",
834                                   format_ip6_address, &next_hop);
835
836       ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
837       ip_adjacency_t *adj6 = ip_get_adjacency (lm6, ai);
838       if (adj6->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
839         {
840           return clib_error_return (0,
841                                     "Next-Hop route has to be a rewrite route");
842         }
843       args.local_adj_index = ai;
844     }
845
846   if ((ret = ila_add_del_entry (&args)))
847     return clib_error_return (0, "ila_add_del_entry returned error %d", ret);
848
849   return NULL;
850 }
851
852 VLIB_CLI_COMMAND (ila_entry_command, static) =
853 {
854   .path = "ila entry",
855   .short_help = "ila entry [type <type>] [sir-address <address>] [locator <locator>] [vnid <hex-vnid>]"
856     " [adj-index <adj-index>] [next-hop <next-hop>]"
857     " [csum-mode (no-action|neutral-map|transport-adjust)] [del]",
858   .function = ila_entry_command_fn,
859 };
860
861 static clib_error_t *
862 ila_interface_command_fn (vlib_main_t * vm,
863                           unformat_input_t * input, vlib_cli_command_t * cmd)
864 {
865   vnet_main_t *vnm = vnet_get_main ();
866   u32 sw_if_index = ~0;
867   u8 disable = 0;
868
869   if (!unformat (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
870     {
871       return clib_error_return (0, "Invalid interface name");
872     }
873
874   if (unformat (input, "disable"))
875     {
876       disable = 1;
877     }
878
879   int ret;
880   if ((ret = ila_interface (sw_if_index, disable)))
881     return clib_error_return (0, "ila_interface returned error %d", ret);
882
883   return NULL;
884 }
885
886 VLIB_CLI_COMMAND (ila_interface_command, static) =
887 {
888   .path = "ila interface",
889   .short_help = "ila interface <interface-name> [disable]",
890   .function = ila_interface_command_fn,
891 };
892
893 static clib_error_t *
894 ila_show_entries_command_fn (vlib_main_t * vm,
895                              unformat_input_t * input,
896                              vlib_cli_command_t * cmd)
897 {
898   vnet_main_t *vnm = vnet_get_main ();
899   ila_main_t *ilm = &ila_main;
900   ila_entry_t *e;
901
902   vlib_cli_output (vm, "  %U\n", format_ila_entry, vnm, NULL);
903   pool_foreach (e, ilm->entries,
904     ({
905       vlib_cli_output (vm, "  %U\n", format_ila_entry, vnm, e);
906     }));
907
908   return NULL;
909 }
910
911 VLIB_CLI_COMMAND (ila_show_entries_command, static) =
912 {
913   .path = "show ila entries",
914   .short_help = "show ila entries",
915   .function = ila_show_entries_command_fn,
916 };