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