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