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