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