VPP-376: Refactor LISP dump API + VAT
[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 <vlibmemory/api.h>
17 #include <vnet/lisp-cp/control.h>
18 #include <vnet/lisp-cp/packets.h>
19 #include <vnet/lisp-cp/lisp_msg_serdes.h>
20 #include <vnet/lisp-gpe/lisp_gpe.h>
21
22 typedef struct
23 {
24   u8 is_resend;
25   gid_address_t seid;
26   gid_address_t deid;
27   u8 smr_invoked;
28 } map_request_args_t;
29
30 static int
31 queue_map_request (gid_address_t * seid, gid_address_t * deid,
32                    u8 smr_invoked, u8 is_resend);
33
34 ip_interface_address_t *
35 ip_interface_get_first_interface_address (ip_lookup_main_t * lm,
36                                           u32 sw_if_index, u8 loop)
37 {
38   vnet_main_t *vnm = vnet_get_main ();
39   vnet_sw_interface_t *swif = vnet_get_sw_interface (vnm, sw_if_index);
40   if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
41     sw_if_index = swif->unnumbered_sw_if_index;
42   u32 ia =
43     (vec_len ((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
44     vec_elt ((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
45     (u32) ~ 0;
46   return pool_elt_at_index ((lm)->if_address_pool, ia);
47 }
48
49 void *
50 ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
51                                 u8 version)
52 {
53   ip_interface_address_t *ia;
54
55   ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
56   if (!ia)
57     return 0;
58   return ip_interface_address_get_address (lm, ia);
59 }
60
61 int
62 ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
63                                    u8 version, ip_address_t * result)
64 {
65   ip_lookup_main_t *lm;
66   void *addr;
67
68   lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
69   addr = ip_interface_get_first_address (lm, sw_if_index, version);
70   if (!addr)
71     return 0;
72
73   ip_address_set (result, addr, version);
74   return 1;
75 }
76
77 static u32
78 ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
79                           ip_address_t * dst)
80 {
81   if (ip_addr_version (dst) == IP4)
82     return ip4_fib_lookup_with_table (lcm->im4, fib_index, &ip_addr_v4 (dst),
83                                       0);
84   else
85     return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6 (dst));
86 }
87
88 u32
89 ip_fib_get_egress_iface_for_dst_with_lm (lisp_cp_main_t * lcm,
90                                          ip_address_t * dst,
91                                          ip_lookup_main_t * lm)
92 {
93   u32 adj_index;
94   ip_adjacency_t *adj;
95
96   adj_index = ip_fib_lookup_with_table (lcm, 0, dst);
97   adj = ip_get_adjacency (lm, adj_index);
98
99   if (adj == 0)
100     return ~0;
101
102   /* we only want outgoing routes */
103   if (adj->lookup_next_index != IP_LOOKUP_NEXT_ARP
104       && adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
105     return ~0;
106
107   return adj->rewrite_header.sw_if_index;
108 }
109
110 /**
111  * Find the sw_if_index of the interface that would be used to egress towards
112  * dst.
113  */
114 u32
115 ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
116 {
117   ip_lookup_main_t *lm;
118
119   lm = ip_addr_version (dst) == IP4 ?
120     &lcm->im4->lookup_main : &lcm->im6->lookup_main;
121
122   return ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
123 }
124
125 /**
126  * Find first IP of the interface that would be used to egress towards dst.
127  * Returns 1 if the address is found 0 otherwise.
128  */
129 int
130 ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
131                                     ip_address_t * result)
132 {
133   u32 si;
134   ip_lookup_main_t *lm;
135   void *addr = 0;
136   u8 ipver;
137
138   ASSERT (result != 0);
139
140   ipver = ip_addr_version (dst);
141
142   lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
143   si = ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
144
145   if ((u32) ~ 0 == si)
146     return 0;
147
148   /* find the first ip address */
149   addr = ip_interface_get_first_address (lm, si, ipver);
150   if (0 == addr)
151     return 0;
152
153   ip_address_set (result, addr, ipver);
154   return 1;
155 }
156
157 static int
158 dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_l2, u8 is_add)
159 {
160   uword *dp_table, *intf;
161   vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
162
163   if (!is_l2)
164     {
165       dp_table = hash_get (lcm->table_id_by_vni, vni);
166
167       if (!dp_table)
168         {
169           clib_warning ("vni %d not associated to a vrf!", vni);
170           return VNET_API_ERROR_INVALID_VALUE;
171         }
172     }
173   else
174     {
175       dp_table = hash_get (lcm->bd_id_by_vni, vni);
176       if (!dp_table)
177         {
178           clib_warning ("vni %d not associated to a bridge domain!", vni);
179           return VNET_API_ERROR_INVALID_VALUE;
180         }
181     }
182
183   intf = hash_get (is_l2 ? lcm->l2_dp_intf_by_vni : lcm->dp_intf_by_vni, vni);
184
185   /* enable/disable data-plane interface */
186   if (is_add)
187     {
188       /* create interface */
189       if (!intf)
190         {
191           ai->is_add = 1;
192           ai->vni = vni;
193           ai->is_l2 = is_l2;
194           ai->dp_table = dp_table[0];
195
196           vnet_lisp_gpe_add_del_iface (ai, 0);
197
198           /* keep track of vnis for which interfaces have been created */
199           hash_set (lcm->dp_intf_by_vni, vni, 1);
200         }
201     }
202   else
203     {
204       if (intf == 0)
205         {
206           clib_warning ("interface for vni %d doesn't exist!", vni);
207           return VNET_API_ERROR_INVALID_VALUE;
208         }
209
210       ai->is_add = 0;
211       ai->vni = vni;
212       ai->dp_table = dp_table[0];
213       vnet_lisp_gpe_add_del_iface (ai, 0);
214       hash_unset (lcm->dp_intf_by_vni, vni);
215     }
216
217   return 0;
218 }
219
220 static void
221 dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
222 {
223   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
224   fwd_entry_t *fe = 0;
225   uword *feip = 0;
226   memset (a, 0, sizeof (*a));
227
228   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
229   if (!feip)
230     return;
231
232   fe = pool_elt_at_index (lcm->fwd_entry_pool, feip[0]);
233
234   /* delete dp fwd entry */
235   u32 sw_if_index;
236   a->is_add = 0;
237   a->locator_pairs = fe->locator_pairs;
238   a->vni = gid_address_vni (&fe->deid);
239   gid_address_copy (&a->rmt_eid, &fe->deid);
240
241   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
242
243   /* delete entry in fwd table */
244   hash_unset (lcm->fwd_entry_by_mapping_index, dst_map_index);
245   vec_free (fe->locator_pairs);
246   pool_put (lcm->fwd_entry_pool, fe);
247 }
248
249 /**
250  * Finds first remote locator with best (lowest) priority that has a local
251  * peer locator with an underlying route to it.
252  *
253  */
254 static u32
255 get_locator_pairs (lisp_cp_main_t * lcm, mapping_t * lcl_map,
256                    mapping_t * rmt_map, locator_pair_t ** locator_pairs)
257 {
258   u32 i, limitp = 0, li, found = 0, esi;
259   locator_set_t *rmt_ls, *lcl_ls;
260   ip_address_t _lcl_addr, *lcl_addr = &_lcl_addr;
261   locator_t *lp, *rmt = 0;
262   uword *checked = 0;
263   locator_pair_t pair;
264
265   rmt_ls =
266     pool_elt_at_index (lcm->locator_set_pool, rmt_map->locator_set_index);
267   lcl_ls =
268     pool_elt_at_index (lcm->locator_set_pool, lcl_map->locator_set_index);
269
270   if (!rmt_ls || vec_len (rmt_ls->locator_indices) == 0)
271     return 0;
272
273   while (1)
274     {
275       rmt = 0;
276
277       /* find unvisited remote locator with best priority */
278       for (i = 0; i < vec_len (rmt_ls->locator_indices); i++)
279         {
280           if (0 != hash_get (checked, i))
281             continue;
282
283           li = vec_elt (rmt_ls->locator_indices, i);
284           lp = pool_elt_at_index (lcm->locator_pool, li);
285
286           /* we don't support non-IP locators for now */
287           if (gid_address_type (&lp->address) != GID_ADDR_IP_PREFIX)
288             continue;
289
290           if ((found && lp->priority == limitp)
291               || (!found && lp->priority >= limitp))
292             {
293               rmt = lp;
294
295               /* don't search for locators with lower priority and don't
296                * check this locator again*/
297               limitp = lp->priority;
298               hash_set (checked, i, 1);
299               break;
300             }
301         }
302       /* check if a local locator with a route to remote locator exists */
303       if (rmt != 0)
304         {
305           /* find egress sw_if_index for rmt locator */
306           esi =
307             ip_fib_get_egress_iface_for_dst (lcm,
308                                              &gid_address_ip (&rmt->address));
309           if ((u32) ~ 0 == esi)
310             continue;
311
312           for (i = 0; i < vec_len (lcl_ls->locator_indices); i++)
313             {
314               li = vec_elt (lcl_ls->locator_indices, i);
315               locator_t *sl = pool_elt_at_index (lcm->locator_pool, li);
316
317               /* found local locator with the needed sw_if_index */
318               if (sl->sw_if_index == esi)
319                 {
320                   /* and it has an address */
321                   if (0 == ip_interface_get_first_ip_address (lcm,
322                                                               sl->sw_if_index,
323                                                               gid_address_ip_version
324                                                               (&rmt->address),
325                                                               lcl_addr))
326                     continue;
327
328                   memset (&pair, 0, sizeof (pair));
329                   ip_address_copy (&pair.rmt_loc,
330                                    &gid_address_ip (&rmt->address));
331                   ip_address_copy (&pair.lcl_loc, lcl_addr);
332                   pair.weight = rmt->weight;
333                   vec_add1 (locator_pairs[0], pair);
334                   found = 1;
335                 }
336             }
337         }
338       else
339         break;
340     }
341
342   hash_free (checked);
343   return found;
344 }
345
346 static void
347 dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
348 {
349   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
350   mapping_t *src_map, *dst_map;
351   u32 sw_if_index;
352   uword *feip = 0, *dpid;
353   fwd_entry_t *fe;
354   u8 type;
355
356   memset (a, 0, sizeof (*a));
357
358   /* remove entry if it already exists */
359   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
360   if (feip)
361     dp_del_fwd_entry (lcm, src_map_index, dst_map_index);
362
363   src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
364   dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
365
366   /* insert data plane forwarding entry */
367   a->is_add = 1;
368
369   gid_address_copy (&a->rmt_eid, &dst_map->eid);
370   a->vni = gid_address_vni (&a->rmt_eid);
371
372   /* get vrf or bd_index associated to vni */
373   type = gid_address_type (&dst_map->eid);
374   if (GID_ADDR_IP_PREFIX == type)
375     {
376       dpid = hash_get (lcm->table_id_by_vni, a->vni);
377       if (!dpid)
378         {
379           clib_warning ("vni %d not associated to a vrf!", a->vni);
380           return;
381         }
382       a->table_id = dpid[0];
383     }
384   else if (GID_ADDR_MAC == type)
385     {
386       dpid = hash_get (lcm->bd_id_by_vni, a->vni);
387       if (!dpid)
388         {
389           clib_warning ("vni %d not associated to a bridge domain !", a->vni);
390           return;
391         }
392       a->bd_id = dpid[0];
393     }
394
395   /* find best locator pair that 1) verifies LISP policy 2) are connected */
396   if (0 == get_locator_pairs (lcm, src_map, dst_map, &a->locator_pairs))
397     {
398       /* negative entry */
399       a->is_negative = 1;
400       a->action = dst_map->action;
401     }
402
403   /* TODO remove */
404   u8 ipver = ip_prefix_version (&gid_address_ippref (&a->rmt_eid));
405   a->decap_next_index = (ipver == IP4) ?
406     LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
407
408   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
409
410   /* add tunnel to fwd entry table XXX check return value from DP insertion */
411   pool_get (lcm->fwd_entry_pool, fe);
412   fe->locator_pairs = a->locator_pairs;
413   gid_address_copy (&fe->deid, &a->rmt_eid);
414   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
415             fe - lcm->fwd_entry_pool);
416 }
417
418 /**
419  * Add/remove mapping to/from map-cache. Overwriting not allowed.
420  */
421 int
422 vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a,
423                              u32 * map_index_result)
424 {
425   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
426   u32 mi, *map_indexp, map_index, i;
427   mapping_t *m, *old_map;
428   u32 **eid_indexes;
429
430   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid);
431   old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
432   if (a->is_add)
433     {
434       /* TODO check if overwriting and take appropriate actions */
435       if (mi != GID_LOOKUP_MISS && !gid_address_cmp (&old_map->eid, &a->eid))
436         {
437           clib_warning ("eid %U found in the eid-table", format_gid_address,
438                         &a->eid);
439           return VNET_API_ERROR_VALUE_EXIST;
440         }
441
442       pool_get (lcm->mapping_pool, m);
443       gid_address_copy (&m->eid, &a->eid);
444       m->locator_set_index = a->locator_set_index;
445       m->ttl = a->ttl;
446       m->action = a->action;
447       m->local = a->local;
448       m->is_static = a->is_static;
449
450       map_index = m - lcm->mapping_pool;
451       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, map_index,
452                               1);
453
454       if (pool_is_free_index (lcm->locator_set_pool, a->locator_set_index))
455         {
456           clib_warning ("Locator set with index %d doesn't exist",
457                         a->locator_set_index);
458           return VNET_API_ERROR_INVALID_VALUE;
459         }
460
461       /* add eid to list of eids supported by locator-set */
462       vec_validate (lcm->locator_set_to_eids, a->locator_set_index);
463       eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
464                                       a->locator_set_index);
465       vec_add1 (eid_indexes[0], map_index);
466
467       if (a->local)
468         {
469           /* mark as local */
470           vec_add1 (lcm->local_mappings_indexes, map_index);
471         }
472       map_index_result[0] = map_index;
473     }
474   else
475     {
476       if (mi == GID_LOOKUP_MISS)
477         {
478           clib_warning ("eid %U not found in the eid-table",
479                         format_gid_address, &a->eid);
480           return VNET_API_ERROR_INVALID_VALUE;
481         }
482
483       /* clear locator-set to eids binding */
484       eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
485                                       a->locator_set_index);
486       for (i = 0; i < vec_len (eid_indexes[0]); i++)
487         {
488           map_indexp = vec_elt_at_index (eid_indexes[0], i);
489           if (map_indexp[0] == mi)
490             break;
491         }
492       vec_del1 (eid_indexes[0], i);
493
494       /* remove local mark if needed */
495       m = pool_elt_at_index (lcm->mapping_pool, mi);
496       if (m->local)
497         {
498           u32 k, *lm_indexp;
499           for (k = 0; k < vec_len (lcm->local_mappings_indexes); k++)
500             {
501               lm_indexp = vec_elt_at_index (lcm->local_mappings_indexes, k);
502               if (lm_indexp[0] == mi)
503                 break;
504             }
505           vec_del1 (lcm->local_mappings_indexes, k);
506         }
507
508       /* remove mapping from dictionary */
509       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, 0, 0);
510       gid_address_free (&m->eid);
511       pool_put_index (lcm->mapping_pool, mi);
512     }
513
514   return 0;
515 }
516
517 /**
518  *  Add/update/delete mapping to/in/from map-cache.
519  */
520 int
521 vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
522                                  u32 * map_index_result)
523 {
524   uword *dp_table = 0;
525   u32 vni;
526   u8 type;
527
528   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
529
530   if (vnet_lisp_enable_disable_status () == 0)
531     {
532       clib_warning ("LISP is disabled!");
533       return VNET_API_ERROR_LISP_DISABLED;
534     }
535
536   vni = gid_address_vni (&a->eid);
537   type = gid_address_type (&a->eid);
538   if (GID_ADDR_IP_PREFIX == type)
539     dp_table = hash_get (lcm->table_id_by_vni, vni);
540   else if (GID_ADDR_MAC == type)
541     dp_table = hash_get (lcm->bd_id_by_vni, vni);
542
543   if (!dp_table)
544     {
545       clib_warning ("vni %d not associated to a %s!", vni,
546                     GID_ADDR_IP_PREFIX == type ? "vrf" : "bd");
547       return VNET_API_ERROR_INVALID_VALUE;
548     }
549
550   /* store/remove mapping from map-cache */
551   return vnet_lisp_map_cache_add_del (a, map_index_result);
552 }
553
554 static clib_error_t *
555 lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
556                                    vlib_cli_command_t * cmd)
557 {
558   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
559   unformat_input_t _line_input, *line_input = &_line_input;
560   u8 is_add = 1;
561   gid_address_t eid;
562   gid_address_t *eids = 0;
563   clib_error_t *error = 0;
564   u8 *locator_set_name = 0;
565   u32 locator_set_index = 0, map_index = 0;
566   uword *p;
567   vnet_lisp_add_del_mapping_args_t _a, *a = &_a;
568   int rv = 0;
569   u32 vni = 0;
570
571   memset (&eid, 0, sizeof (eid));
572   memset (a, 0, sizeof (*a));
573
574   /* Get a line of input. */
575   if (!unformat_user (input, unformat_line_input, line_input))
576     return 0;
577
578   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
579     {
580       if (unformat (line_input, "add"))
581         is_add = 1;
582       else if (unformat (line_input, "del"))
583         is_add = 0;
584       else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
585         ;
586       else if (unformat (line_input, "vni %d", &vni))
587         gid_address_vni (&eid) = vni;
588       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
589         {
590           p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
591           if (!p)
592             {
593               error = clib_error_return (0, "locator-set %s doesn't exist",
594                                          locator_set_name);
595               goto done;
596             }
597           locator_set_index = p[0];
598         }
599       else
600         {
601           error = unformat_parse_error (line_input);
602           goto done;
603         }
604     }
605   /* XXX treat batch configuration */
606
607   if (GID_ADDR_SRC_DST == gid_address_type (&eid))
608     {
609       error =
610         clib_error_return (0, "src/dst is not supported for local EIDs!");
611       goto done;
612     }
613
614   gid_address_copy (&a->eid, &eid);
615   a->is_add = is_add;
616   a->locator_set_index = locator_set_index;
617   a->local = 1;
618
619   rv = vnet_lisp_add_del_local_mapping (a, &map_index);
620   if (0 != rv)
621     {
622       error = clib_error_return (0, "failed to %s local mapping!",
623                                  is_add ? "add" : "delete");
624     }
625 done:
626   vec_free (eids);
627   if (locator_set_name)
628     vec_free (locator_set_name);
629   gid_address_free (&a->eid);
630   return error;
631 }
632
633 /* *INDENT-OFF* */
634 VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = {
635     .path = "lisp eid-table",
636     .short_help = "lisp eid-table add/del [vni <vni>] eid <eid> "
637       "locator-set <locator-set>",
638     .function = lisp_add_del_local_eid_command_fn,
639 };
640 /* *INDENT-ON* */
641
642 int
643 vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add)
644 {
645   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
646   uword *dp_idp, *vnip, **dp_table_by_vni, **vni_by_dp_table;
647
648   if (vnet_lisp_enable_disable_status () == 0)
649     {
650       clib_warning ("LISP is disabled!");
651       return -1;
652     }
653
654   dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni;
655   vni_by_dp_table = is_l2 ? &lcm->vni_by_bd_id : &lcm->vni_by_table_id;
656
657   if (!is_l2 && (vni == 0 || dp_id == 0))
658     {
659       clib_warning ("can't add/del default vni-vrf mapping!");
660       return -1;
661     }
662
663   dp_idp = hash_get (dp_table_by_vni[0], vni);
664   vnip = hash_get (vni_by_dp_table[0], dp_id);
665
666   if (is_add)
667     {
668       if (dp_idp || vnip)
669         {
670           clib_warning ("vni %d or vrf %d already used in vrf/vni "
671                         "mapping!", vni, dp_id);
672           return -1;
673         }
674       hash_set (dp_table_by_vni[0], vni, dp_id);
675       hash_set (vni_by_dp_table[0], dp_id, vni);
676
677       /* create dp iface */
678       dp_add_del_iface (lcm, vni, is_l2, 1);
679     }
680   else
681     {
682       if (!dp_idp || !vnip)
683         {
684           clib_warning ("vni %d or vrf %d not used in any vrf/vni! "
685                         "mapping!", vni, dp_id);
686           return -1;
687         }
688       hash_unset (dp_table_by_vni[0], vni);
689       hash_unset (vni_by_dp_table[0], dp_id);
690
691       /* remove dp iface */
692       dp_add_del_iface (lcm, vni, is_l2, 0);
693     }
694   return 0;
695
696 }
697
698 static clib_error_t *
699 lisp_eid_table_map_command_fn (vlib_main_t * vm,
700                                unformat_input_t * input,
701                                vlib_cli_command_t * cmd)
702 {
703   u8 is_add = 1, is_l2 = 0;
704   u32 vni = 0, dp_id = 0;
705   unformat_input_t _line_input, *line_input = &_line_input;
706
707   /* Get a line of input. */
708   if (!unformat_user (input, unformat_line_input, line_input))
709     return 0;
710
711   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
712     {
713       if (unformat (line_input, "del"))
714         is_add = 0;
715       else if (unformat (line_input, "vni %d", &vni))
716         ;
717       else if (unformat (line_input, "vrf %d", &dp_id))
718         ;
719       else if (unformat (line_input, "bd %d", &dp_id))
720         is_l2 = 1;
721       else
722         {
723           return unformat_parse_error (line_input);
724         }
725     }
726   vnet_lisp_eid_table_map (vni, dp_id, is_l2, is_add);
727   return 0;
728 }
729
730 /* *INDENT-OFF* */
731 VLIB_CLI_COMMAND (lisp_eid_table_map_command) = {
732     .path = "lisp eid-table map",
733     .short_help = "lisp eid-table map [del] vni <vni> vrf <vrf> | bd <bdi>",
734     .function = lisp_eid_table_map_command_fn,
735 };
736 /* *INDENT-ON* */
737
738 /* return 0 if the two locator sets are identical 1 otherwise */
739 static u8
740 compare_locators (lisp_cp_main_t * lcm, u32 * old_ls_indexes,
741                   locator_t * new_locators)
742 {
743   u32 i, old_li;
744   locator_t *old_loc, *new_loc;
745
746   if (vec_len (old_ls_indexes) != vec_len (new_locators))
747     return 1;
748
749   for (i = 0; i < vec_len (new_locators); i++)
750     {
751       old_li = vec_elt (old_ls_indexes, i);
752       old_loc = pool_elt_at_index (lcm->locator_pool, old_li);
753
754       new_loc = vec_elt_at_index (new_locators, i);
755
756       if (locator_cmp (old_loc, new_loc))
757         return 1;
758     }
759   return 0;
760 }
761
762 /**
763  * Adds/removes/updates mapping. Does not program forwarding.
764  *
765  * @param eid end-host identifier
766  * @param rlocs vector of remote locators
767  * @param action action for negative map-reply
768  * @param is_add add mapping if non-zero, delete otherwise
769  * @param res_map_index the map-index that was created/updated/removed. It is
770  *                      set to ~0 if no action is taken.
771  * @param is_static used for distinguishing between statically learned
772                     remote mappings and mappings obtained from MR
773  * @return return code
774  */
775 int
776 vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
777                            u8 authoritative, u32 ttl, u8 is_add, u8 is_static,
778                            u32 * res_map_index)
779 {
780   vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args;
781   vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
782   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
783   u32 mi, ls_index = 0, dst_map_index;
784   mapping_t *old_map;
785
786   if (vnet_lisp_enable_disable_status () == 0)
787     {
788       clib_warning ("LISP is disabled!");
789       return VNET_API_ERROR_LISP_DISABLED;
790     }
791
792   if (res_map_index)
793     res_map_index[0] = ~0;
794
795   memset (m_args, 0, sizeof (m_args[0]));
796   memset (ls_args, 0, sizeof (ls_args[0]));
797
798   ls_args->locators = rlocs;
799
800   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid);
801   old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
802
803   if (is_add)
804     {
805       /* overwrite: if mapping already exists, decide if locators should be
806        * updated and be done */
807       if (old_map && gid_address_cmp (&old_map->eid, eid) == 0)
808         {
809           if (!is_static && (old_map->is_static || old_map->local))
810             {
811               /* do not overwrite local or static remote mappings */
812               clib_warning ("mapping %U rejected due to collision with local "
813                             "or static remote mapping!", format_gid_address,
814                             &eid);
815               return 0;
816             }
817
818           locator_set_t *old_ls;
819
820           /* update mapping attributes */
821           old_map->action = action;
822           old_map->authoritative = authoritative;
823           old_map->ttl = ttl;
824
825           old_ls = pool_elt_at_index (lcm->locator_set_pool,
826                                       old_map->locator_set_index);
827           if (compare_locators (lcm, old_ls->locator_indices,
828                                 ls_args->locators))
829             {
830               /* set locator-set index to overwrite */
831               ls_args->is_add = 1;
832               ls_args->index = old_map->locator_set_index;
833               vnet_lisp_add_del_locator_set (ls_args, 0);
834               if (res_map_index)
835                 res_map_index[0] = mi;
836             }
837         }
838       /* new mapping */
839       else
840         {
841           ls_args->is_add = 1;
842           ls_args->index = ~0;
843
844           vnet_lisp_add_del_locator_set (ls_args, &ls_index);
845
846           /* add mapping */
847           gid_address_copy (&m_args->eid, eid);
848           m_args->is_add = 1;
849           m_args->action = action;
850           m_args->locator_set_index = ls_index;
851           m_args->is_static = is_static;
852           vnet_lisp_map_cache_add_del (m_args, &dst_map_index);
853
854           if (res_map_index)
855             res_map_index[0] = dst_map_index;
856         }
857     }
858   else
859     {
860       if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0)
861         {
862           clib_warning ("cannot delete mapping for eid %U",
863                         format_gid_address, eid);
864           return -1;
865         }
866
867       m_args->is_add = 0;
868       gid_address_copy (&m_args->eid, eid);
869       m_args->locator_set_index = old_map->locator_set_index;
870
871       /* delete mapping associated from map-cache */
872       vnet_lisp_map_cache_add_del (m_args, 0);
873
874       ls_args->is_add = 0;
875       ls_args->index = old_map->locator_set_index;
876       /* delete locator set */
877       vnet_lisp_add_del_locator_set (ls_args, 0);
878
879       /* return old mapping index */
880       if (res_map_index)
881         res_map_index[0] = mi;
882     }
883
884   /* success */
885   return 0;
886 }
887
888 int
889 vnet_lisp_clear_all_remote_adjacencies (void)
890 {
891   int rv = 0;
892   u32 mi, *map_indices = 0, *map_indexp;
893   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
894   vnet_lisp_add_del_mapping_args_t _dm_args, *dm_args = &_dm_args;
895   vnet_lisp_add_del_locator_set_args_t _ls, *ls = &_ls;
896
897   /* *INDENT-OFF* */
898   pool_foreach_index (mi, lcm->mapping_pool,
899   ({
900     vec_add1 (map_indices, mi);
901   }));
902   /* *INDENT-ON* */
903
904   vec_foreach (map_indexp, map_indices)
905   {
906     mapping_t *map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
907     if (!map->local)
908       {
909         dp_del_fwd_entry (lcm, 0, map_indexp[0]);
910
911         dm_args->is_add = 0;
912         gid_address_copy (&dm_args->eid, &map->eid);
913         dm_args->locator_set_index = map->locator_set_index;
914
915         /* delete mapping associated to fwd entry */
916         vnet_lisp_map_cache_add_del (dm_args, 0);
917
918         ls->is_add = 0;
919         ls->local = 0;
920         ls->index = map->locator_set_index;
921         /* delete locator set */
922         rv = vnet_lisp_add_del_locator_set (ls, 0);
923         if (rv != 0)
924           goto cleanup;
925       }
926   }
927
928 cleanup:
929   if (map_indices)
930     vec_free (map_indices);
931   return rv;
932 }
933
934 /**
935  * Adds adjacency or removes forwarding entry associated to remote mapping.
936  * Note that adjacencies are not stored, they only result in forwarding entries
937  * being created.
938  */
939 int
940 lisp_add_del_adjacency (lisp_cp_main_t * lcm, gid_address_t * local_eid,
941                         gid_address_t * remote_eid, u8 is_add)
942 {
943   u32 local_mi, remote_mi = ~0;
944
945   if (vnet_lisp_enable_disable_status () == 0)
946     {
947       clib_warning ("LISP is disabled!");
948       return VNET_API_ERROR_LISP_DISABLED;
949     }
950
951   remote_mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, remote_eid);
952   if (GID_LOOKUP_MISS == remote_mi)
953     {
954       clib_warning ("Remote eid %U not found. Cannot add adjacency!",
955                     format_gid_address, remote_eid);
956
957       return -1;
958     }
959
960   if (is_add)
961     {
962       /* TODO 1) check if src/dst 2) once we have src/dst working, use it in
963        * delete*/
964
965       /* check if source eid has an associated mapping. If pitr mode is on,
966        * just use the pitr's mapping */
967       local_mi = lcm->lisp_pitr ? lcm->pitr_map_index :
968         gid_dictionary_lookup (&lcm->mapping_index_by_gid, local_eid);
969
970
971       if (GID_LOOKUP_MISS == local_mi)
972         {
973           clib_warning ("Local eid %U not found. Cannot add adjacency!",
974                         format_gid_address, local_eid);
975
976           return -1;
977         }
978
979       /* update forwarding */
980       dp_add_fwd_entry (lcm, local_mi, remote_mi);
981     }
982   else
983     dp_del_fwd_entry (lcm, 0, remote_mi);
984
985   return 0;
986 }
987
988 int
989 vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a)
990 {
991   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
992   return lisp_add_del_adjacency (lcm, &a->seid, &a->deid, a->is_add);
993 }
994
995 /**
996  * Handler for add/del remote mapping CLI.
997  *
998  * @param vm vlib context
999  * @param input input from user
1000  * @param cmd cmd
1001  * @return pointer to clib error structure
1002  */
1003 static clib_error_t *
1004 lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
1005                                         unformat_input_t * input,
1006                                         vlib_cli_command_t * cmd)
1007 {
1008   clib_error_t *error = 0;
1009   unformat_input_t _line_input, *line_input = &_line_input;
1010   u8 is_add = 1, del_all = 0;
1011   locator_t rloc, *rlocs = 0, *curr_rloc = 0;
1012   gid_address_t eid;
1013   u8 eid_set = 0;
1014   u32 vni, action = ~0, p, w;
1015   int rv;
1016
1017   /* Get a line of input. */
1018   if (!unformat_user (input, unformat_line_input, line_input))
1019     return 0;
1020
1021   memset (&eid, 0, sizeof (eid));
1022   memset (&rloc, 0, sizeof (rloc));
1023
1024   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1025     {
1026       if (unformat (line_input, "del-all"))
1027         del_all = 1;
1028       else if (unformat (line_input, "del"))
1029         is_add = 0;
1030       else if (unformat (line_input, "add"))
1031         ;
1032       else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
1033         eid_set = 1;
1034       else if (unformat (line_input, "vni %u", &vni))
1035         {
1036           gid_address_vni (&eid) = vni;
1037         }
1038       else if (unformat (line_input, "p %d w %d", &p, &w))
1039         {
1040           if (!curr_rloc)
1041             {
1042               clib_warning
1043                 ("No RLOC configured for setting priority/weight!");
1044               goto done;
1045             }
1046           curr_rloc->priority = p;
1047           curr_rloc->weight = w;
1048         }
1049       else if (unformat (line_input, "rloc %U", unformat_ip_address,
1050                          &gid_address_ip (&rloc.address)))
1051         {
1052           /* since rloc is stored in ip prefix we need to set prefix length */
1053           ip_prefix_t *pref = &gid_address_ippref (&rloc.address);
1054
1055           u8 version = gid_address_ip_version (&rloc.address);
1056           ip_prefix_len (pref) = ip_address_max_len (version);
1057
1058           vec_add1 (rlocs, rloc);
1059           curr_rloc = &rlocs[vec_len (rlocs) - 1];
1060         }
1061       else if (unformat (line_input, "action %U",
1062                          unformat_negative_mapping_action, &action))
1063         ;
1064       else
1065         {
1066           clib_warning ("parse error");
1067           goto done;
1068         }
1069     }
1070
1071   if (!eid_set)
1072     {
1073       clib_warning ("missing eid!");
1074       goto done;
1075     }
1076
1077   if (!del_all)
1078     {
1079       if (is_add && (~0 == action) && 0 == vec_len (rlocs))
1080         {
1081           clib_warning ("no action set for negative map-reply!");
1082           goto done;
1083         }
1084     }
1085   else
1086     {
1087       vnet_lisp_clear_all_remote_adjacencies ();
1088       goto done;
1089     }
1090
1091   /* TODO build src/dst with seid */
1092
1093   /* if it's a delete, clean forwarding */
1094   if (!is_add)
1095     {
1096       lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1097       rv = lisp_add_del_adjacency (lcm, 0, &eid, /* is_add */ 0);
1098       if (rv)
1099         {
1100           goto done;
1101         }
1102     }
1103
1104   /* add as static remote mapping, i.e., not authoritative and infinite
1105    * ttl */
1106   rv = vnet_lisp_add_del_mapping (&eid, rlocs, action, 0, ~0, is_add,
1107                                   1 /* is_static */ , 0);
1108
1109   if (rv)
1110     clib_warning ("failed to %s remote mapping!", is_add ? "add" : "delete");
1111
1112 done:
1113   vec_free (rlocs);
1114   unformat_free (line_input);
1115   return error;
1116 }
1117
1118 VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) =
1119 {
1120 .path = "lisp remote-mapping",.short_help =
1121     "lisp remote-mapping add|del [del-all] vni <vni> "
1122     "eid <est-eid> [action <no-action|natively-forward|"
1123     "send-map-request|drop>] rloc <dst-locator> p <prio> w <weight> "
1124     "[rloc <dst-locator> ... ]",.function =
1125     lisp_add_del_remote_mapping_command_fn,};
1126
1127 /**
1128  * Handler for add/del adjacency CLI.
1129  */
1130 static clib_error_t *
1131 lisp_add_del_adjacency_command_fn (vlib_main_t * vm, unformat_input_t * input,
1132                                    vlib_cli_command_t * cmd)
1133 {
1134   clib_error_t *error = 0;
1135   unformat_input_t _line_input, *line_input = &_line_input;
1136   vnet_lisp_add_del_adjacency_args_t _a, *a = &_a;
1137   u8 is_add = 1;
1138   locator_t rloc, *rlocs = 0;
1139   ip_prefix_t *deid_ippref, *seid_ippref;
1140   gid_address_t seid, deid;
1141   u8 *dmac = gid_address_mac (&deid);
1142   u8 *smac = gid_address_mac (&seid);
1143   u8 deid_set = 0, seid_set = 0;
1144   u8 *s = 0;
1145   u32 vni, action = ~0;
1146   int rv;
1147
1148   /* Get a line of input. */
1149   if (!unformat_user (input, unformat_line_input, line_input))
1150     return 0;
1151
1152   memset (&deid, 0, sizeof (deid));
1153   memset (&seid, 0, sizeof (seid));
1154   memset (&rloc, 0, sizeof (rloc));
1155
1156   seid_ippref = &gid_address_ippref (&seid);
1157   deid_ippref = &gid_address_ippref (&deid);
1158
1159   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1160     {
1161       if (unformat (line_input, "del"))
1162         is_add = 0;
1163       else if (unformat (line_input, "add"))
1164         ;
1165       else if (unformat (line_input, "deid %U",
1166                          unformat_ip_prefix, deid_ippref))
1167         {
1168           gid_address_type (&deid) = GID_ADDR_IP_PREFIX;
1169           deid_set = 1;
1170         }
1171       else if (unformat (line_input, "deid %U", unformat_mac_address, dmac))
1172         {
1173           gid_address_type (&deid) = GID_ADDR_MAC;
1174           deid_set = 1;
1175         }
1176       else if (unformat (line_input, "vni %u", &vni))
1177         {
1178           gid_address_vni (&seid) = vni;
1179           gid_address_vni (&deid) = vni;
1180         }
1181       else if (unformat (line_input, "seid %U",
1182                          unformat_ip_prefix, seid_ippref))
1183         {
1184           gid_address_type (&seid) = GID_ADDR_IP_PREFIX;
1185           seid_set = 1;
1186         }
1187       else if (unformat (line_input, "seid %U", unformat_mac_address, smac))
1188         {
1189           gid_address_type (&seid) = GID_ADDR_MAC;
1190           seid_set = 1;
1191         }
1192       else
1193         {
1194           clib_warning ("parse error");
1195           goto done;
1196         }
1197     }
1198
1199   if (!deid_set)
1200     {
1201       clib_warning ("missing deid!");
1202       goto done;
1203     }
1204
1205   if (GID_ADDR_IP_PREFIX == gid_address_type (&deid))
1206     {
1207       /* if seid not set, make sure the ip version is the same as that
1208        * of the deid. This ensures the seid to be configured will be
1209        * either 0/0 or ::/0 */
1210       if (!seid_set)
1211         ip_prefix_version (seid_ippref) = ip_prefix_version (deid_ippref);
1212
1213       if (is_add &&
1214           (ip_prefix_version (deid_ippref)
1215            != ip_prefix_version (seid_ippref)))
1216         {
1217           clib_warning ("source and destination EIDs are not"
1218                         " in the same IP family!");
1219           goto done;
1220         }
1221     }
1222
1223   if (is_add && (~0 == action) && 0 == vec_len (rlocs))
1224     {
1225       clib_warning ("no action set for negative map-reply!");
1226       goto done;
1227     }
1228
1229   memset (a, 0, sizeof (a[0]));
1230   gid_address_copy (&a->seid, &deid);
1231   gid_address_copy (&a->deid, &seid);
1232
1233   a->is_add = is_add;
1234   rv = vnet_lisp_add_del_adjacency (a);
1235
1236   if (rv)
1237     clib_warning ("failed to %s adjacency!", is_add ? "add" : "delete");
1238
1239 done:
1240   unformat_free (line_input);
1241   if (s)
1242     vec_free (s);
1243   return error;
1244 }
1245
1246 /* *INDENT-OFF* */
1247 VLIB_CLI_COMMAND (lisp_add_del_adjacency_command) = {
1248     .path = "lisp adjacency",
1249     .short_help = "lisp adjacency add|del vni <vni>"
1250      "deid <dest-eid> seid <src-eid> [action <no-action|natively-forward|"
1251      "send-map-request|drop>] rloc <dst-locator> [rloc <dst-locator> ... ]",
1252     .function = lisp_add_del_adjacency_command_fn,
1253 };
1254 /* *INDENT-ON* */
1255
1256 static clib_error_t *
1257 lisp_show_map_resolvers_command_fn (vlib_main_t * vm,
1258                                     unformat_input_t * input,
1259                                     vlib_cli_command_t * cmd)
1260 {
1261   map_resolver_t *mr;
1262   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1263
1264   vec_foreach (mr, lcm->map_resolvers)
1265   {
1266     vlib_cli_output (vm, "%U", format_ip_address, &mr->address);
1267   }
1268   return 0;
1269 }
1270
1271 /* *INDENT-OFF* */
1272 VLIB_CLI_COMMAND (lisp_show_map_resolvers_command) = {
1273     .path = "show lisp map-resolvers",
1274     .short_help = "show lisp map-resolvers",
1275     .function = lisp_show_map_resolvers_command_fn,
1276 };
1277 /* *INDENT-ON* */
1278
1279 int
1280 vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
1281 {
1282   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1283   u32 locator_set_index = ~0;
1284   mapping_t *m;
1285   uword *p;
1286
1287   if (vnet_lisp_enable_disable_status () == 0)
1288     {
1289       clib_warning ("LISP is disabled!");
1290       return VNET_API_ERROR_LISP_DISABLED;
1291     }
1292
1293   p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1294   if (!p)
1295     {
1296       clib_warning ("locator-set %v doesn't exist", locator_set_name);
1297       return -1;
1298     }
1299   locator_set_index = p[0];
1300
1301   if (is_add)
1302     {
1303       pool_get (lcm->mapping_pool, m);
1304       m->locator_set_index = locator_set_index;
1305       m->local = 1;
1306       lcm->pitr_map_index = m - lcm->mapping_pool;
1307
1308       /* enable pitr mode */
1309       lcm->lisp_pitr = 1;
1310     }
1311   else
1312     {
1313       /* remove pitr mapping */
1314       pool_put_index (lcm->mapping_pool, lcm->pitr_map_index);
1315
1316       /* disable pitr mode */
1317       lcm->lisp_pitr = 0;
1318     }
1319   return 0;
1320 }
1321
1322 static clib_error_t *
1323 lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm,
1324                                       unformat_input_t * input,
1325                                       vlib_cli_command_t * cmd)
1326 {
1327   u8 locator_name_set = 0;
1328   u8 *locator_set_name = 0;
1329   u8 is_add = 1;
1330   unformat_input_t _line_input, *line_input = &_line_input;
1331   clib_error_t *error = 0;
1332   int rv = 0;
1333
1334   /* Get a line of input. */
1335   if (!unformat_user (input, unformat_line_input, line_input))
1336     return 0;
1337
1338   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1339     {
1340       if (unformat (line_input, "ls %_%v%_", &locator_set_name))
1341         locator_name_set = 1;
1342       else if (unformat (line_input, "disable"))
1343         is_add = 0;
1344       else
1345         return clib_error_return (0, "parse error");
1346     }
1347
1348   if (!locator_name_set)
1349     {
1350       clib_warning ("No locator set specified!");
1351       goto done;
1352     }
1353   rv = vnet_lisp_pitr_set_locator_set (locator_set_name, is_add);
1354   if (0 != rv)
1355     {
1356       error = clib_error_return (0, "failed to %s pitr!",
1357                                  is_add ? "add" : "delete");
1358     }
1359
1360 done:
1361   if (locator_set_name)
1362     vec_free (locator_set_name);
1363   return error;
1364 }
1365
1366 /* *INDENT-OFF* */
1367 VLIB_CLI_COMMAND (lisp_pitr_set_locator_set_command) = {
1368     .path = "lisp pitr",
1369     .short_help = "lisp pitr [disable] ls <locator-set-name>",
1370     .function = lisp_pitr_set_locator_set_command_fn,
1371 };
1372 /* *INDENT-ON* */
1373
1374 static clib_error_t *
1375 lisp_show_pitr_command_fn (vlib_main_t * vm,
1376                            unformat_input_t * input, vlib_cli_command_t * cmd)
1377 {
1378   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1379   mapping_t *m;
1380   locator_set_t *ls;
1381   u8 *tmp_str = 0;
1382
1383   vlib_cli_output (vm, "%=20s%=16s",
1384                    "pitr", lcm->lisp_pitr ? "locator-set" : "");
1385
1386   if (!lcm->lisp_pitr)
1387     {
1388       vlib_cli_output (vm, "%=20s", "disable");
1389       return 0;
1390     }
1391
1392   if (~0 == lcm->pitr_map_index)
1393     {
1394       tmp_str = format (0, "N/A");
1395     }
1396   else
1397     {
1398       m = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
1399       if (~0 != m->locator_set_index)
1400         {
1401           ls =
1402             pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
1403           tmp_str = format (0, "%s", ls->name);
1404         }
1405       else
1406         {
1407           tmp_str = format (0, "N/A");
1408         }
1409     }
1410   vec_add1 (tmp_str, 0);
1411
1412   vlib_cli_output (vm, "%=20s%=16s", "enable", tmp_str);
1413
1414   vec_free (tmp_str);
1415
1416   return 0;
1417 }
1418
1419 /* *INDENT-OFF* */
1420 VLIB_CLI_COMMAND (lisp_show_pitr_command) = {
1421     .path = "show lisp pitr",
1422     .short_help = "Show pitr",
1423     .function = lisp_show_pitr_command_fn,
1424 };
1425 /* *INDENT-ON* */
1426
1427 static u8 *
1428 format_eid_entry (u8 * s, va_list * args)
1429 {
1430   vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
1431   lisp_cp_main_t *lcm = va_arg (*args, lisp_cp_main_t *);
1432   mapping_t *mapit = va_arg (*args, mapping_t *);
1433   locator_set_t *ls = va_arg (*args, locator_set_t *);
1434   gid_address_t *gid = &mapit->eid;
1435   u32 ttl = mapit->ttl;
1436   u8 aut = mapit->authoritative;
1437   u32 *loc_index;
1438   u8 first_line = 1;
1439   u8 *loc;
1440
1441   u8 *type = ls->local ? format (0, "local(%s)", ls->name)
1442     : format (0, "remote");
1443
1444   if (vec_len (ls->locator_indices) == 0)
1445     {
1446       s = format (s, "%-35U%-30s%-20u%-u", format_gid_address, gid,
1447                   type, ttl, aut);
1448     }
1449   else
1450     {
1451       vec_foreach (loc_index, ls->locator_indices)
1452       {
1453         locator_t *l = pool_elt_at_index (lcm->locator_pool, loc_index[0]);
1454         if (l->local)
1455           loc = format (0, "%U", format_vnet_sw_if_index_name, vnm,
1456                         l->sw_if_index);
1457         else
1458           loc = format (0, "%U", format_ip_address,
1459                         &gid_address_ip (&l->address));
1460
1461         if (first_line)
1462           {
1463             s = format (s, "%-35U%-20s%-30v%-20u%-u\n", format_gid_address,
1464                         gid, type, loc, ttl, aut);
1465             first_line = 0;
1466           }
1467         else
1468           s = format (s, "%55s%v\n", "", loc);
1469       }
1470     }
1471   return s;
1472 }
1473
1474 static clib_error_t *
1475 lisp_show_eid_table_command_fn (vlib_main_t * vm,
1476                                 unformat_input_t * input,
1477                                 vlib_cli_command_t * cmd)
1478 {
1479   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1480   mapping_t *mapit;
1481   unformat_input_t _line_input, *line_input = &_line_input;
1482   u32 mi;
1483   gid_address_t eid;
1484   u8 print_all = 1;
1485   u8 filter = 0;
1486
1487   memset (&eid, 0, sizeof (eid));
1488
1489   /* Get a line of input. */
1490   if (!unformat_user (input, unformat_line_input, line_input))
1491     return 0;
1492
1493   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1494     {
1495       if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
1496         print_all = 0;
1497       else if (unformat (line_input, "local"))
1498         filter = 1;
1499       else if (unformat (line_input, "remote"))
1500         filter = 2;
1501       else
1502         return clib_error_return (0, "parse error: '%U'",
1503                                   format_unformat_error, line_input);
1504     }
1505
1506   vlib_cli_output (vm, "%-35s%-20s%-30s%-20s%-s",
1507                    "EID", "type", "locators", "ttl", "autoritative");
1508
1509   if (print_all)
1510     {
1511       /* *INDENT-OFF* */
1512       pool_foreach (mapit, lcm->mapping_pool,
1513       ({
1514         locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
1515                                                 mapit->locator_set_index);
1516         if (filter && !((1 == filter && ls->local) ||
1517           (2 == filter && !ls->local)))
1518           {
1519             continue;
1520           }
1521         vlib_cli_output (vm, "%U", format_eid_entry, lcm->vnet_main,
1522                          lcm, mapit, ls);
1523       }));
1524       /* *INDENT-ON* */
1525     }
1526   else
1527     {
1528       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &eid);
1529       if ((u32) ~ 0 == mi)
1530         return 0;
1531
1532       mapit = pool_elt_at_index (lcm->mapping_pool, mi);
1533       locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool,
1534                                              mapit->locator_set_index);
1535
1536       if (filter && !((1 == filter && ls->local) ||
1537                       (2 == filter && !ls->local)))
1538         {
1539           return 0;
1540         }
1541
1542       vlib_cli_output (vm, "%U,", format_eid_entry, lcm->vnet_main,
1543                        lcm, mapit, ls);
1544     }
1545
1546   return 0;
1547 }
1548
1549 /* *INDENT-OFF* */
1550 VLIB_CLI_COMMAND (lisp_cp_show_eid_table_command) = {
1551     .path = "show lisp eid-table",
1552     .short_help = "Shows EID table",
1553     .function = lisp_show_eid_table_command_fn,
1554 };
1555 /* *INDENT-ON* */
1556
1557 /* cleans locator to locator-set data and removes locators not part of
1558  * any locator-set */
1559 static void
1560 clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
1561 {
1562   u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
1563   locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool, lsi);
1564   for (i = 0; i < vec_len (ls->locator_indices); i++)
1565     {
1566       loc_indexp = vec_elt_at_index (ls->locator_indices, i);
1567       ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
1568                                      loc_indexp[0]);
1569       for (j = 0; j < vec_len (ls_indexes[0]); j++)
1570         {
1571           ls_indexp = vec_elt_at_index (ls_indexes[0], j);
1572           if (ls_indexp[0] == lsi)
1573             break;
1574         }
1575
1576       /* delete index for removed locator-set */
1577       vec_del1 (ls_indexes[0], j);
1578
1579       /* delete locator if it's part of no locator-set */
1580       if (vec_len (ls_indexes[0]) == 0)
1581         {
1582           pool_put_index (lcm->locator_pool, loc_indexp[0]);
1583           vec_add1 (to_be_deleted, i);
1584         }
1585     }
1586
1587   if (to_be_deleted)
1588     {
1589       for (i = 0; i < vec_len (to_be_deleted); i++)
1590         {
1591           loc_indexp = vec_elt_at_index (to_be_deleted, i);
1592           vec_del1 (ls->locator_indices, loc_indexp[0]);
1593         }
1594       vec_free (to_be_deleted);
1595     }
1596 }
1597
1598 static inline uword *
1599 get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p)
1600 {
1601   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1602
1603   ASSERT (a != NULL);
1604   ASSERT (p != NULL);
1605
1606   /* find locator-set */
1607   if (a->local)
1608     {
1609       p = hash_get_mem (lcm->locator_set_index_by_name, a->name);
1610     }
1611   else
1612     {
1613       *p = a->index;
1614     }
1615
1616   return p;
1617 }
1618
1619 static inline int
1620 is_locator_in_locator_set (lisp_cp_main_t * lcm, locator_set_t * ls,
1621                            locator_t * loc)
1622 {
1623   locator_t *itloc;
1624   u32 *locit;
1625
1626   ASSERT (ls != NULL);
1627   ASSERT (loc != NULL);
1628
1629   vec_foreach (locit, ls->locator_indices)
1630   {
1631     itloc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1632     if ((ls->local && itloc->sw_if_index == loc->sw_if_index) ||
1633         (!ls->local && !gid_address_cmp (&itloc->address, &loc->address)))
1634       {
1635         clib_warning ("Duplicate locator");
1636         return VNET_API_ERROR_VALUE_EXIST;
1637       }
1638   }
1639
1640   return 0;
1641 }
1642
1643 static inline void
1644 remove_locator_from_locator_set (locator_set_t * ls, u32 * locit,
1645                                  u32 ls_index, u32 loc_id)
1646 {
1647   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1648   u32 **ls_indexes = NULL;
1649
1650   ASSERT (ls != NULL);
1651   ASSERT (locit != NULL);
1652
1653   ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets, locit[0]);
1654   pool_put_index (lcm->locator_pool, locit[0]);
1655   vec_del1 (ls->locator_indices, loc_id);
1656   vec_del1 (ls_indexes[0], ls_index);
1657 }
1658
1659 int
1660 vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
1661                            locator_set_t * ls, u32 * ls_result)
1662 {
1663   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1664   locator_t *loc = NULL, *itloc = NULL;
1665   uword _p = (u32) ~ 0, *p = &_p;
1666   u32 loc_index = ~0, ls_index = ~0, *locit = NULL, **ls_indexes = NULL;
1667   u32 loc_id = ~0;
1668   int ret = 0;
1669
1670   ASSERT (a != NULL);
1671
1672   if (vnet_lisp_enable_disable_status () == 0)
1673     {
1674       clib_warning ("LISP is disabled!");
1675       return VNET_API_ERROR_LISP_DISABLED;
1676     }
1677
1678   p = get_locator_set_index (a, p);
1679   if (!p)
1680     {
1681       clib_warning ("locator-set %v doesn't exist", a->name);
1682       return VNET_API_ERROR_INVALID_ARGUMENT;
1683     }
1684
1685   if (ls == 0)
1686     {
1687       ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
1688       if (!ls)
1689         {
1690           clib_warning ("locator-set %d to be overwritten doesn't exist!",
1691                         p[0]);
1692           return VNET_API_ERROR_INVALID_ARGUMENT;
1693         }
1694     }
1695
1696   if (a->is_add)
1697     {
1698       if (ls_result)
1699         ls_result[0] = p[0];
1700
1701       /* allocate locators */
1702       vec_foreach (itloc, a->locators)
1703       {
1704         ret = is_locator_in_locator_set (lcm, ls, itloc);
1705         if (0 != ret)
1706           {
1707             return ret;
1708           }
1709
1710         pool_get (lcm->locator_pool, loc);
1711         loc[0] = itloc[0];
1712         loc_index = loc - lcm->locator_pool;
1713
1714         vec_add1 (ls->locator_indices, loc_index);
1715
1716         vec_validate (lcm->locator_to_locator_sets, loc_index);
1717         ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
1718                                        loc_index);
1719         vec_add1 (ls_indexes[0], p[0]);
1720       }
1721     }
1722   else
1723     {
1724       ls_index = p[0];
1725
1726       itloc = a->locators;
1727       loc_id = 0;
1728       vec_foreach (locit, ls->locator_indices)
1729       {
1730         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1731
1732         if (loc->local && loc->sw_if_index == itloc->sw_if_index)
1733           {
1734             remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
1735           }
1736         if (0 == loc->local &&
1737             !gid_address_cmp (&loc->address, &itloc->address))
1738           {
1739             remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
1740           }
1741
1742         loc_id++;
1743       }
1744     }
1745
1746   return 0;
1747 }
1748
1749 int
1750 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
1751                                u32 * ls_result)
1752 {
1753   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1754   locator_set_t *ls;
1755   uword _p = (u32) ~ 0, *p = &_p;
1756   u32 ls_index;
1757   u32 **eid_indexes;
1758   int ret = 0;
1759
1760   if (vnet_lisp_enable_disable_status () == 0)
1761     {
1762       clib_warning ("LISP is disabled!");
1763       return VNET_API_ERROR_LISP_DISABLED;
1764     }
1765
1766   if (a->is_add)
1767     {
1768       p = get_locator_set_index (a, p);
1769
1770       /* overwrite */
1771       if (p && p[0] != (u32) ~ 0)
1772         {
1773           ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
1774           if (!ls)
1775             {
1776               clib_warning ("locator-set %d to be overwritten doesn't exist!",
1777                             p[0]);
1778               return -1;
1779             }
1780
1781           /* clean locator to locator-set vectors and remove locators if
1782            * they're not part of another locator-set */
1783           clean_locator_to_locator_set (lcm, p[0]);
1784
1785           /* remove locator indices from locator set */
1786           vec_free (ls->locator_indices);
1787
1788           ls_index = p[0];
1789
1790           if (ls_result)
1791             ls_result[0] = p[0];
1792         }
1793       /* new locator-set */
1794       else
1795         {
1796           pool_get (lcm->locator_set_pool, ls);
1797           memset (ls, 0, sizeof (*ls));
1798           ls_index = ls - lcm->locator_set_pool;
1799
1800           if (a->local)
1801             {
1802               ls->name = vec_dup (a->name);
1803
1804               if (!lcm->locator_set_index_by_name)
1805                 lcm->locator_set_index_by_name = hash_create_vec (
1806                                                                    /* size */
1807                                                                    0,
1808                                                                    sizeof
1809                                                                    (ls->name
1810                                                                     [0]),
1811                                                                    sizeof
1812                                                                    (uword));
1813               hash_set_mem (lcm->locator_set_index_by_name, ls->name,
1814                             ls_index);
1815
1816               /* mark as local locator-set */
1817               vec_add1 (lcm->local_locator_set_indexes, ls_index);
1818             }
1819           ls->local = a->local;
1820           if (ls_result)
1821             ls_result[0] = ls_index;
1822         }
1823
1824       ret = vnet_lisp_add_del_locator (a, ls, NULL);
1825       if (0 != ret)
1826         {
1827           return ret;
1828         }
1829     }
1830   else
1831     {
1832       p = get_locator_set_index (a, p);
1833       if (!p)
1834         {
1835           clib_warning ("locator-set %v doesn't exists", a->name);
1836           return -1;
1837         }
1838
1839       ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
1840       if (!ls)
1841         {
1842           clib_warning ("locator-set with index %d doesn't exists", p[0]);
1843           return -1;
1844         }
1845
1846       if (lcm->mreq_itr_rlocs == p[0])
1847         {
1848           clib_warning ("Can't delete the locator-set used to constrain "
1849                         "the itr-rlocs in map-requests!");
1850           return -1;
1851         }
1852
1853       if (vec_len (lcm->locator_set_to_eids) != 0)
1854         {
1855           eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids, p[0]);
1856           if (vec_len (eid_indexes[0]) != 0)
1857             {
1858               clib_warning
1859                 ("Can't delete a locator that supports a mapping!");
1860               return -1;
1861             }
1862         }
1863
1864       /* clean locator to locator-sets data */
1865       clean_locator_to_locator_set (lcm, p[0]);
1866
1867       if (ls->local)
1868         {
1869           u32 it, lsi;
1870
1871           vec_foreach_index (it, lcm->local_locator_set_indexes)
1872           {
1873             lsi = vec_elt (lcm->local_locator_set_indexes, it);
1874             if (lsi == p[0])
1875               {
1876                 vec_del1 (lcm->local_locator_set_indexes, it);
1877                 break;
1878               }
1879           }
1880           hash_unset_mem (lcm->locator_set_index_by_name, ls->name);
1881         }
1882       vec_free (ls->name);
1883       vec_free (ls->locator_indices);
1884       pool_put (lcm->locator_set_pool, ls);
1885     }
1886   return 0;
1887 }
1888
1889 clib_error_t *
1890 vnet_lisp_enable_disable (u8 is_enable)
1891 {
1892   u32 vni, dp_table;
1893   clib_error_t *error = 0;
1894   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1895   vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a;
1896
1897   a->is_en = is_enable;
1898   error = vnet_lisp_gpe_enable_disable (a);
1899   if (error)
1900     {
1901       return clib_error_return (0, "failed to %s data-plane!",
1902                                 a->is_en ? "enable" : "disable");
1903     }
1904
1905   if (is_enable)
1906     {
1907       /* enable all l2 and l3 ifaces */
1908
1909       /* *INDENT-OFF* */
1910       hash_foreach(vni, dp_table, lcm->table_id_by_vni, ({
1911         dp_add_del_iface(lcm, vni, 0, 1);
1912       }));
1913       hash_foreach(vni, dp_table, lcm->bd_id_by_vni, ({
1914         dp_add_del_iface(lcm, vni, /* is_l2 */ 1, 1);
1915       }));
1916       /* *INDENT-ON* */
1917     }
1918   else
1919     {
1920       /* clear interface table */
1921       hash_free (lcm->dp_intf_by_vni);
1922       hash_free (lcm->fwd_entry_by_mapping_index);
1923       pool_free (lcm->fwd_entry_pool);
1924     }
1925
1926   /* update global flag */
1927   lcm->is_enabled = is_enable;
1928
1929   return 0;
1930 }
1931
1932 static clib_error_t *
1933 lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
1934                                 vlib_cli_command_t * cmd)
1935 {
1936   unformat_input_t _line_input, *line_input = &_line_input;
1937   u8 is_enabled = 0;
1938   u8 is_set = 0;
1939
1940   /* Get a line of input. */
1941   if (!unformat_user (input, unformat_line_input, line_input))
1942     return 0;
1943
1944   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1945     {
1946       if (unformat (line_input, "enable"))
1947         {
1948           is_set = 1;
1949           is_enabled = 1;
1950         }
1951       else if (unformat (line_input, "disable"))
1952         is_set = 1;
1953       else
1954         {
1955           return clib_error_return (0, "parse error: '%U'",
1956                                     format_unformat_error, line_input);
1957         }
1958     }
1959
1960   if (!is_set)
1961     return clib_error_return (0, "state not set");
1962
1963   return vnet_lisp_enable_disable (is_enabled);
1964 }
1965
1966 /* *INDENT-OFF* */
1967 VLIB_CLI_COMMAND (lisp_cp_enable_disable_command) = {
1968     .path = "lisp",
1969     .short_help = "lisp [enable|disable]",
1970     .function = lisp_enable_disable_command_fn,
1971 };
1972 /* *INDENT-ON* */
1973
1974 u8
1975 vnet_lisp_enable_disable_status (void)
1976 {
1977   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1978   return lcm->is_enabled;
1979 }
1980
1981 static u8 *
1982 format_lisp_status (u8 * s, va_list * args)
1983 {
1984   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1985   return format (s, "%s", lcm->is_enabled ? "enabled" : "disabled");
1986 }
1987
1988 static clib_error_t *
1989 lisp_show_status_command_fn (vlib_main_t * vm, unformat_input_t * input,
1990                              vlib_cli_command_t * cmd)
1991 {
1992   u8 *msg = 0;
1993   msg = format (msg, "feature: %U\ngpe: %U\n",
1994                 format_lisp_status, format_vnet_lisp_gpe_status);
1995   vlib_cli_output (vm, "%v", msg);
1996   vec_free (msg);
1997   return 0;
1998 }
1999
2000 /* *INDENT-OFF* */
2001 VLIB_CLI_COMMAND (lisp_show_status_command) = {
2002     .path = "show lisp status",
2003     .short_help = "show lisp status",
2004     .function = lisp_show_status_command_fn,
2005 };
2006 /* *INDENT-ON* */
2007
2008 static clib_error_t *
2009 lisp_show_eid_table_map_command_fn (vlib_main_t * vm,
2010                                     unformat_input_t * input,
2011                                     vlib_cli_command_t * cmd)
2012 {
2013   hash_pair_t *p;
2014   unformat_input_t _line_input, *line_input = &_line_input;
2015   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2016   uword *vni_table = 0;
2017   u8 is_l2 = 0;
2018
2019   /* Get a line of input. */
2020   if (!unformat_user (input, unformat_line_input, line_input))
2021     return 0;
2022
2023   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2024     {
2025       if (unformat (line_input, "l2"))
2026         {
2027           vni_table = lcm->bd_id_by_vni;
2028           is_l2 = 1;
2029         }
2030       else if (unformat (line_input, "l3"))
2031         {
2032           vni_table = lcm->table_id_by_vni;
2033           is_l2 = 0;
2034         }
2035       else
2036         return clib_error_return (0, "parse error: '%U'",
2037                                   format_unformat_error, line_input);
2038     }
2039
2040   if (!vni_table)
2041     {
2042       vlib_cli_output (vm, "Error: expected l2|l3 param!\n");
2043       return 0;
2044     }
2045
2046   vlib_cli_output (vm, "%=10s%=10s", "VNI", is_l2 ? "BD" : "VRF");
2047
2048   /* *INDENT-OFF* */
2049   hash_foreach_pair (p, vni_table,
2050   ({
2051     vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
2052   }));
2053   /* *INDENT-ON* */
2054
2055   return 0;
2056 }
2057
2058 /* *INDENT-OFF* */
2059 VLIB_CLI_COMMAND (lisp_show_eid_table_map_command) = {
2060     .path = "show lisp eid-table map",
2061     .short_help = "show lisp eid-table l2|l3",
2062     .function = lisp_show_eid_table_map_command_fn,
2063 };
2064 /* *INDENT-ON* */
2065
2066 static clib_error_t *
2067 lisp_add_del_locator_set_command_fn (vlib_main_t * vm,
2068                                      unformat_input_t * input,
2069                                      vlib_cli_command_t * cmd)
2070 {
2071   lisp_gpe_main_t *lgm = &lisp_gpe_main;
2072   vnet_main_t *vnm = lgm->vnet_main;
2073   unformat_input_t _line_input, *line_input = &_line_input;
2074   u8 is_add = 1;
2075   clib_error_t *error = 0;
2076   u8 *locator_set_name = 0;
2077   locator_t locator, *locators = 0;
2078   vnet_lisp_add_del_locator_set_args_t _a, *a = &_a;
2079   u32 ls_index = 0;
2080   int rv = 0;
2081
2082   memset (&locator, 0, sizeof (locator));
2083   memset (a, 0, sizeof (a[0]));
2084
2085   /* Get a line of input. */
2086   if (!unformat_user (input, unformat_line_input, line_input))
2087     return 0;
2088
2089   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2090     {
2091       if (unformat (line_input, "add %_%v%_", &locator_set_name))
2092         is_add = 1;
2093       else if (unformat (line_input, "del %_%v%_", &locator_set_name))
2094         is_add = 0;
2095       else if (unformat (line_input, "iface %U p %d w %d",
2096                          unformat_vnet_sw_interface, vnm,
2097                          &locator.sw_if_index, &locator.priority,
2098                          &locator.weight))
2099         {
2100           locator.local = 1;
2101           vec_add1 (locators, locator);
2102         }
2103       else
2104         {
2105           error = unformat_parse_error (line_input);
2106           goto done;
2107         }
2108     }
2109
2110   a->name = locator_set_name;
2111   a->locators = locators;
2112   a->is_add = is_add;
2113   a->local = 1;
2114
2115   rv = vnet_lisp_add_del_locator_set (a, &ls_index);
2116   if (0 != rv)
2117     {
2118       error = clib_error_return (0, "failed to %s locator-set!",
2119                                  is_add ? "add" : "delete");
2120     }
2121
2122 done:
2123   vec_free (locators);
2124   if (locator_set_name)
2125     vec_free (locator_set_name);
2126   return error;
2127 }
2128
2129 /* *INDENT-OFF* */
2130 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
2131     .path = "lisp locator-set",
2132     .short_help = "lisp locator-set add/del <name> [iface <iface-name> "
2133         "p <priority> w <weight>]",
2134     .function = lisp_add_del_locator_set_command_fn,
2135 };
2136 /* *INDENT-ON* */
2137
2138 static clib_error_t *
2139 lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm,
2140                                         unformat_input_t * input,
2141                                         vlib_cli_command_t * cmd)
2142 {
2143   lisp_gpe_main_t *lgm = &lisp_gpe_main;
2144   vnet_main_t *vnm = lgm->vnet_main;
2145   unformat_input_t _line_input, *line_input = &_line_input;
2146   u8 is_add = 1;
2147   clib_error_t *error = 0;
2148   u8 *locator_set_name = 0;
2149   u8 locator_set_name_set = 0;
2150   locator_t locator, *locators = 0;
2151   vnet_lisp_add_del_locator_set_args_t _a, *a = &_a;
2152   u32 ls_index = 0;
2153
2154   memset (&locator, 0, sizeof (locator));
2155   memset (a, 0, sizeof (a[0]));
2156
2157   /* Get a line of input. */
2158   if (!unformat_user (input, unformat_line_input, line_input))
2159     return 0;
2160
2161   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2162     {
2163       if (unformat (line_input, "add"))
2164         is_add = 1;
2165       else if (unformat (line_input, "del"))
2166         is_add = 0;
2167       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
2168         locator_set_name_set = 1;
2169       else if (unformat (line_input, "iface %U p %d w %d",
2170                          unformat_vnet_sw_interface, vnm,
2171                          &locator.sw_if_index, &locator.priority,
2172                          &locator.weight))
2173         {
2174           locator.local = 1;
2175           vec_add1 (locators, locator);
2176         }
2177       else
2178         {
2179           error = unformat_parse_error (line_input);
2180           goto done;
2181         }
2182     }
2183
2184   if (!locator_set_name_set)
2185     {
2186       error = clib_error_return (0, "locator_set name not set!");
2187       goto done;
2188     }
2189
2190   a->name = locator_set_name;
2191   a->locators = locators;
2192   a->is_add = is_add;
2193   a->local = 1;
2194
2195   vnet_lisp_add_del_locator (a, 0, &ls_index);
2196
2197 done:
2198   vec_free (locators);
2199   vec_free (locator_set_name);
2200   return error;
2201 }
2202
2203 /* *INDENT-OFF* */
2204 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_in_set_command) = {
2205     .path = "lisp locator",
2206     .short_help = "lisp locator add/del locator-set <name> iface <iface-name> "
2207                   "p <priority> w <weight>",
2208     .function = lisp_add_del_locator_in_set_command_fn,
2209 };
2210 /* *INDENT-ON* */
2211
2212 static clib_error_t *
2213 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
2214                                       unformat_input_t * input,
2215                                       vlib_cli_command_t * cmd)
2216 {
2217   locator_set_t *lsit;
2218   locator_t *loc;
2219   u32 *locit;
2220   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2221
2222   vlib_cli_output (vm, "%s%=16s%=16s%=16s", "Locator-set", "Locator",
2223                    "Priority", "Weight");
2224
2225   /* *INDENT-OFF* */
2226   pool_foreach (lsit, lcm->locator_set_pool,
2227   ({
2228     u8 * msg = 0;
2229     int next_line = 0;
2230     if (lsit->local)
2231       {
2232         msg = format (msg, "%v", lsit->name);
2233       }
2234     else
2235       {
2236         msg = format (msg, "<%s-%d>", "remote", lsit - lcm->locator_set_pool);
2237       }
2238     vec_foreach (locit, lsit->locator_indices)
2239       {
2240         if (next_line)
2241           {
2242             msg = format (msg, "%16s", " ");
2243           }
2244         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
2245         if (loc->local)
2246           msg = format (msg, "%16d%16d%16d\n", loc->sw_if_index, loc->priority,
2247                         loc->weight);
2248         else
2249           msg = format (msg, "%16U%16d%16d\n", format_ip_address,
2250                         &gid_address_ip(&loc->address), loc->priority,
2251                         loc->weight);
2252         next_line = 1;
2253       }
2254     vlib_cli_output (vm, "%v", msg);
2255     vec_free (msg);
2256   }));
2257   /* *INDENT-ON* */
2258   return 0;
2259 }
2260
2261 /* *INDENT-OFF* */
2262 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
2263     .path = "show lisp locator-set",
2264     .short_help = "Shows locator-sets",
2265     .function = lisp_cp_show_locator_sets_command_fn,
2266 };
2267 /* *INDENT-ON* */
2268
2269 static map_resolver_t *
2270 get_map_resolver (ip_address_t * a)
2271 {
2272   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2273   map_resolver_t *mr;
2274
2275   vec_foreach (mr, lcm->map_resolvers)
2276   {
2277     if (!ip_address_cmp (&mr->address, a))
2278       {
2279         return mr;
2280       }
2281   }
2282   return 0;
2283 }
2284
2285 int
2286 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
2287 {
2288   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2289   u32 i;
2290   map_resolver_t _mr, *mr = &_mr;
2291
2292   if (vnet_lisp_enable_disable_status () == 0)
2293     {
2294       clib_warning ("LISP is disabled!");
2295       return VNET_API_ERROR_LISP_DISABLED;
2296     }
2297
2298   if (a->is_add)
2299     {
2300
2301       if (get_map_resolver (&a->address))
2302         {
2303           clib_warning ("map-resolver %U already exists!", format_ip_address,
2304                         &a->address);
2305           return -1;
2306         }
2307
2308       memset (mr, 0, sizeof (*mr));
2309       ip_address_copy (&mr->address, &a->address);
2310       vec_add1 (lcm->map_resolvers, *mr);
2311
2312       if (vec_len (lcm->map_resolvers) == 1)
2313         lcm->do_map_resolver_election = 1;
2314     }
2315   else
2316     {
2317       for (i = 0; i < vec_len (lcm->map_resolvers); i++)
2318         {
2319           mr = vec_elt_at_index (lcm->map_resolvers, i);
2320           if (!ip_address_cmp (&mr->address, &a->address))
2321             {
2322               if (!ip_address_cmp (&mr->address, &lcm->active_map_resolver))
2323                 lcm->do_map_resolver_election = 1;
2324
2325               vec_del1 (lcm->map_resolvers, i);
2326               break;
2327             }
2328         }
2329     }
2330   return 0;
2331 }
2332
2333 static clib_error_t *
2334 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
2335                                       unformat_input_t * input,
2336                                       vlib_cli_command_t * cmd)
2337 {
2338   unformat_input_t _line_input, *line_input = &_line_input;
2339   u8 is_add = 1, addr_set = 0;
2340   ip_address_t ip_addr;
2341   clib_error_t *error = 0;
2342   int rv = 0;
2343   vnet_lisp_add_del_map_resolver_args_t _a, *a = &_a;
2344
2345   /* Get a line of input. */
2346   if (!unformat_user (input, unformat_line_input, line_input))
2347     return 0;
2348
2349   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2350     {
2351       if (unformat (line_input, "add"))
2352         is_add = 1;
2353       else if (unformat (line_input, "del"))
2354         is_add = 0;
2355       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
2356         addr_set = 1;
2357       else
2358         {
2359           error = unformat_parse_error (line_input);
2360           goto done;
2361         }
2362     }
2363
2364   if (!addr_set)
2365     {
2366       error = clib_error_return (0, "Map-resolver address must be set!");
2367       goto done;
2368     }
2369
2370   a->is_add = is_add;
2371   a->address = ip_addr;
2372   rv = vnet_lisp_add_del_map_resolver (a);
2373   if (0 != rv)
2374     {
2375       error = clib_error_return (0, "failed to %s map-resolver!",
2376                                  is_add ? "add" : "delete");
2377     }
2378
2379 done:
2380   return error;
2381 }
2382
2383 /* *INDENT-OFF* */
2384 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
2385     .path = "lisp map-resolver",
2386     .short_help = "lisp map-resolver add/del <ip_address>",
2387     .function = lisp_add_del_map_resolver_command_fn,
2388 };
2389 /* *INDENT-ON* */
2390
2391 int
2392 vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
2393 {
2394   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2395   uword *p = 0;
2396
2397   if (vnet_lisp_enable_disable_status () == 0)
2398     {
2399       clib_warning ("LISP is disabled!");
2400       return VNET_API_ERROR_LISP_DISABLED;
2401     }
2402
2403   if (a->is_add)
2404     {
2405       p = hash_get_mem (lcm->locator_set_index_by_name, a->locator_set_name);
2406       if (!p)
2407         {
2408           clib_warning ("locator-set %v doesn't exist", a->locator_set_name);
2409           return VNET_API_ERROR_INVALID_ARGUMENT;
2410         }
2411
2412       lcm->mreq_itr_rlocs = p[0];
2413     }
2414   else
2415     {
2416       lcm->mreq_itr_rlocs = ~0;
2417     }
2418
2419   return 0;
2420 }
2421
2422 static clib_error_t *
2423 lisp_add_del_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
2424                                         unformat_input_t * input,
2425                                         vlib_cli_command_t * cmd)
2426 {
2427   unformat_input_t _line_input, *line_input = &_line_input;
2428   u8 is_add = 1;
2429   u8 *locator_set_name = 0;
2430   clib_error_t *error = 0;
2431   int rv = 0;
2432   vnet_lisp_add_del_mreq_itr_rloc_args_t _a, *a = &_a;
2433
2434   /* Get a line of input. */
2435   if (!unformat_user (input, unformat_line_input, line_input))
2436     return 0;
2437
2438   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2439     {
2440       if (unformat (line_input, "del"))
2441         is_add = 0;
2442       else if (unformat (line_input, "add %s", &locator_set_name))
2443         is_add = 1;
2444       else
2445         {
2446           error = unformat_parse_error (line_input);
2447           goto done;
2448         }
2449     }
2450
2451   a->is_add = is_add;
2452   a->locator_set_name = locator_set_name;
2453   rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
2454   if (0 != rv)
2455     {
2456       error = clib_error_return (0, "failed to %s map-request itr-rlocs!",
2457                                  is_add ? "add" : "delete");
2458     }
2459
2460   vec_free (locator_set_name);
2461
2462 done:
2463   return error;
2464
2465 }
2466
2467 /* *INDENT-OFF* */
2468 VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
2469     .path = "lisp map-request itr-rlocs",
2470     .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
2471     .function = lisp_add_del_mreq_itr_rlocs_command_fn,
2472 };
2473 /* *INDENT-ON* */
2474
2475 static clib_error_t *
2476 lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
2477                                      unformat_input_t * input,
2478                                      vlib_cli_command_t * cmd)
2479 {
2480   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2481   locator_set_t *loc_set;
2482
2483   vlib_cli_output (vm, "%=20s", "itr-rlocs");
2484
2485   if (~0 == lcm->mreq_itr_rlocs)
2486     {
2487       return 0;
2488     }
2489
2490   loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
2491
2492   vlib_cli_output (vm, "%=20s", loc_set->name);
2493
2494   return 0;
2495 }
2496
2497 /* *INDENT-OFF* */
2498 VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
2499     .path = "show lisp map-request itr-rlocs",
2500     .short_help = "Shows map-request itr-rlocs",
2501     .function = lisp_show_mreq_itr_rlocs_command_fn,
2502 };
2503 /* *INDENT-ON* */
2504
2505 /* Statistics (not really errors) */
2506 #define foreach_lisp_cp_lookup_error           \
2507 _(DROP, "drop")                                \
2508 _(MAP_REQUESTS_SENT, "map-request sent")
2509
2510 static char *lisp_cp_lookup_error_strings[] = {
2511 #define _(sym,string) string,
2512   foreach_lisp_cp_lookup_error
2513 #undef _
2514 };
2515
2516 typedef enum
2517 {
2518 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
2519   foreach_lisp_cp_lookup_error
2520 #undef _
2521     LISP_CP_LOOKUP_N_ERROR,
2522 } lisp_cp_lookup_error_t;
2523
2524 typedef enum
2525 {
2526   LISP_CP_LOOKUP_NEXT_DROP,
2527   LISP_CP_LOOKUP_NEXT_IP4_LOOKUP,
2528   LISP_CP_LOOKUP_NEXT_IP6_LOOKUP,
2529   LISP_CP_LOOKUP_N_NEXT,
2530 } lisp_cp_lookup_next_t;
2531
2532 typedef struct
2533 {
2534   gid_address_t dst_eid;
2535   ip_address_t map_resolver_ip;
2536 } lisp_cp_lookup_trace_t;
2537
2538 u8 *
2539 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
2540 {
2541   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2542   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2543   lisp_cp_lookup_trace_t *t = va_arg (*args, lisp_cp_lookup_trace_t *);
2544
2545   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
2546               format_ip_address, &t->map_resolver_ip, format_gid_address,
2547               &t->dst_eid);
2548   return s;
2549 }
2550
2551 int
2552 get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
2553                            ip_address_t * sloc)
2554 {
2555   map_resolver_t *mrit;
2556   ip_address_t *a;
2557
2558   if (vec_len (lcm->map_resolvers) == 0)
2559     {
2560       clib_warning ("No map-resolver configured");
2561       return 0;
2562     }
2563
2564   /* find the first mr ip we have a route to and the ip of the
2565    * iface that has a route to it */
2566   vec_foreach (mrit, lcm->map_resolvers)
2567   {
2568     a = &mrit->address;
2569     if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, a, sloc))
2570       {
2571         ip_address_copy (mr_ip, a);
2572
2573         /* also update globals */
2574         return 1;
2575       }
2576   }
2577
2578   clib_warning ("Can't find map-resolver and local interface ip!");
2579   return 0;
2580 }
2581
2582 static gid_address_t *
2583 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
2584 {
2585   void *addr;
2586   u32 i;
2587   locator_t *loc;
2588   u32 *loc_indexp;
2589   ip_interface_address_t *ia = 0;
2590   gid_address_t gid_data, *gid = &gid_data;
2591   gid_address_t *rlocs = 0;
2592   ip_prefix_t *ippref = &gid_address_ippref (gid);
2593   ip_address_t *rloc = &ip_prefix_addr (ippref);
2594
2595   memset (gid, 0, sizeof (gid[0]));
2596   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
2597   for (i = 0; i < vec_len (loc_set->locator_indices); i++)
2598     {
2599       loc_indexp = vec_elt_at_index (loc_set->locator_indices, i);
2600       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
2601
2602       /* Add ipv4 locators first TODO sort them */
2603
2604       /* *INDENT-OFF* */
2605       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2606                                     loc->sw_if_index, 1 /* unnumbered */,
2607       ({
2608         addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
2609         ip_address_set (rloc, addr, IP4);
2610         ip_prefix_len (ippref) = 32;
2611         ip_prefix_normalize (ippref);
2612         vec_add1 (rlocs, gid[0]);
2613       }));
2614
2615       /* Add ipv6 locators */
2616       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2617                                     loc->sw_if_index, 1 /* unnumbered */,
2618       ({
2619         addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
2620         ip_address_set (rloc, addr, IP6);
2621         ip_prefix_len (ippref) = 128;
2622         ip_prefix_normalize (ippref);
2623         vec_add1 (rlocs, gid[0]);
2624       }));
2625       /* *INDENT-ON* */
2626
2627     }
2628   return rlocs;
2629 }
2630
2631 static vlib_buffer_t *
2632 build_encapsulated_map_request (lisp_cp_main_t * lcm,
2633                                 gid_address_t * seid, gid_address_t * deid,
2634                                 locator_set_t * loc_set, ip_address_t * mr_ip,
2635                                 ip_address_t * sloc, u8 is_smr_invoked,
2636                                 u64 * nonce_res, u32 * bi_res)
2637 {
2638   vlib_buffer_t *b;
2639   u32 bi;
2640   gid_address_t *rlocs = 0;
2641   vlib_main_t *vm = lcm->vlib_main;
2642
2643   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2644     {
2645       clib_warning ("Can't allocate buffer for Map-Request!");
2646       return 0;
2647     }
2648
2649   b = vlib_get_buffer (vm, bi);
2650
2651   /* leave some space for the encap headers */
2652   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2653
2654   /* get rlocs */
2655   rlocs = build_itr_rloc_list (lcm, loc_set);
2656
2657   /* put lisp msg */
2658   lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked, nonce_res);
2659
2660   /* push ecm: udp-ip-lisp */
2661   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
2662
2663   /* push outer ip header */
2664   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
2665                        mr_ip);
2666
2667   bi_res[0] = bi;
2668
2669   vec_free (rlocs);
2670   return b;
2671 }
2672
2673 static void
2674 reset_pending_mr_counters (pending_map_request_t * r)
2675 {
2676   r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
2677   r->retries_num = 0;
2678 }
2679
2680 static int
2681 elect_map_resolver (lisp_cp_main_t * lcm)
2682 {
2683   map_resolver_t *mr;
2684
2685   vec_foreach (mr, lcm->map_resolvers)
2686   {
2687     if (!mr->is_down)
2688       {
2689         ip_address_copy (&lcm->active_map_resolver, &mr->address);
2690         lcm->do_map_resolver_election = 0;
2691         return 1;
2692       }
2693   }
2694   return 0;
2695 }
2696
2697 #define send_encapsulated_map_request(lcm, seid, deid, smr) \
2698   _send_encapsulated_map_request(lcm, seid, deid, smr, 0)
2699
2700 #define resend_encapsulated_map_request(lcm, seid, deid, smr) \
2701   _send_encapsulated_map_request(lcm, seid, deid, smr, 1)
2702
2703 static int
2704 _send_encapsulated_map_request (lisp_cp_main_t * lcm,
2705                                 gid_address_t * seid, gid_address_t * deid,
2706                                 u8 is_smr_invoked, u8 is_resend)
2707 {
2708   map_resolver_t *mr;
2709   u32 next_index, bi = 0, *to_next, map_index;
2710   vlib_buffer_t *b;
2711   vlib_frame_t *f;
2712   u64 nonce = 0;
2713   locator_set_t *loc_set;
2714   mapping_t *map;
2715   pending_map_request_t *pmr, *duplicate_pmr = 0;
2716   ip_address_t sloc;
2717   u32 ls_index;
2718
2719   ASSERT (*lcm->pending_map_request_lock);
2720
2721   /* if there is already a pending request remember it */
2722
2723   /* *INDENT-OFF* */
2724   pool_foreach(pmr, lcm->pending_map_requests_pool,
2725   ({
2726     if (!gid_address_cmp (&pmr->src, seid)
2727         && !gid_address_cmp (&pmr->dst, deid))
2728       {
2729         duplicate_pmr = pmr;
2730         break;
2731       }
2732   }));
2733   /* *INDENT-ON* */
2734
2735   if (!is_resend && duplicate_pmr)
2736     {
2737       /* don't send the request if there is a pending map request already */
2738       return 0;
2739     }
2740
2741   /* get locator-set for seid */
2742   if (!lcm->lisp_pitr)
2743     {
2744       map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
2745       if (map_index == ~0)
2746         {
2747           clib_warning ("No local mapping found in eid-table for %U!",
2748                         format_gid_address, seid);
2749           return -1;
2750         }
2751
2752       map = pool_elt_at_index (lcm->mapping_pool, map_index);
2753
2754       if (!map->local)
2755         {
2756           clib_warning
2757             ("Mapping found for src eid %U is not marked as local!",
2758              format_gid_address, seid);
2759           return -1;
2760         }
2761       ls_index = map->locator_set_index;
2762     }
2763   else
2764     {
2765       map_index = lcm->pitr_map_index;
2766       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
2767       ls_index = map->locator_set_index;
2768     }
2769
2770   /* overwrite locator set if map-request itr-rlocs configured */
2771   if (~0 != lcm->mreq_itr_rlocs)
2772     {
2773       ls_index = lcm->mreq_itr_rlocs;
2774     }
2775
2776   loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
2777
2778   while (lcm->do_map_resolver_election
2779          | (0 == ip_fib_get_first_egress_ip_for_dst (lcm,
2780                                                      &lcm->active_map_resolver,
2781                                                      &sloc)))
2782     {
2783       if (0 == elect_map_resolver (lcm))
2784         /* all Mrs are down */
2785         {
2786           if (duplicate_pmr)
2787             duplicate_pmr->to_be_removed = 1;
2788
2789           /* restart MR checking by marking all of them up */
2790           vec_foreach (mr, lcm->map_resolvers) mr->is_down = 0;
2791
2792           return -1;
2793         }
2794     }
2795
2796   /* build the encapsulated map request */
2797   b = build_encapsulated_map_request (lcm, seid, deid, loc_set,
2798                                       &lcm->active_map_resolver,
2799                                       &sloc, is_smr_invoked, &nonce, &bi);
2800
2801   if (!b)
2802     return -1;
2803
2804   /* set fib index to default and lookup node */
2805   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
2806   next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
2807     ip4_lookup_node.index : ip6_lookup_node.index;
2808
2809   f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
2810
2811   /* Enqueue the packet */
2812   to_next = vlib_frame_vector_args (f);
2813   to_next[0] = bi;
2814   f->n_vectors = 1;
2815   vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
2816
2817   if (duplicate_pmr)
2818     /* if there is a pending request already update it */
2819     {
2820       if (clib_fifo_elts (duplicate_pmr->nonces) >= PENDING_MREQ_QUEUE_LEN)
2821         {
2822           /* remove the oldest nonce */
2823           u64 CLIB_UNUSED (tmp), *nonce_del;
2824           nonce_del = clib_fifo_head (duplicate_pmr->nonces);
2825           hash_unset (lcm->pending_map_requests_by_nonce, nonce_del[0]);
2826           clib_fifo_sub1 (duplicate_pmr->nonces, tmp);
2827         }
2828
2829       clib_fifo_add1 (duplicate_pmr->nonces, nonce);
2830       hash_set (lcm->pending_map_requests_by_nonce, nonce,
2831                 duplicate_pmr - lcm->pending_map_requests_pool);
2832     }
2833   else
2834     {
2835       /* add map-request to pending requests table */
2836       pool_get (lcm->pending_map_requests_pool, pmr);
2837       memset (pmr, 0, sizeof (*pmr));
2838       gid_address_copy (&pmr->src, seid);
2839       gid_address_copy (&pmr->dst, deid);
2840       clib_fifo_add1 (pmr->nonces, nonce);
2841       pmr->is_smr_invoked = is_smr_invoked;
2842       reset_pending_mr_counters (pmr);
2843       hash_set (lcm->pending_map_requests_by_nonce, nonce,
2844                 pmr - lcm->pending_map_requests_pool);
2845     }
2846
2847   return 0;
2848 }
2849
2850 static void
2851 get_src_and_dst_ip (void *hdr, ip_address_t * src, ip_address_t * dst)
2852 {
2853   ip4_header_t *ip4 = hdr;
2854   ip6_header_t *ip6;
2855
2856   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
2857     {
2858       ip_address_set (src, &ip4->src_address, IP4);
2859       ip_address_set (dst, &ip4->dst_address, IP4);
2860     }
2861   else
2862     {
2863       ip6 = hdr;
2864       ip_address_set (src, &ip6->src_address, IP6);
2865       ip_address_set (dst, &ip6->dst_address, IP6);
2866     }
2867 }
2868
2869 static u32
2870 lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b,
2871                              u8 version)
2872 {
2873   uword *vnip;
2874   u32 vni = ~0, table_id = ~0, fib_index;
2875
2876   if (version == IP4)
2877     {
2878       ip4_fib_t *fib;
2879       ip4_main_t *im4 = &ip4_main;
2880       fib_index = vec_elt (im4->fib_index_by_sw_if_index,
2881                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2882       fib = find_ip4_fib_by_table_index_or_id (im4, fib_index,
2883                                                IP4_ROUTE_FLAG_FIB_INDEX);
2884       table_id = fib->table_id;
2885     }
2886   else
2887     {
2888       ip6_fib_t *fib;
2889       ip6_main_t *im6 = &ip6_main;
2890       fib_index = vec_elt (im6->fib_index_by_sw_if_index,
2891                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2892       fib = find_ip6_fib_by_table_index_or_id (im6, fib_index,
2893                                                IP6_ROUTE_FLAG_FIB_INDEX);
2894       table_id = fib->table_id;
2895     }
2896
2897   vnip = hash_get (lcm->vni_by_table_id, table_id);
2898   if (vnip)
2899     vni = vnip[0];
2900   else
2901     clib_warning ("vrf %d is not mapped to any vni!", table_id);
2902
2903   return vni;
2904 }
2905
2906 always_inline u32
2907 lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b)
2908 {
2909   uword *vnip;
2910   u32 vni = ~0;
2911   u32 sw_if_index0;
2912
2913   l2input_main_t *l2im = &l2input_main;
2914   l2_input_config_t *config;
2915   l2_bridge_domain_t *bd_config;
2916
2917   sw_if_index0 = vnet_buffer (b)->sw_if_index[VLIB_RX];
2918   config = vec_elt_at_index (l2im->configs, sw_if_index0);
2919   bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index);
2920
2921   vnip = hash_get (lcm->vni_by_bd_id, bd_config->bd_id);
2922   if (vnip)
2923     vni = vnip[0];
2924   else
2925     clib_warning ("bridge domain %d is not mapped to any vni!",
2926                   config->bd_index);
2927
2928   return vni;
2929 }
2930
2931 always_inline void
2932 get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
2933                                   gid_address_t * src, gid_address_t * dst)
2934 {
2935   u32 vni = 0;
2936   u16 type;
2937
2938   memset (src, 0, sizeof (*src));
2939   memset (dst, 0, sizeof (*dst));
2940   type = vnet_buffer (b)->lisp.overlay_afi;
2941
2942   if (LISP_AFI_IP == type || LISP_AFI_IP6 == type)
2943     {
2944       ip4_header_t *ip;
2945       u8 version, preflen;
2946
2947       gid_address_type (src) = GID_ADDR_IP_PREFIX;
2948       gid_address_type (dst) = GID_ADDR_IP_PREFIX;
2949
2950       ip = vlib_buffer_get_current (b);
2951       get_src_and_dst_ip (ip, &gid_address_ip (src), &gid_address_ip (dst));
2952
2953       version = gid_address_ip_version (src);
2954       preflen = ip_address_max_len (version);
2955       gid_address_ippref_len (src) = preflen;
2956       gid_address_ippref_len (dst) = preflen;
2957
2958       vni = lisp_get_vni_from_buffer_ip (lcm, b, version);
2959       gid_address_vni (dst) = vni;
2960       gid_address_vni (src) = vni;
2961     }
2962   else if (LISP_AFI_MAC == type)
2963     {
2964       ethernet_header_t *eh;
2965
2966       eh = vlib_buffer_get_current (b);
2967
2968       gid_address_type (src) = GID_ADDR_MAC;
2969       gid_address_type (dst) = GID_ADDR_MAC;
2970       mac_copy (&gid_address_mac (src), eh->src_address);
2971       mac_copy (&gid_address_mac (dst), eh->dst_address);
2972
2973       /* get vni */
2974       vni = lisp_get_vni_from_buffer_eth (lcm, b);
2975
2976       gid_address_vni (dst) = vni;
2977       gid_address_vni (src) = vni;
2978     }
2979 }
2980
2981 static uword
2982 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
2983                 vlib_frame_t * from_frame)
2984 {
2985   u32 *from, *to_next_drop, di, si;
2986   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2987   u32 pkts_mapped = 0;
2988   uword n_left_from, n_left_to_next_drop;
2989
2990   from = vlib_frame_vector_args (from_frame);
2991   n_left_from = from_frame->n_vectors;
2992
2993   while (n_left_from > 0)
2994     {
2995       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
2996                            to_next_drop, n_left_to_next_drop);
2997
2998       while (n_left_from > 0 && n_left_to_next_drop > 0)
2999         {
3000           u32 pi0;
3001           vlib_buffer_t *b0;
3002           gid_address_t src, dst;
3003
3004           pi0 = from[0];
3005           from += 1;
3006           n_left_from -= 1;
3007           to_next_drop[0] = pi0;
3008           to_next_drop += 1;
3009           n_left_to_next_drop -= 1;
3010
3011           b0 = vlib_get_buffer (vm, pi0);
3012           b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
3013
3014           /* src/dst eid pair */
3015           get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst);
3016
3017           /* if we have remote mapping for destination already in map-chache
3018              add forwarding tunnel directly. If not send a map-request */
3019           di = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
3020           if (~0 != di)
3021             {
3022               mapping_t *m = vec_elt_at_index (lcm->mapping_pool, di);
3023               /* send a map-request also in case of negative mapping entry
3024                  with corresponding action */
3025               if (m->action == LISP_SEND_MAP_REQUEST)
3026                 {
3027                   /* send map-request */
3028                   queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3029                                      0 /* is_resend */ );
3030                   pkts_mapped++;
3031                 }
3032               else
3033                 {
3034                   si = gid_dictionary_lookup (&lcm->mapping_index_by_gid,
3035                                               &src);
3036                   if (~0 != si)
3037                     {
3038                       dp_add_fwd_entry (lcm, si, di);
3039                     }
3040                 }
3041             }
3042           else
3043             {
3044               /* send map-request */
3045               queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3046                                  0 /* is_resend */ );
3047               pkts_mapped++;
3048             }
3049
3050           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3051             {
3052               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
3053                                                            sizeof (*tr));
3054
3055               memset (tr, 0, sizeof (*tr));
3056               gid_address_copy (&tr->dst_eid, &dst);
3057               ip_address_copy (&tr->map_resolver_ip,
3058                                &lcm->active_map_resolver);
3059             }
3060           gid_address_free (&dst);
3061           gid_address_free (&src);
3062         }
3063
3064       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
3065                            n_left_to_next_drop);
3066     }
3067   vlib_node_increment_counter (vm, node->node_index,
3068                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
3069                                pkts_mapped);
3070   return from_frame->n_vectors;
3071 }
3072
3073 /* *INDENT-OFF* */
3074 VLIB_REGISTER_NODE (lisp_cp_lookup_node) = {
3075   .function = lisp_cp_lookup,
3076   .name = "lisp-cp-lookup",
3077   .vector_size = sizeof (u32),
3078   .format_trace = format_lisp_cp_lookup_trace,
3079   .type = VLIB_NODE_TYPE_INTERNAL,
3080
3081   .n_errors = LISP_CP_LOOKUP_N_ERROR,
3082   .error_strings = lisp_cp_lookup_error_strings,
3083
3084   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3085
3086   .next_nodes = {
3087       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
3088       [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup",
3089       [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup",
3090   },
3091 };
3092 /* *INDENT-ON* */
3093
3094 /* lisp_cp_input statistics */
3095 #define foreach_lisp_cp_input_error                     \
3096 _(DROP, "drop")                                         \
3097 _(MAP_REPLIES_RECEIVED, "map-replies received")
3098
3099 static char *lisp_cp_input_error_strings[] = {
3100 #define _(sym,string) string,
3101   foreach_lisp_cp_input_error
3102 #undef _
3103 };
3104
3105 typedef enum
3106 {
3107 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
3108   foreach_lisp_cp_input_error
3109 #undef _
3110     LISP_CP_INPUT_N_ERROR,
3111 } lisp_cp_input_error_t;
3112
3113 typedef enum
3114 {
3115   LISP_CP_INPUT_NEXT_DROP,
3116   LISP_CP_INPUT_N_NEXT,
3117 } lisp_cp_input_next_t;
3118
3119 typedef struct
3120 {
3121   gid_address_t dst_eid;
3122   ip4_address_t map_resolver_ip;
3123 } lisp_cp_input_trace_t;
3124
3125 u8 *
3126 format_lisp_cp_input_trace (u8 * s, va_list * args)
3127 {
3128   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
3129   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
3130   CLIB_UNUSED (lisp_cp_input_trace_t * t) =
3131     va_arg (*args, lisp_cp_input_trace_t *);
3132
3133   s = format (s, "LISP-CP-INPUT: TODO");
3134   return s;
3135 }
3136
3137 void *
3138 process_map_reply (void *arg)
3139 {
3140   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3141   vlib_buffer_t *b = arg;
3142   u32 len = 0, i, ttl, dst_map_index = 0;
3143   void *h;
3144   pending_map_request_t *pmr;
3145   locator_t probed;
3146   map_reply_hdr_t *mrep_hdr;
3147   u64 nonce, *noncep;
3148   gid_address_t deid;
3149   uword *pmr_index;
3150   u8 authoritative, action;
3151   locator_t *locators = 0, *loc;
3152
3153   mrep_hdr = vlib_buffer_get_current (b);
3154
3155   lisp_pending_map_request_lock (lcm);
3156
3157   /* Check pending requests table and nonce */
3158   nonce = MREP_NONCE (mrep_hdr);
3159   pmr_index = hash_get (lcm->pending_map_requests_by_nonce, nonce);
3160   if (!pmr_index)
3161     {
3162       clib_warning ("No pending map-request entry with nonce %lu!", nonce);
3163       goto done;
3164     }
3165   pmr = pool_elt_at_index (lcm->pending_map_requests_pool, pmr_index[0]);
3166
3167   vlib_buffer_pull (b, sizeof (*mrep_hdr));
3168
3169   for (i = 0; i < MREP_REC_COUNT (mrep_hdr); i++)
3170     {
3171       h = vlib_buffer_get_current (b);
3172       ttl = clib_net_to_host_u32 (MAP_REC_TTL (h));
3173       action = MAP_REC_ACTION (h);
3174       authoritative = MAP_REC_AUTH (h);
3175
3176       len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
3177       if (len == ~0)
3178         {
3179           clib_warning ("Failed to parse mapping record!");
3180           vec_foreach (loc, locators)
3181           {
3182             locator_free (loc);
3183           }
3184           vec_free (locators);
3185           goto done;
3186         }
3187
3188       /* insert/update mappings cache */
3189       vnet_lisp_add_del_mapping (&deid, locators, action, authoritative, ttl,
3190                                  1, 0 /* is_static */ , &dst_map_index);
3191
3192       /* try to program forwarding only if mapping saved or updated */
3193       if ((u32) ~ 0 != dst_map_index)
3194         lisp_add_del_adjacency (lcm, &pmr->src, &deid, 1);
3195
3196       vec_free (locators);
3197     }
3198
3199   /* remove pending map request entry */
3200
3201   /* *INDENT-OFF* */
3202   clib_fifo_foreach (noncep, pmr->nonces, ({
3203     hash_unset(lcm->pending_map_requests_by_nonce, noncep[0]);
3204   }));
3205   /* *INDENT-ON* */
3206
3207   clib_fifo_free (pmr->nonces);
3208   pool_put (lcm->pending_map_requests_pool, pmr);
3209
3210 done:
3211   lisp_pending_map_request_unlock (lcm);
3212   return 0;
3213 }
3214
3215 void
3216 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
3217                      vlib_buffer_t * b)
3218 {
3219   map_request_hdr_t *mreq_hdr;
3220   gid_address_t src, dst;
3221 //  u64 nonce;
3222   u32 i, len = 0;
3223   gid_address_t *itr_rlocs = 0, *rloc;
3224
3225   mreq_hdr = vlib_buffer_get_current (b);
3226   vlib_buffer_pull (b, sizeof (*mreq_hdr));
3227
3228 //  nonce = MREQ_NONCE(mreq_hdr);
3229
3230   if (!MREQ_SMR (mreq_hdr))
3231     {
3232       clib_warning ("Only SMR Map-Requests supported for now!");
3233       return;
3234     }
3235
3236   /* parse src eid */
3237   len = lisp_msg_parse_addr (b, &src);
3238   if (len == ~0)
3239     return;
3240
3241   /* for now we don't do anything with the itr's rlocs */
3242   len =
3243     lisp_msg_parse_itr_rlocs (b, &itr_rlocs,
3244                               MREQ_ITR_RLOC_COUNT (mreq_hdr) + 1);
3245   if (len == ~0)
3246     return;
3247
3248   /* TODO: RLOCs are currently unused, so free them for now */
3249   vec_foreach (rloc, itr_rlocs)
3250   {
3251     gid_address_free (rloc);
3252   }
3253
3254   /* parse eid records and send SMR-invoked map-requests */
3255   for (i = 0; i < MREQ_REC_COUNT (mreq_hdr); i++)
3256     {
3257       memset (&dst, 0, sizeof (dst));
3258       len = lisp_msg_parse_eid_rec (b, &dst);
3259       if (len == ~0)
3260         {
3261           clib_warning ("Can't parse map-request EID-record");
3262           return;
3263         }
3264       /* send SMR-invoked map-requests */
3265       queue_map_request (&dst, &src, 1 /* invoked */ , 0 /* resend */ );
3266     }
3267 }
3268
3269 static void
3270 queue_map_reply (vlib_buffer_t * b)
3271 {
3272   vlib_buffer_t *a = clib_mem_alloc (sizeof (a[0]) + b->current_length);
3273
3274   clib_memcpy (a->data, b->data + b->current_data, b->current_length);
3275   a->current_length = b->current_length;
3276   a->current_data = 0;
3277
3278   vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (a[0])
3279                                + a->current_length);
3280   clib_mem_free (a);
3281 }
3282
3283 static uword
3284 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
3285                vlib_frame_t * from_frame)
3286 {
3287   u32 n_left_from, *from, *to_next_drop;
3288   lisp_msg_type_e type;
3289   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3290
3291   from = vlib_frame_vector_args (from_frame);
3292   n_left_from = from_frame->n_vectors;
3293
3294
3295   while (n_left_from > 0)
3296     {
3297       u32 n_left_to_next_drop;
3298
3299       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
3300                            to_next_drop, n_left_to_next_drop);
3301       while (n_left_from > 0 && n_left_to_next_drop > 0)
3302         {
3303           u32 bi0;
3304           vlib_buffer_t *b0;
3305
3306           bi0 = from[0];
3307           from += 1;
3308           n_left_from -= 1;
3309           to_next_drop[0] = bi0;
3310           to_next_drop += 1;
3311           n_left_to_next_drop -= 1;
3312
3313           b0 = vlib_get_buffer (vm, bi0);
3314
3315           type = lisp_msg_type (vlib_buffer_get_current (b0));
3316           switch (type)
3317             {
3318             case LISP_MAP_REPLY:
3319               queue_map_reply (b0);
3320               break;
3321             case LISP_MAP_REQUEST:
3322               process_map_request (vm, lcm, b0);
3323               break;
3324             default:
3325               clib_warning ("Unsupported LISP message type %d", type);
3326               break;
3327             }
3328
3329           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
3330
3331           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3332             {
3333
3334             }
3335         }
3336
3337       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
3338                            n_left_to_next_drop);
3339     }
3340   return from_frame->n_vectors;
3341 }
3342
3343 /* *INDENT-OFF* */
3344 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
3345   .function = lisp_cp_input,
3346   .name = "lisp-cp-input",
3347   .vector_size = sizeof (u32),
3348   .format_trace = format_lisp_cp_input_trace,
3349   .type = VLIB_NODE_TYPE_INTERNAL,
3350
3351   .n_errors = LISP_CP_INPUT_N_ERROR,
3352   .error_strings = lisp_cp_input_error_strings,
3353
3354   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
3355
3356   .next_nodes = {
3357       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
3358   },
3359 };
3360 /* *INDENT-ON* */
3361
3362 clib_error_t *
3363 lisp_cp_init (vlib_main_t * vm)
3364 {
3365   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3366   clib_error_t *error = 0;
3367
3368   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
3369     return error;
3370
3371   lcm->im4 = &ip4_main;
3372   lcm->im6 = &ip6_main;
3373   lcm->vlib_main = vm;
3374   lcm->vnet_main = vnet_get_main ();
3375   lcm->mreq_itr_rlocs = ~0;
3376   lcm->lisp_pitr = 0;
3377   memset (&lcm->active_map_resolver, 0, sizeof (lcm->active_map_resolver));
3378
3379   lcm->pending_map_request_lock =
3380     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
3381
3382   lcm->pending_map_request_lock[0] = 0;
3383   gid_dictionary_init (&lcm->mapping_index_by_gid);
3384   lcm->do_map_resolver_election = 1;
3385
3386   /* default vrf mapped to vni 0 */
3387   hash_set (lcm->table_id_by_vni, 0, 0);
3388   hash_set (lcm->vni_by_table_id, 0, 0);
3389
3390   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
3391                          lisp_cp_input_node.index, 1 /* is_ip4 */ );
3392   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
3393                          lisp_cp_input_node.index, 0 /* is_ip4 */ );
3394
3395   return 0;
3396 }
3397
3398 static void *
3399 send_map_request_thread_fn (void *arg)
3400 {
3401   map_request_args_t *a = arg;
3402   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3403
3404   lisp_pending_map_request_lock (lcm);
3405
3406   if (a->is_resend)
3407     resend_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
3408   else
3409     send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
3410
3411   lisp_pending_map_request_unlock (lcm);
3412
3413   return 0;
3414 }
3415
3416 static int
3417 queue_map_request (gid_address_t * seid, gid_address_t * deid,
3418                    u8 smr_invoked, u8 is_resend)
3419 {
3420   map_request_args_t a;
3421
3422   a.is_resend = is_resend;
3423   gid_address_copy (&a.seid, seid);
3424   gid_address_copy (&a.deid, deid);
3425   a.smr_invoked = smr_invoked;
3426
3427   vl_api_rpc_call_main_thread (send_map_request_thread_fn,
3428                                (u8 *) & a, sizeof (a));
3429   return 0;
3430 }
3431
3432 /**
3433  * Take an action with a pending map request depending on expiration time
3434  * and re-try counters.
3435  */
3436 static void
3437 update_pending_request (pending_map_request_t * r, f64 dt)
3438 {
3439   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3440   map_resolver_t *mr;
3441
3442   if (r->time_to_expire - dt < 0)
3443     /* it's time to decide what to do with this pending request */
3444     {
3445       if (r->retries_num >= NUMBER_OF_RETRIES)
3446         /* too many retries -> assume current map resolver is not available */
3447         {
3448           mr = get_map_resolver (&lcm->active_map_resolver);
3449           if (!mr)
3450             {
3451               clib_warning ("Map resolver %U not found - probably deleted "
3452                             "by the user recently.", format_ip_address,
3453                             &lcm->active_map_resolver);
3454             }
3455           else
3456             {
3457               clib_warning ("map resolver %U is unreachable, ignoring",
3458                             format_ip_address, &lcm->active_map_resolver);
3459
3460               /* mark current map resolver unavailable so it won't be
3461                * selected next time */
3462               mr->is_down = 1;
3463               mr->last_update = vlib_time_now (lcm->vlib_main);
3464             }
3465
3466           reset_pending_mr_counters (r);
3467           elect_map_resolver (lcm);
3468
3469           /* try to find a next eligible map resolver and re-send */
3470           queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
3471                              1 /* resend */ );
3472         }
3473       else
3474         {
3475           /* try again */
3476           queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
3477                              1 /* resend */ );
3478           r->retries_num++;
3479           r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
3480         }
3481     }
3482   else
3483     r->time_to_expire -= dt;
3484 }
3485
3486 static void
3487 remove_dead_pending_map_requests (lisp_cp_main_t * lcm)
3488 {
3489   u64 *nonce;
3490   pending_map_request_t *pmr;
3491   u32 *to_be_removed = 0, *pmr_index;
3492
3493   ASSERT (*lcm->pending_map_request_lock);
3494
3495   /* *INDENT-OFF* */
3496   pool_foreach (pmr, lcm->pending_map_requests_pool,
3497   ({
3498     if (pmr->to_be_removed)
3499       {
3500         clib_fifo_foreach (nonce, pmr->nonces, ({
3501           hash_unset (lcm->pending_map_requests_by_nonce, nonce[0]);
3502         }));
3503
3504         vec_add1 (to_be_removed, pmr - lcm->pending_map_requests_pool);
3505       }
3506   }));
3507   /* *INDENT-ON* */
3508
3509   vec_foreach (pmr_index, to_be_removed)
3510     pool_put_index (lcm->pending_map_requests_by_nonce, pmr_index[0]);
3511
3512   vec_free (to_be_removed);
3513 }
3514
3515 static uword
3516 send_map_resolver_service (vlib_main_t * vm,
3517                            vlib_node_runtime_t * rt, vlib_frame_t * f)
3518 {
3519   f64 period = 2.0;
3520   pending_map_request_t *pmr;
3521   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3522
3523   while (1)
3524     {
3525       vlib_process_wait_for_event_or_clock (vm, period);
3526
3527       /* currently no signals are expected - just wait for clock */
3528       (void) vlib_process_get_events (vm, 0);
3529
3530       lisp_pending_map_request_lock (lcm);
3531
3532       /* *INDENT-OFF* */
3533       pool_foreach (pmr, lcm->pending_map_requests_pool,
3534       ({
3535         if (!pmr->to_be_removed)
3536           update_pending_request (pmr, period);
3537       }));
3538       /* *INDENT-ON* */
3539
3540       remove_dead_pending_map_requests (lcm);
3541
3542       lisp_pending_map_request_unlock (lcm);
3543     }
3544
3545   /* unreachable */
3546   return 0;
3547 }
3548
3549 /* *INDENT-OFF* */
3550 VLIB_REGISTER_NODE (lisp_retry_service_node,static) = {
3551     .function = send_map_resolver_service,
3552     .type = VLIB_NODE_TYPE_PROCESS,
3553     .name = "lisp-retry-service",
3554     .process_log2_n_stack_bytes = 16,
3555 };
3556 /* *INDENT-ON* */
3557
3558 VLIB_INIT_FUNCTION (lisp_cp_init);
3559
3560 /*
3561  * fd.io coding-style-patch-verification: ON
3562  *
3563  * Local Variables:
3564  * eval: (c-set-style "gnu")
3565  * End:
3566  */