ONE-4: Add LISP enable/disable API/CLI
[vpp.git] / vnet / vnet / lisp-cp / control.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 <vnet/lisp-cp/control.h>
17 #include <vnet/lisp-cp/packets.h>
18 #include <vnet/lisp-cp/lisp_msg_serdes.h>
19 #include <vnet/lisp-gpe/lisp_gpe.h>
20
21 /* Stores mapping in map-cache. It does NOT program data plane forwarding for
22  * remote/learned mappings. */
23 int
24 vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
25                            u32 * map_index_result)
26 {
27   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
28   u32 mi, * map_indexp, map_index, i;
29   mapping_t * m;
30   u32 ** eid_indexes;
31
32   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->deid);
33   if (a->is_add)
34     {
35       /* TODO check if overwriting and take appropriate actions */
36       if (mi != GID_LOOKUP_MISS)
37         {
38           clib_warning("eid %U found in the eid-table", format_ip_address,
39                        &a->deid);
40           return VNET_API_ERROR_VALUE_EXIST;
41         }
42
43       pool_get(lcm->mapping_pool, m);
44       m->eid = a->deid;
45       m->locator_set_index = a->locator_set_index;
46       m->ttl = a->ttl;
47       m->local = a->local;
48
49       map_index = m - lcm->mapping_pool;
50       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->deid, map_index,
51                               1);
52
53       if (pool_is_free_index(lcm->locator_set_pool, a->locator_set_index))
54         {
55           clib_warning("Locator set with index %d doesn't exist",
56                        a->locator_set_index);
57           return VNET_API_ERROR_INVALID_VALUE;
58         }
59
60       /* add eid to list of eids supported by locator-set */
61       vec_validate (lcm->locator_set_to_eids, a->locator_set_index);
62       eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
63                                      a->locator_set_index);
64       vec_add1(eid_indexes[0], map_index);
65
66       if (a->local)
67         {
68           /* mark as local */
69           vec_add1(lcm->local_mappings_indexes, map_index);
70         }
71       map_index_result[0] = map_index;
72     }
73   else
74     {
75       if (mi == GID_LOOKUP_MISS)
76         {
77           clib_warning("eid %U not found in the eid-table", format_ip_address,
78                        &a->deid);
79           return VNET_API_ERROR_INVALID_VALUE;
80         }
81
82       /* clear locator-set to eids binding */
83       eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
84                                      a->locator_set_index);
85       for (i = 0; i < vec_len(eid_indexes[0]); i++)
86         {
87           map_indexp = vec_elt_at_index(eid_indexes[0], i);
88           if (map_indexp[0] == mi)
89               break;
90         }
91       vec_del1(eid_indexes[0], i);
92
93       /* remove local mark if needed */
94       m = pool_elt_at_index(lcm->mapping_pool, mi);
95       if (m->local)
96         {
97           u32 k, * lm_indexp;
98           for (k = 0; k < vec_len(lcm->local_mappings_indexes); k++)
99             {
100               lm_indexp = vec_elt_at_index(lcm->local_mappings_indexes, k);
101               if (lm_indexp[0] == mi)
102                 break;
103             }
104           vec_del1(lcm->local_mappings_indexes, k);
105         }
106       else
107         {
108           /* remove tunnel ??? */
109         }
110
111       /* remove mapping from dictionary */
112       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->deid, 0, 0);
113       pool_put_index (lcm->mapping_pool, mi);
114     }
115
116   return 0;
117 }
118
119 /* Stores mapping in map-cache and programs data plane for local mappings. */
120 int
121 vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
122                                  u32 * map_index_result)
123 {
124   uword * table_id, * refc;
125   u32 rv, vni;
126   vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
127   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
128
129   vni = gid_address_vni(&a->deid);
130
131   /* store/remove mapping from map-cache */
132   rv = vnet_lisp_add_del_mapping (a, map_index_result);
133   if (rv)
134     return rv;
135
136   table_id = hash_get(lcm->table_id_by_vni, vni);
137
138   if (!table_id)
139     {
140       clib_warning ("vni %d not associated to a vrf!", vni);
141       return VNET_API_ERROR_INVALID_VALUE;
142     }
143
144   refc = hash_get(lcm->dp_if_refcount_by_vni, vni);
145
146   /* enable/disable data-plane interface */
147   if (a->is_add)
148     {
149       /* create interface or update refcount */
150       if (!refc)
151         {
152           ai->is_add = 1;
153           ai->vni = vni;
154           ai->table_id = table_id[0];
155           vnet_lisp_gpe_add_del_iface (ai, 0);
156
157           /* counts the number of eids in a vni that use the interface */
158           hash_set(lcm->dp_if_refcount_by_vni, vni, 1);
159         }
160       else
161         {
162           refc[0]++;
163         }
164     }
165   else
166     {
167       /* since this is a remove for an existing eid, the iface should exist */
168       ASSERT(refc != 0);
169       refc[0]--;
170
171       /* remove iface if needed */
172       if (refc[0] == 0)
173         {
174           ai->is_add = 0;
175           ai->vni = vni;
176           ai->table_id = table_id[0];
177           vnet_lisp_gpe_add_del_iface (ai, 0);
178         }
179     }
180
181   return rv;
182 }
183
184 static clib_error_t *
185 lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
186                                    vlib_cli_command_t * cmd)
187 {
188   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
189   unformat_input_t _line_input, * line_input = &_line_input;
190   u8 is_add = 1;
191   gid_address_t eid;
192   ip_prefix_t * prefp = &gid_address_ippref(&eid);
193   gid_address_t * eids = 0;
194   clib_error_t * error = 0;
195   u8 * locator_set_name;
196   u32 locator_set_index = 0, map_index = 0;
197   uword * p;
198   vnet_lisp_add_del_mapping_args_t _a, * a = &_a;
199
200   gid_address_type (&eid) = GID_ADDR_IP_PREFIX;
201
202   /* Get a line of input. */
203   if (! unformat_user (input, unformat_line_input, line_input))
204     return 0;
205
206   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
207     {
208       if (unformat (line_input, "add"))
209         is_add = 1;
210       else if (unformat (line_input, "del"))
211         is_add = 0;
212       else if (unformat (line_input, "eid %U", unformat_ip_prefix, prefp))
213         {
214           vec_add1(eids, eid);
215         }
216       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
217         {
218           p = hash_get_mem(lcm->locator_set_index_by_name, locator_set_name);
219           if (!p)
220             {
221               error = clib_error_return(0, "locator-set %s doesn't exist",
222                                         locator_set_name);
223               goto done;
224             }
225           locator_set_index = p[0];
226         }
227       else
228         {
229           error = unformat_parse_error(line_input);
230           goto done;
231         }
232     }
233
234   /* XXX treat batch configuration */
235   a->deid = eid;
236   a->is_add = is_add;
237   a->locator_set_index = locator_set_index;
238   a->local = 1;
239
240   vnet_lisp_add_del_local_mapping (a, &map_index);
241  done:
242   vec_free(eids);
243   return error;
244 }
245
246 VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = {
247     .path = "lisp eid-table",
248     .short_help = "lisp eid-table add/del eid <eid> locator-set <locator-set>",
249     .function = lisp_add_del_local_eid_command_fn,
250 };
251
252 static clib_error_t *
253 lisp_show_local_eid_table_command_fn (vlib_main_t * vm,
254                                       unformat_input_t * input,
255                                       vlib_cli_command_t * cmd)
256 {
257   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
258   mapping_t * mapit;
259
260   vlib_cli_output (vm, "%=20s%=16s", "EID", "Locator");
261   pool_foreach (mapit, lcm->mapping_pool,
262   ({
263     u8 * msg = 0;
264     locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
265                                             mapit->locator_set_index);
266     vlib_cli_output (vm, "%-16U%16v", format_gid_address, &mapit->eid,
267                      ls->name);
268     vec_free (msg);
269   }));
270
271   return 0;
272 }
273
274 VLIB_CLI_COMMAND (lisp_cp_show_local_eid_table_command) = {
275     .path = "show lisp eid-table",
276     .short_help = "Shows local EID table",
277     .function = lisp_show_local_eid_table_command_fn,
278 };
279
280 /* cleans locator to locator-set data and removes locators not part of
281  * any locator-set */
282 static void
283 clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
284 {
285   u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes;
286   locator_set_t * ls = pool_elt_at_index(lcm->locator_set_pool, lsi);
287   for (i = 0; i < vec_len(ls->locator_indices); i++)
288     {
289       loc_indexp = vec_elt_at_index(ls->locator_indices, i);
290       ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
291                                     loc_indexp[0]);
292       for (j = 0; j < vec_len(ls_indexes[0]); j++)
293         {
294           ls_indexp = vec_elt_at_index(ls_indexes[0], j);
295           if (ls_indexp[0] == lsi)
296             break;
297         }
298
299       /* delete index for removed locator-set*/
300       vec_del1(ls_indexes[0], j);
301
302       /* delete locator if it's part of no locator-set */
303       if (vec_len (ls_indexes[0]) == 0)
304         pool_put_index(lcm->locator_pool, loc_indexp[0]);
305     }
306 }
307 int
308 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
309                                u32 * ls_result)
310 {
311   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
312   locator_set_t * ls;
313   locator_t * loc, * itloc;
314   uword _p = (u32)~0, * p = &_p;
315   u32 loc_index, ls_index, ** ls_indexes;
316   u32 **eid_indexes;
317
318   if (a->is_add)
319     {
320       /* check if overwrite */
321       if (a->local)
322         p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
323       else
324         *p = a->index;
325
326       /* overwrite */
327       if (p && p[0] != (u32)~0)
328         {
329           ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
330           if (!ls)
331             {
332               clib_warning("locator-set %d to be overwritten doesn't exist!",
333                            p[0]);
334               return -1;
335             }
336
337           /* clean locator to locator-set vectors and remove locators if
338            * they're not part of another locator-set */
339           clean_locator_to_locator_set (lcm, p[0]);
340
341           /* remove locator indices from locator set */
342           vec_free(ls->locator_indices);
343
344           ls_index = p[0];
345
346           if (ls_result)
347             ls_result[0] = p[0];
348         }
349       /* new locator-set */
350       else
351         {
352           pool_get(lcm->locator_set_pool, ls);
353           ls_index = ls - lcm->locator_set_pool;
354
355           if (a->local)
356             {
357               ls->name = vec_dup(a->name);
358
359               if (!lcm->locator_set_index_by_name)
360                 lcm->locator_set_index_by_name = hash_create_vec(
361                     /* size */0, sizeof(ls->name[0]), sizeof(uword));
362               hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index);
363
364               /* mark as local locator-set */
365               vec_add1(lcm->local_locator_set_indexes, ls_index);
366             }
367           ls->local = a->local;
368           if (ls_result)
369             ls_result[0] = ls_index;
370         }
371
372       /* allocate locators */
373       vec_foreach (itloc, a->locators)
374         {
375           pool_get(lcm->locator_pool, loc);
376           loc[0] = itloc[0];
377           loc_index = loc - lcm->locator_pool;
378
379           vec_add1(ls->locator_indices, loc_index);
380
381           vec_validate (lcm->locator_to_locator_sets, loc_index);
382           ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
383                                         loc_index);
384           vec_add1(ls_indexes[0], ls_index);
385         }
386     }
387   else
388     {
389       /* find locator-set */
390       if (a->local)
391         {
392           p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
393           if (!p)
394             {
395               clib_warning("locator-set %v doesn't exists", a->name);
396               return -1;
397             }
398         }
399       else
400         *p = a->index;
401
402       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
403       if (!ls)
404         {
405           clib_warning("locator-set with index %d doesn't exists", p[0]);
406           return -1;
407         }
408 //      /* XXX what happens when a mapping is configured to use the loc-set ? */
409 //      if (vec_len (vec_elt_at_index(lcm->locator_set_to_eids, p[0])) != 0)
410 //        {
411 //          clib_warning ("Can't delete a locator that supports a mapping!");
412 //          return -1;
413 //        }
414
415       if (vec_len(lcm->locator_set_to_eids) != 0)
416       {
417           eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, p[0]);
418           if (vec_len(eid_indexes[0]) != 0)
419           {
420               clib_warning ("Can't delete a locator that supports a mapping!");
421               return -1;
422           }
423       }
424
425       /* clean locator to locator-sets data */
426       clean_locator_to_locator_set (lcm, p[0]);
427
428       if (ls->local)
429         {
430           u32 it, lsi;
431
432           vec_foreach_index(it, lcm->local_locator_set_indexes)
433           {
434             lsi = vec_elt(lcm->local_locator_set_indexes, it);
435             if (lsi == p[0])
436               {
437                 vec_del1(lcm->local_locator_set_indexes, it);
438                 break;
439               }
440           }
441           hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
442           vec_free(ls->name);
443         }
444       pool_put(lcm->locator_set_pool, ls);
445     }
446   return 0;
447 }
448
449 static inline
450 uword *vnet_lisp_get_locator(vnet_lisp_add_del_locator_set_args_t * a,
451                              uword *p)
452 {
453   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
454
455   ASSERT(a != NULL);
456   ASSERT(p != NULL);
457
458   /* find locator-set */
459   if (a->local)
460   {
461       p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
462   }
463   else
464   {
465       *p = a->index;
466   }
467
468   return p;
469 }
470
471 int
472 vnet_lisp_add_del_locator_set_name (vnet_lisp_add_del_locator_set_args_t * a,
473                                     u32 * ls_result)
474 {
475   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
476   locator_set_t * ls;
477   uword _p = (u32)~0, * p = &_p;
478   u32 ls_index = ~0;
479   u32 **eid_indexes = NULL;
480
481   ASSERT(a != NULL);
482   ASSERT(ls_result != NULL);
483
484   p = vnet_lisp_get_locator(a, p);
485
486   if (a->is_add)
487     {
488       /* overwrite */
489       if (p && p[0] != (u32)~0)
490         {
491           ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
492           if (!ls)
493             {
494               clib_warning("locator-set %d to be overwritten doesn't exist!",
495                            p[0]);
496               return VNET_API_ERROR_UNSPECIFIED;
497             }
498
499           /* clean locator to locator-set vectors and remove locators if
500            * they're not part of another locator-set */
501           clean_locator_to_locator_set (lcm, p[0]);
502
503           /* remove locator indices from locator set */
504           vec_free(ls->locator_indices);
505
506           ls_index = p[0];
507
508           if (ls_result)
509             ls_result[0] = p[0];
510         }
511       /* new locator-set */
512       else
513         {
514           pool_get(lcm->locator_set_pool, ls);
515           ls_index = ls - lcm->locator_set_pool;
516
517           if (a->local)
518             {
519               ls->name = vec_dup(a->name);
520
521               if (!lcm->locator_set_index_by_name)
522                 lcm->locator_set_index_by_name = hash_create_vec(
523                     /* size */0, sizeof(ls->name[0]), sizeof(uword));
524               hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index);
525
526               /* mark as local locator-set */
527               vec_add1(lcm->local_locator_set_indexes, ls_index);
528             }
529           ls->local = a->local;
530           ls->locator_indices = NULL;
531           if (ls_result)
532             ls_result[0] = ls_index;
533         }
534     }
535   else
536     {
537        if (!p)
538        {
539            clib_warning("locator-set %v doesn't exists", a->name);
540            return VNET_API_ERROR_INVALID_ARGUMENT;
541        }
542
543        ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
544        if (!ls)
545        {
546            clib_warning("locator-set with index %d doesn't exists", p[0]);
547            return VNET_API_ERROR_INVALID_ARGUMENT;
548        }
549
550       if (vec_len(lcm->locator_set_to_eids) != 0)
551       {
552           eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, p[0]);
553           if (vec_len(eid_indexes[0]) != 0)
554           {
555               clib_warning ("Can't delete a locator that supports a mapping!");
556               return -1;
557           }
558       }
559
560       /* clean locator to locator-sets data */
561       clean_locator_to_locator_set (lcm, p[0]);
562
563       if (ls->local)
564         {
565           u32 it, lsi;
566
567           vec_foreach_index(it, lcm->local_locator_set_indexes)
568             {
569               lsi = vec_elt(lcm->local_locator_set_indexes, it);
570               if (lsi == p[0])
571                 {
572                   vec_del1(lcm->local_locator_set_indexes, it);
573                   break;
574                 }
575             }
576           hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
577           vec_free(ls->name);
578         }
579       pool_put(lcm->locator_set_pool, ls);
580     }
581   return 0;
582 }
583
584 int
585 vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t *a,
586                            u32 *ls_result)
587 {
588   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
589   locator_set_t *ls = NULL;
590   locator_t *loc = NULL, *itloc = NULL;
591   uword _p = (u32)~0, * p = &_p;
592   u32 loc_index = ~0, ls_index = ~0, *locit = NULL, **ls_indexes = NULL;
593   u32 i = ~0;
594
595   ASSERT(a != NULL);
596   ASSERT(ls_result != NULL);
597
598   p = vnet_lisp_get_locator(a, p);
599   if (!p) {
600       clib_warning("locator-set %v doesn't exists", a->name);
601       return VNET_API_ERROR_INVALID_ARGUMENT;
602   }
603
604   ls_index = p[0];
605
606   if (a->is_add)
607     {
608         ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
609         if (!ls)
610         {
611             clib_warning("locator-set %d to be overwritten doesn't exist!",
612                          p[0]);
613             return VNET_API_ERROR_INVALID_ARGUMENT;
614         }
615
616         if (ls_result)
617             ls_result[0] = p[0];
618
619       /* allocate locators */
620       itloc = a->locators;
621       pool_get(lcm->locator_pool, loc);
622       loc[0] = itloc[0];
623       loc_index = loc - lcm->locator_pool;
624
625       vec_add1(ls->locator_indices, loc_index);
626
627       vec_validate (lcm->locator_to_locator_sets, loc_index);
628       ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
629                                     loc_index);
630       vec_add1(ls_indexes[0], ls_index);
631     }
632   else
633     {
634       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
635       if (!ls)
636         {
637           clib_warning("locator-set with index %d doesn't exists", p[0]);
638           return VNET_API_ERROR_INVALID_ARGUMENT;
639         }
640
641       if (ls->local)
642       {
643           itloc = a->locators;
644           i = 0;
645           vec_foreach (locit, ls->locator_indices)
646           {
647               loc = pool_elt_at_index(lcm->locator_pool, locit[0]);
648               if (loc->local && loc->sw_if_index == itloc->sw_if_index)
649               {
650                   ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
651                                                 locit[0]);
652                   pool_put_index(lcm->locator_pool, locit[0]);
653                   vec_del1(ls->locator_indices, i);
654                   vec_del1(ls_indexes[0], ls_index);
655               }
656               i++;
657           }
658       }
659     }
660   return 0;
661 }
662
663 clib_error_t *
664 vnet_lisp_enable_disable (u8 is_enabled)
665 {
666   vnet_lisp_gpe_add_del_iface_args_t _ai, * ai= &_ai;
667   uword * table_id, * refc;
668   u32 i;
669   clib_error_t * error = 0;
670   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
671   vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
672
673   a->is_en = is_enabled;
674   error = vnet_lisp_gpe_enable_disable (a);
675   if (error)
676     {
677       return clib_error_return (0, "failed to %s data-plane!",
678                                 a->is_en ? "enable" : "disable");
679     }
680
681   if (is_enabled)
682     {
683       /* enable all ifaces */
684       for (i = 0; i < vec_len (lcm->local_mappings_indexes); i++)
685         {
686           mapping_t * m = vec_elt_at_index (lcm->mapping_pool, i);
687           ai->is_add = 1;
688           ai->vni = gid_address_vni (&m->eid);
689
690           refc = hash_get (lcm->dp_if_refcount_by_vni, ai->vni);
691           if (!refc)
692             {
693               table_id = hash_get (lcm->table_id_by_vni, ai->vni);
694               if (table_id)
695                 {
696                   ai->table_id = table_id[0];
697                   /* enables interface and adds defaults */
698                   vnet_lisp_gpe_add_del_iface (ai, 0);
699                 }
700               else
701                 return clib_error_return (0, "no table_id found for vni %u!",
702                                           ai->vni);
703
704               hash_set (lcm->dp_if_refcount_by_vni, ai->vni, 1);
705             }
706           else
707             {
708               refc[0]++;
709             }
710         }
711     }
712   else
713     {
714       /* clear refcount table */
715       hash_free (lcm->dp_if_refcount_by_vni);
716     }
717
718   /* update global flag */
719   lcm->is_enabled = is_enabled;
720
721   return 0;
722 }
723
724 static clib_error_t *
725 lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
726                                    vlib_cli_command_t * cmd)
727 {
728   unformat_input_t _line_input, * line_input = &_line_input;
729   u8 is_enabled = 0;
730   u8 is_set = 0;
731
732   /* Get a line of input. */
733   if (! unformat_user (input, unformat_line_input, line_input))
734     return 0;
735
736   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
737     {
738       if (unformat (line_input, "enable"))
739         {
740           is_set = 1;
741           is_enabled = 1;
742         }
743       else if (unformat (line_input, "disable"))
744         is_set = 1;
745       else
746         {
747           return clib_error_return (0, "parse error: '%U'",
748                                    format_unformat_error, line_input);
749         }
750     }
751
752   if (!is_set)
753       return clib_error_return (0, "state not set");
754
755   return vnet_lisp_enable_disable (is_enabled);
756 }
757
758 VLIB_CLI_COMMAND (lisp_cp_enable_disable_command) = {
759     .path = "lisp",
760     .short_help = "lisp [enable|disable]",
761     .function = lisp_enable_disable_command_fn,
762 };
763
764 u8
765 vnet_lisp_enable_disable_status (void)
766 {
767   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
768   return lcm->is_enabled;
769 }
770
771 static u8 *
772 format_lisp_status (u8 * s, va_list * args)
773 {
774   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
775   return format (s, "%s", lcm->is_enabled ? "enabled" : "disabled");
776 }
777
778 static clib_error_t *
779 lisp_show_status_command_fn (vlib_main_t * vm, unformat_input_t * input,
780                              vlib_cli_command_t * cmd)
781 {
782   u8 * msg = 0;
783   msg = format (msg, "feature: %U\ngpe: %U\n",
784                 format_lisp_status, format_vnet_lisp_gpe_status);
785   vlib_cli_output (vm, "%v", msg);
786   vec_free (msg);
787   return 0;
788 }
789
790 VLIB_CLI_COMMAND (lisp_show_status_command) = {
791     .path = "show lisp status",
792     .short_help = "show lisp status",
793     .function = lisp_show_status_command_fn,
794 };
795 static clib_error_t *
796 lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
797                                      vlib_cli_command_t * cmd)
798 {
799   lisp_gpe_main_t * lgm = &lisp_gpe_main;
800   vnet_main_t * vnm = lgm->vnet_main;
801   unformat_input_t _line_input, * line_input = &_line_input;
802   u8 is_add = 1;
803   clib_error_t * error = 0;
804   u8 * locator_set_name = 0;
805   locator_t locator, * locators = 0;
806   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
807   u32 ls_index = 0;
808
809   memset(&locator, 0, sizeof(locator));
810   memset(a, 0, sizeof(a[0]));
811
812   /* Get a line of input. */
813   if (! unformat_user (input, unformat_line_input, line_input))
814     return 0;
815
816   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
817     {
818       if (unformat (line_input, "add %_%v%_", &locator_set_name))
819         is_add = 1;
820       else if (unformat (line_input, "del %_%v%_", &locator_set_name))
821         is_add = 0;
822       else if (unformat (line_input, "iface %U p %d w %d",
823                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
824                          &locator.priority, &locator.weight))
825         {
826           locator.local = 1;
827           vec_add1(locators, locator);
828         }
829       else
830         {
831           error = unformat_parse_error(line_input);
832           goto done;
833         }
834     }
835
836   a->name = locator_set_name;
837   a->locators = locators;
838   a->is_add = is_add;
839   a->local = 1;
840
841   vnet_lisp_add_del_locator_set(a, &ls_index);
842
843  done:
844   vec_free(locators);
845   vec_free(locator_set_name);
846   return error;
847 }
848
849 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
850     .path = "lisp locator-set",
851     .short_help = "lisp locator-set add/del <name> iface <iface-name> "
852         "<priority> <weight>",
853     .function = lisp_add_del_locator_set_command_fn,
854 };
855
856 static clib_error_t *
857 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
858                                       unformat_input_t * input,
859                                       vlib_cli_command_t * cmd)
860 {
861   locator_set_t * lsit;
862   locator_t * loc;
863   u32 * locit;
864   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
865
866   vlib_cli_output (vm, "%=20s%=16s%=16s%=16s", "Locator-set", "Locator",
867                    "Priority", "Weight");
868   pool_foreach (lsit, lcm->locator_set_pool,
869   ({
870     u8 * msg = 0;
871     msg = format (msg, "%-16v", lsit->name);
872     vec_foreach (locit, lsit->locator_indices)
873       {
874         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
875         if (loc->local)
876           msg = format (msg, "%16d%16d%16d", loc->sw_if_index, loc->priority,
877                         loc->weight);
878         else
879           msg = format (msg, "%16U%16d%16d", format_gid_address, &loc->address,
880                         loc->priority, loc->weight);
881       }
882     vlib_cli_output (vm, "%v", msg);
883     vec_free (msg);
884   }));
885   return 0;
886 }
887
888 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
889     .path = "show lisp locator-set",
890     .short_help = "Shows locator-sets",
891     .function = lisp_cp_show_locator_sets_command_fn,
892 };
893
894 int
895 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
896 {
897   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
898   ip_address_t * addr;
899   u32 i;
900
901   if (a->is_add)
902     {
903       vec_foreach(addr, lcm->map_resolvers)
904         {
905           if (!ip_address_cmp (addr, &a->address))
906             {
907               clib_warning("map-resolver %U already exists!", format_ip_address,
908                            &a->address);
909               return -1;
910             }
911         }
912       vec_add1(lcm->map_resolvers, a->address);
913     }
914   else
915     {
916       for (i = 0; i < vec_len(lcm->map_resolvers); i++)
917         {
918           addr = vec_elt_at_index(lcm->map_resolvers, i);
919           if (!ip_address_cmp (addr, &a->address))
920             {
921               vec_delete(lcm->map_resolvers, 1, i);
922               break;
923             }
924         }
925     }
926   return 0;
927 }
928
929 static clib_error_t *
930 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
931                                          unformat_input_t * input,
932                                          vlib_cli_command_t * cmd)
933 {
934   unformat_input_t _line_input, * line_input = &_line_input;
935   u8 is_add = 1;
936   ip_address_t ip_addr;
937   clib_error_t * error = 0;
938   vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a;
939
940   /* Get a line of input. */
941   if (! unformat_user (input, unformat_line_input, line_input))
942     return 0;
943
944   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
945     {
946       if (unformat (line_input, "add"))
947         is_add = 1;
948       else if (unformat (line_input, "del"))
949         is_add = 0;
950       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
951         ;
952       else
953         {
954           error = unformat_parse_error(line_input);
955           goto done;
956         }
957     }
958   a->is_add = is_add;
959   a->address = ip_addr;
960   vnet_lisp_add_del_map_resolver (a);
961
962  done:
963   return error;
964 }
965
966 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
967     .path = "lisp map-resolver",
968     .short_help = "lisp map-resolver add/del <ip_address>",
969     .function = lisp_add_del_map_resolver_command_fn,
970 };
971
972 /* Statistics (not really errors) */
973 #define foreach_lisp_cp_lookup_error           \
974 _(DROP, "drop")                                \
975 _(MAP_REQUESTS_SENT, "map-request sent")
976
977 static char * lisp_cp_lookup_error_strings[] = {
978 #define _(sym,string) string,
979   foreach_lisp_cp_lookup_error
980 #undef _
981 };
982
983 typedef enum
984 {
985 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
986     foreach_lisp_cp_lookup_error
987 #undef _
988     LISP_CP_LOOKUP_N_ERROR,
989 } lisp_cp_lookup_error_t;
990
991 typedef enum
992 {
993   LISP_CP_LOOKUP_NEXT_DROP,
994   LISP_CP_LOOKUP_NEXT_IP4_LOOKUP,
995   LISP_CP_LOOKUP_NEXT_IP6_LOOKUP,
996   LISP_CP_LOOKUP_N_NEXT,
997 } lisp_cp_lookup_next_t;
998
999 typedef struct
1000 {
1001   gid_address_t dst_eid;
1002   ip4_address_t map_resolver_ip;
1003 } lisp_cp_lookup_trace_t;
1004
1005 u8 *
1006 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
1007 {
1008   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1009   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1010   lisp_cp_lookup_trace_t * t = va_arg (*args, lisp_cp_lookup_trace_t *);
1011
1012   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
1013               format_ip_address, &t->map_resolver_ip, format_gid_address,
1014               &t->dst_eid);
1015   return s;
1016 }
1017
1018 static u32
1019 ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
1020                           ip_address_t * dst)
1021 {
1022   if (ip_addr_version (dst) == IP4)
1023       return ip4_fib_lookup_with_table (lcm->im4, fib_index, &ip_addr_v4(dst),
1024                                         0);
1025   else
1026       return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6(dst));
1027 }
1028
1029 void
1030 get_local_iface_ip_for_dst (lisp_cp_main_t *lcm, ip_address_t * dst,
1031                             ip_address_t * sloc)
1032 {
1033   u32 adj_index;
1034   ip_adjacency_t * adj;
1035   ip_interface_address_t * ia = 0;
1036   ip_lookup_main_t * lm;
1037   ip4_address_t * l4 = 0;
1038   ip6_address_t * l6 = 0;
1039
1040   lm = ip_addr_version (dst) == IP4 ?
1041       &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1042
1043   adj_index = ip_fib_lookup_with_table (lcm, 0, dst);
1044   adj = ip_get_adjacency (lm, adj_index);
1045
1046   if (adj->lookup_next_index == IP_LOOKUP_NEXT_ARP)
1047     {
1048       ia = pool_elt_at_index(lm->if_address_pool, adj->if_address_index);
1049       if (ip_addr_version(dst) == IP4)
1050         {
1051           l4 = ip_interface_address_get_address (lm, ia);
1052         }
1053       else
1054         {
1055           l6 = ip_interface_address_get_address (lm, ia);
1056         }
1057     }
1058   else if (adj->lookup_next_index == IP_LOOKUP_NEXT_REWRITE)
1059     {
1060       /* find sw_if_index in rewrite header */
1061       u32 sw_if_index = adj->rewrite_header.sw_if_index;
1062
1063       /* find suitable address */
1064       if (ip_addr_version(dst) == IP4)
1065         {
1066           /* find the first ip address */
1067           foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
1068                                         sw_if_index, 1 /* unnumbered */,
1069           ({
1070             l4 = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
1071             break;
1072           }));
1073         }
1074       else
1075         {
1076           /* find the first ip address */
1077           foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
1078                                         sw_if_index, 1 /* unnumbered */,
1079           ({
1080             l6 = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
1081             break;
1082           }));
1083         }
1084     }
1085   else
1086     {
1087       clib_warning("Can't find local local interface ip for dst %U",
1088                    format_ip_address, dst);
1089       return;
1090     }
1091
1092   if (l4)
1093     {
1094       ip_addr_v4(sloc).as_u32 = l4->as_u32;
1095       ip_addr_version(sloc) = IP4;
1096     }
1097   else if (l6)
1098     {
1099       clib_memcpy (&ip_addr_v6(sloc), l6, sizeof(*l6));
1100       ip_addr_version(sloc) = IP6;
1101     }
1102   else
1103     {
1104       clib_warning("Can't find local interface addr for dst %U",
1105                    format_ip_address, dst);
1106     }
1107 }
1108
1109
1110 static gid_address_t *
1111 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
1112 {
1113   ip4_address_t * l4;
1114   ip6_address_t * l6;
1115   u32 i;
1116   locator_t * loc;
1117   u32 * loc_indexp;
1118   ip_interface_address_t * ia = 0;
1119   gid_address_t gid_data, * gid = &gid_data;
1120   gid_address_t * rlocs = 0;
1121   ip_prefix_t * ippref = &gid_address_ippref (gid);
1122   ip_address_t * rloc = &ip_prefix_addr (ippref);
1123
1124   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
1125   for (i = 0; i < vec_len(loc_set->locator_indices); i++)
1126     {
1127       loc_indexp = vec_elt_at_index(loc_set->locator_indices, i);
1128       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
1129
1130       ip_addr_version(rloc) = IP4;
1131       /* Add ipv4 locators first TODO sort them */
1132       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
1133                                     loc->sw_if_index, 1 /* unnumbered */,
1134       ({
1135         l4 = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
1136         ip_addr_v4 (rloc) = l4[0];
1137         vec_add1 (rlocs, gid[0]);
1138       }));
1139
1140       ip_addr_version(rloc) = IP6;
1141       /* Add ipv6 locators */
1142       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
1143                                     loc->sw_if_index, 1 /* unnumbered */,
1144       ({
1145         l6 = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
1146         ip_addr_v6 (rloc) = l6[0];
1147         vec_add1 (rlocs, gid[0]);
1148       }));
1149     }
1150   return rlocs;
1151 }
1152
1153 static vlib_buffer_t *
1154 build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
1155                                 gid_address_t * seid, gid_address_t * deid,
1156                                 locator_set_t * loc_set, u8 is_smr_invoked,
1157                                 u64 *nonce_res, u32 * bi_res)
1158 {
1159   vlib_buffer_t * b;
1160   u32 bi;
1161   ip_address_t * mr_ip, sloc;
1162   gid_address_t * rlocs = 0;
1163
1164   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
1165     {
1166       clib_warning ("Can't allocate buffer for Map-Request!");
1167       return 0;
1168     }
1169
1170   b = vlib_get_buffer (vm, bi);
1171
1172   /* leave some space for the encap headers */
1173   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
1174
1175   /* get rlocs */
1176   rlocs = build_itr_rloc_list (lcm, loc_set);
1177
1178   /* put lisp msg */
1179   lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked, nonce_res);
1180
1181   /* push ecm: udp-ip-lisp */
1182   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
1183
1184   /* get map-resolver ip XXX use first*/
1185   mr_ip = vec_elt_at_index(lcm->map_resolvers, 0);
1186
1187   /* get local iface ip to use in map-request XXX fib 0 for now*/
1188   get_local_iface_ip_for_dst (lcm, mr_ip, &sloc);
1189
1190   /* push outer ip header */
1191   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, &sloc,
1192                        mr_ip);
1193
1194   bi_res[0] = bi;
1195
1196   if (rlocs)
1197     vec_free(rlocs);
1198   return b;
1199 }
1200
1201 static void
1202 send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
1203                                gid_address_t * seid, gid_address_t * deid,
1204                                u8 is_smr_invoked)
1205 {
1206   u32 next_index, bi = 0, * to_next, map_index;
1207   vlib_buffer_t * b;
1208   vlib_frame_t * f;
1209   u64 nonce = 0;
1210   locator_set_t * loc_set;
1211   mapping_t * map;
1212   pending_map_request_t * pmr;
1213
1214   /* get locator-set for seid */
1215   map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
1216   if (map_index == ~0)
1217     {
1218       clib_warning("No local mapping found in eid-table for %U!",
1219                    format_gid_address, seid);
1220       return;
1221     }
1222
1223   map = pool_elt_at_index (lcm->mapping_pool, map_index);
1224
1225   if (!map->local)
1226     {
1227       clib_warning("Mapping found for src eid %U is not marked as local!",
1228                    format_gid_address, seid);
1229       return;
1230     }
1231   loc_set = pool_elt_at_index (lcm->locator_set_pool, map->locator_set_index);
1232
1233   /* build the encapsulated map request */
1234   b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set,
1235                                       is_smr_invoked, &nonce, &bi);
1236
1237   if (!b)
1238     return;
1239
1240   vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0;
1241   next_index = (ip_prefix_version(&gid_address_ippref(seid)) == IP4) ?
1242       ip4_lookup_node.index : ip6_lookup_node.index;
1243
1244   f = vlib_get_frame_to_node (vm, next_index);
1245
1246   /* Enqueue the packet */
1247   to_next = vlib_frame_vector_args (f);
1248   to_next[0] = bi;
1249   f->n_vectors = 1;
1250   vlib_put_frame_to_node (vm, next_index, f);
1251
1252   /* add map-request to pending requests table */
1253   pool_get(lcm->pending_map_requests_pool, pmr);
1254   gid_address_copy (&pmr->src, seid);
1255   gid_address_copy (&pmr->dst, deid);
1256   pmr->src_mapping_index = map_index;
1257   hash_set(lcm->pending_map_requests_by_nonce, nonce,
1258            pmr - lcm->pending_map_requests_pool);
1259 }
1260
1261 static void
1262 get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst)
1263 {
1264   ip4_header_t * ip4 = hdr;
1265   ip6_header_t * ip6;
1266
1267   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
1268     {
1269       ip_addr_v4(src).as_u32 = ip4->src_address.as_u32;
1270       ip_addr_version(src) = IP4;
1271       ip_addr_v4(dst).as_u32 = ip4->dst_address.as_u32;
1272       ip_addr_version(dst) = IP4;
1273     }
1274   else
1275     {
1276       ip6 = hdr;
1277       clib_memcpy (&ip_addr_v6(src), &ip6->src_address, sizeof(ip6->src_address));
1278       ip_addr_version(src) = IP6;
1279       clib_memcpy (&ip_addr_v6(dst), &ip6->dst_address, sizeof(ip6->dst_address));
1280       ip_addr_version(dst) = IP6;
1281     }
1282 }
1283
1284 static uword
1285 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
1286               vlib_frame_t * from_frame)
1287 {
1288   u32 * from, * to_next_drop;
1289   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main();
1290   u32 pkts_mapped = 0;
1291   uword n_left_from, n_left_to_next_drop;
1292
1293   from = vlib_frame_vector_args (from_frame);
1294   n_left_from = from_frame->n_vectors;
1295
1296   while (n_left_from > 0)
1297     {
1298       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
1299                            to_next_drop, n_left_to_next_drop);
1300
1301       while (n_left_from > 0 && n_left_to_next_drop > 0)
1302         {
1303           u32 pi0;
1304           vlib_buffer_t * p0;
1305           ip4_header_t * ip0;
1306           gid_address_t src, dst;
1307           ip_prefix_t * spref, * dpref;
1308
1309           gid_address_type (&src) = GID_ADDR_IP_PREFIX;
1310           spref = &gid_address_ippref(&src);
1311           gid_address_type (&dst) = GID_ADDR_IP_PREFIX;
1312           dpref = &gid_address_ippref(&dst);
1313
1314           pi0 = from[0];
1315           from += 1;
1316           n_left_from -= 1;
1317           to_next_drop[0] = pi0;
1318           to_next_drop += 1;
1319           n_left_to_next_drop -= 1;
1320
1321           p0 = vlib_get_buffer (vm, pi0);
1322           p0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
1323
1324           /* src/dst eid pair */
1325           ip0 = vlib_buffer_get_current (p0);
1326           get_src_and_dst (ip0, &ip_prefix_addr(spref), &ip_prefix_addr(dpref));
1327           ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref));
1328           ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref));
1329
1330           /* send map-request */
1331           send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
1332
1333           pkts_mapped++;
1334
1335           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
1336             {
1337               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, p0,
1338                                                           sizeof(*tr));
1339               gid_address_copy (&tr->dst_eid, &dst);
1340               clib_memcpy (&tr->map_resolver_ip,
1341                       vec_elt_at_index(lcm->map_resolvers, 0),
1342                       sizeof(ip_address_t));
1343             }
1344         }
1345
1346       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop);
1347     }
1348   vlib_node_increment_counter (vm, node->node_index,
1349                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
1350                                pkts_mapped);
1351   return from_frame->n_vectors;
1352 }
1353
1354 VLIB_REGISTER_NODE (lisp_cp_lookup_node) = {
1355   .function = lisp_cp_lookup,
1356   .name = "lisp-cp-lookup",
1357   .vector_size = sizeof (u32),
1358   .format_trace = format_lisp_cp_lookup_trace,
1359   .type = VLIB_NODE_TYPE_INTERNAL,
1360
1361   .n_errors = LISP_CP_LOOKUP_N_ERROR,
1362   .error_strings = lisp_cp_lookup_error_strings,
1363
1364   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
1365
1366   .next_nodes = {
1367       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
1368       [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup",
1369       [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup",
1370   },
1371 };
1372
1373 /* lisp_cp_input statistics */
1374 #define foreach_lisp_cp_input_error                   \
1375 _(DROP, "drop")                                        \
1376 _(MAP_REPLIES_RECEIVED, "map-replies received")
1377
1378 static char * lisp_cp_input_error_strings[] = {
1379 #define _(sym,string) string,
1380   foreach_lisp_cp_input_error
1381 #undef _
1382 };
1383
1384 typedef enum
1385 {
1386 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
1387     foreach_lisp_cp_input_error
1388 #undef _
1389     LISP_CP_INPUT_N_ERROR,
1390 } lisp_cp_input_error_t;
1391
1392 typedef enum
1393 {
1394   LISP_CP_INPUT_NEXT_DROP,
1395   LISP_CP_INPUT_N_NEXT,
1396 } lisp_cp_input_next_t;
1397
1398 typedef struct
1399 {
1400   gid_address_t dst_eid;
1401   ip4_address_t map_resolver_ip;
1402 } lisp_cp_input_trace_t;
1403
1404 u8 *
1405 format_lisp_cp_input_trace (u8 * s, va_list * args)
1406 {
1407   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1408   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1409   CLIB_UNUSED(lisp_cp_input_trace_t * t) = va_arg (*args, lisp_cp_input_trace_t *);
1410
1411   s = format (s, "LISP-CP-INPUT: TODO");
1412   return s;
1413 }
1414
1415 ip_interface_address_t *
1416 ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
1417                                           u8 loop)
1418 {
1419   vnet_main_t *vnm = vnet_get_main ();
1420   vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index);
1421   if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
1422     sw_if_index = swif->unnumbered_sw_if_index;
1423   u32 ia =
1424       (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
1425           vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
1426           (u32) ~0;
1427   return pool_elt_at_index((lm)->if_address_pool, ia);
1428 }
1429
1430 void *
1431 ip_interface_get_first_ip_addres (ip_lookup_main_t *lm, u32 sw_if_index,
1432                                    u8 loop)
1433 {
1434   ip_interface_address_t * ia = ip_interface_get_first_interface_address (
1435       lm, sw_if_index, loop);
1436   return ip_interface_address_get_address (lm, ia);
1437 }
1438
1439 void
1440 del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
1441                u32 dst_map_index)
1442 {
1443   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
1444   fwd_entry_t * fe = 0;
1445   uword * feip = 0;
1446   memset(a, 0, sizeof(*a));
1447
1448   feip = hash_get(lcm->fwd_entry_by_mapping_index, dst_map_index);
1449   if (!feip)
1450     return;
1451
1452   fe = pool_elt_at_index(lcm->fwd_entry_pool, feip[0]);
1453
1454   /* delete dp fwd entry */
1455   u32 sw_if_index;
1456   a->is_add = 0;
1457   a->dlocator = fe->dst_loc;
1458   a->slocator = fe->src_loc;
1459   a->vni = gid_address_vni(&a->deid);
1460   gid_address_copy(&a->deid, &fe->deid);
1461
1462   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
1463
1464   /* delete entry in fwd table */
1465   hash_unset(lcm->fwd_entry_by_mapping_index, dst_map_index);
1466   pool_put(lcm->fwd_entry_pool, fe);
1467 }
1468
1469 void
1470 add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
1471 {
1472   mapping_t * src_map, * dst_map;
1473   locator_set_t * dst_ls, * src_ls;
1474   u32 i, minp = ~0, sw_if_index;
1475   locator_t * dl = 0;
1476   uword * feip = 0, * tidp;
1477   fwd_entry_t* fe;
1478   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
1479
1480   memset (a, 0, sizeof(*a));
1481
1482   /* remove entry if it already exists */
1483   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
1484   if (feip)
1485     del_fwd_entry (lcm, src_map_index, dst_map_index);
1486
1487   src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
1488   dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
1489
1490   gid_address_copy (&a->deid, &dst_map->eid);
1491   a->vni = gid_address_vni(&a->deid);
1492
1493   tidp = hash_get(lcm->table_id_by_vni, a->vni);
1494   if (!tidp)
1495     {
1496       clib_warning("vni %d not associated to a vrf!", a->vni);
1497       return;
1498     }
1499   a->table_id = tidp[0];
1500
1501   /* XXX simple forwarding policy: first lowest (value) priority locator */
1502   dst_ls = pool_elt_at_index (lcm->locator_set_pool,
1503                               dst_map->locator_set_index);
1504   for (i = 0; i < vec_len (dst_ls->locator_indices); i++)
1505     {
1506       u32 li = vec_elt (dst_ls->locator_indices, i);
1507       locator_t * l = pool_elt_at_index (lcm->locator_pool, li);
1508       if (l->priority < minp && gid_address_type(&l->address)
1509             == GID_ADDR_IP_PREFIX)
1510         {
1511           minp = l->priority;
1512           dl = l;
1513         }
1514     }
1515   if (dl)
1516     {
1517       src_ls = pool_elt_at_index(lcm->locator_set_pool,
1518                                  src_map->locator_set_index);
1519       for (i = 0; i < vec_len(src_ls->locator_indices); i++)
1520         {
1521           u32 li = vec_elt (src_ls->locator_indices, i);
1522           locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
1523
1524           if (ip_addr_version(&gid_address_ip(&dl->address)) == IP4)
1525             {
1526               ip4_address_t * l4;
1527               l4 = ip_interface_get_first_ip_addres (&lcm->im4->lookup_main,
1528                                                      sl->sw_if_index,
1529                                                      1 /* unnumbered */);
1530               ip_addr_v4(&a->slocator) = *l4;
1531               ip_addr_version(&a->slocator) = IP4;
1532             }
1533           else
1534             {
1535               ip6_address_t * l6;
1536               l6 = ip_interface_get_first_ip_addres (&lcm->im6->lookup_main,
1537                                                      sl->sw_if_index,
1538                                                      1 /* unnumbered */);
1539               ip_addr_v6(&a->slocator) = *l6;
1540               ip_addr_version(&a->slocator) = IP6;
1541             }
1542         }
1543     }
1544
1545   /* insert data plane forwarding entry */
1546   a->is_add = 1;
1547   if (dl)
1548     a->dlocator = gid_address_ip(&dl->address);
1549   else
1550     {
1551       a->is_negative = 1;
1552       a->action = dst_map->action;
1553     }
1554
1555   /* TODO remove */
1556   u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid));
1557   a->decap_next_index = (ipver == IP4) ?
1558           LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
1559
1560   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
1561
1562   /* add tunnel to fwd entry table XXX check return value from DP insertion */
1563   pool_get (lcm->fwd_entry_pool, fe);
1564   fe->dst_loc = a->dlocator;
1565   fe->src_loc = a->slocator;
1566   gid_address_copy (&fe->deid, &a->deid);
1567   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
1568             fe - lcm->fwd_entry_pool);
1569 }
1570
1571 /* return 0 if the two locator sets are identical 1 otherwise */
1572 static u8
1573 compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes,
1574                   locator_t * new_locators)
1575 {
1576   u32 i, old_li;
1577   locator_t * old_loc, * new_loc;
1578
1579   if (vec_len (old_ls_indexes) != vec_len(new_locators))
1580     return 1;
1581
1582   for (i = 0; i < vec_len(new_locators); i++)
1583     {
1584       old_li = vec_elt(old_ls_indexes, i);
1585       old_loc = pool_elt_at_index(lcm->locator_pool, old_li);
1586
1587       new_loc = vec_elt_at_index(new_locators, i);
1588
1589       if (locator_cmp (old_loc, new_loc))
1590         return 1;
1591     }
1592   return 0;
1593 }
1594
1595 void
1596 process_map_reply (lisp_cp_main_t * lcm, vlib_buffer_t * b)
1597 {
1598   locator_t * loc;
1599   u32 len = 0, i, ls_index = 0;
1600   void * h;
1601   vnet_lisp_add_del_locator_set_args_t _ls_arg, * ls_arg = &_ls_arg;
1602   vnet_lisp_add_del_mapping_args_t _m_args, * m_args = &_m_args;
1603   pending_map_request_t * pmr;
1604   locator_t probed;
1605   map_reply_hdr_t * mrep_hdr;
1606   u64 nonce;
1607   u32 dst_map_index, mi;
1608   uword * pmr_index;
1609
1610   mrep_hdr = vlib_buffer_get_current (b);
1611
1612   /* Check pending requests table and nonce */
1613   nonce = MREP_NONCE(mrep_hdr);
1614   pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce);
1615   if (!pmr_index)
1616     {
1617       clib_warning("No pending map-request entry with nonce %lu!", nonce);
1618       return;
1619     }
1620   pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]);
1621
1622   vlib_buffer_pull (b, sizeof(*mrep_hdr));
1623
1624   for (i = 0; i < MREP_REC_COUNT(mrep_hdr); i++)
1625     {
1626       memset (ls_arg, 0, sizeof(*ls_arg));
1627       memset (m_args, 0, sizeof(*m_args));
1628
1629       h = vlib_buffer_get_current (b);
1630       m_args->ttl = clib_net_to_host_u32 (MAP_REC_TTL(h));
1631       m_args->action = MAP_REC_ACTION(h);
1632       m_args->authoritative = MAP_REC_AUTH(h);
1633
1634       len = lisp_msg_parse_mapping_record (b, &m_args->deid, &ls_arg->locators,
1635                                            &probed);
1636       if (len == ~0)
1637         {
1638           clib_warning ("Failed to parse mapping record!");
1639           vec_foreach (loc, ls_arg->locators)
1640             {
1641               locator_free (loc);
1642             }
1643           vec_free(ls_arg->locators);
1644           return;
1645         }
1646
1647       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &m_args->deid);
1648
1649       /* if mapping already exists, decide if locators (and forwarding) should
1650        * be updated and be done */
1651       if (mi != ~0)
1652         {
1653           mapping_t * old_map;
1654           locator_set_t * old_ls;
1655           old_map = pool_elt_at_index(lcm->mapping_pool, mi);
1656
1657           /* update mapping attributes */
1658           old_map->action = m_args->action;
1659           old_map->authoritative = m_args->authoritative;
1660           old_map->ttl = m_args->ttl;
1661
1662           old_ls = pool_elt_at_index(lcm->locator_set_pool,
1663                                      old_map->locator_set_index);
1664           /* if the two locators are not equal, update them and forwarding
1665            * otherwise there's nothing to be done */
1666           if (compare_locators (lcm, old_ls->locator_indices, ls_arg->locators))
1667             {
1668               /* set locator-set index to overwrite */
1669               ls_arg->is_add = 1;
1670               ls_arg->index = old_map->locator_set_index;
1671               vnet_lisp_add_del_locator_set (ls_arg, 0);
1672               add_fwd_entry (lcm, pmr->src_mapping_index, mi);
1673             }
1674         }
1675       /* new mapping */
1676       else
1677         {
1678           /* add locator-set */
1679           ls_arg->is_add = 1;
1680           ls_arg->index = ~0;
1681           vnet_lisp_add_del_locator_set (ls_arg, &ls_index);
1682
1683           /* add mapping */
1684           m_args->is_add = 1;
1685           m_args->locator_set_index = ls_index;
1686           vnet_lisp_add_del_mapping (m_args, &dst_map_index);
1687
1688           /* add forwarding tunnel */
1689           add_fwd_entry (lcm, pmr->src_mapping_index, dst_map_index);
1690         }
1691       vec_free(ls_arg->locators);
1692     }
1693
1694   /* remove pending map request entry */
1695   hash_unset(lcm->pending_map_requests_by_nonce, nonce);
1696   pool_put(lcm->pending_map_requests_pool, pmr);
1697 }
1698
1699 void
1700 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
1701 {
1702   map_request_hdr_t * mreq_hdr;
1703   gid_address_t src, dst;
1704 //  u64 nonce;
1705   u32 i, len = 0;
1706   gid_address_t * itr_rlocs = 0, * rloc;
1707
1708   mreq_hdr = vlib_buffer_get_current (b);
1709   vlib_buffer_pull (b, sizeof(*mreq_hdr));
1710
1711 //  nonce = MREQ_NONCE(mreq_hdr);
1712
1713   if (!MREQ_SMR(mreq_hdr)) {
1714       clib_warning("Only SMR Map-Requests supported for now!");
1715       return;
1716   }
1717
1718   /* parse src eid */
1719   len = lisp_msg_parse_addr (b, &src);
1720   if (len == ~0)
1721     return;
1722
1723   /* for now we don't do anything with the itr's rlocs */
1724   len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs, MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1);
1725   if (len == ~0)
1726     return;
1727
1728   /* TODO: RLOCs are currently unused, so free them for now */
1729   vec_foreach (rloc, itr_rlocs)
1730     {
1731       gid_address_free (rloc);
1732     }
1733
1734   /* parse eid records and send SMR-invoked map-requests */
1735   for (i = 0; i < MREQ_REC_COUNT(mreq_hdr); i++)
1736     {
1737       memset(&dst, 0, sizeof(dst));
1738       len = lisp_msg_parse_eid_rec (b, &dst);
1739       if (len == ~0)
1740         {
1741           clib_warning("Can't parse map-request EID-record");
1742           return;
1743         }
1744       /* send SMR-invoked map-requests */
1745       send_encapsulated_map_request (vm, lcm, &dst, &src, /* invoked */ 1);
1746     }
1747 }
1748
1749 static uword
1750 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
1751                vlib_frame_t * from_frame)
1752 {
1753   u32 n_left_from, * from, * to_next_drop;
1754   lisp_msg_type_e type;
1755   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1756
1757   from = vlib_frame_vector_args (from_frame);
1758   n_left_from = from_frame->n_vectors;
1759
1760
1761   while (n_left_from > 0)
1762     {
1763       u32 n_left_to_next_drop;
1764
1765       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
1766                            to_next_drop, n_left_to_next_drop);
1767       while (n_left_from > 0 && n_left_to_next_drop > 0)
1768         {
1769           u32 bi0;
1770           vlib_buffer_t * b0;
1771
1772           bi0 = from[0];
1773           from += 1;
1774           n_left_from -= 1;
1775           to_next_drop[0] = bi0;
1776           to_next_drop += 1;
1777           n_left_to_next_drop -= 1;
1778
1779           b0 = vlib_get_buffer (vm, bi0);
1780
1781           type = lisp_msg_type(vlib_buffer_get_current (b0));
1782           switch (type)
1783             {
1784             case LISP_MAP_REPLY:
1785               process_map_reply (lcm, b0);
1786               break;
1787             case LISP_MAP_REQUEST:
1788               process_map_request(vm, lcm, b0);
1789               break;
1790             default:
1791               clib_warning("Unsupported LISP message type %d", type);
1792               break;
1793             }
1794
1795           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
1796
1797           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
1798             {
1799
1800             }
1801         }
1802
1803       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, n_left_to_next_drop);
1804     }
1805   return from_frame->n_vectors;
1806 }
1807
1808 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
1809   .function = lisp_cp_input,
1810   .name = "lisp-cp-input",
1811   .vector_size = sizeof (u32),
1812   .format_trace = format_lisp_cp_input_trace,
1813   .type = VLIB_NODE_TYPE_INTERNAL,
1814
1815   .n_errors = LISP_CP_INPUT_N_ERROR,
1816   .error_strings = lisp_cp_input_error_strings,
1817
1818   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
1819
1820   .next_nodes = {
1821       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
1822   },
1823 };
1824
1825 clib_error_t *
1826 lisp_cp_init (vlib_main_t *vm)
1827 {
1828   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1829   clib_error_t * error = 0;
1830
1831   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
1832     return error;
1833
1834   lcm->im4 = &ip4_main;
1835   lcm->im6 = &ip6_main;
1836   lcm->vlib_main = vm;
1837   lcm->vnet_main = vnet_get_main();
1838
1839   gid_dictionary_init (&lcm->mapping_index_by_gid);
1840
1841   /* default vrf mapped to vni 0 */
1842   hash_set(lcm->table_id_by_vni, 0, 0);
1843
1844   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
1845                          lisp_cp_input_node.index, 1 /* is_ip4 */);
1846   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
1847                          lisp_cp_input_node.index, 0 /* is_ip4 */);
1848
1849   return 0;
1850 }
1851
1852 VLIB_INIT_FUNCTION(lisp_cp_init);