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