b6612c44bb422f354684055476cb870cdc0ff078
[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_cp_show_locator_sets_command_fn (vlib_main_t * vm,
1367                                       unformat_input_t * input,
1368                                       vlib_cli_command_t * cmd)
1369 {
1370   locator_set_t * lsit;
1371   locator_t * loc;
1372   u32 * locit;
1373   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1374
1375   vlib_cli_output (vm, "%=20s%=16s%=16s%=16s", "Locator-set", "Locator",
1376                    "Priority", "Weight");
1377   pool_foreach (lsit, lcm->locator_set_pool,
1378   ({
1379     u8 * msg = 0;
1380     msg = format (msg, "%-16v", lsit->name);
1381     vec_foreach (locit, lsit->locator_indices)
1382       {
1383         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1384         if (loc->local)
1385           msg = format (msg, "%16d%16d%16d", loc->sw_if_index, loc->priority,
1386                         loc->weight);
1387         else
1388           msg = format (msg, "%16U%16d%16d", format_gid_address, &loc->address,
1389                         loc->priority, loc->weight);
1390       }
1391     vlib_cli_output (vm, "%v", msg);
1392     vec_free (msg);
1393   }));
1394   return 0;
1395 }
1396
1397 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
1398     .path = "show lisp locator-set",
1399     .short_help = "Shows locator-sets",
1400     .function = lisp_cp_show_locator_sets_command_fn,
1401 };
1402
1403 int
1404 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
1405 {
1406   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1407   ip_address_t * addr;
1408   u32 i;
1409
1410   if (vnet_lisp_enable_disable_status () == 0)
1411     {
1412       clib_warning ("LISP is disabled!");
1413       return VNET_API_ERROR_LISP_DISABLED;
1414     }
1415
1416   if (a->is_add)
1417     {
1418       vec_foreach(addr, lcm->map_resolvers)
1419         {
1420           if (!ip_address_cmp (addr, &a->address))
1421             {
1422               clib_warning("map-resolver %U already exists!", format_ip_address,
1423                            &a->address);
1424               return -1;
1425             }
1426         }
1427       vec_add1(lcm->map_resolvers, a->address);
1428     }
1429   else
1430     {
1431       for (i = 0; i < vec_len(lcm->map_resolvers); i++)
1432         {
1433           addr = vec_elt_at_index(lcm->map_resolvers, i);
1434           if (!ip_address_cmp (addr, &a->address))
1435             {
1436               vec_delete(lcm->map_resolvers, 1, i);
1437               break;
1438             }
1439         }
1440     }
1441   return 0;
1442 }
1443
1444 static clib_error_t *
1445 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
1446                                          unformat_input_t * input,
1447                                          vlib_cli_command_t * cmd)
1448 {
1449   unformat_input_t _line_input, * line_input = &_line_input;
1450   u8 is_add = 1;
1451   ip_address_t ip_addr;
1452   clib_error_t * error = 0;
1453   int rv = 0;
1454   vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a;
1455
1456   /* Get a line of input. */
1457   if (! unformat_user (input, unformat_line_input, line_input))
1458     return 0;
1459
1460   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1461     {
1462       if (unformat (line_input, "add"))
1463         is_add = 1;
1464       else if (unformat (line_input, "del"))
1465         is_add = 0;
1466       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
1467         ;
1468       else
1469         {
1470           error = unformat_parse_error(line_input);
1471           goto done;
1472         }
1473     }
1474   a->is_add = is_add;
1475   a->address = ip_addr;
1476   rv = vnet_lisp_add_del_map_resolver (a);
1477   if (0 != rv)
1478     {
1479       error = clib_error_return(0, "failed to %s map-resolver!",
1480                                 is_add ? "add" : "delete");
1481     }
1482
1483  done:
1484   return error;
1485 }
1486
1487 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
1488     .path = "lisp map-resolver",
1489     .short_help = "lisp map-resolver add/del <ip_address>",
1490     .function = lisp_add_del_map_resolver_command_fn,
1491 };
1492
1493 int
1494 vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
1495 {
1496   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1497   uword * p = 0;
1498
1499   //TODO: Wait for merge https://gerrit.fd.io/r/#/c/1427/
1500 //   if (vnet_lisp_enable_disable_status () == 0)
1501 //     {
1502 //       clib_warning ("LISP is disabled!");
1503 //       return VNET_API_ERROR_LISP_DISABLED;
1504 //     }
1505
1506   if (a->is_add)
1507     {
1508       p = hash_get_mem(lcm->locator_set_index_by_name, a->locator_set_name);
1509       if (!p)
1510         {
1511           clib_warning("locator-set %v doesn't exist", a->locator_set_name);
1512           return VNET_API_ERROR_INVALID_ARGUMENT;
1513         }
1514
1515       lcm->mreq_itr_rlocs = p[0];
1516     }
1517   else
1518     {
1519       lcm->mreq_itr_rlocs = ~0;
1520     }
1521
1522   return 0;
1523 }
1524
1525 static clib_error_t *
1526 lisp_add_del_mreq_itr_rlocs_command_fn(vlib_main_t * vm,
1527                                        unformat_input_t * input,
1528                                        vlib_cli_command_t * cmd)
1529 {
1530   unformat_input_t _line_input, * line_input = &_line_input;
1531   u8 is_add = 1;
1532   u8 * locator_set_name = 0;
1533   clib_error_t * error = 0;
1534   int rv = 0;
1535   vnet_lisp_add_del_mreq_itr_rloc_args_t _a, * a = &_a;
1536
1537   /* Get a line of input. */
1538   if (! unformat_user (input, unformat_line_input, line_input))
1539     return 0;
1540
1541   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1542     {
1543       if (unformat (line_input, "del"))
1544         is_add = 0;
1545       else if (unformat (line_input, "add %s", &locator_set_name))
1546         is_add = 1;
1547       else
1548         {
1549           error = unformat_parse_error(line_input);
1550           goto done;
1551         }
1552     }
1553
1554   a->is_add = is_add;
1555   a->locator_set_name = locator_set_name;
1556   rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
1557   if (0 != rv)
1558     {
1559       error = clib_error_return(0, "failed to %s map-request itr-rlocs!",
1560                                 is_add ? "add" : "delete");
1561     }
1562
1563   vec_free(locator_set_name);
1564
1565  done:
1566   return error;
1567
1568 }
1569
1570 VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
1571     .path = "lisp map-request itr-rlocs",
1572     .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
1573     .function = lisp_add_del_mreq_itr_rlocs_command_fn,
1574 };
1575
1576 static clib_error_t *
1577 lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
1578                                     unformat_input_t * input,
1579                                     vlib_cli_command_t * cmd)
1580 {
1581   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1582   locator_set_t * loc_set;
1583
1584   vlib_cli_output (vm, "%=20s", "itr-rlocs");
1585
1586   if (~0 == lcm->mreq_itr_rlocs)
1587     {
1588       return 0;
1589     }
1590
1591   loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
1592
1593   vlib_cli_output (vm, "%=20s", loc_set->name);
1594
1595   return 0;
1596 }
1597
1598 VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
1599     .path = "show lisp map-request itr-rlocs",
1600     .short_help = "Shows map-request itr-rlocs",
1601     .function = lisp_show_mreq_itr_rlocs_command_fn,
1602 };
1603
1604 /* Statistics (not really errors) */
1605 #define foreach_lisp_cp_lookup_error           \
1606 _(DROP, "drop")                                \
1607 _(MAP_REQUESTS_SENT, "map-request sent")
1608
1609 static char * lisp_cp_lookup_error_strings[] = {
1610 #define _(sym,string) string,
1611   foreach_lisp_cp_lookup_error
1612 #undef _
1613 };
1614
1615 typedef enum
1616 {
1617 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
1618     foreach_lisp_cp_lookup_error
1619 #undef _
1620     LISP_CP_LOOKUP_N_ERROR,
1621 } lisp_cp_lookup_error_t;
1622
1623 typedef enum
1624 {
1625   LISP_CP_LOOKUP_NEXT_DROP,
1626   LISP_CP_LOOKUP_NEXT_IP4_LOOKUP,
1627   LISP_CP_LOOKUP_NEXT_IP6_LOOKUP,
1628   LISP_CP_LOOKUP_N_NEXT,
1629 } lisp_cp_lookup_next_t;
1630
1631 typedef struct
1632 {
1633   gid_address_t dst_eid;
1634   ip_address_t map_resolver_ip;
1635 } lisp_cp_lookup_trace_t;
1636
1637 u8 *
1638 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
1639 {
1640   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1641   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1642   lisp_cp_lookup_trace_t * t = va_arg (*args, lisp_cp_lookup_trace_t *);
1643
1644   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
1645               format_ip_address, &t->map_resolver_ip, format_gid_address,
1646               &t->dst_eid);
1647   return s;
1648 }
1649
1650 ip_interface_address_t *
1651 ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
1652                                           u8 loop)
1653 {
1654   vnet_main_t *vnm = vnet_get_main ();
1655   vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index);
1656   if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
1657     sw_if_index = swif->unnumbered_sw_if_index;
1658   u32 ia =
1659       (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
1660           vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
1661           (u32) ~0;
1662   return pool_elt_at_index((lm)->if_address_pool, ia);
1663 }
1664
1665 void *
1666 ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
1667                                 u8 version)
1668 {
1669   ip_interface_address_t * ia;
1670
1671   ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
1672   if (!ia)
1673     return 0;
1674   return ip_interface_address_get_address (lm, ia);
1675 }
1676
1677 int
1678 ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
1679                                    u8 version, ip_address_t * result)
1680 {
1681   ip_lookup_main_t * lm;
1682   void * addr;
1683
1684   lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1685   addr = ip_interface_get_first_address (lm, sw_if_index, version);
1686   if (!addr)
1687     return 0;
1688
1689   ip_address_set (result, addr, version);
1690   return 1;
1691 }
1692
1693 static u32
1694 ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
1695                           ip_address_t * dst)
1696 {
1697   if (ip_addr_version (dst) == IP4)
1698       return ip4_fib_lookup_with_table (lcm->im4, fib_index, &ip_addr_v4(dst),
1699                                         0);
1700   else
1701       return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6(dst));
1702 }
1703
1704 u32
1705 ip_fib_get_egress_iface_for_dst_with_lm (lisp_cp_main_t * lcm,
1706                                          ip_address_t * dst,
1707                                          ip_lookup_main_t * lm)
1708 {
1709   u32 adj_index;
1710   ip_adjacency_t * adj;
1711
1712   adj_index = ip_fib_lookup_with_table (lcm, 0, dst);
1713   adj = ip_get_adjacency (lm, adj_index);
1714
1715   if (adj == 0)
1716     return ~0;
1717
1718   /* we only want outgoing routes */
1719   if (adj->lookup_next_index != IP_LOOKUP_NEXT_ARP
1720       && adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
1721     return ~0;
1722
1723   return adj->rewrite_header.sw_if_index;
1724 }
1725
1726 /**
1727  * Find the sw_if_index of the interface that would be used to egress towards
1728  * dst.
1729  */
1730 u32
1731 ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
1732 {
1733   ip_lookup_main_t * lm;
1734
1735   lm = ip_addr_version (dst) == IP4 ?
1736       &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1737
1738   return ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
1739 }
1740
1741 /**
1742  * Find first IP of the interface that would be used to egress towards dst.
1743  * Returns 1 if the address is found 0 otherwise.
1744  */
1745 int
1746 ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
1747                                     ip_address_t * result)
1748 {
1749   u32 si;
1750   ip_lookup_main_t * lm;
1751   void * addr = 0;
1752   u8 ipver;
1753
1754   ASSERT(result != 0);
1755
1756   ipver = ip_addr_version(dst);
1757
1758   lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1759   si = ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
1760
1761   if ((u32) ~0 == si)
1762     return 0;
1763
1764   /* find the first ip address */
1765   addr = ip_interface_get_first_address (lm, si, ipver);
1766   if (0 == addr)
1767     return 0;
1768
1769   ip_address_set (result, addr, ipver);
1770   return 1;
1771 }
1772
1773 int
1774 get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
1775                            ip_address_t * sloc)
1776 {
1777   ip_address_t * mrit;
1778
1779   if (vec_len(lcm->map_resolvers) == 0)
1780     {
1781       clib_warning("No map-resolver configured");
1782       return 0;
1783     }
1784
1785   /* find the first mr ip we have a route to and the ip of the
1786    * iface that has a route to it */
1787   vec_foreach(mrit, lcm->map_resolvers)
1788     {
1789       if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, mrit, sloc)) {
1790           ip_address_copy(mr_ip, mrit);
1791           return 1;
1792       }
1793     }
1794
1795   clib_warning("Can't find map-resolver and local interface ip!");
1796   return 0;
1797 }
1798
1799 static gid_address_t *
1800 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
1801 {
1802   void * addr;
1803   u32 i;
1804   locator_t * loc;
1805   u32 * loc_indexp;
1806   ip_interface_address_t * ia = 0;
1807   gid_address_t gid_data, * gid = &gid_data;
1808   gid_address_t * rlocs = 0;
1809   ip_prefix_t * ippref = &gid_address_ippref (gid);
1810   ip_address_t * rloc = &ip_prefix_addr (ippref);
1811
1812   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
1813   for (i = 0; i < vec_len(loc_set->locator_indices); i++)
1814     {
1815       loc_indexp = vec_elt_at_index(loc_set->locator_indices, i);
1816       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
1817
1818       /* Add ipv4 locators first TODO sort them */
1819       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
1820                                     loc->sw_if_index, 1 /* unnumbered */,
1821       ({
1822         addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
1823         ip_address_set (rloc, addr, IP4);
1824         ip_prefix_len (ippref) = 32;
1825         vec_add1 (rlocs, gid[0]);
1826       }));
1827
1828       /* Add ipv6 locators */
1829       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
1830                                     loc->sw_if_index, 1 /* unnumbered */,
1831       ({
1832         addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
1833         ip_address_set (rloc, addr, IP6);
1834         ip_prefix_len (ippref) = 128;
1835         vec_add1 (rlocs, gid[0]);
1836       }));
1837     }
1838   return rlocs;
1839 }
1840
1841 static vlib_buffer_t *
1842 build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
1843                                 gid_address_t * seid, gid_address_t * deid,
1844                                 locator_set_t * loc_set, ip_address_t * mr_ip,
1845                                 ip_address_t * sloc, u8 is_smr_invoked,
1846                                 u64 *nonce_res, u32 * bi_res)
1847 {
1848   vlib_buffer_t * b;
1849   u32 bi;
1850   gid_address_t * rlocs = 0;
1851
1852   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
1853     {
1854       clib_warning ("Can't allocate buffer for Map-Request!");
1855       return 0;
1856     }
1857
1858   b = vlib_get_buffer (vm, bi);
1859
1860   /* leave some space for the encap headers */
1861   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
1862
1863   /* get rlocs */
1864   rlocs = build_itr_rloc_list (lcm, loc_set);
1865
1866   /* put lisp msg */
1867   lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked, nonce_res);
1868
1869   /* push ecm: udp-ip-lisp */
1870   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
1871
1872   /* push outer ip header */
1873   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
1874                        mr_ip);
1875
1876   bi_res[0] = bi;
1877
1878   vec_free(rlocs);
1879   return b;
1880 }
1881
1882 static void
1883 send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
1884                                gid_address_t * seid, gid_address_t * deid,
1885                                u8 is_smr_invoked)
1886 {
1887   u32 next_index, bi = 0, * to_next, map_index;
1888   vlib_buffer_t * b;
1889   vlib_frame_t * f;
1890   u64 nonce = 0;
1891   locator_set_t * loc_set;
1892   mapping_t * map;
1893   pending_map_request_t * pmr;
1894   ip_address_t mr_ip, sloc;
1895   u32 ls_index;
1896
1897   /* get locator-set for seid */
1898   if (!lcm->lisp_pitr)
1899     {
1900       map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
1901       if (map_index == ~0)
1902         {
1903           clib_warning("No local mapping found in eid-table for %U!",
1904                        format_gid_address, seid);
1905           return;
1906         }
1907
1908       map = pool_elt_at_index (lcm->mapping_pool, map_index);
1909
1910       if (!map->local)
1911         {
1912           clib_warning("Mapping found for src eid %U is not marked as local!",
1913                        format_gid_address, seid);
1914           return;
1915         }
1916       ls_index = map->locator_set_index;
1917     }
1918   else
1919     {
1920       map_index = lcm->pitr_map_index;
1921       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
1922       ls_index = map->locator_set_index;
1923     }
1924
1925   /* overwrite locator set if map-request itr-rlocs configured */
1926   if (~0 != lcm->mreq_itr_rlocs)
1927     {
1928       ls_index = lcm->mreq_itr_rlocs;
1929     }
1930
1931   loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
1932
1933   /* get local iface ip to use in map-request */
1934   if (0 == get_mr_and_local_iface_ip (lcm, &mr_ip, &sloc))
1935     return;
1936
1937   /* build the encapsulated map request */
1938   b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set, &mr_ip,
1939                                       &sloc, is_smr_invoked, &nonce, &bi);
1940
1941   if (!b)
1942     return;
1943
1944   /* set fib index and lookup node */
1945   vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0;
1946   next_index = (ip_addr_version(&mr_ip) == IP4) ?
1947       ip4_lookup_node.index : ip6_lookup_node.index;
1948
1949   f = vlib_get_frame_to_node (vm, next_index);
1950
1951   /* Enqueue the packet */
1952   to_next = vlib_frame_vector_args (f);
1953   to_next[0] = bi;
1954   f->n_vectors = 1;
1955   vlib_put_frame_to_node (vm, next_index, f);
1956
1957   /* add map-request to pending requests table */
1958   pool_get(lcm->pending_map_requests_pool, pmr);
1959   gid_address_copy (&pmr->src, seid);
1960   gid_address_copy (&pmr->dst, deid);
1961   pmr->src_mapping_index = map_index;
1962   hash_set(lcm->pending_map_requests_by_nonce, nonce,
1963            pmr - lcm->pending_map_requests_pool);
1964 }
1965
1966 static void
1967 get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst)
1968 {
1969   ip4_header_t * ip4 = hdr;
1970   ip6_header_t * ip6;
1971
1972   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
1973     {
1974       ip_address_set(src, &ip4->src_address, IP4);
1975       ip_address_set(dst, &ip4->dst_address, IP4);
1976     }
1977   else
1978     {
1979       ip6 = hdr;
1980       ip_address_set(src, &ip6->src_address, IP6);
1981       ip_address_set(dst, &ip6->dst_address, IP6);
1982     }
1983 }
1984
1985 static uword
1986 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
1987               vlib_frame_t * from_frame)
1988 {
1989   u32 * from, * to_next_drop, di, si;
1990   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main();
1991   u32 pkts_mapped = 0;
1992   uword n_left_from, n_left_to_next_drop;
1993
1994   from = vlib_frame_vector_args (from_frame);
1995   n_left_from = from_frame->n_vectors;
1996
1997   while (n_left_from > 0)
1998     {
1999       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
2000                            to_next_drop, n_left_to_next_drop);
2001
2002       while (n_left_from > 0 && n_left_to_next_drop > 0)
2003         {
2004           u32 pi0;
2005           vlib_buffer_t * p0;
2006           ip4_header_t * ip0;
2007           gid_address_t src, dst;
2008           ip_prefix_t * spref, * dpref;
2009
2010           gid_address_type (&src) = GID_ADDR_IP_PREFIX;
2011           spref = &gid_address_ippref(&src);
2012           gid_address_type (&dst) = GID_ADDR_IP_PREFIX;
2013           dpref = &gid_address_ippref(&dst);
2014
2015           pi0 = from[0];
2016           from += 1;
2017           n_left_from -= 1;
2018           to_next_drop[0] = pi0;
2019           to_next_drop += 1;
2020           n_left_to_next_drop -= 1;
2021
2022           p0 = vlib_get_buffer (vm, pi0);
2023           p0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
2024
2025           /* src/dst eid pair */
2026           ip0 = vlib_buffer_get_current (p0);
2027           get_src_and_dst (ip0, &ip_prefix_addr(spref), &ip_prefix_addr(dpref));
2028           ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref));
2029           ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref));
2030
2031           /* if we have remote mapping for destination already in map-chache
2032              add forwarding tunnel directly. If not send a map-request */
2033           di = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
2034           if (~0 != di)
2035             {
2036               mapping_t * m =  vec_elt_at_index (lcm->mapping_pool, di);
2037               /* send a map-request also in case of negative mapping entry
2038                 with corresponding action */
2039               if (m->action == ACTION_SEND_MAP_REQUEST)
2040                 {
2041                   /* send map-request */
2042                   send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2043                   pkts_mapped++;
2044                 }
2045               else
2046                 {
2047                   si =  gid_dictionary_lookup (&lcm->mapping_index_by_gid,
2048                                                &src);
2049                   if (~0 != si)
2050                     {
2051                       add_fwd_entry (lcm, si, di);
2052                     }
2053                 }
2054             }
2055           else
2056             {
2057               /* send map-request */
2058               send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2059               pkts_mapped++;
2060             }
2061
2062           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
2063             {
2064               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, p0,
2065                                                           sizeof(*tr));
2066
2067               memset(tr, 0, sizeof(*tr));
2068               gid_address_copy (&tr->dst_eid, &dst);
2069               if (vec_len(lcm->map_resolvers) > 0)
2070                 {
2071                   clib_memcpy (&tr->map_resolver_ip,
2072                                vec_elt_at_index(lcm->map_resolvers, 0),
2073                                sizeof(ip_address_t));
2074                 }
2075             }
2076         }
2077
2078       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop);
2079     }
2080   vlib_node_increment_counter (vm, node->node_index,
2081                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
2082                                pkts_mapped);
2083   return from_frame->n_vectors;
2084 }
2085
2086 VLIB_REGISTER_NODE (lisp_cp_lookup_node) = {
2087   .function = lisp_cp_lookup,
2088   .name = "lisp-cp-lookup",
2089   .vector_size = sizeof (u32),
2090   .format_trace = format_lisp_cp_lookup_trace,
2091   .type = VLIB_NODE_TYPE_INTERNAL,
2092
2093   .n_errors = LISP_CP_LOOKUP_N_ERROR,
2094   .error_strings = lisp_cp_lookup_error_strings,
2095
2096   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
2097
2098   .next_nodes = {
2099       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
2100       [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup",
2101       [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup",
2102   },
2103 };
2104
2105 /* lisp_cp_input statistics */
2106 #define foreach_lisp_cp_input_error                   \
2107 _(DROP, "drop")                                        \
2108 _(MAP_REPLIES_RECEIVED, "map-replies received")
2109
2110 static char * lisp_cp_input_error_strings[] = {
2111 #define _(sym,string) string,
2112   foreach_lisp_cp_input_error
2113 #undef _
2114 };
2115
2116 typedef enum
2117 {
2118 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
2119     foreach_lisp_cp_input_error
2120 #undef _
2121     LISP_CP_INPUT_N_ERROR,
2122 } lisp_cp_input_error_t;
2123
2124 typedef enum
2125 {
2126   LISP_CP_INPUT_NEXT_DROP,
2127   LISP_CP_INPUT_N_NEXT,
2128 } lisp_cp_input_next_t;
2129
2130 typedef struct
2131 {
2132   gid_address_t dst_eid;
2133   ip4_address_t map_resolver_ip;
2134 } lisp_cp_input_trace_t;
2135
2136 u8 *
2137 format_lisp_cp_input_trace (u8 * s, va_list * args)
2138 {
2139   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2140   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2141   CLIB_UNUSED(lisp_cp_input_trace_t * t) = va_arg (*args, lisp_cp_input_trace_t *);
2142
2143   s = format (s, "LISP-CP-INPUT: TODO");
2144   return s;
2145 }
2146
2147 static void
2148 del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
2149                u32 dst_map_index)
2150 {
2151   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
2152   fwd_entry_t * fe = 0;
2153   uword * feip = 0;
2154   memset(a, 0, sizeof(*a));
2155
2156   feip = hash_get(lcm->fwd_entry_by_mapping_index, dst_map_index);
2157   if (!feip)
2158     return;
2159
2160   fe = pool_elt_at_index(lcm->fwd_entry_pool, feip[0]);
2161
2162   /* delete dp fwd entry */
2163   u32 sw_if_index;
2164   a->is_add = 0;
2165   a->dlocator = fe->dst_loc;
2166   a->slocator = fe->src_loc;
2167   a->vni = gid_address_vni(&a->deid);
2168   gid_address_copy(&a->deid, &fe->deid);
2169
2170   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
2171
2172   /* delete entry in fwd table */
2173   hash_unset(lcm->fwd_entry_by_mapping_index, dst_map_index);
2174   pool_put(lcm->fwd_entry_pool, fe);
2175 }
2176
2177 /**
2178  * Finds first remote locator with best (lowest) priority that has a local
2179  * peer locator with an underlying route to it.
2180  *
2181  */
2182 static u32
2183 get_locator_pair (lisp_cp_main_t* lcm, mapping_t * lcl_map, mapping_t * rmt_map,
2184                   ip_address_t * lcl_loc, ip_address_t * rmt_loc)
2185 {
2186   u32 i, minp = ~0, limitp = 0, li, check_index = 0, done = 0, esi;
2187   locator_set_t * rmt_ls, * lcl_ls;
2188   ip_address_t _lcl, * lcl = &_lcl;
2189   locator_t * l, * rmt = 0;
2190   uword * checked = 0;
2191
2192   rmt_ls = pool_elt_at_index(lcm->locator_set_pool, rmt_map->locator_set_index);
2193   lcl_ls = pool_elt_at_index(lcm->locator_set_pool, lcl_map->locator_set_index);
2194
2195   if (!rmt_ls || vec_len(rmt_ls->locator_indices) == 0)
2196     return 0;
2197
2198   while (!done)
2199     {
2200       /* find unvisited remote locator with best priority */
2201       for (i = 0; i < vec_len(rmt_ls->locator_indices); i++)
2202         {
2203           if (0 != hash_get(checked, i))
2204             continue;
2205
2206           li = vec_elt(rmt_ls->locator_indices, i);
2207           l = pool_elt_at_index(lcm->locator_pool, li);
2208
2209           /* we don't support non-IP locators for now */
2210           if (gid_address_type(&l->address) != GID_ADDR_IP_PREFIX)
2211             continue;
2212
2213           if (l->priority < minp && l->priority >= limitp)
2214             {
2215               minp = l->priority;
2216               rmt = l;
2217               check_index = i;
2218             }
2219         }
2220       /* check if a local locator with a route to remote locator exists */
2221       if (rmt != 0)
2222         {
2223           esi = ip_fib_get_egress_iface_for_dst (
2224               lcm, &gid_address_ip(&rmt->address));
2225           if ((u32) ~0 == esi)
2226             continue;
2227
2228           for (i = 0; i < vec_len(lcl_ls->locator_indices); i++)
2229             {
2230               li = vec_elt (lcl_ls->locator_indices, i);
2231               locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
2232
2233               /* found local locator */
2234               if (sl->sw_if_index == esi)
2235                 {
2236                   if (0 == ip_interface_get_first_ip_address (lcm,
2237                              sl->sw_if_index,
2238                              gid_address_ip_version(&rmt->address), lcl))
2239                     continue;
2240
2241                   ip_address_copy(rmt_loc, &gid_address_ip(&rmt->address));
2242                   ip_address_copy(lcl_loc, lcl);
2243                   done = 2;
2244                 }
2245             }
2246
2247           /* skip this remote locator in next searches */
2248           limitp = minp;
2249           hash_set(checked, check_index, 1);
2250         }
2251       else
2252         done = 1;
2253     }
2254   hash_free(checked);
2255   return (done == 2) ? 1 : 0;
2256 }
2257
2258 static void
2259 add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
2260 {
2261   mapping_t * src_map, * dst_map;
2262   u32 sw_if_index;
2263   uword * feip = 0, * tidp;
2264   fwd_entry_t* fe;
2265   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
2266
2267   memset (a, 0, sizeof(*a));
2268
2269   /* remove entry if it already exists */
2270   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
2271   if (feip)
2272     del_fwd_entry (lcm, src_map_index, dst_map_index);
2273
2274   src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
2275   dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
2276
2277   gid_address_copy (&a->deid, &dst_map->eid);
2278   a->vni = gid_address_vni(&a->deid);
2279
2280   tidp = hash_get(lcm->table_id_by_vni, a->vni);
2281   if (!tidp)
2282     {
2283       clib_warning("vni %d not associated to a vrf!", a->vni);
2284       return;
2285     }
2286   a->table_id = tidp[0];
2287
2288   /* insert data plane forwarding entry */
2289   a->is_add = 1;
2290
2291   /* find best locator pair that 1) verifies LISP policy 2) are connected */
2292   if (0 == get_locator_pair (lcm, src_map, dst_map, &a->slocator, &a->dlocator))
2293     {
2294       /* negative entry */
2295       a->is_negative = 1;
2296       a->action = dst_map->action;
2297     }
2298
2299   /* TODO remove */
2300   u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid));
2301   a->decap_next_index = (ipver == IP4) ?
2302           LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
2303
2304   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
2305
2306   /* add tunnel to fwd entry table XXX check return value from DP insertion */
2307   pool_get (lcm->fwd_entry_pool, fe);
2308   fe->dst_loc = a->dlocator;
2309   fe->src_loc = a->slocator;
2310   gid_address_copy (&fe->deid, &a->deid);
2311   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
2312             fe - lcm->fwd_entry_pool);
2313 }
2314
2315 /* return 0 if the two locator sets are identical 1 otherwise */
2316 static u8
2317 compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes,
2318                   locator_t * new_locators)
2319 {
2320   u32 i, old_li;
2321   locator_t * old_loc, * new_loc;
2322
2323   if (vec_len (old_ls_indexes) != vec_len(new_locators))
2324     return 1;
2325
2326   for (i = 0; i < vec_len(new_locators); i++)
2327     {
2328       old_li = vec_elt(old_ls_indexes, i);
2329       old_loc = pool_elt_at_index(lcm->locator_pool, old_li);
2330
2331       new_loc = vec_elt_at_index(new_locators, i);
2332
2333       if (locator_cmp (old_loc, new_loc))
2334         return 1;
2335     }
2336   return 0;
2337 }
2338
2339 void
2340 process_map_reply (lisp_cp_main_t * lcm, vlib_buffer_t * b)
2341 {
2342   mapping_t * old_map;
2343   locator_t * loc;
2344   u32 len = 0, i, ls_index = 0;
2345   void * h;
2346   vnet_lisp_add_del_locator_set_args_t _ls_arg, * ls_arg = &_ls_arg;
2347   vnet_lisp_add_del_mapping_args_t _m_args, * m_args = &_m_args;
2348   pending_map_request_t * pmr;
2349   locator_t probed;
2350   map_reply_hdr_t * mrep_hdr;
2351   u64 nonce;
2352   u32 dst_map_index, mi;
2353   uword * pmr_index;
2354
2355   mrep_hdr = vlib_buffer_get_current (b);
2356
2357   /* Check pending requests table and nonce */
2358   nonce = MREP_NONCE(mrep_hdr);
2359   pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce);
2360   if (!pmr_index)
2361     {
2362       clib_warning("No pending map-request entry with nonce %lu!", nonce);
2363       return;
2364     }
2365   pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]);
2366
2367   vlib_buffer_pull (b, sizeof(*mrep_hdr));
2368
2369   for (i = 0; i < MREP_REC_COUNT(mrep_hdr); i++)
2370     {
2371       memset (ls_arg, 0, sizeof(*ls_arg));
2372       memset (m_args, 0, sizeof(*m_args));
2373
2374       h = vlib_buffer_get_current (b);
2375       m_args->ttl = clib_net_to_host_u32 (MAP_REC_TTL(h));
2376       m_args->action = MAP_REC_ACTION(h);
2377       m_args->authoritative = MAP_REC_AUTH(h);
2378
2379       len = lisp_msg_parse_mapping_record (b, &m_args->deid, &ls_arg->locators,
2380                                            &probed);
2381       if (len == ~0)
2382         {
2383           clib_warning ("Failed to parse mapping record!");
2384           vec_foreach (loc, ls_arg->locators)
2385             {
2386               locator_free (loc);
2387             }
2388           vec_free(ls_arg->locators);
2389           return;
2390         }
2391
2392       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &m_args->deid);
2393       old_map = mi != ~0 ? pool_elt_at_index(lcm->mapping_pool, mi) : 0;
2394
2395       /* if mapping already exists, decide if locators (and forwarding) should
2396        * be updated and be done */
2397       if (old_map != 0 && !gid_address_cmp (&old_map->eid, &m_args->deid))
2398         {
2399           locator_set_t * old_ls;
2400
2401           /* update mapping attributes */
2402           old_map->action = m_args->action;
2403           old_map->authoritative = m_args->authoritative;
2404           old_map->ttl = m_args->ttl;
2405
2406           old_ls = pool_elt_at_index(lcm->locator_set_pool,
2407                                      old_map->locator_set_index);
2408           /* if the two locators are not equal, update them and forwarding
2409            * otherwise there's nothing to be done */
2410           if (compare_locators (lcm, old_ls->locator_indices, ls_arg->locators))
2411             {
2412               /* set locator-set index to overwrite */
2413               ls_arg->is_add = 1;
2414               ls_arg->index = old_map->locator_set_index;
2415               vnet_lisp_add_del_locator_set (ls_arg, 0);
2416               add_fwd_entry (lcm, pmr->src_mapping_index, mi);
2417             }
2418         }
2419       /* new mapping */
2420       else
2421         {
2422           /* add locator-set */
2423           ls_arg->is_add = 1;
2424           ls_arg->index = ~0;
2425           vnet_lisp_add_del_locator_set (ls_arg, &ls_index);
2426
2427           /* add mapping */
2428           m_args->is_add = 1;
2429           m_args->locator_set_index = ls_index;
2430           vnet_lisp_add_del_mapping (m_args, &dst_map_index);
2431
2432           /* add forwarding tunnel */
2433           add_fwd_entry (lcm, pmr->src_mapping_index, dst_map_index);
2434         }
2435       vec_free(ls_arg->locators);
2436     }
2437
2438   /* remove pending map request entry */
2439   hash_unset(lcm->pending_map_requests_by_nonce, nonce);
2440   pool_put(lcm->pending_map_requests_pool, pmr);
2441 }
2442
2443 void
2444 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
2445 {
2446   map_request_hdr_t * mreq_hdr;
2447   gid_address_t src, dst;
2448 //  u64 nonce;
2449   u32 i, len = 0;
2450   gid_address_t * itr_rlocs = 0, * rloc;
2451
2452   mreq_hdr = vlib_buffer_get_current (b);
2453   vlib_buffer_pull (b, sizeof(*mreq_hdr));
2454
2455 //  nonce = MREQ_NONCE(mreq_hdr);
2456
2457   if (!MREQ_SMR(mreq_hdr)) {
2458       clib_warning("Only SMR Map-Requests supported for now!");
2459       return;
2460   }
2461
2462   /* parse src eid */
2463   len = lisp_msg_parse_addr (b, &src);
2464   if (len == ~0)
2465     return;
2466
2467   /* for now we don't do anything with the itr's rlocs */
2468   len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs, MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1);
2469   if (len == ~0)
2470     return;
2471
2472   /* TODO: RLOCs are currently unused, so free them for now */
2473   vec_foreach (rloc, itr_rlocs)
2474     {
2475       gid_address_free (rloc);
2476     }
2477
2478   /* parse eid records and send SMR-invoked map-requests */
2479   for (i = 0; i < MREQ_REC_COUNT(mreq_hdr); i++)
2480     {
2481       memset(&dst, 0, sizeof(dst));
2482       len = lisp_msg_parse_eid_rec (b, &dst);
2483       if (len == ~0)
2484         {
2485           clib_warning("Can't parse map-request EID-record");
2486           return;
2487         }
2488       /* send SMR-invoked map-requests */
2489       send_encapsulated_map_request (vm, lcm, &dst, &src, /* invoked */ 1);
2490     }
2491 }
2492
2493 static uword
2494 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
2495                vlib_frame_t * from_frame)
2496 {
2497   u32 n_left_from, * from, * to_next_drop;
2498   lisp_msg_type_e type;
2499   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2500
2501   from = vlib_frame_vector_args (from_frame);
2502   n_left_from = from_frame->n_vectors;
2503
2504
2505   while (n_left_from > 0)
2506     {
2507       u32 n_left_to_next_drop;
2508
2509       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
2510                            to_next_drop, n_left_to_next_drop);
2511       while (n_left_from > 0 && n_left_to_next_drop > 0)
2512         {
2513           u32 bi0;
2514           vlib_buffer_t * b0;
2515
2516           bi0 = from[0];
2517           from += 1;
2518           n_left_from -= 1;
2519           to_next_drop[0] = bi0;
2520           to_next_drop += 1;
2521           n_left_to_next_drop -= 1;
2522
2523           b0 = vlib_get_buffer (vm, bi0);
2524
2525           type = lisp_msg_type(vlib_buffer_get_current (b0));
2526           switch (type)
2527             {
2528             case LISP_MAP_REPLY:
2529               process_map_reply (lcm, b0);
2530               break;
2531             case LISP_MAP_REQUEST:
2532               process_map_request(vm, lcm, b0);
2533               break;
2534             default:
2535               clib_warning("Unsupported LISP message type %d", type);
2536               break;
2537             }
2538
2539           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
2540
2541           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2542             {
2543
2544             }
2545         }
2546
2547       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, n_left_to_next_drop);
2548     }
2549   return from_frame->n_vectors;
2550 }
2551
2552 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
2553   .function = lisp_cp_input,
2554   .name = "lisp-cp-input",
2555   .vector_size = sizeof (u32),
2556   .format_trace = format_lisp_cp_input_trace,
2557   .type = VLIB_NODE_TYPE_INTERNAL,
2558
2559   .n_errors = LISP_CP_INPUT_N_ERROR,
2560   .error_strings = lisp_cp_input_error_strings,
2561
2562   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
2563
2564   .next_nodes = {
2565       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
2566   },
2567 };
2568
2569 clib_error_t *
2570 lisp_cp_init (vlib_main_t *vm)
2571 {
2572   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2573   clib_error_t * error = 0;
2574
2575   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
2576     return error;
2577
2578   lcm->im4 = &ip4_main;
2579   lcm->im6 = &ip6_main;
2580   lcm->vlib_main = vm;
2581   lcm->vnet_main = vnet_get_main();
2582   lcm->mreq_itr_rlocs = ~0;
2583
2584   gid_dictionary_init (&lcm->mapping_index_by_gid);
2585
2586   /* default vrf mapped to vni 0 */
2587   hash_set(lcm->table_id_by_vni, 0, 0);
2588
2589   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
2590                          lisp_cp_input_node.index, 1 /* is_ip4 */);
2591   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
2592                          lisp_cp_input_node.index, 0 /* is_ip4 */);
2593
2594   return 0;
2595 }
2596
2597 VLIB_INIT_FUNCTION(lisp_cp_init);