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