54a83f487526fef4d27bb7631ccfcfdb8aca1c5a
[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 static void
22 add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index);
23
24 static void
25 del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index);
26
27 static u8
28 compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes,
29                   locator_t * new_locators);
30
31 /* Stores mapping in map-cache. It does NOT program data plane forwarding for
32  * remote/learned mappings. */
33 int
34 vnet_lisp_add_del_mapping (vnet_lisp_add_del_mapping_args_t * a,
35                            u32 * map_index_result)
36 {
37   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
38   u32 mi, * map_indexp, map_index, i;
39   mapping_t * m, * old_map;
40   u32 ** eid_indexes;
41
42   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->deid);
43   old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
44   if (a->is_add)
45     {
46       /* TODO check if overwriting and take appropriate actions */
47       if (mi != GID_LOOKUP_MISS && !gid_address_cmp (&old_map->eid,
48                                                      &a->deid))
49         {
50           clib_warning("eid %U found in the eid-table", format_ip_address,
51                        &a->deid);
52           return VNET_API_ERROR_VALUE_EXIST;
53         }
54
55       pool_get(lcm->mapping_pool, m);
56       m->eid = a->deid;
57       m->locator_set_index = a->locator_set_index;
58       m->ttl = a->ttl;
59       m->action = a->action;
60       m->local = a->local;
61
62       map_index = m - lcm->mapping_pool;
63       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->deid, map_index,
64                               1);
65
66       if (pool_is_free_index(lcm->locator_set_pool, a->locator_set_index))
67         {
68           clib_warning("Locator set with index %d doesn't exist",
69                        a->locator_set_index);
70           return VNET_API_ERROR_INVALID_VALUE;
71         }
72
73       /* add eid to list of eids supported by locator-set */
74       vec_validate (lcm->locator_set_to_eids, a->locator_set_index);
75       eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
76                                      a->locator_set_index);
77       vec_add1(eid_indexes[0], map_index);
78
79       if (a->local)
80         {
81           /* mark as local */
82           vec_add1(lcm->local_mappings_indexes, map_index);
83         }
84       map_index_result[0] = map_index;
85     }
86   else
87     {
88       if (mi == GID_LOOKUP_MISS)
89         {
90           clib_warning("eid %U not found in the eid-table", format_ip_address,
91                        &a->deid);
92           return VNET_API_ERROR_INVALID_VALUE;
93         }
94
95       /* clear locator-set to eids binding */
96       eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
97                                      a->locator_set_index);
98       for (i = 0; i < vec_len(eid_indexes[0]); i++)
99         {
100           map_indexp = vec_elt_at_index(eid_indexes[0], i);
101           if (map_indexp[0] == mi)
102               break;
103         }
104       vec_del1(eid_indexes[0], i);
105
106       /* remove local mark if needed */
107       m = pool_elt_at_index(lcm->mapping_pool, mi);
108       if (m->local)
109         {
110           u32 k, * lm_indexp;
111           for (k = 0; k < vec_len(lcm->local_mappings_indexes); k++)
112             {
113               lm_indexp = vec_elt_at_index(lcm->local_mappings_indexes, k);
114               if (lm_indexp[0] == mi)
115                 break;
116             }
117           vec_del1(lcm->local_mappings_indexes, k);
118         }
119       else
120         {
121           /* remove tunnel ??? */
122         }
123
124       /* remove mapping from dictionary */
125       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->deid, 0, 0);
126       pool_put_index (lcm->mapping_pool, mi);
127     }
128
129   return 0;
130 }
131
132 /* Stores mapping in map-cache and programs data plane for local mappings. */
133 int
134 vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
135                                  u32 * map_index_result)
136 {
137   uword * table_id, * refc;
138   u32 rv, vni;
139   vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
140   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
141
142   if (vnet_lisp_enable_disable_status () == 0)
143     {
144       clib_warning ("LISP is disabled!");
145       return VNET_API_ERROR_LISP_DISABLED;
146     }
147
148   vni = gid_address_vni(&a->deid);
149
150   /* store/remove mapping from map-cache */
151   rv = vnet_lisp_add_del_mapping (a, map_index_result);
152   if (rv)
153     return rv;
154
155   table_id = hash_get(lcm->table_id_by_vni, vni);
156
157   if (!table_id)
158     {
159       clib_warning ("vni %d not associated to a vrf!", vni);
160       return VNET_API_ERROR_INVALID_VALUE;
161     }
162
163   refc = hash_get(lcm->dp_if_refcount_by_vni, vni);
164
165   /* enable/disable data-plane interface */
166   if (a->is_add)
167     {
168       /* create interface or update refcount */
169       if (!refc)
170         {
171           ai->is_add = 1;
172           ai->vni = vni;
173           ai->table_id = table_id[0];
174           vnet_lisp_gpe_add_del_iface (ai, 0);
175
176           /* counts the number of eids in a vni that use the interface */
177           hash_set(lcm->dp_if_refcount_by_vni, vni, 1);
178         }
179       else
180         {
181           refc[0]++;
182         }
183     }
184   else
185     {
186       /* since this is a remove for an existing eid, the iface should exist */
187       ASSERT(refc != 0);
188       refc[0]--;
189
190       /* remove iface if needed */
191       if (refc[0] == 0)
192         {
193           ai->is_add = 0;
194           ai->vni = vni;
195           ai->table_id = table_id[0];
196           vnet_lisp_gpe_add_del_iface (ai, 0);
197           hash_unset (lcm->dp_if_refcount_by_vni, vni);
198         }
199     }
200
201   return rv;
202 }
203
204 static clib_error_t *
205 lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
206                                    vlib_cli_command_t * cmd)
207 {
208   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
209   unformat_input_t _line_input, * line_input = &_line_input;
210   u8 is_add = 1;
211   gid_address_t eid;
212   ip_prefix_t * prefp = &gid_address_ippref(&eid);
213   gid_address_t * eids = 0;
214   clib_error_t * error = 0;
215   u8 * locator_set_name = 0;
216   u32 locator_set_index = 0, map_index = 0;
217   uword * p;
218   vnet_lisp_add_del_mapping_args_t _a, * a = &_a;
219   int rv = 0;
220
221   gid_address_type (&eid) = GID_ADDR_IP_PREFIX;
222
223   /* Get a line of input. */
224   if (! unformat_user (input, unformat_line_input, line_input))
225     return 0;
226
227   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
228     {
229       if (unformat (line_input, "add"))
230         is_add = 1;
231       else if (unformat (line_input, "del"))
232         is_add = 0;
233       else if (unformat (line_input, "eid %U", unformat_ip_prefix, prefp))
234         {
235           vec_add1(eids, eid);
236         }
237       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
238         {
239           p = hash_get_mem(lcm->locator_set_index_by_name, locator_set_name);
240           if (!p)
241             {
242               error = clib_error_return(0, "locator-set %s doesn't exist",
243                                         locator_set_name);
244               goto done;
245             }
246           locator_set_index = p[0];
247         }
248       else
249         {
250           error = unformat_parse_error(line_input);
251           goto done;
252         }
253     }
254
255   /* XXX treat batch configuration */
256   a->deid = eid;
257   a->is_add = is_add;
258   a->locator_set_index = locator_set_index;
259   a->local = 1;
260
261   rv = vnet_lisp_add_del_local_mapping (a, &map_index);
262   if (0 != rv)
263    {
264       error = clib_error_return(0, "failed to %s eid-table!",
265                                 is_add ? "add" : "delete");
266    }
267  done:
268   vec_free(eids);
269   if (locator_set_name)
270     vec_free (locator_set_name);
271   return error;
272 }
273
274 VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = {
275     .path = "lisp eid-table",
276     .short_help = "lisp eid-table add/del eid <eid> locator-set <locator-set>",
277     .function = lisp_add_del_local_eid_command_fn,
278 };
279
280 static int
281 lisp_add_del_negative_static_mapping (gid_address_t * deid,
282     vnet_lisp_add_del_locator_set_args_t * ls, u8 action, u8 is_add)
283 {
284   uword * p;
285   mapping_t * map;
286   u32 mi = ~0;
287   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
288   uword * refc;
289   vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args;
290   int rv = 0;
291   u32 ls_index = 0, dst_map_index;
292   vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
293
294   memset (dm_args, 0, sizeof (dm_args[0]));
295   u32 vni = gid_address_vni (deid);
296   refc = hash_get (lcm->dp_if_refcount_by_vni, vni);
297
298   p = hash_get (lcm->table_id_by_vni, vni);
299   if (!p)
300     {
301       clib_warning ("vni %d not associated to a vrf!", vni);
302       return VNET_API_ERROR_INVALID_VALUE;
303     }
304
305   if (is_add)
306     {
307       vnet_lisp_add_del_locator_set (ls, &ls_index);
308       /* add mapping */
309       gid_address_copy (&dm_args->deid, deid);
310       dm_args->is_add = 1;
311       dm_args->action = action;
312       dm_args->locator_set_index = ls_index;
313
314       /* create interface or update refcount */
315       if (!refc)
316         {
317           vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
318           ai->is_add = 1;
319           ai->vni = vni;
320           ai->table_id = p[0];
321           vnet_lisp_gpe_add_del_iface (ai, 0);
322
323           /* counts the number of eids in a vni that use the interface */
324           hash_set (lcm->dp_if_refcount_by_vni, vni, 1);
325         }
326       else
327         refc[0]++;
328
329       rv = vnet_lisp_add_del_local_mapping (dm_args, &dst_map_index);
330       if (!rv)
331         add_fwd_entry (lcm, lcm->pitr_map_index, dst_map_index);
332     }
333   else
334     {
335       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, deid);
336       if ((u32)~0 == mi)
337         {
338           clib_warning ("eid %U marked for removal, but not found in "
339                         "map-cache!", unformat_gid_address, deid);
340           return VNET_API_ERROR_INVALID_VALUE;
341         }
342
343       /* delete forwarding entry */
344       del_fwd_entry (lcm, 0, mi);
345
346       dm_args->is_add = 0;
347       gid_address_copy (&dm_args->deid, deid);
348       map = pool_elt_at_index (lcm->mapping_pool, mi);
349       dm_args->locator_set_index = map->locator_set_index;
350
351       /* delete mapping associated to fwd entry */
352       vnet_lisp_add_del_mapping (dm_args, 0);
353
354       refc = hash_get (lcm->dp_if_refcount_by_vni, vni);
355       ASSERT(refc != 0);
356       refc[0]--;
357
358       /* remove iface if needed */
359       if (refc[0] == 0)
360         {
361           ai->is_add = 0;
362           ai->vni = vni;
363           ai->table_id = p[0];
364           vnet_lisp_gpe_add_del_iface (ai, 0);
365           hash_unset (lcm->dp_if_refcount_by_vni, vni);
366         }
367     }
368   return rv;
369 }
370
371 /**
372  * Adds/removes/updates static remote mapping.
373  *
374  * This function also modifies forwarding entries if needed.
375  *
376  * @param deid destination EID
377  * @param seid source EID
378  * @param rlocs vector of remote locators
379  * @param action action for negative map-reply
380  * @param is_add add mapping if non-zero, delete otherwise
381  * @param del_all if set, delete all remote mappings
382  * @return return code
383  */
384 int
385 vnet_lisp_add_del_remote_mapping (gid_address_t * deid, gid_address_t * seid,
386                                   ip_address_t * rlocs, u8 action, u8 is_add,
387                                   u8 del_all)
388 {
389   vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args;
390   vnet_lisp_add_del_mapping_args_t _sm_args, * sm_args = &_sm_args;
391   vnet_lisp_add_del_locator_set_args_t _ls, * ls = &_ls;
392   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
393   u32 mi, ls_index = 0, dst_map_index, src_map_index;
394   locator_t loc;
395   ip_address_t * dl;
396   int rc = -1;
397
398   if (vnet_lisp_enable_disable_status() == 0)
399     {
400       clib_warning ("LISP is disabled!");
401       return VNET_API_ERROR_LISP_DISABLED;
402     }
403
404   if (del_all)
405     return vnet_lisp_clear_all_remote_mappings ();
406
407   memset (sm_args, 0, sizeof (sm_args[0]));
408   memset (dm_args, 0, sizeof (dm_args[0]));
409   memset (ls, 0, sizeof (ls[0]));
410
411   /* prepare remote locator set */
412   vec_foreach (dl, rlocs)
413     {
414       memset (&loc, 0, sizeof (loc));
415       gid_address_ip (&loc.address) = dl[0];
416       vec_add1 (ls->locators, loc);
417     }
418   src_map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
419
420   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, deid);
421   /* new mapping */
422   if ((u32)~0 == mi)
423     {
424       ls->is_add = 1;
425       ls->index = ~0;
426
427       /* process a negative mapping */
428       if (0 == vec_len (rlocs))
429         return lisp_add_del_negative_static_mapping (deid, ls,
430                                                      action, is_add);
431
432       if ((u32)~0 == src_map_index)
433         {
434           clib_warning ("seid %U not found!", format_gid_address, seid);
435           goto done;
436         }
437
438       if (!is_add)
439         {
440           clib_warning ("deid %U marked for removal but not "
441                         "found!", format_gid_address, deid);
442           goto done;
443         }
444
445       vnet_lisp_add_del_locator_set (ls, &ls_index);
446
447       /* add mapping */
448       gid_address_copy (&dm_args->deid, deid);
449       dm_args->is_add = 1;
450       dm_args->action = action;
451       dm_args->locator_set_index = ls_index;
452       vnet_lisp_add_del_mapping (dm_args, &dst_map_index);
453
454       /* add fwd tunnel */
455       add_fwd_entry (lcm, src_map_index, dst_map_index);
456     }
457   else
458     {
459       /* delete mapping */
460       if (!is_add)
461         {
462           /* delete forwarding entry */
463           del_fwd_entry (lcm, 0, mi);
464           dm_args->is_add = 0;
465           gid_address_copy (&dm_args->deid, deid);
466           mapping_t * map = pool_elt_at_index (lcm->mapping_pool, mi);
467           dm_args->locator_set_index = map->locator_set_index;
468
469           /* delete mapping associated to fwd entry */
470           vnet_lisp_add_del_mapping (dm_args, 0);
471
472           ls->is_add = 0;
473           ls->index = map->locator_set_index;
474           /* delete locator set */
475           vnet_lisp_add_del_locator_set (ls, 0);
476         }
477       /* update existing locator set */
478       else
479         {
480           if ((u32)~0 == src_map_index)
481             {
482               clib_warning ("seid %U not found!", format_gid_address, seid);
483               goto done;
484             }
485
486           mapping_t * old_map;
487           locator_set_t * old_ls;
488           old_map = pool_elt_at_index (lcm->mapping_pool, mi);
489
490           /* update mapping attributes */
491           old_map->action = action;
492
493           old_ls = pool_elt_at_index(lcm->locator_set_pool,
494                                      old_map->locator_set_index);
495           if (compare_locators (lcm, old_ls->locator_indices,
496                                 ls->locators))
497             {
498               /* set locator-set index to overwrite */
499               ls->is_add = 1;
500               ls->index = old_map->locator_set_index;
501               vnet_lisp_add_del_locator_set (ls, 0);
502               add_fwd_entry (lcm, src_map_index, mi);
503             }
504         }
505     }
506   /* success */
507   rc = 0;
508 done:
509   vec_free (ls->locators);
510   return rc;
511 }
512
513 int
514 vnet_lisp_clear_all_remote_mappings (void)
515 {
516   int rv = 0;
517   u32 mi, * map_indices = 0, * map_indexp;
518   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
519   vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args;
520   vnet_lisp_add_del_locator_set_args_t _ls, * ls = &_ls;
521
522   pool_foreach_index (mi, lcm->mapping_pool,
523     ({
524       vec_add1 (map_indices, mi);
525     }));
526
527   vec_foreach (map_indexp, map_indices)
528     {
529       mapping_t * map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
530       if (!map->local)
531         {
532           del_fwd_entry (lcm, 0, map_indexp[0]);
533
534           dm_args->is_add = 0;
535           gid_address_copy (&dm_args->deid, &map->eid);
536           dm_args->locator_set_index = map->locator_set_index;
537
538           /* delete mapping associated to fwd entry */
539           vnet_lisp_add_del_mapping (dm_args, 0);
540
541           ls->is_add = 0;
542           ls->local = 0;
543           ls->index = map->locator_set_index;
544           /* delete locator set */
545           rv = vnet_lisp_add_del_locator_set (ls, 0);
546           if (rv != 0)
547             goto cleanup;
548         }
549     }
550
551 cleanup:
552   if (map_indices)
553     vec_free (map_indices);
554   return rv;
555 }
556
557 /**
558  * Handler for add/del remote mapping CLI.
559  *
560  * @param vm vlib context
561  * @param input input from user
562  * @param cmd cmd
563  * @return pointer to clib error structure
564  */
565 static clib_error_t *
566 lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
567                                         unformat_input_t * input,
568                                         vlib_cli_command_t * cmd)
569 {
570   clib_error_t * error = 0;
571   unformat_input_t _line_input, * line_input = &_line_input;
572   u8 is_add = 1, del_all = 0;
573   ip_address_t rloc, * rlocs = 0;
574   ip_prefix_t * deid_ippref, * seid_ippref;
575   gid_address_t seid, deid;
576   u8 deid_set = 0, seid_set = 0;
577   u8 * s = 0;
578   u32 vni, action = ~0;
579
580   /* Get a line of input. */
581   if (! unformat_user (input, unformat_line_input, line_input))
582     return 0;
583
584   memset (&deid, 0, sizeof (deid));
585   memset (&seid, 0, sizeof (seid));
586
587   seid_ippref = &gid_address_ippref(&seid);
588   deid_ippref = &gid_address_ippref(&deid);
589
590   gid_address_type (&deid) = GID_ADDR_IP_PREFIX;
591   gid_address_type (&seid) = GID_ADDR_IP_PREFIX;
592
593   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
594     {
595       if (unformat (line_input, "del-all"))
596         del_all = 1;
597       else if (unformat (line_input, "del"))
598         is_add = 0;
599       else if (unformat (line_input, "add"))
600         ;
601       else if (unformat (line_input, "deid %U",
602                          unformat_ip_prefix, deid_ippref))
603         {
604           deid_set = 1;
605         }
606       else if (unformat (line_input, "vni %u", &vni))
607         {
608           gid_address_set_vni (&seid, vni);
609           gid_address_set_vni (&deid, vni);
610         }
611       else if (unformat (line_input, "seid %U",
612                          unformat_ip_prefix, seid_ippref))
613         {
614           seid_set = 1;
615         }
616       else if (unformat (line_input, "rloc %U", unformat_ip_address, &rloc))
617         vec_add1 (rlocs, rloc);
618       else if (unformat (line_input, "action %s", &s))
619         {
620           if (!strcmp ((char *)s, "no-action"))
621             action = ACTION_NONE;
622           if (!strcmp ((char *)s, "natively-forward"))
623             action = ACTION_NATIVELY_FORWARDED;
624           if (!strcmp ((char *)s, "send-map-request"))
625             action = ACTION_SEND_MAP_REQUEST;
626           else if (!strcmp ((char *)s, "drop"))
627             action = ACTION_DROP;
628           else
629             {
630               clib_warning ("invalid action: '%s'", s);
631               goto done;
632             }
633         }
634       else
635         {
636           clib_warning ("parse error");
637           goto done;
638         }
639     }
640
641   if (!del_all)
642     {
643       if (!deid_set)
644         {
645           clib_warning ("missing deid!");
646           goto done;
647         }
648
649       /* if seid not set, make sure the ip version is the same as that of the
650        * deid. This ensures the seid to be configured will be either 0/0 or
651        * ::/0 */
652       if (!seid_set)
653         ip_prefix_version(seid_ippref) = ip_prefix_version(deid_ippref);
654
655       if (is_add &&
656           (ip_prefix_version (deid_ippref) != ip_prefix_version(seid_ippref)))
657         {
658           clib_warning ("source and destination EIDs are not"
659                         " in the same IP family!");
660           goto done;
661         }
662
663       if (is_add && (~0 == action)
664           && 0 == vec_len (rlocs))
665         {
666           clib_warning ("no action set for negative map-reply!");
667           goto done;
668         }
669     }
670
671   int rv = vnet_lisp_add_del_remote_mapping (&deid, &seid, rlocs,
672                                              action, is_add, del_all);
673   if (rv)
674     clib_warning ("failed to %s remote mapping!",
675                   is_add ? "add" : "delete");
676
677 done:
678   unformat_free (line_input);
679   if (s)
680     vec_free (s);
681   return error;
682 }
683
684 VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) = {
685     .path = "lisp remote-mapping",
686     .short_help = "lisp remote-mapping add|del [del-all] vni <vni>"
687      "deid <dest-eid> seid <src-eid> [action <no-action|natively-forward|"
688      "send-map-request|drop>] rloc <dst-locator> [rloc <dst-locator> ... ]",
689     .function = lisp_add_del_remote_mapping_command_fn,
690 };
691
692 static clib_error_t *
693 lisp_show_map_resolvers_command_fn (vlib_main_t * vm,
694                                     unformat_input_t * input,
695                                     vlib_cli_command_t * cmd)
696 {
697   ip_address_t * addr;
698   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
699
700   vec_foreach (addr, lcm->map_resolvers)
701     {
702       vlib_cli_output (vm, "%U", format_ip_address, addr);
703     }
704   return 0;
705 }
706
707 VLIB_CLI_COMMAND (lisp_show_map_resolvers_command) = {
708     .path = "show lisp map-resolvers",
709     .short_help = "show lisp map-resolvers",
710     .function = lisp_show_map_resolvers_command_fn,
711 };
712
713 int
714 vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
715 {
716   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
717   u32 locator_set_index = ~0;
718   mapping_t * m;
719   uword * p;
720
721   if (vnet_lisp_enable_disable_status () == 0)
722     {
723       clib_warning ("LISP is disabled!");
724       return VNET_API_ERROR_LISP_DISABLED;
725     }
726
727   p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
728   if (!p)
729     {
730       clib_warning ("locator-set %v doesn't exist", locator_set_name);
731       return -1;
732     }
733   locator_set_index = p[0];
734
735   if (is_add)
736     {
737       pool_get (lcm->mapping_pool, m);
738       m->locator_set_index = locator_set_index;
739       m->local = 1;
740       lcm->pitr_map_index = m - lcm->mapping_pool;
741
742       /* enable pitr mode */
743       lcm->lisp_pitr = 1;
744     }
745   else
746     {
747       /* remove pitr mapping */
748       pool_put_index (lcm->mapping_pool, lcm->pitr_map_index);
749
750       /* disable pitr mode */
751       lcm->lisp_pitr = 0;
752     }
753   return 0;
754 }
755
756 static clib_error_t *
757 lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm,
758                                       unformat_input_t * input,
759                                       vlib_cli_command_t * cmd)
760 {
761   u8 locator_name_set = 0;
762   u8 * locator_set_name = 0;
763   u8 is_add = 1;
764   unformat_input_t _line_input, * line_input = &_line_input;
765   clib_error_t * error = 0;
766   int rv = 0;
767
768   /* Get a line of input. */
769   if (! unformat_user (input, unformat_line_input, line_input))
770     return 0;
771
772   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
773     {
774       if (unformat (line_input, "ls %_%v%_", &locator_set_name))
775         locator_name_set = 1;
776       else if (unformat (line_input, "disable"))
777         is_add = 0;
778       else
779         return clib_error_return (0, "parse error");
780     }
781
782   if (!locator_name_set)
783     {
784       clib_warning ("No locator set specified!");
785       goto done;
786     }
787   rv = vnet_lisp_pitr_set_locator_set (locator_set_name, is_add);
788   if (0 != rv)
789     {
790       error = clib_error_return(0, "failed to %s pitr!",
791                                 is_add ? "add" : "delete");
792     }
793
794 done:
795   if (locator_set_name)
796     vec_free (locator_set_name);
797   return error;
798 }
799
800 VLIB_CLI_COMMAND (lisp_pitr_set_locator_set_command) = {
801     .path = "lisp pitr",
802     .short_help = "lisp pitr [disable] ls <locator-set-name>",
803     .function = lisp_pitr_set_locator_set_command_fn,
804 };
805
806 static clib_error_t *
807 lisp_show_local_eid_table_command_fn (vlib_main_t * vm,
808                                       unformat_input_t * input,
809                                       vlib_cli_command_t * cmd)
810 {
811   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
812   mapping_t * mapit;
813
814   vlib_cli_output (vm, "%=20s%=16s", "EID", "Locator");
815   pool_foreach (mapit, lcm->mapping_pool,
816   ({
817     u8 * msg = 0;
818     locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
819                                             mapit->locator_set_index);
820     vlib_cli_output (vm, "%-16U%16v", format_gid_address, &mapit->eid,
821                      ls->name);
822     vec_free (msg);
823   }));
824
825   return 0;
826 }
827
828 VLIB_CLI_COMMAND (lisp_cp_show_local_eid_table_command) = {
829     .path = "show lisp eid-table",
830     .short_help = "Shows local EID table",
831     .function = lisp_show_local_eid_table_command_fn,
832 };
833
834 /* cleans locator to locator-set data and removes locators not part of
835  * any locator-set */
836 static void
837 clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
838 {
839   u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
840   locator_set_t * ls = pool_elt_at_index(lcm->locator_set_pool, lsi);
841   for (i = 0; i < vec_len(ls->locator_indices); i++)
842     {
843       loc_indexp = vec_elt_at_index(ls->locator_indices, i);
844       ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
845                                     loc_indexp[0]);
846       for (j = 0; j < vec_len(ls_indexes[0]); j++)
847         {
848           ls_indexp = vec_elt_at_index(ls_indexes[0], j);
849           if (ls_indexp[0] == lsi)
850             break;
851         }
852
853       /* delete index for removed locator-set*/
854       vec_del1(ls_indexes[0], j);
855
856       /* delete locator if it's part of no locator-set */
857       if (vec_len (ls_indexes[0]) == 0)
858         {
859           pool_put_index (lcm->locator_pool, loc_indexp[0]);
860           vec_add1 (to_be_deleted, i);
861         }
862     }
863
864   if (to_be_deleted)
865     {
866       for (i = 0; i < vec_len (to_be_deleted); i++)
867         {
868           loc_indexp = vec_elt_at_index (to_be_deleted, i);
869           vec_del1 (ls->locator_indices, loc_indexp[0]);
870         }
871       vec_free (to_be_deleted);
872     }
873 }
874
875 static inline
876 uword *get_locator_set_index(vnet_lisp_add_del_locator_set_args_t * a,
877                              uword * p)
878 {
879   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
880
881   ASSERT(a != NULL);
882   ASSERT(p != NULL);
883
884   /* find locator-set */
885   if (a->local)
886     {
887       p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
888     }
889   else
890     {
891       *p = a->index;
892     }
893
894   return p;
895 }
896
897 static inline
898 int is_locator_in_locator_set(lisp_cp_main_t * lcm, locator_set_t * ls,
899                               locator_t * loc)
900 {
901   locator_t * itloc;
902   u32 * locit;
903
904   ASSERT(ls != NULL);
905   ASSERT(loc != NULL);
906
907   vec_foreach(locit, ls->locator_indices)
908     {
909       itloc = pool_elt_at_index(lcm->locator_pool, locit[0]);
910       if (itloc->sw_if_index == loc->sw_if_index ||
911           !gid_address_cmp(&itloc->address, &loc->address))
912         {
913           clib_warning("Duplicate locator");
914           return VNET_API_ERROR_VALUE_EXIST;
915         }
916     }
917
918   return 0;
919 }
920
921 static inline
922 void remove_locator_from_locator_set(locator_set_t * ls, u32 * locit,
923                                      u32 ls_index, u32 loc_id)
924 {
925   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
926   u32 ** ls_indexes = NULL;
927
928   ASSERT(ls != NULL);
929   ASSERT(locit != NULL);
930
931   ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
932                                 locit[0]);
933   pool_put_index(lcm->locator_pool, locit[0]);
934   vec_del1(ls->locator_indices, loc_id);
935   vec_del1(ls_indexes[0], ls_index);
936 }
937
938 int
939 vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
940                            locator_set_t * ls, u32 * ls_result)
941 {
942   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
943   locator_t * loc = NULL, *itloc = NULL;
944   uword _p = (u32)~0, * p = &_p;
945   u32 loc_index = ~0, ls_index = ~0, * locit = NULL, ** ls_indexes = NULL;
946   u32 loc_id = ~0;
947   int ret = 0;
948
949   ASSERT(a != NULL);
950
951   if (vnet_lisp_enable_disable_status () == 0)
952     {
953       clib_warning ("LISP is disabled!");
954       return VNET_API_ERROR_LISP_DISABLED;
955     }
956
957   p = get_locator_set_index(a, p);
958   if (!p)
959     {
960       clib_warning("locator-set %v doesn't exist", a->name);
961       return VNET_API_ERROR_INVALID_ARGUMENT;
962     }
963
964   if (ls == 0)
965     {
966       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
967       if (!ls)
968         {
969           clib_warning("locator-set %d to be overwritten doesn't exist!",
970                        p[0]);
971           return VNET_API_ERROR_INVALID_ARGUMENT;
972         }
973     }
974
975   if (a->is_add)
976     {
977
978         if (ls_result)
979           ls_result[0] = p[0];
980
981         /* allocate locators */
982         vec_foreach (itloc, a->locators)
983           {
984             ret = is_locator_in_locator_set(lcm, ls, itloc);
985             if (0 != ret)
986               {
987                 return ret;
988               }
989
990             pool_get(lcm->locator_pool, loc);
991             loc[0] = itloc[0];
992             loc_index = loc - lcm->locator_pool;
993
994             vec_add1(ls->locator_indices, loc_index);
995
996             vec_validate (lcm->locator_to_locator_sets, loc_index);
997             ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
998                                           loc_index);
999             vec_add1(ls_indexes[0], ls_index);
1000           }
1001       }
1002     else
1003       {
1004         ls_index = p[0];
1005
1006         itloc = a->locators;
1007         loc_id = 0;
1008         vec_foreach (locit, ls->locator_indices)
1009           {
1010             loc = pool_elt_at_index(lcm->locator_pool, locit[0]);
1011
1012             if (loc->local && loc->sw_if_index == itloc->sw_if_index)
1013               {
1014                 remove_locator_from_locator_set(ls, locit,
1015                                                 ls_index, loc_id);
1016               }
1017             if (0 == loc->local &&
1018                 !gid_address_cmp(&loc->address, &itloc->address))
1019               {
1020                 remove_locator_from_locator_set(ls, locit,
1021                                                 ls_index, loc_id);
1022               }
1023
1024             loc_id++;
1025           }
1026       }
1027
1028   return 0;
1029 }
1030
1031 int
1032 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
1033                                u32 * ls_result)
1034 {
1035   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1036   locator_set_t * ls;
1037   uword _p = (u32)~0, * p = &_p;
1038   u32 ls_index;
1039   u32 ** eid_indexes;
1040   int ret = 0;
1041
1042   if (vnet_lisp_enable_disable_status () == 0)
1043     {
1044       clib_warning ("LISP is disabled!");
1045       return VNET_API_ERROR_LISP_DISABLED;
1046     }
1047
1048   if (a->is_add)
1049     {
1050       p = get_locator_set_index(a, p);
1051
1052       /* overwrite */
1053       if (p && p[0] != (u32)~0)
1054         {
1055           ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1056           if (!ls)
1057             {
1058               clib_warning("locator-set %d to be overwritten doesn't exist!",
1059                            p[0]);
1060               return -1;
1061             }
1062
1063           /* clean locator to locator-set vectors and remove locators if
1064            * they're not part of another locator-set */
1065           clean_locator_to_locator_set (lcm, p[0]);
1066
1067           /* remove locator indices from locator set */
1068           vec_free(ls->locator_indices);
1069
1070           ls_index = p[0];
1071
1072           if (ls_result)
1073             ls_result[0] = p[0];
1074         }
1075       /* new locator-set */
1076       else
1077         {
1078           pool_get(lcm->locator_set_pool, ls);
1079           memset(ls, 0, sizeof(*ls));
1080           ls_index = ls - lcm->locator_set_pool;
1081
1082           if (a->local)
1083             {
1084               ls->name = vec_dup(a->name);
1085
1086               if (!lcm->locator_set_index_by_name)
1087                 lcm->locator_set_index_by_name = hash_create_vec(
1088                     /* size */0, sizeof(ls->name[0]), sizeof(uword));
1089               hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index);
1090
1091               /* mark as local locator-set */
1092               vec_add1(lcm->local_locator_set_indexes, ls_index);
1093             }
1094           ls->local = a->local;
1095           if (ls_result)
1096             ls_result[0] = ls_index;
1097         }
1098
1099       ret = vnet_lisp_add_del_locator(a, ls, NULL);
1100       if (0 != ret)
1101         {
1102           return ret;
1103         }
1104     }
1105   else
1106     {
1107       p = get_locator_set_index(a, p);
1108       if (!p)
1109         {
1110           clib_warning("locator-set %v doesn't exists", a->name);
1111           return -1;
1112         }
1113
1114       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1115       if (!ls)
1116         {
1117           clib_warning("locator-set with index %d doesn't exists", p[0]);
1118           return -1;
1119         }
1120
1121       if (lcm->mreq_itr_rlocs == p[0])
1122         {
1123           clib_warning ("Can't delete the locator-set used to constrain "
1124                         "the itr-rlocs in map-requests!");
1125           return -1;
1126         }
1127
1128       if (vec_len(lcm->locator_set_to_eids) != 0)
1129       {
1130           eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, p[0]);
1131           if (vec_len(eid_indexes[0]) != 0)
1132           {
1133               clib_warning ("Can't delete a locator that supports a mapping!");
1134               return -1;
1135           }
1136       }
1137
1138       /* clean locator to locator-sets data */
1139       clean_locator_to_locator_set (lcm, p[0]);
1140
1141       if (ls->local)
1142         {
1143           u32 it, lsi;
1144
1145           vec_foreach_index(it, lcm->local_locator_set_indexes)
1146           {
1147             lsi = vec_elt(lcm->local_locator_set_indexes, it);
1148             if (lsi == p[0])
1149               {
1150                 vec_del1(lcm->local_locator_set_indexes, it);
1151                 break;
1152               }
1153           }
1154           hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
1155         }
1156       vec_free(ls->name);
1157       vec_free(ls->locator_indices);
1158       pool_put(lcm->locator_set_pool, ls);
1159     }
1160   return 0;
1161 }
1162
1163 clib_error_t *
1164 vnet_lisp_enable_disable (u8 is_enabled)
1165 {
1166   vnet_lisp_gpe_add_del_iface_args_t _ai, * ai= &_ai;
1167   uword * table_id, * refc;
1168   u32 i;
1169   clib_error_t * error = 0;
1170   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1171   vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
1172
1173   a->is_en = is_enabled;
1174   error = vnet_lisp_gpe_enable_disable (a);
1175   if (error)
1176     {
1177       return clib_error_return (0, "failed to %s data-plane!",
1178                                 a->is_en ? "enable" : "disable");
1179     }
1180
1181   if (is_enabled)
1182     {
1183       /* enable all ifaces */
1184       for (i = 0; i < vec_len (lcm->local_mappings_indexes); i++)
1185         {
1186           mapping_t * m = vec_elt_at_index (lcm->mapping_pool, i);
1187           ai->is_add = 1;
1188           ai->vni = gid_address_vni (&m->eid);
1189
1190           refc = hash_get (lcm->dp_if_refcount_by_vni, ai->vni);
1191           if (!refc)
1192             {
1193               table_id = hash_get (lcm->table_id_by_vni, ai->vni);
1194               if (table_id)
1195                 {
1196                   ai->table_id = table_id[0];
1197                   /* enables interface and adds defaults */
1198                   vnet_lisp_gpe_add_del_iface (ai, 0);
1199                 }
1200               else
1201                 return clib_error_return (0, "no table_id found for vni %u!",
1202                                           ai->vni);
1203
1204               hash_set (lcm->dp_if_refcount_by_vni, ai->vni, 1);
1205             }
1206           else
1207             {
1208               refc[0]++;
1209             }
1210         }
1211     }
1212   else
1213     {
1214       /* clear refcount table */
1215       hash_free (lcm->dp_if_refcount_by_vni);
1216       hash_free (lcm->fwd_entry_by_mapping_index);
1217       pool_free (lcm->fwd_entry_pool);
1218     }
1219
1220   /* update global flag */
1221   lcm->is_enabled = is_enabled;
1222
1223   return 0;
1224 }
1225
1226 static clib_error_t *
1227 lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
1228                                    vlib_cli_command_t * cmd)
1229 {
1230   unformat_input_t _line_input, * line_input = &_line_input;
1231   u8 is_enabled = 0;
1232   u8 is_set = 0;
1233
1234   /* Get a line of input. */
1235   if (! unformat_user (input, unformat_line_input, line_input))
1236     return 0;
1237
1238   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1239     {
1240       if (unformat (line_input, "enable"))
1241         {
1242           is_set = 1;
1243           is_enabled = 1;
1244         }
1245       else if (unformat (line_input, "disable"))
1246         is_set = 1;
1247       else
1248         {
1249           return clib_error_return (0, "parse error: '%U'",
1250                                    format_unformat_error, line_input);
1251         }
1252     }
1253
1254   if (!is_set)
1255       return clib_error_return (0, "state not set");
1256
1257   return vnet_lisp_enable_disable (is_enabled);
1258 }
1259
1260 VLIB_CLI_COMMAND (lisp_cp_enable_disable_command) = {
1261     .path = "lisp",
1262     .short_help = "lisp [enable|disable]",
1263     .function = lisp_enable_disable_command_fn,
1264 };
1265
1266 u8
1267 vnet_lisp_enable_disable_status (void)
1268 {
1269   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1270   return lcm->is_enabled;
1271 }
1272
1273 static u8 *
1274 format_lisp_status (u8 * s, va_list * args)
1275 {
1276   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1277   return format (s, "%s", lcm->is_enabled ? "enabled" : "disabled");
1278 }
1279
1280 static clib_error_t *
1281 lisp_show_status_command_fn (vlib_main_t * vm, unformat_input_t * input,
1282                              vlib_cli_command_t * cmd)
1283 {
1284   u8 * msg = 0;
1285   msg = format (msg, "feature: %U\ngpe: %U\n",
1286                 format_lisp_status, format_vnet_lisp_gpe_status);
1287   vlib_cli_output (vm, "%v", msg);
1288   vec_free (msg);
1289   return 0;
1290 }
1291
1292 VLIB_CLI_COMMAND (lisp_show_status_command) = {
1293     .path = "show lisp status",
1294     .short_help = "show lisp status",
1295     .function = lisp_show_status_command_fn,
1296 };
1297 static clib_error_t *
1298 lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
1299                                      vlib_cli_command_t * cmd)
1300 {
1301   lisp_gpe_main_t * lgm = &lisp_gpe_main;
1302   vnet_main_t * vnm = lgm->vnet_main;
1303   unformat_input_t _line_input, * line_input = &_line_input;
1304   u8 is_add = 1;
1305   clib_error_t * error = 0;
1306   u8 * locator_set_name = 0;
1307   locator_t locator, * locators = 0;
1308   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
1309   u32 ls_index = 0;
1310   int rv = 0;
1311
1312   memset(&locator, 0, sizeof(locator));
1313   memset(a, 0, sizeof(a[0]));
1314
1315   /* Get a line of input. */
1316   if (! unformat_user (input, unformat_line_input, line_input))
1317     return 0;
1318
1319   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1320     {
1321       if (unformat (line_input, "add %_%v%_", &locator_set_name))
1322         is_add = 1;
1323       else if (unformat (line_input, "del %_%v%_", &locator_set_name))
1324         is_add = 0;
1325       else if (unformat (line_input, "iface %U p %d w %d",
1326                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
1327                          &locator.priority, &locator.weight))
1328         {
1329           locator.local = 1;
1330           vec_add1(locators, locator);
1331         }
1332       else
1333         {
1334           error = unformat_parse_error(line_input);
1335           goto done;
1336         }
1337     }
1338
1339   a->name = locator_set_name;
1340   a->locators = locators;
1341   a->is_add = is_add;
1342   a->local = 1;
1343
1344   rv = vnet_lisp_add_del_locator_set(a, &ls_index);
1345   if (0 != rv)
1346     {
1347       error = clib_error_return(0, "failed to %s locator-set!",
1348                                 is_add ? "add" : "delete");
1349     }
1350
1351  done:
1352   vec_free(locators);
1353   if (locator_set_name)
1354     vec_free (locator_set_name);
1355   return error;
1356 }
1357
1358 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
1359     .path = "lisp locator-set",
1360     .short_help = "lisp locator-set add/del <name> [iface <iface-name> "
1361         "p <priority> w <weight>]",
1362     .function = lisp_add_del_locator_set_command_fn,
1363 };
1364
1365 static clib_error_t *
1366 lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
1367                                      vlib_cli_command_t * cmd)
1368 {
1369   lisp_gpe_main_t * lgm = &lisp_gpe_main;
1370   vnet_main_t * vnm = lgm->vnet_main;
1371   unformat_input_t _line_input, * line_input = &_line_input;
1372   u8 is_add = 1;
1373   clib_error_t * error = 0;
1374   u8 * locator_set_name = 0;
1375   u8 locator_set_name_set = 0;
1376   locator_t locator, * locators = 0;
1377   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
1378   u32 ls_index = 0;
1379
1380   memset(&locator, 0, sizeof(locator));
1381   memset(a, 0, sizeof(a[0]));
1382
1383   /* Get a line of input. */
1384   if (! unformat_user (input, unformat_line_input, line_input))
1385     return 0;
1386
1387   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1388     {
1389       if (unformat (line_input, "add"))
1390         is_add = 1;
1391       else if (unformat (line_input, "del"))
1392         is_add = 0;
1393       else if (unformat(line_input, "locator-set %_%v%_", &locator_set_name))
1394         locator_set_name_set = 1;
1395       else if (unformat (line_input, "iface %U p %d w %d",
1396                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
1397                          &locator.priority, &locator.weight))
1398         {
1399           locator.local = 1;
1400           vec_add1(locators, locator);
1401         }
1402       else
1403         {
1404           error = unformat_parse_error(line_input);
1405           goto done;
1406         }
1407     }
1408
1409   if (!locator_set_name_set)
1410     {
1411       error = clib_error_return(0, "locator_set name not set!");
1412       goto done;
1413   }
1414
1415   a->name = locator_set_name;
1416   a->locators = locators;
1417   a->is_add = is_add;
1418   a->local = 1;
1419
1420   vnet_lisp_add_del_locator(a, 0, &ls_index);
1421
1422  done:
1423   vec_free(locators);
1424   vec_free (locator_set_name);
1425   return error;
1426 }
1427
1428 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_in_set_command) = {
1429     .path = "lisp locator",
1430     .short_help = "lisp locator add/del locator-set <name> iface <iface-name> "
1431                   "p <priority> w <weight>",
1432     .function = lisp_add_del_locator_in_set_command_fn,
1433 };
1434
1435 static clib_error_t *
1436 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
1437                                       unformat_input_t * input,
1438                                       vlib_cli_command_t * cmd)
1439 {
1440   locator_set_t * lsit;
1441   locator_t * loc;
1442   u32 * locit;
1443   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1444
1445   vlib_cli_output (vm, "%=20s%=16s%=16s%=16s", "Locator-set", "Locator",
1446                    "Priority", "Weight");
1447   pool_foreach (lsit, lcm->locator_set_pool,
1448   ({
1449     u8 * msg = 0;
1450     int next_line = 0;
1451     msg = format (msg, "%=16v", lsit->name);
1452     vec_foreach (locit, lsit->locator_indices)
1453       {
1454         if (next_line)
1455           {
1456             msg = format (msg, "%16s", " ");
1457           }
1458         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1459         if (loc->local)
1460           msg = format (msg, "%16d%16d%16d\n", loc->sw_if_index, loc->priority,
1461                         loc->weight);
1462         else
1463           msg = format (msg, "%16U%16d%16d\n", format_ip_address,
1464                         gid_address_ip(&loc->address), loc->priority,
1465                         loc->weight);
1466         next_line = 1;
1467       }
1468     vlib_cli_output (vm, "%v", msg);
1469     vec_free (msg);
1470   }));
1471   return 0;
1472 }
1473
1474 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
1475     .path = "show lisp locator-set",
1476     .short_help = "Shows locator-sets",
1477     .function = lisp_cp_show_locator_sets_command_fn,
1478 };
1479
1480 int
1481 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
1482 {
1483   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1484   ip_address_t * addr;
1485   u32 i;
1486
1487   if (vnet_lisp_enable_disable_status () == 0)
1488     {
1489       clib_warning ("LISP is disabled!");
1490       return VNET_API_ERROR_LISP_DISABLED;
1491     }
1492
1493   if (a->is_add)
1494     {
1495       vec_foreach(addr, lcm->map_resolvers)
1496         {
1497           if (!ip_address_cmp (addr, &a->address))
1498             {
1499               clib_warning("map-resolver %U already exists!", format_ip_address,
1500                            &a->address);
1501               return -1;
1502             }
1503         }
1504       vec_add1(lcm->map_resolvers, a->address);
1505     }
1506   else
1507     {
1508       for (i = 0; i < vec_len(lcm->map_resolvers); i++)
1509         {
1510           addr = vec_elt_at_index(lcm->map_resolvers, i);
1511           if (!ip_address_cmp (addr, &a->address))
1512             {
1513               vec_delete(lcm->map_resolvers, 1, i);
1514               break;
1515             }
1516         }
1517     }
1518   return 0;
1519 }
1520
1521 static clib_error_t *
1522 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
1523                                          unformat_input_t * input,
1524                                          vlib_cli_command_t * cmd)
1525 {
1526   unformat_input_t _line_input, * line_input = &_line_input;
1527   u8 is_add = 1;
1528   ip_address_t ip_addr;
1529   clib_error_t * error = 0;
1530   int rv = 0;
1531   vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a;
1532
1533   /* Get a line of input. */
1534   if (! unformat_user (input, unformat_line_input, line_input))
1535     return 0;
1536
1537   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1538     {
1539       if (unformat (line_input, "add"))
1540         is_add = 1;
1541       else if (unformat (line_input, "del"))
1542         is_add = 0;
1543       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
1544         ;
1545       else
1546         {
1547           error = unformat_parse_error(line_input);
1548           goto done;
1549         }
1550     }
1551   a->is_add = is_add;
1552   a->address = ip_addr;
1553   rv = vnet_lisp_add_del_map_resolver (a);
1554   if (0 != rv)
1555     {
1556       error = clib_error_return(0, "failed to %s map-resolver!",
1557                                 is_add ? "add" : "delete");
1558     }
1559
1560  done:
1561   return error;
1562 }
1563
1564 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
1565     .path = "lisp map-resolver",
1566     .short_help = "lisp map-resolver add/del <ip_address>",
1567     .function = lisp_add_del_map_resolver_command_fn,
1568 };
1569
1570 int
1571 vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
1572 {
1573   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1574   uword * p = 0;
1575
1576   //TODO: Wait for merge https://gerrit.fd.io/r/#/c/1427/
1577 //   if (vnet_lisp_enable_disable_status () == 0)
1578 //     {
1579 //       clib_warning ("LISP is disabled!");
1580 //       return VNET_API_ERROR_LISP_DISABLED;
1581 //     }
1582
1583   if (a->is_add)
1584     {
1585       p = hash_get_mem(lcm->locator_set_index_by_name, a->locator_set_name);
1586       if (!p)
1587         {
1588           clib_warning("locator-set %v doesn't exist", a->locator_set_name);
1589           return VNET_API_ERROR_INVALID_ARGUMENT;
1590         }
1591
1592       lcm->mreq_itr_rlocs = p[0];
1593     }
1594   else
1595     {
1596       lcm->mreq_itr_rlocs = ~0;
1597     }
1598
1599   return 0;
1600 }
1601
1602 static clib_error_t *
1603 lisp_add_del_mreq_itr_rlocs_command_fn(vlib_main_t * vm,
1604                                        unformat_input_t * input,
1605                                        vlib_cli_command_t * cmd)
1606 {
1607   unformat_input_t _line_input, * line_input = &_line_input;
1608   u8 is_add = 1;
1609   u8 * locator_set_name = 0;
1610   clib_error_t * error = 0;
1611   int rv = 0;
1612   vnet_lisp_add_del_mreq_itr_rloc_args_t _a, * a = &_a;
1613
1614   /* Get a line of input. */
1615   if (! unformat_user (input, unformat_line_input, line_input))
1616     return 0;
1617
1618   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1619     {
1620       if (unformat (line_input, "del"))
1621         is_add = 0;
1622       else if (unformat (line_input, "add %s", &locator_set_name))
1623         is_add = 1;
1624       else
1625         {
1626           error = unformat_parse_error(line_input);
1627           goto done;
1628         }
1629     }
1630
1631   a->is_add = is_add;
1632   a->locator_set_name = locator_set_name;
1633   rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
1634   if (0 != rv)
1635     {
1636       error = clib_error_return(0, "failed to %s map-request itr-rlocs!",
1637                                 is_add ? "add" : "delete");
1638     }
1639
1640   vec_free(locator_set_name);
1641
1642  done:
1643   return error;
1644
1645 }
1646
1647 VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
1648     .path = "lisp map-request itr-rlocs",
1649     .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
1650     .function = lisp_add_del_mreq_itr_rlocs_command_fn,
1651 };
1652
1653 static clib_error_t *
1654 lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
1655                                     unformat_input_t * input,
1656                                     vlib_cli_command_t * cmd)
1657 {
1658   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1659   locator_set_t * loc_set;
1660
1661   vlib_cli_output (vm, "%=20s", "itr-rlocs");
1662
1663   if (~0 == lcm->mreq_itr_rlocs)
1664     {
1665       return 0;
1666     }
1667
1668   loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
1669
1670   vlib_cli_output (vm, "%=20s", loc_set->name);
1671
1672   return 0;
1673 }
1674
1675 VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
1676     .path = "show lisp map-request itr-rlocs",
1677     .short_help = "Shows map-request itr-rlocs",
1678     .function = lisp_show_mreq_itr_rlocs_command_fn,
1679 };
1680
1681 /* Statistics (not really errors) */
1682 #define foreach_lisp_cp_lookup_error           \
1683 _(DROP, "drop")                                \
1684 _(MAP_REQUESTS_SENT, "map-request sent")
1685
1686 static char * lisp_cp_lookup_error_strings[] = {
1687 #define _(sym,string) string,
1688   foreach_lisp_cp_lookup_error
1689 #undef _
1690 };
1691
1692 typedef enum
1693 {
1694 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
1695     foreach_lisp_cp_lookup_error
1696 #undef _
1697     LISP_CP_LOOKUP_N_ERROR,
1698 } lisp_cp_lookup_error_t;
1699
1700 typedef enum
1701 {
1702   LISP_CP_LOOKUP_NEXT_DROP,
1703   LISP_CP_LOOKUP_NEXT_IP4_LOOKUP,
1704   LISP_CP_LOOKUP_NEXT_IP6_LOOKUP,
1705   LISP_CP_LOOKUP_N_NEXT,
1706 } lisp_cp_lookup_next_t;
1707
1708 typedef struct
1709 {
1710   gid_address_t dst_eid;
1711   ip_address_t map_resolver_ip;
1712 } lisp_cp_lookup_trace_t;
1713
1714 u8 *
1715 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
1716 {
1717   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1718   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1719   lisp_cp_lookup_trace_t * t = va_arg (*args, lisp_cp_lookup_trace_t *);
1720
1721   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
1722               format_ip_address, &t->map_resolver_ip, format_gid_address,
1723               &t->dst_eid);
1724   return s;
1725 }
1726
1727 ip_interface_address_t *
1728 ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
1729                                           u8 loop)
1730 {
1731   vnet_main_t *vnm = vnet_get_main ();
1732   vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index);
1733   if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
1734     sw_if_index = swif->unnumbered_sw_if_index;
1735   u32 ia =
1736       (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
1737           vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
1738           (u32) ~0;
1739   return pool_elt_at_index((lm)->if_address_pool, ia);
1740 }
1741
1742 void *
1743 ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
1744                                 u8 version)
1745 {
1746   ip_interface_address_t * ia;
1747
1748   ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
1749   if (!ia)
1750     return 0;
1751   return ip_interface_address_get_address (lm, ia);
1752 }
1753
1754 int
1755 ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
1756                                    u8 version, ip_address_t * result)
1757 {
1758   ip_lookup_main_t * lm;
1759   void * addr;
1760
1761   lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1762   addr = ip_interface_get_first_address (lm, sw_if_index, version);
1763   if (!addr)
1764     return 0;
1765
1766   ip_address_set (result, addr, version);
1767   return 1;
1768 }
1769
1770 static u32
1771 ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
1772                           ip_address_t * dst)
1773 {
1774   if (ip_addr_version (dst) == IP4)
1775       return ip4_fib_lookup_with_table (lcm->im4, fib_index, &ip_addr_v4(dst),
1776                                         0);
1777   else
1778       return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6(dst));
1779 }
1780
1781 u32
1782 ip_fib_get_egress_iface_for_dst_with_lm (lisp_cp_main_t * lcm,
1783                                          ip_address_t * dst,
1784                                          ip_lookup_main_t * lm)
1785 {
1786   u32 adj_index;
1787   ip_adjacency_t * adj;
1788
1789   adj_index = ip_fib_lookup_with_table (lcm, 0, dst);
1790   adj = ip_get_adjacency (lm, adj_index);
1791
1792   if (adj == 0)
1793     return ~0;
1794
1795   /* we only want outgoing routes */
1796   if (adj->lookup_next_index != IP_LOOKUP_NEXT_ARP
1797       && adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
1798     return ~0;
1799
1800   return adj->rewrite_header.sw_if_index;
1801 }
1802
1803 /**
1804  * Find the sw_if_index of the interface that would be used to egress towards
1805  * dst.
1806  */
1807 u32
1808 ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
1809 {
1810   ip_lookup_main_t * lm;
1811
1812   lm = ip_addr_version (dst) == IP4 ?
1813       &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1814
1815   return ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
1816 }
1817
1818 /**
1819  * Find first IP of the interface that would be used to egress towards dst.
1820  * Returns 1 if the address is found 0 otherwise.
1821  */
1822 int
1823 ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
1824                                     ip_address_t * result)
1825 {
1826   u32 si;
1827   ip_lookup_main_t * lm;
1828   void * addr = 0;
1829   u8 ipver;
1830
1831   ASSERT(result != 0);
1832
1833   ipver = ip_addr_version(dst);
1834
1835   lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1836   si = ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
1837
1838   if ((u32) ~0 == si)
1839     return 0;
1840
1841   /* find the first ip address */
1842   addr = ip_interface_get_first_address (lm, si, ipver);
1843   if (0 == addr)
1844     return 0;
1845
1846   ip_address_set (result, addr, ipver);
1847   return 1;
1848 }
1849
1850 int
1851 get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
1852                            ip_address_t * sloc)
1853 {
1854   ip_address_t * mrit;
1855
1856   if (vec_len(lcm->map_resolvers) == 0)
1857     {
1858       clib_warning("No map-resolver configured");
1859       return 0;
1860     }
1861
1862   /* find the first mr ip we have a route to and the ip of the
1863    * iface that has a route to it */
1864   vec_foreach(mrit, lcm->map_resolvers)
1865     {
1866       if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, mrit, sloc)) {
1867           ip_address_copy(mr_ip, mrit);
1868           return 1;
1869       }
1870     }
1871
1872   clib_warning("Can't find map-resolver and local interface ip!");
1873   return 0;
1874 }
1875
1876 static gid_address_t *
1877 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
1878 {
1879   void * addr;
1880   u32 i;
1881   locator_t * loc;
1882   u32 * loc_indexp;
1883   ip_interface_address_t * ia = 0;
1884   gid_address_t gid_data, * gid = &gid_data;
1885   gid_address_t * rlocs = 0;
1886   ip_prefix_t * ippref = &gid_address_ippref (gid);
1887   ip_address_t * rloc = &ip_prefix_addr (ippref);
1888
1889   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
1890   for (i = 0; i < vec_len(loc_set->locator_indices); i++)
1891     {
1892       loc_indexp = vec_elt_at_index(loc_set->locator_indices, i);
1893       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
1894
1895       /* Add ipv4 locators first TODO sort them */
1896       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
1897                                     loc->sw_if_index, 1 /* unnumbered */,
1898       ({
1899         addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
1900         ip_address_set (rloc, addr, IP4);
1901         ip_prefix_len (ippref) = 32;
1902         vec_add1 (rlocs, gid[0]);
1903       }));
1904
1905       /* Add ipv6 locators */
1906       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
1907                                     loc->sw_if_index, 1 /* unnumbered */,
1908       ({
1909         addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
1910         ip_address_set (rloc, addr, IP6);
1911         ip_prefix_len (ippref) = 128;
1912         vec_add1 (rlocs, gid[0]);
1913       }));
1914     }
1915   return rlocs;
1916 }
1917
1918 static vlib_buffer_t *
1919 build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
1920                                 gid_address_t * seid, gid_address_t * deid,
1921                                 locator_set_t * loc_set, ip_address_t * mr_ip,
1922                                 ip_address_t * sloc, u8 is_smr_invoked,
1923                                 u64 *nonce_res, u32 * bi_res)
1924 {
1925   vlib_buffer_t * b;
1926   u32 bi;
1927   gid_address_t * rlocs = 0;
1928
1929   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
1930     {
1931       clib_warning ("Can't allocate buffer for Map-Request!");
1932       return 0;
1933     }
1934
1935   b = vlib_get_buffer (vm, bi);
1936
1937   /* leave some space for the encap headers */
1938   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
1939
1940   /* get rlocs */
1941   rlocs = build_itr_rloc_list (lcm, loc_set);
1942
1943   /* put lisp msg */
1944   lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked, nonce_res);
1945
1946   /* push ecm: udp-ip-lisp */
1947   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
1948
1949   /* push outer ip header */
1950   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
1951                        mr_ip);
1952
1953   bi_res[0] = bi;
1954
1955   vec_free(rlocs);
1956   return b;
1957 }
1958
1959 static void
1960 send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
1961                                gid_address_t * seid, gid_address_t * deid,
1962                                u8 is_smr_invoked)
1963 {
1964   u32 next_index, bi = 0, * to_next, map_index;
1965   vlib_buffer_t * b;
1966   vlib_frame_t * f;
1967   u64 nonce = 0;
1968   locator_set_t * loc_set;
1969   mapping_t * map;
1970   pending_map_request_t * pmr;
1971   ip_address_t mr_ip, sloc;
1972   u32 ls_index;
1973
1974   /* get locator-set for seid */
1975   if (!lcm->lisp_pitr)
1976     {
1977       map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
1978       if (map_index == ~0)
1979         {
1980           clib_warning("No local mapping found in eid-table for %U!",
1981                        format_gid_address, seid);
1982           return;
1983         }
1984
1985       map = pool_elt_at_index (lcm->mapping_pool, map_index);
1986
1987       if (!map->local)
1988         {
1989           clib_warning("Mapping found for src eid %U is not marked as local!",
1990                        format_gid_address, seid);
1991           return;
1992         }
1993       ls_index = map->locator_set_index;
1994     }
1995   else
1996     {
1997       map_index = lcm->pitr_map_index;
1998       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
1999       ls_index = map->locator_set_index;
2000     }
2001
2002   /* overwrite locator set if map-request itr-rlocs configured */
2003   if (~0 != lcm->mreq_itr_rlocs)
2004     {
2005       ls_index = lcm->mreq_itr_rlocs;
2006     }
2007
2008   loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
2009
2010   /* get local iface ip to use in map-request */
2011   if (0 == get_mr_and_local_iface_ip (lcm, &mr_ip, &sloc))
2012     return;
2013
2014   /* build the encapsulated map request */
2015   b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set, &mr_ip,
2016                                       &sloc, is_smr_invoked, &nonce, &bi);
2017
2018   if (!b)
2019     return;
2020
2021   /* set fib index and lookup node */
2022   vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0;
2023   next_index = (ip_addr_version(&mr_ip) == IP4) ?
2024       ip4_lookup_node.index : ip6_lookup_node.index;
2025
2026   f = vlib_get_frame_to_node (vm, next_index);
2027
2028   /* Enqueue the packet */
2029   to_next = vlib_frame_vector_args (f);
2030   to_next[0] = bi;
2031   f->n_vectors = 1;
2032   vlib_put_frame_to_node (vm, next_index, f);
2033
2034   /* add map-request to pending requests table */
2035   pool_get(lcm->pending_map_requests_pool, pmr);
2036   gid_address_copy (&pmr->src, seid);
2037   gid_address_copy (&pmr->dst, deid);
2038   pmr->src_mapping_index = map_index;
2039   hash_set(lcm->pending_map_requests_by_nonce, nonce,
2040            pmr - lcm->pending_map_requests_pool);
2041 }
2042
2043 static void
2044 get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst)
2045 {
2046   ip4_header_t * ip4 = hdr;
2047   ip6_header_t * ip6;
2048
2049   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
2050     {
2051       ip_address_set(src, &ip4->src_address, IP4);
2052       ip_address_set(dst, &ip4->dst_address, IP4);
2053     }
2054   else
2055     {
2056       ip6 = hdr;
2057       ip_address_set(src, &ip6->src_address, IP6);
2058       ip_address_set(dst, &ip6->dst_address, IP6);
2059     }
2060 }
2061
2062 static uword
2063 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
2064               vlib_frame_t * from_frame)
2065 {
2066   u32 * from, * to_next_drop, di, si;
2067   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main();
2068   u32 pkts_mapped = 0;
2069   uword n_left_from, n_left_to_next_drop;
2070
2071   from = vlib_frame_vector_args (from_frame);
2072   n_left_from = from_frame->n_vectors;
2073
2074   while (n_left_from > 0)
2075     {
2076       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
2077                            to_next_drop, n_left_to_next_drop);
2078
2079       while (n_left_from > 0 && n_left_to_next_drop > 0)
2080         {
2081           u32 pi0;
2082           vlib_buffer_t * p0;
2083           ip4_header_t * ip0;
2084           gid_address_t src, dst;
2085           ip_prefix_t * spref, * dpref;
2086
2087           gid_address_type (&src) = GID_ADDR_IP_PREFIX;
2088           spref = &gid_address_ippref(&src);
2089           gid_address_type (&dst) = GID_ADDR_IP_PREFIX;
2090           dpref = &gid_address_ippref(&dst);
2091
2092           pi0 = from[0];
2093           from += 1;
2094           n_left_from -= 1;
2095           to_next_drop[0] = pi0;
2096           to_next_drop += 1;
2097           n_left_to_next_drop -= 1;
2098
2099           p0 = vlib_get_buffer (vm, pi0);
2100           p0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
2101
2102           /* src/dst eid pair */
2103           ip0 = vlib_buffer_get_current (p0);
2104           get_src_and_dst (ip0, &ip_prefix_addr(spref), &ip_prefix_addr(dpref));
2105           ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref));
2106           ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref));
2107
2108           /* if we have remote mapping for destination already in map-chache
2109              add forwarding tunnel directly. If not send a map-request */
2110           di = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
2111           if (~0 != di)
2112             {
2113               mapping_t * m =  vec_elt_at_index (lcm->mapping_pool, di);
2114               /* send a map-request also in case of negative mapping entry
2115                 with corresponding action */
2116               if (m->action == ACTION_SEND_MAP_REQUEST)
2117                 {
2118                   /* send map-request */
2119                   send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2120                   pkts_mapped++;
2121                 }
2122               else
2123                 {
2124                   si =  gid_dictionary_lookup (&lcm->mapping_index_by_gid,
2125                                                &src);
2126                   if (~0 != si)
2127                     {
2128                       add_fwd_entry (lcm, si, di);
2129                     }
2130                 }
2131             }
2132           else
2133             {
2134               /* send map-request */
2135               send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2136               pkts_mapped++;
2137             }
2138
2139           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
2140             {
2141               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, p0,
2142                                                           sizeof(*tr));
2143
2144               memset(tr, 0, sizeof(*tr));
2145               gid_address_copy (&tr->dst_eid, &dst);
2146               if (vec_len(lcm->map_resolvers) > 0)
2147                 {
2148                   clib_memcpy (&tr->map_resolver_ip,
2149                                vec_elt_at_index(lcm->map_resolvers, 0),
2150                                sizeof(ip_address_t));
2151                 }
2152             }
2153         }
2154
2155       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop);
2156     }
2157   vlib_node_increment_counter (vm, node->node_index,
2158                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
2159                                pkts_mapped);
2160   return from_frame->n_vectors;
2161 }
2162
2163 VLIB_REGISTER_NODE (lisp_cp_lookup_node) = {
2164   .function = lisp_cp_lookup,
2165   .name = "lisp-cp-lookup",
2166   .vector_size = sizeof (u32),
2167   .format_trace = format_lisp_cp_lookup_trace,
2168   .type = VLIB_NODE_TYPE_INTERNAL,
2169
2170   .n_errors = LISP_CP_LOOKUP_N_ERROR,
2171   .error_strings = lisp_cp_lookup_error_strings,
2172
2173   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
2174
2175   .next_nodes = {
2176       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
2177       [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup",
2178       [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup",
2179   },
2180 };
2181
2182 /* lisp_cp_input statistics */
2183 #define foreach_lisp_cp_input_error                   \
2184 _(DROP, "drop")                                        \
2185 _(MAP_REPLIES_RECEIVED, "map-replies received")
2186
2187 static char * lisp_cp_input_error_strings[] = {
2188 #define _(sym,string) string,
2189   foreach_lisp_cp_input_error
2190 #undef _
2191 };
2192
2193 typedef enum
2194 {
2195 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
2196     foreach_lisp_cp_input_error
2197 #undef _
2198     LISP_CP_INPUT_N_ERROR,
2199 } lisp_cp_input_error_t;
2200
2201 typedef enum
2202 {
2203   LISP_CP_INPUT_NEXT_DROP,
2204   LISP_CP_INPUT_N_NEXT,
2205 } lisp_cp_input_next_t;
2206
2207 typedef struct
2208 {
2209   gid_address_t dst_eid;
2210   ip4_address_t map_resolver_ip;
2211 } lisp_cp_input_trace_t;
2212
2213 u8 *
2214 format_lisp_cp_input_trace (u8 * s, va_list * args)
2215 {
2216   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2217   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2218   CLIB_UNUSED(lisp_cp_input_trace_t * t) = va_arg (*args, lisp_cp_input_trace_t *);
2219
2220   s = format (s, "LISP-CP-INPUT: TODO");
2221   return s;
2222 }
2223
2224 static void
2225 del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
2226                u32 dst_map_index)
2227 {
2228   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
2229   fwd_entry_t * fe = 0;
2230   uword * feip = 0;
2231   memset(a, 0, sizeof(*a));
2232
2233   feip = hash_get(lcm->fwd_entry_by_mapping_index, dst_map_index);
2234   if (!feip)
2235     return;
2236
2237   fe = pool_elt_at_index(lcm->fwd_entry_pool, feip[0]);
2238
2239   /* delete dp fwd entry */
2240   u32 sw_if_index;
2241   a->is_add = 0;
2242   a->dlocator = fe->dst_loc;
2243   a->slocator = fe->src_loc;
2244   a->vni = gid_address_vni(&a->deid);
2245   gid_address_copy(&a->deid, &fe->deid);
2246
2247   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
2248
2249   /* delete entry in fwd table */
2250   hash_unset(lcm->fwd_entry_by_mapping_index, dst_map_index);
2251   pool_put(lcm->fwd_entry_pool, fe);
2252 }
2253
2254 /**
2255  * Finds first remote locator with best (lowest) priority that has a local
2256  * peer locator with an underlying route to it.
2257  *
2258  */
2259 static u32
2260 get_locator_pair (lisp_cp_main_t* lcm, mapping_t * lcl_map, mapping_t * rmt_map,
2261                   ip_address_t * lcl_loc, ip_address_t * rmt_loc)
2262 {
2263   u32 i, minp = ~0, limitp = 0, li, check_index = 0, done = 0, esi;
2264   locator_set_t * rmt_ls, * lcl_ls;
2265   ip_address_t _lcl, * lcl = &_lcl;
2266   locator_t * l, * rmt = 0;
2267   uword * checked = 0;
2268
2269   rmt_ls = pool_elt_at_index(lcm->locator_set_pool, rmt_map->locator_set_index);
2270   lcl_ls = pool_elt_at_index(lcm->locator_set_pool, lcl_map->locator_set_index);
2271
2272   if (!rmt_ls || vec_len(rmt_ls->locator_indices) == 0)
2273     return 0;
2274
2275   while (!done)
2276     {
2277       /* find unvisited remote locator with best priority */
2278       for (i = 0; i < vec_len(rmt_ls->locator_indices); i++)
2279         {
2280           if (0 != hash_get(checked, i))
2281             continue;
2282
2283           li = vec_elt(rmt_ls->locator_indices, i);
2284           l = pool_elt_at_index(lcm->locator_pool, li);
2285
2286           /* we don't support non-IP locators for now */
2287           if (gid_address_type(&l->address) != GID_ADDR_IP_PREFIX)
2288             continue;
2289
2290           if (l->priority < minp && l->priority >= limitp)
2291             {
2292               minp = l->priority;
2293               rmt = l;
2294               check_index = i;
2295             }
2296         }
2297       /* check if a local locator with a route to remote locator exists */
2298       if (rmt != 0)
2299         {
2300           esi = ip_fib_get_egress_iface_for_dst (
2301               lcm, &gid_address_ip(&rmt->address));
2302           if ((u32) ~0 == esi)
2303             continue;
2304
2305           for (i = 0; i < vec_len(lcl_ls->locator_indices); i++)
2306             {
2307               li = vec_elt (lcl_ls->locator_indices, i);
2308               locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
2309
2310               /* found local locator */
2311               if (sl->sw_if_index == esi)
2312                 {
2313                   if (0 == ip_interface_get_first_ip_address (lcm,
2314                              sl->sw_if_index,
2315                              gid_address_ip_version(&rmt->address), lcl))
2316                     continue;
2317
2318                   ip_address_copy(rmt_loc, &gid_address_ip(&rmt->address));
2319                   ip_address_copy(lcl_loc, lcl);
2320                   done = 2;
2321                 }
2322             }
2323
2324           /* skip this remote locator in next searches */
2325           limitp = minp;
2326           hash_set(checked, check_index, 1);
2327         }
2328       else
2329         done = 1;
2330     }
2331   hash_free(checked);
2332   return (done == 2) ? 1 : 0;
2333 }
2334
2335 static void
2336 add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
2337 {
2338   mapping_t * src_map, * dst_map;
2339   u32 sw_if_index;
2340   uword * feip = 0, * tidp;
2341   fwd_entry_t* fe;
2342   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
2343
2344   memset (a, 0, sizeof(*a));
2345
2346   /* remove entry if it already exists */
2347   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
2348   if (feip)
2349     del_fwd_entry (lcm, src_map_index, dst_map_index);
2350
2351   src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
2352   dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
2353
2354   gid_address_copy (&a->deid, &dst_map->eid);
2355   a->vni = gid_address_vni(&a->deid);
2356
2357   tidp = hash_get(lcm->table_id_by_vni, a->vni);
2358   if (!tidp)
2359     {
2360       clib_warning("vni %d not associated to a vrf!", a->vni);
2361       return;
2362     }
2363   a->table_id = tidp[0];
2364
2365   /* insert data plane forwarding entry */
2366   a->is_add = 1;
2367
2368   /* find best locator pair that 1) verifies LISP policy 2) are connected */
2369   if (0 == get_locator_pair (lcm, src_map, dst_map, &a->slocator, &a->dlocator))
2370     {
2371       /* negative entry */
2372       a->is_negative = 1;
2373       a->action = dst_map->action;
2374     }
2375
2376   /* TODO remove */
2377   u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid));
2378   a->decap_next_index = (ipver == IP4) ?
2379           LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
2380
2381   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
2382
2383   /* add tunnel to fwd entry table XXX check return value from DP insertion */
2384   pool_get (lcm->fwd_entry_pool, fe);
2385   fe->dst_loc = a->dlocator;
2386   fe->src_loc = a->slocator;
2387   gid_address_copy (&fe->deid, &a->deid);
2388   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
2389             fe - lcm->fwd_entry_pool);
2390 }
2391
2392 /* return 0 if the two locator sets are identical 1 otherwise */
2393 static u8
2394 compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes,
2395                   locator_t * new_locators)
2396 {
2397   u32 i, old_li;
2398   locator_t * old_loc, * new_loc;
2399
2400   if (vec_len (old_ls_indexes) != vec_len(new_locators))
2401     return 1;
2402
2403   for (i = 0; i < vec_len(new_locators); i++)
2404     {
2405       old_li = vec_elt(old_ls_indexes, i);
2406       old_loc = pool_elt_at_index(lcm->locator_pool, old_li);
2407
2408       new_loc = vec_elt_at_index(new_locators, i);
2409
2410       if (locator_cmp (old_loc, new_loc))
2411         return 1;
2412     }
2413   return 0;
2414 }
2415
2416 void
2417 process_map_reply (lisp_cp_main_t * lcm, vlib_buffer_t * b)
2418 {
2419   mapping_t * old_map;
2420   locator_t * loc;
2421   u32 len = 0, i, ls_index = 0;
2422   void * h;
2423   vnet_lisp_add_del_locator_set_args_t _ls_arg, * ls_arg = &_ls_arg;
2424   vnet_lisp_add_del_mapping_args_t _m_args, * m_args = &_m_args;
2425   pending_map_request_t * pmr;
2426   locator_t probed;
2427   map_reply_hdr_t * mrep_hdr;
2428   u64 nonce;
2429   u32 dst_map_index, mi;
2430   uword * pmr_index;
2431
2432   mrep_hdr = vlib_buffer_get_current (b);
2433
2434   /* Check pending requests table and nonce */
2435   nonce = MREP_NONCE(mrep_hdr);
2436   pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce);
2437   if (!pmr_index)
2438     {
2439       clib_warning("No pending map-request entry with nonce %lu!", nonce);
2440       return;
2441     }
2442   pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]);
2443
2444   vlib_buffer_pull (b, sizeof(*mrep_hdr));
2445
2446   for (i = 0; i < MREP_REC_COUNT(mrep_hdr); i++)
2447     {
2448       memset (ls_arg, 0, sizeof(*ls_arg));
2449       memset (m_args, 0, sizeof(*m_args));
2450
2451       h = vlib_buffer_get_current (b);
2452       m_args->ttl = clib_net_to_host_u32 (MAP_REC_TTL(h));
2453       m_args->action = MAP_REC_ACTION(h);
2454       m_args->authoritative = MAP_REC_AUTH(h);
2455
2456       len = lisp_msg_parse_mapping_record (b, &m_args->deid, &ls_arg->locators,
2457                                            &probed);
2458       if (len == ~0)
2459         {
2460           clib_warning ("Failed to parse mapping record!");
2461           vec_foreach (loc, ls_arg->locators)
2462             {
2463               locator_free (loc);
2464             }
2465           vec_free(ls_arg->locators);
2466           return;
2467         }
2468
2469       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &m_args->deid);
2470       old_map = mi != ~0 ? pool_elt_at_index(lcm->mapping_pool, mi) : 0;
2471
2472       /* if mapping already exists, decide if locators (and forwarding) should
2473        * be updated and be done */
2474       if (old_map != 0 && !gid_address_cmp (&old_map->eid, &m_args->deid))
2475         {
2476           locator_set_t * old_ls;
2477
2478           /* update mapping attributes */
2479           old_map->action = m_args->action;
2480           old_map->authoritative = m_args->authoritative;
2481           old_map->ttl = m_args->ttl;
2482
2483           old_ls = pool_elt_at_index(lcm->locator_set_pool,
2484                                      old_map->locator_set_index);
2485           /* if the two locators are not equal, update them and forwarding
2486            * otherwise there's nothing to be done */
2487           if (compare_locators (lcm, old_ls->locator_indices, ls_arg->locators))
2488             {
2489               /* set locator-set index to overwrite */
2490               ls_arg->is_add = 1;
2491               ls_arg->index = old_map->locator_set_index;
2492               vnet_lisp_add_del_locator_set (ls_arg, 0);
2493               add_fwd_entry (lcm, pmr->src_mapping_index, mi);
2494             }
2495         }
2496       /* new mapping */
2497       else
2498         {
2499           /* add locator-set */
2500           ls_arg->is_add = 1;
2501           ls_arg->index = ~0;
2502           vnet_lisp_add_del_locator_set (ls_arg, &ls_index);
2503
2504           /* add mapping */
2505           m_args->is_add = 1;
2506           m_args->locator_set_index = ls_index;
2507           vnet_lisp_add_del_mapping (m_args, &dst_map_index);
2508
2509           /* add forwarding tunnel */
2510           add_fwd_entry (lcm, pmr->src_mapping_index, dst_map_index);
2511         }
2512       vec_free(ls_arg->locators);
2513     }
2514
2515   /* remove pending map request entry */
2516   hash_unset(lcm->pending_map_requests_by_nonce, nonce);
2517   pool_put(lcm->pending_map_requests_pool, pmr);
2518 }
2519
2520 void
2521 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
2522 {
2523   map_request_hdr_t * mreq_hdr;
2524   gid_address_t src, dst;
2525 //  u64 nonce;
2526   u32 i, len = 0;
2527   gid_address_t * itr_rlocs = 0, * rloc;
2528
2529   mreq_hdr = vlib_buffer_get_current (b);
2530   vlib_buffer_pull (b, sizeof(*mreq_hdr));
2531
2532 //  nonce = MREQ_NONCE(mreq_hdr);
2533
2534   if (!MREQ_SMR(mreq_hdr)) {
2535       clib_warning("Only SMR Map-Requests supported for now!");
2536       return;
2537   }
2538
2539   /* parse src eid */
2540   len = lisp_msg_parse_addr (b, &src);
2541   if (len == ~0)
2542     return;
2543
2544   /* for now we don't do anything with the itr's rlocs */
2545   len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs, MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1);
2546   if (len == ~0)
2547     return;
2548
2549   /* TODO: RLOCs are currently unused, so free them for now */
2550   vec_foreach (rloc, itr_rlocs)
2551     {
2552       gid_address_free (rloc);
2553     }
2554
2555   /* parse eid records and send SMR-invoked map-requests */
2556   for (i = 0; i < MREQ_REC_COUNT(mreq_hdr); i++)
2557     {
2558       memset(&dst, 0, sizeof(dst));
2559       len = lisp_msg_parse_eid_rec (b, &dst);
2560       if (len == ~0)
2561         {
2562           clib_warning("Can't parse map-request EID-record");
2563           return;
2564         }
2565       /* send SMR-invoked map-requests */
2566       send_encapsulated_map_request (vm, lcm, &dst, &src, /* invoked */ 1);
2567     }
2568 }
2569
2570 static uword
2571 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
2572                vlib_frame_t * from_frame)
2573 {
2574   u32 n_left_from, * from, * to_next_drop;
2575   lisp_msg_type_e type;
2576   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2577
2578   from = vlib_frame_vector_args (from_frame);
2579   n_left_from = from_frame->n_vectors;
2580
2581
2582   while (n_left_from > 0)
2583     {
2584       u32 n_left_to_next_drop;
2585
2586       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
2587                            to_next_drop, n_left_to_next_drop);
2588       while (n_left_from > 0 && n_left_to_next_drop > 0)
2589         {
2590           u32 bi0;
2591           vlib_buffer_t * b0;
2592
2593           bi0 = from[0];
2594           from += 1;
2595           n_left_from -= 1;
2596           to_next_drop[0] = bi0;
2597           to_next_drop += 1;
2598           n_left_to_next_drop -= 1;
2599
2600           b0 = vlib_get_buffer (vm, bi0);
2601
2602           type = lisp_msg_type(vlib_buffer_get_current (b0));
2603           switch (type)
2604             {
2605             case LISP_MAP_REPLY:
2606               process_map_reply (lcm, b0);
2607               break;
2608             case LISP_MAP_REQUEST:
2609               process_map_request(vm, lcm, b0);
2610               break;
2611             default:
2612               clib_warning("Unsupported LISP message type %d", type);
2613               break;
2614             }
2615
2616           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
2617
2618           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2619             {
2620
2621             }
2622         }
2623
2624       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, n_left_to_next_drop);
2625     }
2626   return from_frame->n_vectors;
2627 }
2628
2629 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
2630   .function = lisp_cp_input,
2631   .name = "lisp-cp-input",
2632   .vector_size = sizeof (u32),
2633   .format_trace = format_lisp_cp_input_trace,
2634   .type = VLIB_NODE_TYPE_INTERNAL,
2635
2636   .n_errors = LISP_CP_INPUT_N_ERROR,
2637   .error_strings = lisp_cp_input_error_strings,
2638
2639   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
2640
2641   .next_nodes = {
2642       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
2643   },
2644 };
2645
2646 clib_error_t *
2647 lisp_cp_init (vlib_main_t *vm)
2648 {
2649   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2650   clib_error_t * error = 0;
2651
2652   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
2653     return error;
2654
2655   lcm->im4 = &ip4_main;
2656   lcm->im6 = &ip6_main;
2657   lcm->vlib_main = vm;
2658   lcm->vnet_main = vnet_get_main();
2659   lcm->mreq_itr_rlocs = ~0;
2660
2661   gid_dictionary_init (&lcm->mapping_index_by_gid);
2662
2663   /* default vrf mapped to vni 0 */
2664   hash_set(lcm->table_id_by_vni, 0, 0);
2665
2666   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
2667                          lisp_cp_input_node.index, 1 /* is_ip4 */);
2668   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
2669                          lisp_cp_input_node.index, 0 /* is_ip4 */);
2670
2671   return 0;
2672 }
2673
2674 VLIB_INIT_FUNCTION(lisp_cp_init);