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