8b3d25f8dfae1293bbb4abc0744934b9a36d86c0
[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 static clib_error_t *
895 lisp_show_local_eid_table_command_fn (vlib_main_t * vm,
896                                       unformat_input_t * input,
897                                       vlib_cli_command_t * cmd)
898 {
899   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
900   mapping_t * mapit;
901
902   vlib_cli_output (vm, "%=30s%=16s", "EID", "Locator");
903   pool_foreach (mapit, lcm->mapping_pool,
904   ({
905     u8 * msg = 0;
906     locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
907                                             mapit->locator_set_index);
908     vlib_cli_output (vm, "%-30U%16v", format_gid_address, &mapit->eid,
909                      ls->name);
910     vec_free (msg);
911   }));
912
913   return 0;
914 }
915
916 VLIB_CLI_COMMAND (lisp_cp_show_local_eid_table_command) = {
917     .path = "show lisp eid-table",
918     .short_help = "Shows local EID table",
919     .function = lisp_show_local_eid_table_command_fn,
920 };
921
922 /* cleans locator to locator-set data and removes locators not part of
923  * any locator-set */
924 static void
925 clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
926 {
927   u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
928   locator_set_t * ls = pool_elt_at_index(lcm->locator_set_pool, lsi);
929   for (i = 0; i < vec_len(ls->locator_indices); i++)
930     {
931       loc_indexp = vec_elt_at_index(ls->locator_indices, i);
932       ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
933                                     loc_indexp[0]);
934       for (j = 0; j < vec_len(ls_indexes[0]); j++)
935         {
936           ls_indexp = vec_elt_at_index(ls_indexes[0], j);
937           if (ls_indexp[0] == lsi)
938             break;
939         }
940
941       /* delete index for removed locator-set*/
942       vec_del1(ls_indexes[0], j);
943
944       /* delete locator if it's part of no locator-set */
945       if (vec_len (ls_indexes[0]) == 0)
946         {
947           pool_put_index (lcm->locator_pool, loc_indexp[0]);
948           vec_add1 (to_be_deleted, i);
949         }
950     }
951
952   if (to_be_deleted)
953     {
954       for (i = 0; i < vec_len (to_be_deleted); i++)
955         {
956           loc_indexp = vec_elt_at_index (to_be_deleted, i);
957           vec_del1 (ls->locator_indices, loc_indexp[0]);
958         }
959       vec_free (to_be_deleted);
960     }
961 }
962
963 static inline
964 uword *get_locator_set_index(vnet_lisp_add_del_locator_set_args_t * a,
965                              uword * p)
966 {
967   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
968
969   ASSERT(a != NULL);
970   ASSERT(p != NULL);
971
972   /* find locator-set */
973   if (a->local)
974     {
975       p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
976     }
977   else
978     {
979       *p = a->index;
980     }
981
982   return p;
983 }
984
985 static inline
986 int is_locator_in_locator_set(lisp_cp_main_t * lcm, locator_set_t * ls,
987                               locator_t * loc)
988 {
989   locator_t * itloc;
990   u32 * locit;
991
992   ASSERT(ls != NULL);
993   ASSERT(loc != NULL);
994
995   vec_foreach(locit, ls->locator_indices)
996     {
997       itloc = pool_elt_at_index(lcm->locator_pool, locit[0]);
998       if (itloc->sw_if_index == loc->sw_if_index ||
999           !gid_address_cmp(&itloc->address, &loc->address))
1000         {
1001           clib_warning("Duplicate locator");
1002           return VNET_API_ERROR_VALUE_EXIST;
1003         }
1004     }
1005
1006   return 0;
1007 }
1008
1009 static inline
1010 void remove_locator_from_locator_set(locator_set_t * ls, u32 * locit,
1011                                      u32 ls_index, u32 loc_id)
1012 {
1013   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1014   u32 ** ls_indexes = NULL;
1015
1016   ASSERT(ls != NULL);
1017   ASSERT(locit != NULL);
1018
1019   ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1020                                 locit[0]);
1021   pool_put_index(lcm->locator_pool, locit[0]);
1022   vec_del1(ls->locator_indices, loc_id);
1023   vec_del1(ls_indexes[0], ls_index);
1024 }
1025
1026 int
1027 vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
1028                            locator_set_t * ls, u32 * ls_result)
1029 {
1030   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1031   locator_t * loc = NULL, *itloc = NULL;
1032   uword _p = (u32)~0, * p = &_p;
1033   u32 loc_index = ~0, ls_index = ~0, * locit = NULL, ** ls_indexes = NULL;
1034   u32 loc_id = ~0;
1035   int ret = 0;
1036
1037   ASSERT(a != NULL);
1038
1039   if (vnet_lisp_enable_disable_status () == 0)
1040     {
1041       clib_warning ("LISP is disabled!");
1042       return VNET_API_ERROR_LISP_DISABLED;
1043     }
1044
1045   p = get_locator_set_index(a, p);
1046   if (!p)
1047     {
1048       clib_warning("locator-set %v doesn't exist", a->name);
1049       return VNET_API_ERROR_INVALID_ARGUMENT;
1050     }
1051
1052   if (ls == 0)
1053     {
1054       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1055       if (!ls)
1056         {
1057           clib_warning("locator-set %d to be overwritten doesn't exist!",
1058                        p[0]);
1059           return VNET_API_ERROR_INVALID_ARGUMENT;
1060         }
1061     }
1062
1063   if (a->is_add)
1064     {
1065
1066         if (ls_result)
1067           ls_result[0] = p[0];
1068
1069         /* allocate locators */
1070         vec_foreach (itloc, a->locators)
1071           {
1072             ret = is_locator_in_locator_set(lcm, ls, itloc);
1073             if (0 != ret)
1074               {
1075                 return ret;
1076               }
1077
1078             pool_get(lcm->locator_pool, loc);
1079             loc[0] = itloc[0];
1080             loc_index = loc - lcm->locator_pool;
1081
1082             vec_add1(ls->locator_indices, loc_index);
1083
1084             vec_validate (lcm->locator_to_locator_sets, loc_index);
1085             ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1086                                           loc_index);
1087             vec_add1(ls_indexes[0], ls_index);
1088           }
1089       }
1090     else
1091       {
1092         ls_index = p[0];
1093
1094         itloc = a->locators;
1095         loc_id = 0;
1096         vec_foreach (locit, ls->locator_indices)
1097           {
1098             loc = pool_elt_at_index(lcm->locator_pool, locit[0]);
1099
1100             if (loc->local && loc->sw_if_index == itloc->sw_if_index)
1101               {
1102                 remove_locator_from_locator_set(ls, locit,
1103                                                 ls_index, loc_id);
1104               }
1105             if (0 == loc->local &&
1106                 !gid_address_cmp(&loc->address, &itloc->address))
1107               {
1108                 remove_locator_from_locator_set(ls, locit,
1109                                                 ls_index, loc_id);
1110               }
1111
1112             loc_id++;
1113           }
1114       }
1115
1116   return 0;
1117 }
1118
1119 int
1120 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
1121                                u32 * ls_result)
1122 {
1123   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1124   locator_set_t * ls;
1125   uword _p = (u32)~0, * p = &_p;
1126   u32 ls_index;
1127   u32 ** eid_indexes;
1128   int ret = 0;
1129
1130   if (vnet_lisp_enable_disable_status () == 0)
1131     {
1132       clib_warning ("LISP is disabled!");
1133       return VNET_API_ERROR_LISP_DISABLED;
1134     }
1135
1136   if (a->is_add)
1137     {
1138       p = get_locator_set_index(a, p);
1139
1140       /* overwrite */
1141       if (p && p[0] != (u32)~0)
1142         {
1143           ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1144           if (!ls)
1145             {
1146               clib_warning("locator-set %d to be overwritten doesn't exist!",
1147                            p[0]);
1148               return -1;
1149             }
1150
1151           /* clean locator to locator-set vectors and remove locators if
1152            * they're not part of another locator-set */
1153           clean_locator_to_locator_set (lcm, p[0]);
1154
1155           /* remove locator indices from locator set */
1156           vec_free(ls->locator_indices);
1157
1158           ls_index = p[0];
1159
1160           if (ls_result)
1161             ls_result[0] = p[0];
1162         }
1163       /* new locator-set */
1164       else
1165         {
1166           pool_get(lcm->locator_set_pool, ls);
1167           memset(ls, 0, sizeof(*ls));
1168           ls_index = ls - lcm->locator_set_pool;
1169
1170           if (a->local)
1171             {
1172               ls->name = vec_dup(a->name);
1173
1174               if (!lcm->locator_set_index_by_name)
1175                 lcm->locator_set_index_by_name = hash_create_vec(
1176                     /* size */0, sizeof(ls->name[0]), sizeof(uword));
1177               hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index);
1178
1179               /* mark as local locator-set */
1180               vec_add1(lcm->local_locator_set_indexes, ls_index);
1181             }
1182           ls->local = a->local;
1183           if (ls_result)
1184             ls_result[0] = ls_index;
1185         }
1186
1187       ret = vnet_lisp_add_del_locator(a, ls, NULL);
1188       if (0 != ret)
1189         {
1190           return ret;
1191         }
1192     }
1193   else
1194     {
1195       p = get_locator_set_index(a, p);
1196       if (!p)
1197         {
1198           clib_warning("locator-set %v doesn't exists", a->name);
1199           return -1;
1200         }
1201
1202       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1203       if (!ls)
1204         {
1205           clib_warning("locator-set with index %d doesn't exists", p[0]);
1206           return -1;
1207         }
1208
1209       if (lcm->mreq_itr_rlocs == p[0])
1210         {
1211           clib_warning ("Can't delete the locator-set used to constrain "
1212                         "the itr-rlocs in map-requests!");
1213           return -1;
1214         }
1215
1216       if (vec_len(lcm->locator_set_to_eids) != 0)
1217       {
1218           eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, p[0]);
1219           if (vec_len(eid_indexes[0]) != 0)
1220           {
1221               clib_warning ("Can't delete a locator that supports a mapping!");
1222               return -1;
1223           }
1224       }
1225
1226       /* clean locator to locator-sets data */
1227       clean_locator_to_locator_set (lcm, p[0]);
1228
1229       if (ls->local)
1230         {
1231           u32 it, lsi;
1232
1233           vec_foreach_index(it, lcm->local_locator_set_indexes)
1234           {
1235             lsi = vec_elt(lcm->local_locator_set_indexes, it);
1236             if (lsi == p[0])
1237               {
1238                 vec_del1(lcm->local_locator_set_indexes, it);
1239                 break;
1240               }
1241           }
1242           hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
1243         }
1244       vec_free(ls->name);
1245       vec_free(ls->locator_indices);
1246       pool_put(lcm->locator_set_pool, ls);
1247     }
1248   return 0;
1249 }
1250
1251 clib_error_t *
1252 vnet_lisp_enable_disable (u8 is_enabled)
1253 {
1254   vnet_lisp_gpe_add_del_iface_args_t _ai, * ai= &_ai;
1255   uword * table_id, * refc;
1256   u32 i;
1257   clib_error_t * error = 0;
1258   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1259   vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
1260
1261   a->is_en = is_enabled;
1262   error = vnet_lisp_gpe_enable_disable (a);
1263   if (error)
1264     {
1265       return clib_error_return (0, "failed to %s data-plane!",
1266                                 a->is_en ? "enable" : "disable");
1267     }
1268
1269   if (is_enabled)
1270     {
1271       /* enable all ifaces */
1272       for (i = 0; i < vec_len (lcm->local_mappings_indexes); i++)
1273         {
1274           mapping_t * m = vec_elt_at_index (lcm->mapping_pool, i);
1275           ai->is_add = 1;
1276           ai->vni = gid_address_vni (&m->eid);
1277
1278           refc = hash_get (lcm->dp_if_refcount_by_vni, ai->vni);
1279           if (!refc)
1280             {
1281               table_id = hash_get (lcm->table_id_by_vni, ai->vni);
1282               if (table_id)
1283                 {
1284                   ai->table_id = table_id[0];
1285                   /* enables interface and adds defaults */
1286                   vnet_lisp_gpe_add_del_iface (ai, 0);
1287                 }
1288               else
1289                 return clib_error_return (0, "no table_id found for vni %u!",
1290                                           ai->vni);
1291
1292               hash_set (lcm->dp_if_refcount_by_vni, ai->vni, 1);
1293             }
1294           else
1295             {
1296               refc[0]++;
1297             }
1298         }
1299     }
1300   else
1301     {
1302       /* clear refcount table */
1303       hash_free (lcm->dp_if_refcount_by_vni);
1304       hash_free (lcm->fwd_entry_by_mapping_index);
1305       pool_free (lcm->fwd_entry_pool);
1306     }
1307
1308   /* update global flag */
1309   lcm->is_enabled = is_enabled;
1310
1311   return 0;
1312 }
1313
1314 static clib_error_t *
1315 lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
1316                                    vlib_cli_command_t * cmd)
1317 {
1318   unformat_input_t _line_input, * line_input = &_line_input;
1319   u8 is_enabled = 0;
1320   u8 is_set = 0;
1321
1322   /* Get a line of input. */
1323   if (! unformat_user (input, unformat_line_input, line_input))
1324     return 0;
1325
1326   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1327     {
1328       if (unformat (line_input, "enable"))
1329         {
1330           is_set = 1;
1331           is_enabled = 1;
1332         }
1333       else if (unformat (line_input, "disable"))
1334         is_set = 1;
1335       else
1336         {
1337           return clib_error_return (0, "parse error: '%U'",
1338                                    format_unformat_error, line_input);
1339         }
1340     }
1341
1342   if (!is_set)
1343       return clib_error_return (0, "state not set");
1344
1345   return vnet_lisp_enable_disable (is_enabled);
1346 }
1347
1348 VLIB_CLI_COMMAND (lisp_cp_enable_disable_command) = {
1349     .path = "lisp",
1350     .short_help = "lisp [enable|disable]",
1351     .function = lisp_enable_disable_command_fn,
1352 };
1353
1354 u8
1355 vnet_lisp_enable_disable_status (void)
1356 {
1357   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1358   return lcm->is_enabled;
1359 }
1360
1361 static u8 *
1362 format_lisp_status (u8 * s, va_list * args)
1363 {
1364   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1365   return format (s, "%s", lcm->is_enabled ? "enabled" : "disabled");
1366 }
1367
1368 static clib_error_t *
1369 lisp_show_status_command_fn (vlib_main_t * vm, unformat_input_t * input,
1370                              vlib_cli_command_t * cmd)
1371 {
1372   u8 * msg = 0;
1373   msg = format (msg, "feature: %U\ngpe: %U\n",
1374                 format_lisp_status, format_vnet_lisp_gpe_status);
1375   vlib_cli_output (vm, "%v", msg);
1376   vec_free (msg);
1377   return 0;
1378 }
1379
1380 VLIB_CLI_COMMAND (lisp_show_status_command) = {
1381     .path = "show lisp status",
1382     .short_help = "show lisp status",
1383     .function = lisp_show_status_command_fn,
1384 };
1385
1386 static clib_error_t *
1387 lisp_show_eid_table_map_command_fn (vlib_main_t * vm, unformat_input_t * input,
1388                                     vlib_cli_command_t * cmd)
1389 {
1390   hash_pair_t * p;
1391   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1392
1393   vlib_cli_output (vm, "%=10s%=10s", "VNI", "VRF");
1394   hash_foreach_pair (p, lcm->table_id_by_vni,
1395     {
1396       vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
1397     });
1398   return 0;
1399 }
1400
1401 VLIB_CLI_COMMAND (lisp_show_eid_table_map_command) = {
1402     .path = "show lisp eid-table map",
1403     .short_help = "show lisp eid-table vni to vrf mappings",
1404     .function = lisp_show_eid_table_map_command_fn,
1405 };
1406
1407 static clib_error_t *
1408 lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
1409                                      vlib_cli_command_t * cmd)
1410 {
1411   lisp_gpe_main_t * lgm = &lisp_gpe_main;
1412   vnet_main_t * vnm = lgm->vnet_main;
1413   unformat_input_t _line_input, * line_input = &_line_input;
1414   u8 is_add = 1;
1415   clib_error_t * error = 0;
1416   u8 * locator_set_name = 0;
1417   locator_t locator, * locators = 0;
1418   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
1419   u32 ls_index = 0;
1420   int rv = 0;
1421
1422   memset(&locator, 0, sizeof(locator));
1423   memset(a, 0, sizeof(a[0]));
1424
1425   /* Get a line of input. */
1426   if (! unformat_user (input, unformat_line_input, line_input))
1427     return 0;
1428
1429   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1430     {
1431       if (unformat (line_input, "add %_%v%_", &locator_set_name))
1432         is_add = 1;
1433       else if (unformat (line_input, "del %_%v%_", &locator_set_name))
1434         is_add = 0;
1435       else if (unformat (line_input, "iface %U p %d w %d",
1436                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
1437                          &locator.priority, &locator.weight))
1438         {
1439           locator.local = 1;
1440           vec_add1(locators, locator);
1441         }
1442       else
1443         {
1444           error = unformat_parse_error(line_input);
1445           goto done;
1446         }
1447     }
1448
1449   a->name = locator_set_name;
1450   a->locators = locators;
1451   a->is_add = is_add;
1452   a->local = 1;
1453
1454   rv = vnet_lisp_add_del_locator_set(a, &ls_index);
1455   if (0 != rv)
1456     {
1457       error = clib_error_return(0, "failed to %s locator-set!",
1458                                 is_add ? "add" : "delete");
1459     }
1460
1461  done:
1462   vec_free(locators);
1463   if (locator_set_name)
1464     vec_free (locator_set_name);
1465   return error;
1466 }
1467
1468 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
1469     .path = "lisp locator-set",
1470     .short_help = "lisp locator-set add/del <name> [iface <iface-name> "
1471         "p <priority> w <weight>]",
1472     .function = lisp_add_del_locator_set_command_fn,
1473 };
1474
1475 static clib_error_t *
1476 lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
1477                                      vlib_cli_command_t * cmd)
1478 {
1479   lisp_gpe_main_t * lgm = &lisp_gpe_main;
1480   vnet_main_t * vnm = lgm->vnet_main;
1481   unformat_input_t _line_input, * line_input = &_line_input;
1482   u8 is_add = 1;
1483   clib_error_t * error = 0;
1484   u8 * locator_set_name = 0;
1485   u8 locator_set_name_set = 0;
1486   locator_t locator, * locators = 0;
1487   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
1488   u32 ls_index = 0;
1489
1490   memset(&locator, 0, sizeof(locator));
1491   memset(a, 0, sizeof(a[0]));
1492
1493   /* Get a line of input. */
1494   if (! unformat_user (input, unformat_line_input, line_input))
1495     return 0;
1496
1497   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1498     {
1499       if (unformat (line_input, "add"))
1500         is_add = 1;
1501       else if (unformat (line_input, "del"))
1502         is_add = 0;
1503       else if (unformat(line_input, "locator-set %_%v%_", &locator_set_name))
1504         locator_set_name_set = 1;
1505       else if (unformat (line_input, "iface %U p %d w %d",
1506                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
1507                          &locator.priority, &locator.weight))
1508         {
1509           locator.local = 1;
1510           vec_add1(locators, locator);
1511         }
1512       else
1513         {
1514           error = unformat_parse_error(line_input);
1515           goto done;
1516         }
1517     }
1518
1519   if (!locator_set_name_set)
1520     {
1521       error = clib_error_return(0, "locator_set name not set!");
1522       goto done;
1523   }
1524
1525   a->name = locator_set_name;
1526   a->locators = locators;
1527   a->is_add = is_add;
1528   a->local = 1;
1529
1530   vnet_lisp_add_del_locator(a, 0, &ls_index);
1531
1532  done:
1533   vec_free(locators);
1534   vec_free (locator_set_name);
1535   return error;
1536 }
1537
1538 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_in_set_command) = {
1539     .path = "lisp locator",
1540     .short_help = "lisp locator add/del locator-set <name> iface <iface-name> "
1541                   "p <priority> w <weight>",
1542     .function = lisp_add_del_locator_in_set_command_fn,
1543 };
1544
1545 static clib_error_t *
1546 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
1547                                       unformat_input_t * input,
1548                                       vlib_cli_command_t * cmd)
1549 {
1550   locator_set_t * lsit;
1551   locator_t * loc;
1552   u32 * locit;
1553   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1554
1555   vlib_cli_output (vm, "%=20s%=16s%=16s%=16s", "Locator-set", "Locator",
1556                    "Priority", "Weight");
1557   pool_foreach (lsit, lcm->locator_set_pool,
1558   ({
1559     u8 * msg = 0;
1560     int next_line = 0;
1561     msg = format (msg, "%=16v", lsit->name);
1562     vec_foreach (locit, lsit->locator_indices)
1563       {
1564         if (next_line)
1565           {
1566             msg = format (msg, "%16s", " ");
1567           }
1568         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1569         if (loc->local)
1570           msg = format (msg, "%16d%16d%16d\n", loc->sw_if_index, loc->priority,
1571                         loc->weight);
1572         else
1573           msg = format (msg, "%16U%16d%16d\n", format_ip_address,
1574                         gid_address_ip(&loc->address), loc->priority,
1575                         loc->weight);
1576         next_line = 1;
1577       }
1578     vlib_cli_output (vm, "%v", msg);
1579     vec_free (msg);
1580   }));
1581   return 0;
1582 }
1583
1584 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
1585     .path = "show lisp locator-set",
1586     .short_help = "Shows locator-sets",
1587     .function = lisp_cp_show_locator_sets_command_fn,
1588 };
1589
1590 int
1591 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
1592 {
1593   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1594   ip_address_t * addr;
1595   u32 i;
1596
1597   if (vnet_lisp_enable_disable_status () == 0)
1598     {
1599       clib_warning ("LISP is disabled!");
1600       return VNET_API_ERROR_LISP_DISABLED;
1601     }
1602
1603   if (a->is_add)
1604     {
1605       vec_foreach(addr, lcm->map_resolvers)
1606         {
1607           if (!ip_address_cmp (addr, &a->address))
1608             {
1609               clib_warning("map-resolver %U already exists!", format_ip_address,
1610                            &a->address);
1611               return -1;
1612             }
1613         }
1614       vec_add1(lcm->map_resolvers, a->address);
1615     }
1616   else
1617     {
1618       for (i = 0; i < vec_len(lcm->map_resolvers); i++)
1619         {
1620           addr = vec_elt_at_index(lcm->map_resolvers, i);
1621           if (!ip_address_cmp (addr, &a->address))
1622             {
1623               vec_delete(lcm->map_resolvers, 1, i);
1624               break;
1625             }
1626         }
1627     }
1628   return 0;
1629 }
1630
1631 static clib_error_t *
1632 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
1633                                          unformat_input_t * input,
1634                                          vlib_cli_command_t * cmd)
1635 {
1636   unformat_input_t _line_input, * line_input = &_line_input;
1637   u8 is_add = 1;
1638   ip_address_t ip_addr;
1639   clib_error_t * error = 0;
1640   int rv = 0;
1641   vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a;
1642
1643   /* Get a line of input. */
1644   if (! unformat_user (input, unformat_line_input, line_input))
1645     return 0;
1646
1647   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1648     {
1649       if (unformat (line_input, "add"))
1650         is_add = 1;
1651       else if (unformat (line_input, "del"))
1652         is_add = 0;
1653       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
1654         ;
1655       else
1656         {
1657           error = unformat_parse_error(line_input);
1658           goto done;
1659         }
1660     }
1661   a->is_add = is_add;
1662   a->address = ip_addr;
1663   rv = vnet_lisp_add_del_map_resolver (a);
1664   if (0 != rv)
1665     {
1666       error = clib_error_return(0, "failed to %s map-resolver!",
1667                                 is_add ? "add" : "delete");
1668     }
1669
1670  done:
1671   return error;
1672 }
1673
1674 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
1675     .path = "lisp map-resolver",
1676     .short_help = "lisp map-resolver add/del <ip_address>",
1677     .function = lisp_add_del_map_resolver_command_fn,
1678 };
1679
1680 int
1681 vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
1682 {
1683   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1684   uword * p = 0;
1685
1686   //TODO: Wait for merge https://gerrit.fd.io/r/#/c/1427/
1687 //   if (vnet_lisp_enable_disable_status () == 0)
1688 //     {
1689 //       clib_warning ("LISP is disabled!");
1690 //       return VNET_API_ERROR_LISP_DISABLED;
1691 //     }
1692
1693   if (a->is_add)
1694     {
1695       p = hash_get_mem(lcm->locator_set_index_by_name, a->locator_set_name);
1696       if (!p)
1697         {
1698           clib_warning("locator-set %v doesn't exist", a->locator_set_name);
1699           return VNET_API_ERROR_INVALID_ARGUMENT;
1700         }
1701
1702       lcm->mreq_itr_rlocs = p[0];
1703     }
1704   else
1705     {
1706       lcm->mreq_itr_rlocs = ~0;
1707     }
1708
1709   return 0;
1710 }
1711
1712 static clib_error_t *
1713 lisp_add_del_mreq_itr_rlocs_command_fn(vlib_main_t * vm,
1714                                        unformat_input_t * input,
1715                                        vlib_cli_command_t * cmd)
1716 {
1717   unformat_input_t _line_input, * line_input = &_line_input;
1718   u8 is_add = 1;
1719   u8 * locator_set_name = 0;
1720   clib_error_t * error = 0;
1721   int rv = 0;
1722   vnet_lisp_add_del_mreq_itr_rloc_args_t _a, * a = &_a;
1723
1724   /* Get a line of input. */
1725   if (! unformat_user (input, unformat_line_input, line_input))
1726     return 0;
1727
1728   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1729     {
1730       if (unformat (line_input, "del"))
1731         is_add = 0;
1732       else if (unformat (line_input, "add %s", &locator_set_name))
1733         is_add = 1;
1734       else
1735         {
1736           error = unformat_parse_error(line_input);
1737           goto done;
1738         }
1739     }
1740
1741   a->is_add = is_add;
1742   a->locator_set_name = locator_set_name;
1743   rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
1744   if (0 != rv)
1745     {
1746       error = clib_error_return(0, "failed to %s map-request itr-rlocs!",
1747                                 is_add ? "add" : "delete");
1748     }
1749
1750   vec_free(locator_set_name);
1751
1752  done:
1753   return error;
1754
1755 }
1756
1757 VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
1758     .path = "lisp map-request itr-rlocs",
1759     .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
1760     .function = lisp_add_del_mreq_itr_rlocs_command_fn,
1761 };
1762
1763 static clib_error_t *
1764 lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
1765                                     unformat_input_t * input,
1766                                     vlib_cli_command_t * cmd)
1767 {
1768   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1769   locator_set_t * loc_set;
1770
1771   vlib_cli_output (vm, "%=20s", "itr-rlocs");
1772
1773   if (~0 == lcm->mreq_itr_rlocs)
1774     {
1775       return 0;
1776     }
1777
1778   loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
1779
1780   vlib_cli_output (vm, "%=20s", loc_set->name);
1781
1782   return 0;
1783 }
1784
1785 VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
1786     .path = "show lisp map-request itr-rlocs",
1787     .short_help = "Shows map-request itr-rlocs",
1788     .function = lisp_show_mreq_itr_rlocs_command_fn,
1789 };
1790
1791 /* Statistics (not really errors) */
1792 #define foreach_lisp_cp_lookup_error           \
1793 _(DROP, "drop")                                \
1794 _(MAP_REQUESTS_SENT, "map-request sent")
1795
1796 static char * lisp_cp_lookup_error_strings[] = {
1797 #define _(sym,string) string,
1798   foreach_lisp_cp_lookup_error
1799 #undef _
1800 };
1801
1802 typedef enum
1803 {
1804 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
1805     foreach_lisp_cp_lookup_error
1806 #undef _
1807     LISP_CP_LOOKUP_N_ERROR,
1808 } lisp_cp_lookup_error_t;
1809
1810 typedef enum
1811 {
1812   LISP_CP_LOOKUP_NEXT_DROP,
1813   LISP_CP_LOOKUP_NEXT_IP4_LOOKUP,
1814   LISP_CP_LOOKUP_NEXT_IP6_LOOKUP,
1815   LISP_CP_LOOKUP_N_NEXT,
1816 } lisp_cp_lookup_next_t;
1817
1818 typedef struct
1819 {
1820   gid_address_t dst_eid;
1821   ip_address_t map_resolver_ip;
1822 } lisp_cp_lookup_trace_t;
1823
1824 u8 *
1825 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
1826 {
1827   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1828   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1829   lisp_cp_lookup_trace_t * t = va_arg (*args, lisp_cp_lookup_trace_t *);
1830
1831   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
1832               format_ip_address, &t->map_resolver_ip, format_gid_address,
1833               &t->dst_eid);
1834   return s;
1835 }
1836
1837 ip_interface_address_t *
1838 ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
1839                                           u8 loop)
1840 {
1841   vnet_main_t *vnm = vnet_get_main ();
1842   vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index);
1843   if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
1844     sw_if_index = swif->unnumbered_sw_if_index;
1845   u32 ia =
1846       (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
1847           vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
1848           (u32) ~0;
1849   return pool_elt_at_index((lm)->if_address_pool, ia);
1850 }
1851
1852 void *
1853 ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
1854                                 u8 version)
1855 {
1856   ip_interface_address_t * ia;
1857
1858   ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
1859   if (!ia)
1860     return 0;
1861   return ip_interface_address_get_address (lm, ia);
1862 }
1863
1864 int
1865 ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
1866                                    u8 version, ip_address_t * result)
1867 {
1868   ip_lookup_main_t * lm;
1869   void * addr;
1870
1871   lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1872   addr = ip_interface_get_first_address (lm, sw_if_index, version);
1873   if (!addr)
1874     return 0;
1875
1876   ip_address_set (result, addr, version);
1877   return 1;
1878 }
1879
1880 static u32
1881 ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
1882                           ip_address_t * dst)
1883 {
1884   if (ip_addr_version (dst) == IP4)
1885       return ip4_fib_lookup_with_table (lcm->im4, fib_index, &ip_addr_v4(dst),
1886                                         0);
1887   else
1888       return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6(dst));
1889 }
1890
1891 u32
1892 ip_fib_get_egress_iface_for_dst_with_lm (lisp_cp_main_t * lcm,
1893                                          ip_address_t * dst,
1894                                          ip_lookup_main_t * lm)
1895 {
1896   u32 adj_index;
1897   ip_adjacency_t * adj;
1898
1899   adj_index = ip_fib_lookup_with_table (lcm, 0, dst);
1900   adj = ip_get_adjacency (lm, adj_index);
1901
1902   if (adj == 0)
1903     return ~0;
1904
1905   /* we only want outgoing routes */
1906   if (adj->lookup_next_index != IP_LOOKUP_NEXT_ARP
1907       && adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
1908     return ~0;
1909
1910   return adj->rewrite_header.sw_if_index;
1911 }
1912
1913 /**
1914  * Find the sw_if_index of the interface that would be used to egress towards
1915  * dst.
1916  */
1917 u32
1918 ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
1919 {
1920   ip_lookup_main_t * lm;
1921
1922   lm = ip_addr_version (dst) == IP4 ?
1923       &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1924
1925   return ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
1926 }
1927
1928 /**
1929  * Find first IP of the interface that would be used to egress towards dst.
1930  * Returns 1 if the address is found 0 otherwise.
1931  */
1932 int
1933 ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
1934                                     ip_address_t * result)
1935 {
1936   u32 si;
1937   ip_lookup_main_t * lm;
1938   void * addr = 0;
1939   u8 ipver;
1940
1941   ASSERT(result != 0);
1942
1943   ipver = ip_addr_version(dst);
1944
1945   lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
1946   si = ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
1947
1948   if ((u32) ~0 == si)
1949     return 0;
1950
1951   /* find the first ip address */
1952   addr = ip_interface_get_first_address (lm, si, ipver);
1953   if (0 == addr)
1954     return 0;
1955
1956   ip_address_set (result, addr, ipver);
1957   return 1;
1958 }
1959
1960 int
1961 get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
1962                            ip_address_t * sloc)
1963 {
1964   ip_address_t * mrit;
1965
1966   if (vec_len(lcm->map_resolvers) == 0)
1967     {
1968       clib_warning("No map-resolver configured");
1969       return 0;
1970     }
1971
1972   /* find the first mr ip we have a route to and the ip of the
1973    * iface that has a route to it */
1974   vec_foreach(mrit, lcm->map_resolvers)
1975     {
1976       if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, mrit, sloc)) {
1977           ip_address_copy(mr_ip, mrit);
1978           return 1;
1979       }
1980     }
1981
1982   clib_warning("Can't find map-resolver and local interface ip!");
1983   return 0;
1984 }
1985
1986 static gid_address_t *
1987 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
1988 {
1989   void * addr;
1990   u32 i;
1991   locator_t * loc;
1992   u32 * loc_indexp;
1993   ip_interface_address_t * ia = 0;
1994   gid_address_t gid_data, * gid = &gid_data;
1995   gid_address_t * rlocs = 0;
1996   ip_prefix_t * ippref = &gid_address_ippref (gid);
1997   ip_address_t * rloc = &ip_prefix_addr (ippref);
1998
1999   memset (gid, 0, sizeof (gid[0]));
2000   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
2001   for (i = 0; i < vec_len(loc_set->locator_indices); i++)
2002     {
2003       loc_indexp = vec_elt_at_index(loc_set->locator_indices, i);
2004       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
2005
2006       /* Add ipv4 locators first TODO sort them */
2007       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2008                                     loc->sw_if_index, 1 /* unnumbered */,
2009       ({
2010         addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
2011         ip_address_set (rloc, addr, IP4);
2012         ip_prefix_len (ippref) = 32;
2013         vec_add1 (rlocs, gid[0]);
2014       }));
2015
2016       /* Add ipv6 locators */
2017       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2018                                     loc->sw_if_index, 1 /* unnumbered */,
2019       ({
2020         addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
2021         ip_address_set (rloc, addr, IP6);
2022         ip_prefix_len (ippref) = 128;
2023         vec_add1 (rlocs, gid[0]);
2024       }));
2025     }
2026   return rlocs;
2027 }
2028
2029 static vlib_buffer_t *
2030 build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
2031                                 gid_address_t * seid, gid_address_t * deid,
2032                                 locator_set_t * loc_set, ip_address_t * mr_ip,
2033                                 ip_address_t * sloc, u8 is_smr_invoked,
2034                                 u64 *nonce_res, u32 * bi_res)
2035 {
2036   vlib_buffer_t * b;
2037   u32 bi;
2038   gid_address_t * rlocs = 0;
2039
2040   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2041     {
2042       clib_warning ("Can't allocate buffer for Map-Request!");
2043       return 0;
2044     }
2045
2046   b = vlib_get_buffer (vm, bi);
2047
2048   /* leave some space for the encap headers */
2049   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2050
2051   /* get rlocs */
2052   rlocs = build_itr_rloc_list (lcm, loc_set);
2053
2054   /* put lisp msg */
2055   lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked, nonce_res);
2056
2057   /* push ecm: udp-ip-lisp */
2058   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
2059
2060   /* push outer ip header */
2061   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
2062                        mr_ip);
2063
2064   bi_res[0] = bi;
2065
2066   vec_free(rlocs);
2067   return b;
2068 }
2069
2070 static void
2071 send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
2072                                gid_address_t * seid, gid_address_t * deid,
2073                                u8 is_smr_invoked)
2074 {
2075   u32 next_index, bi = 0, * to_next, map_index;
2076   vlib_buffer_t * b;
2077   vlib_frame_t * f;
2078   u64 nonce = 0;
2079   locator_set_t * loc_set;
2080   mapping_t * map;
2081   pending_map_request_t * pmr;
2082   ip_address_t mr_ip, sloc;
2083   u32 ls_index;
2084
2085   /* get locator-set for seid */
2086   if (!lcm->lisp_pitr)
2087     {
2088       map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
2089       if (map_index == ~0)
2090         {
2091           clib_warning("No local mapping found in eid-table for %U!",
2092                        format_gid_address, seid);
2093           return;
2094         }
2095
2096       map = pool_elt_at_index (lcm->mapping_pool, map_index);
2097
2098       if (!map->local)
2099         {
2100           clib_warning("Mapping found for src eid %U is not marked as local!",
2101                        format_gid_address, seid);
2102           return;
2103         }
2104       ls_index = map->locator_set_index;
2105     }
2106   else
2107     {
2108       map_index = lcm->pitr_map_index;
2109       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
2110       ls_index = map->locator_set_index;
2111     }
2112
2113   /* overwrite locator set if map-request itr-rlocs configured */
2114   if (~0 != lcm->mreq_itr_rlocs)
2115     {
2116       ls_index = lcm->mreq_itr_rlocs;
2117     }
2118
2119   loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
2120
2121   /* get local iface ip to use in map-request */
2122   if (0 == get_mr_and_local_iface_ip (lcm, &mr_ip, &sloc))
2123     return;
2124
2125   /* build the encapsulated map request */
2126   b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set, &mr_ip,
2127                                       &sloc, is_smr_invoked, &nonce, &bi);
2128
2129   if (!b)
2130     return;
2131
2132   /* set fib index and lookup node */
2133   vnet_buffer(b)->sw_if_index[VLIB_TX] = ~0;
2134   next_index = (ip_addr_version(&mr_ip) == IP4) ?
2135       ip4_lookup_node.index : ip6_lookup_node.index;
2136
2137   f = vlib_get_frame_to_node (vm, next_index);
2138
2139   /* Enqueue the packet */
2140   to_next = vlib_frame_vector_args (f);
2141   to_next[0] = bi;
2142   f->n_vectors = 1;
2143   vlib_put_frame_to_node (vm, next_index, f);
2144
2145   /* add map-request to pending requests table */
2146   pool_get(lcm->pending_map_requests_pool, pmr);
2147   gid_address_copy (&pmr->src, seid);
2148   gid_address_copy (&pmr->dst, deid);
2149   pmr->src_mapping_index = map_index;
2150   hash_set(lcm->pending_map_requests_by_nonce, nonce,
2151            pmr - lcm->pending_map_requests_pool);
2152 }
2153
2154 static void
2155 get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst)
2156 {
2157   ip4_header_t * ip4 = hdr;
2158   ip6_header_t * ip6;
2159
2160   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
2161     {
2162       ip_address_set(src, &ip4->src_address, IP4);
2163       ip_address_set(dst, &ip4->dst_address, IP4);
2164     }
2165   else
2166     {
2167       ip6 = hdr;
2168       ip_address_set(src, &ip6->src_address, IP6);
2169       ip_address_set(dst, &ip6->dst_address, IP6);
2170     }
2171 }
2172
2173 static u32
2174 lisp_get_vni_from_buffer (vlib_buffer_t * b, u8 version)
2175 {
2176   uword * vnip;
2177   u32 vni = ~0, table_id = ~0, fib_index;
2178   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
2179
2180   if (version == IP4)
2181     {
2182       ip4_fib_t * fib;
2183       ip4_main_t * im4 = &ip4_main;
2184       fib_index = vec_elt (im4->fib_index_by_sw_if_index,
2185                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2186       fib = find_ip4_fib_by_table_index_or_id (im4, fib_index,
2187                                                IP4_ROUTE_FLAG_FIB_INDEX);
2188       table_id = fib->table_id;
2189     }
2190   else
2191     {
2192       ip6_fib_t * fib;
2193       ip6_main_t * im6 = &ip6_main;
2194       fib_index = vec_elt (im6->fib_index_by_sw_if_index,
2195                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2196       fib = find_ip6_fib_by_table_index_or_id (im6, fib_index,
2197                                                IP6_ROUTE_FLAG_FIB_INDEX);
2198       table_id = fib->table_id;
2199     }
2200
2201   vnip = hash_get (lcm->vni_by_table_id, table_id);
2202   if (vnip)
2203     vni = vnip[0];
2204   else
2205     clib_warning ("vrf %d is not mapped to any vni!", table_id);
2206
2207   return vni;
2208 }
2209
2210 static uword
2211 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
2212               vlib_frame_t * from_frame)
2213 {
2214   u32 * from, * to_next_drop, di, si;
2215   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main();
2216   u32 pkts_mapped = 0;
2217   uword n_left_from, n_left_to_next_drop;
2218
2219   from = vlib_frame_vector_args (from_frame);
2220   n_left_from = from_frame->n_vectors;
2221
2222   while (n_left_from > 0)
2223     {
2224       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
2225                            to_next_drop, n_left_to_next_drop);
2226
2227       while (n_left_from > 0 && n_left_to_next_drop > 0)
2228         {
2229           u32 pi0, vni;
2230           vlib_buffer_t * p0;
2231           ip4_header_t * ip0;
2232           gid_address_t src, dst;
2233           ip_prefix_t * spref, * dpref;
2234
2235           gid_address_type (&src) = GID_ADDR_IP_PREFIX;
2236           spref = &gid_address_ippref(&src);
2237           gid_address_type (&dst) = GID_ADDR_IP_PREFIX;
2238           dpref = &gid_address_ippref(&dst);
2239
2240           pi0 = from[0];
2241           from += 1;
2242           n_left_from -= 1;
2243           to_next_drop[0] = pi0;
2244           to_next_drop += 1;
2245           n_left_to_next_drop -= 1;
2246
2247           p0 = vlib_get_buffer (vm, pi0);
2248           p0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
2249
2250           /* src/dst eid pair */
2251           ip0 = vlib_buffer_get_current (p0);
2252           get_src_and_dst (ip0, &ip_prefix_addr(spref), &ip_prefix_addr(dpref));
2253           ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref));
2254           ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref));
2255
2256           vni = lisp_get_vni_from_buffer (p0, ip_prefix_version (spref));
2257           gid_address_vni (&dst) = vni;
2258           gid_address_vni (&src) = vni;
2259
2260           /* if we have remote mapping for destination already in map-chache
2261              add forwarding tunnel directly. If not send a map-request */
2262           di = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
2263           if (~0 != di)
2264             {
2265               mapping_t * m =  vec_elt_at_index (lcm->mapping_pool, di);
2266               /* send a map-request also in case of negative mapping entry
2267                 with corresponding action */
2268               if (m->action == ACTION_SEND_MAP_REQUEST)
2269                 {
2270                   /* send map-request */
2271                   send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2272                   pkts_mapped++;
2273                 }
2274               else
2275                 {
2276                   si =  gid_dictionary_lookup (&lcm->mapping_index_by_gid,
2277                                                &src);
2278                   if (~0 != si)
2279                     {
2280                       add_fwd_entry (lcm, si, di);
2281                     }
2282                 }
2283             }
2284           else
2285             {
2286               /* send map-request */
2287               send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2288               pkts_mapped++;
2289             }
2290
2291           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
2292             {
2293               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, p0,
2294                                                           sizeof(*tr));
2295
2296               memset(tr, 0, sizeof(*tr));
2297               gid_address_copy (&tr->dst_eid, &dst);
2298               if (vec_len(lcm->map_resolvers) > 0)
2299                 {
2300                   clib_memcpy (&tr->map_resolver_ip,
2301                                vec_elt_at_index(lcm->map_resolvers, 0),
2302                                sizeof(ip_address_t));
2303                 }
2304             }
2305           gid_address_free (&dst);
2306           gid_address_free (&src);
2307         }
2308
2309       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop);
2310     }
2311   vlib_node_increment_counter (vm, node->node_index,
2312                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
2313                                pkts_mapped);
2314   return from_frame->n_vectors;
2315 }
2316
2317 VLIB_REGISTER_NODE (lisp_cp_lookup_node) = {
2318   .function = lisp_cp_lookup,
2319   .name = "lisp-cp-lookup",
2320   .vector_size = sizeof (u32),
2321   .format_trace = format_lisp_cp_lookup_trace,
2322   .type = VLIB_NODE_TYPE_INTERNAL,
2323
2324   .n_errors = LISP_CP_LOOKUP_N_ERROR,
2325   .error_strings = lisp_cp_lookup_error_strings,
2326
2327   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
2328
2329   .next_nodes = {
2330       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
2331       [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup",
2332       [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup",
2333   },
2334 };
2335
2336 /* lisp_cp_input statistics */
2337 #define foreach_lisp_cp_input_error                   \
2338 _(DROP, "drop")                                        \
2339 _(MAP_REPLIES_RECEIVED, "map-replies received")
2340
2341 static char * lisp_cp_input_error_strings[] = {
2342 #define _(sym,string) string,
2343   foreach_lisp_cp_input_error
2344 #undef _
2345 };
2346
2347 typedef enum
2348 {
2349 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
2350     foreach_lisp_cp_input_error
2351 #undef _
2352     LISP_CP_INPUT_N_ERROR,
2353 } lisp_cp_input_error_t;
2354
2355 typedef enum
2356 {
2357   LISP_CP_INPUT_NEXT_DROP,
2358   LISP_CP_INPUT_N_NEXT,
2359 } lisp_cp_input_next_t;
2360
2361 typedef struct
2362 {
2363   gid_address_t dst_eid;
2364   ip4_address_t map_resolver_ip;
2365 } lisp_cp_input_trace_t;
2366
2367 u8 *
2368 format_lisp_cp_input_trace (u8 * s, va_list * args)
2369 {
2370   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2371   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2372   CLIB_UNUSED(lisp_cp_input_trace_t * t) = va_arg (*args, lisp_cp_input_trace_t *);
2373
2374   s = format (s, "LISP-CP-INPUT: TODO");
2375   return s;
2376 }
2377
2378 static void
2379 del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index,
2380                u32 dst_map_index)
2381 {
2382   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
2383   fwd_entry_t * fe = 0;
2384   uword * feip = 0;
2385   memset(a, 0, sizeof(*a));
2386
2387   feip = hash_get(lcm->fwd_entry_by_mapping_index, dst_map_index);
2388   if (!feip)
2389     return;
2390
2391   fe = pool_elt_at_index(lcm->fwd_entry_pool, feip[0]);
2392
2393   /* delete dp fwd entry */
2394   u32 sw_if_index;
2395   a->is_add = 0;
2396   a->dlocator = fe->dst_loc;
2397   a->slocator = fe->src_loc;
2398   a->vni = gid_address_vni(&a->deid);
2399   gid_address_copy(&a->deid, &fe->deid);
2400
2401   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
2402
2403   /* delete entry in fwd table */
2404   hash_unset(lcm->fwd_entry_by_mapping_index, dst_map_index);
2405   pool_put(lcm->fwd_entry_pool, fe);
2406 }
2407
2408 /**
2409  * Finds first remote locator with best (lowest) priority that has a local
2410  * peer locator with an underlying route to it.
2411  *
2412  */
2413 static u32
2414 get_locator_pair (lisp_cp_main_t* lcm, mapping_t * lcl_map, mapping_t * rmt_map,
2415                   ip_address_t * lcl_loc, ip_address_t * rmt_loc)
2416 {
2417   u32 i, minp = ~0, limitp = 0, li, check_index = 0, done = 0, esi;
2418   locator_set_t * rmt_ls, * lcl_ls;
2419   ip_address_t _lcl, * lcl = &_lcl;
2420   locator_t * l, * rmt = 0;
2421   uword * checked = 0;
2422
2423   rmt_ls = pool_elt_at_index(lcm->locator_set_pool, rmt_map->locator_set_index);
2424   lcl_ls = pool_elt_at_index(lcm->locator_set_pool, lcl_map->locator_set_index);
2425
2426   if (!rmt_ls || vec_len(rmt_ls->locator_indices) == 0)
2427     return 0;
2428
2429   while (!done)
2430     {
2431       /* find unvisited remote locator with best priority */
2432       for (i = 0; i < vec_len(rmt_ls->locator_indices); i++)
2433         {
2434           if (0 != hash_get(checked, i))
2435             continue;
2436
2437           li = vec_elt(rmt_ls->locator_indices, i);
2438           l = pool_elt_at_index(lcm->locator_pool, li);
2439
2440           /* we don't support non-IP locators for now */
2441           if (gid_address_type(&l->address) != GID_ADDR_IP_PREFIX)
2442             continue;
2443
2444           if (l->priority < minp && l->priority >= limitp)
2445             {
2446               minp = l->priority;
2447               rmt = l;
2448               check_index = i;
2449             }
2450         }
2451       /* check if a local locator with a route to remote locator exists */
2452       if (rmt != 0)
2453         {
2454           esi = ip_fib_get_egress_iface_for_dst (
2455               lcm, &gid_address_ip(&rmt->address));
2456           if ((u32) ~0 == esi)
2457             continue;
2458
2459           for (i = 0; i < vec_len(lcl_ls->locator_indices); i++)
2460             {
2461               li = vec_elt (lcl_ls->locator_indices, i);
2462               locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
2463
2464               /* found local locator */
2465               if (sl->sw_if_index == esi)
2466                 {
2467                   if (0 == ip_interface_get_first_ip_address (lcm,
2468                              sl->sw_if_index,
2469                              gid_address_ip_version(&rmt->address), lcl))
2470                     continue;
2471
2472                   ip_address_copy(rmt_loc, &gid_address_ip(&rmt->address));
2473                   ip_address_copy(lcl_loc, lcl);
2474                   done = 2;
2475                 }
2476             }
2477
2478           /* skip this remote locator in next searches */
2479           limitp = minp;
2480           hash_set(checked, check_index, 1);
2481         }
2482       else
2483         done = 1;
2484     }
2485   hash_free(checked);
2486   return (done == 2) ? 1 : 0;
2487 }
2488
2489 static void
2490 add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
2491 {
2492   mapping_t * src_map, * dst_map;
2493   u32 sw_if_index;
2494   uword * feip = 0, * tidp;
2495   fwd_entry_t* fe;
2496   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
2497
2498   memset (a, 0, sizeof(*a));
2499
2500   /* remove entry if it already exists */
2501   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
2502   if (feip)
2503     del_fwd_entry (lcm, src_map_index, dst_map_index);
2504
2505   src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
2506   dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
2507
2508   gid_address_copy (&a->deid, &dst_map->eid);
2509   a->vni = gid_address_vni(&a->deid);
2510
2511   tidp = hash_get(lcm->table_id_by_vni, a->vni);
2512   if (!tidp)
2513     {
2514       clib_warning("vni %d not associated to a vrf!", a->vni);
2515       return;
2516     }
2517   a->table_id = tidp[0];
2518
2519   /* insert data plane forwarding entry */
2520   a->is_add = 1;
2521
2522   /* find best locator pair that 1) verifies LISP policy 2) are connected */
2523   if (0 == get_locator_pair (lcm, src_map, dst_map, &a->slocator, &a->dlocator))
2524     {
2525       /* negative entry */
2526       a->is_negative = 1;
2527       a->action = dst_map->action;
2528     }
2529
2530   /* TODO remove */
2531   u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid));
2532   a->decap_next_index = (ipver == IP4) ?
2533           LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
2534
2535   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
2536
2537   /* add tunnel to fwd entry table XXX check return value from DP insertion */
2538   pool_get (lcm->fwd_entry_pool, fe);
2539   fe->dst_loc = a->dlocator;
2540   fe->src_loc = a->slocator;
2541   gid_address_copy (&fe->deid, &a->deid);
2542   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
2543             fe - lcm->fwd_entry_pool);
2544 }
2545
2546 /* return 0 if the two locator sets are identical 1 otherwise */
2547 static u8
2548 compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes,
2549                   locator_t * new_locators)
2550 {
2551   u32 i, old_li;
2552   locator_t * old_loc, * new_loc;
2553
2554   if (vec_len (old_ls_indexes) != vec_len(new_locators))
2555     return 1;
2556
2557   for (i = 0; i < vec_len(new_locators); i++)
2558     {
2559       old_li = vec_elt(old_ls_indexes, i);
2560       old_loc = pool_elt_at_index(lcm->locator_pool, old_li);
2561
2562       new_loc = vec_elt_at_index(new_locators, i);
2563
2564       if (locator_cmp (old_loc, new_loc))
2565         return 1;
2566     }
2567   return 0;
2568 }
2569
2570 void
2571 process_map_reply (lisp_cp_main_t * lcm, vlib_buffer_t * b)
2572 {
2573   mapping_t * old_map;
2574   locator_t * loc;
2575   u32 len = 0, i, ls_index = 0;
2576   void * h;
2577   vnet_lisp_add_del_locator_set_args_t _ls_arg, * ls_arg = &_ls_arg;
2578   vnet_lisp_add_del_mapping_args_t _m_args, * m_args = &_m_args;
2579   pending_map_request_t * pmr;
2580   locator_t probed;
2581   map_reply_hdr_t * mrep_hdr;
2582   u64 nonce;
2583   u32 dst_map_index, mi;
2584   uword * pmr_index;
2585
2586   mrep_hdr = vlib_buffer_get_current (b);
2587
2588   /* Check pending requests table and nonce */
2589   nonce = MREP_NONCE(mrep_hdr);
2590   pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce);
2591   if (!pmr_index)
2592     {
2593       clib_warning("No pending map-request entry with nonce %lu!", nonce);
2594       return;
2595     }
2596   pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]);
2597
2598   vlib_buffer_pull (b, sizeof(*mrep_hdr));
2599
2600   for (i = 0; i < MREP_REC_COUNT(mrep_hdr); i++)
2601     {
2602       memset (ls_arg, 0, sizeof(*ls_arg));
2603       memset (m_args, 0, sizeof(*m_args));
2604
2605       h = vlib_buffer_get_current (b);
2606       m_args->ttl = clib_net_to_host_u32 (MAP_REC_TTL(h));
2607       m_args->action = MAP_REC_ACTION(h);
2608       m_args->authoritative = MAP_REC_AUTH(h);
2609
2610       len = lisp_msg_parse_mapping_record (b, &m_args->deid, &ls_arg->locators,
2611                                            &probed);
2612       if (len == ~0)
2613         {
2614           clib_warning ("Failed to parse mapping record!");
2615           vec_foreach (loc, ls_arg->locators)
2616             {
2617               locator_free (loc);
2618             }
2619           vec_free(ls_arg->locators);
2620           return;
2621         }
2622
2623       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &m_args->deid);
2624       old_map = mi != ~0 ? pool_elt_at_index(lcm->mapping_pool, mi) : 0;
2625
2626       /* if mapping already exists, decide if locators (and forwarding) should
2627        * be updated and be done */
2628       if (old_map != 0 && !gid_address_cmp (&old_map->eid, &m_args->deid))
2629         {
2630           locator_set_t * old_ls;
2631
2632           /* update mapping attributes */
2633           old_map->action = m_args->action;
2634           old_map->authoritative = m_args->authoritative;
2635           old_map->ttl = m_args->ttl;
2636
2637           old_ls = pool_elt_at_index(lcm->locator_set_pool,
2638                                      old_map->locator_set_index);
2639           /* if the two locators are not equal, update them and forwarding
2640            * otherwise there's nothing to be done */
2641           if (compare_locators (lcm, old_ls->locator_indices, ls_arg->locators))
2642             {
2643               /* set locator-set index to overwrite */
2644               ls_arg->is_add = 1;
2645               ls_arg->index = old_map->locator_set_index;
2646               vnet_lisp_add_del_locator_set (ls_arg, 0);
2647               add_fwd_entry (lcm, pmr->src_mapping_index, mi);
2648             }
2649         }
2650       /* new mapping */
2651       else
2652         {
2653           /* add locator-set */
2654           ls_arg->is_add = 1;
2655           ls_arg->index = ~0;
2656           vnet_lisp_add_del_locator_set (ls_arg, &ls_index);
2657
2658           /* add mapping */
2659           m_args->is_add = 1;
2660           m_args->locator_set_index = ls_index;
2661           vnet_lisp_add_del_mapping (m_args, &dst_map_index);
2662
2663           /* add forwarding tunnel */
2664           add_fwd_entry (lcm, pmr->src_mapping_index, dst_map_index);
2665         }
2666       vec_free(ls_arg->locators);
2667     }
2668
2669   /* remove pending map request entry */
2670   hash_unset(lcm->pending_map_requests_by_nonce, nonce);
2671   pool_put(lcm->pending_map_requests_pool, pmr);
2672 }
2673
2674 void
2675 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
2676 {
2677   map_request_hdr_t * mreq_hdr;
2678   gid_address_t src, dst;
2679 //  u64 nonce;
2680   u32 i, len = 0;
2681   gid_address_t * itr_rlocs = 0, * rloc;
2682
2683   mreq_hdr = vlib_buffer_get_current (b);
2684   vlib_buffer_pull (b, sizeof(*mreq_hdr));
2685
2686 //  nonce = MREQ_NONCE(mreq_hdr);
2687
2688   if (!MREQ_SMR(mreq_hdr)) {
2689       clib_warning("Only SMR Map-Requests supported for now!");
2690       return;
2691   }
2692
2693   /* parse src eid */
2694   len = lisp_msg_parse_addr (b, &src);
2695   if (len == ~0)
2696     return;
2697
2698   /* for now we don't do anything with the itr's rlocs */
2699   len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs, MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1);
2700   if (len == ~0)
2701     return;
2702
2703   /* TODO: RLOCs are currently unused, so free them for now */
2704   vec_foreach (rloc, itr_rlocs)
2705     {
2706       gid_address_free (rloc);
2707     }
2708
2709   /* parse eid records and send SMR-invoked map-requests */
2710   for (i = 0; i < MREQ_REC_COUNT(mreq_hdr); i++)
2711     {
2712       memset(&dst, 0, sizeof(dst));
2713       len = lisp_msg_parse_eid_rec (b, &dst);
2714       if (len == ~0)
2715         {
2716           clib_warning("Can't parse map-request EID-record");
2717           return;
2718         }
2719       /* send SMR-invoked map-requests */
2720       send_encapsulated_map_request (vm, lcm, &dst, &src, /* invoked */ 1);
2721     }
2722 }
2723
2724 static uword
2725 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
2726                vlib_frame_t * from_frame)
2727 {
2728   u32 n_left_from, * from, * to_next_drop;
2729   lisp_msg_type_e type;
2730   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2731
2732   from = vlib_frame_vector_args (from_frame);
2733   n_left_from = from_frame->n_vectors;
2734
2735
2736   while (n_left_from > 0)
2737     {
2738       u32 n_left_to_next_drop;
2739
2740       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
2741                            to_next_drop, n_left_to_next_drop);
2742       while (n_left_from > 0 && n_left_to_next_drop > 0)
2743         {
2744           u32 bi0;
2745           vlib_buffer_t * b0;
2746
2747           bi0 = from[0];
2748           from += 1;
2749           n_left_from -= 1;
2750           to_next_drop[0] = bi0;
2751           to_next_drop += 1;
2752           n_left_to_next_drop -= 1;
2753
2754           b0 = vlib_get_buffer (vm, bi0);
2755
2756           type = lisp_msg_type(vlib_buffer_get_current (b0));
2757           switch (type)
2758             {
2759             case LISP_MAP_REPLY:
2760               process_map_reply (lcm, b0);
2761               break;
2762             case LISP_MAP_REQUEST:
2763               process_map_request(vm, lcm, b0);
2764               break;
2765             default:
2766               clib_warning("Unsupported LISP message type %d", type);
2767               break;
2768             }
2769
2770           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
2771
2772           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2773             {
2774
2775             }
2776         }
2777
2778       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, n_left_to_next_drop);
2779     }
2780   return from_frame->n_vectors;
2781 }
2782
2783 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
2784   .function = lisp_cp_input,
2785   .name = "lisp-cp-input",
2786   .vector_size = sizeof (u32),
2787   .format_trace = format_lisp_cp_input_trace,
2788   .type = VLIB_NODE_TYPE_INTERNAL,
2789
2790   .n_errors = LISP_CP_INPUT_N_ERROR,
2791   .error_strings = lisp_cp_input_error_strings,
2792
2793   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
2794
2795   .next_nodes = {
2796       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
2797   },
2798 };
2799
2800 clib_error_t *
2801 lisp_cp_init (vlib_main_t *vm)
2802 {
2803   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2804   clib_error_t * error = 0;
2805
2806   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
2807     return error;
2808
2809   lcm->im4 = &ip4_main;
2810   lcm->im6 = &ip6_main;
2811   lcm->vlib_main = vm;
2812   lcm->vnet_main = vnet_get_main();
2813   lcm->mreq_itr_rlocs = ~0;
2814
2815   gid_dictionary_init (&lcm->mapping_index_by_gid);
2816
2817   /* default vrf mapped to vni 0 */
2818   hash_set(lcm->table_id_by_vni, 0, 0);
2819   hash_set(lcm->vni_by_table_id, 0, 0);
2820
2821   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
2822                          lisp_cp_input_node.index, 1 /* is_ip4 */);
2823   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
2824                          lisp_cp_input_node.index, 0 /* is_ip4 */);
2825
2826   return 0;
2827 }
2828
2829 VLIB_INIT_FUNCTION(lisp_cp_init);