40ce6b0c4da938dbbbe87365bb62cee0ddd154f2
[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 #include <openssl/evp.h>
27 #include <openssl/hmac.h>
28
29 typedef struct
30 {
31   u8 is_resend;
32   gid_address_t seid;
33   gid_address_t deid;
34   u8 smr_invoked;
35 } map_request_args_t;
36
37 u8
38 vnet_lisp_get_map_request_mode (void)
39 {
40   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
41   return lcm->map_request_mode;
42 }
43
44 static u16
45 auth_data_len_by_key_id (lisp_key_type_t key_id)
46 {
47   switch (key_id)
48     {
49     case HMAC_SHA_1_96:
50       return SHA1_AUTH_DATA_LEN;
51     case HMAC_SHA_256_128:
52       return SHA256_AUTH_DATA_LEN;
53     default:
54       clib_warning ("unsupported key type: %d!", key_id);
55       return (u16) ~ 0;
56     }
57   return (u16) ~ 0;
58 }
59
60 static const EVP_MD *
61 get_encrypt_fcn (lisp_key_type_t key_id)
62 {
63   switch (key_id)
64     {
65     case HMAC_SHA_1_96:
66       return EVP_sha1 ();
67     case HMAC_SHA_256_128:
68       return EVP_sha256 ();
69     default:
70       clib_warning ("unsupported encryption key type: %d!", key_id);
71       break;
72     }
73   return 0;
74 }
75
76 static int
77 queue_map_request (gid_address_t * seid, gid_address_t * deid,
78                    u8 smr_invoked, u8 is_resend);
79
80 ip_interface_address_t *
81 ip_interface_get_first_interface_address (ip_lookup_main_t * lm,
82                                           u32 sw_if_index, u8 loop)
83 {
84   vnet_main_t *vnm = vnet_get_main ();
85   vnet_sw_interface_t *swif = vnet_get_sw_interface (vnm, sw_if_index);
86   if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
87     sw_if_index = swif->unnumbered_sw_if_index;
88   u32 ia =
89     (vec_len ((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
90     vec_elt ((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
91     (u32) ~ 0;
92   return pool_elt_at_index ((lm)->if_address_pool, ia);
93 }
94
95 void *
96 ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
97                                 u8 version)
98 {
99   ip_interface_address_t *ia;
100
101   ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
102   if (!ia)
103     return 0;
104   return ip_interface_address_get_address (lm, ia);
105 }
106
107 int
108 ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
109                                    u8 version, ip_address_t * result)
110 {
111   ip_lookup_main_t *lm;
112   void *addr;
113
114   lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
115   addr = ip_interface_get_first_address (lm, sw_if_index, version);
116   if (!addr)
117     return 0;
118
119   ip_address_set (result, addr, version);
120   return 1;
121 }
122
123 /**
124  * convert from a LISP address to a FIB prefix
125  */
126 void
127 ip_address_to_fib_prefix (const ip_address_t * addr, fib_prefix_t * prefix)
128 {
129   if (addr->version == IP4)
130     {
131       prefix->fp_len = 32;
132       prefix->fp_proto = FIB_PROTOCOL_IP4;
133       memset (&prefix->fp_addr.pad, 0, sizeof (prefix->fp_addr.pad));
134       memcpy (&prefix->fp_addr.ip4, &addr->ip, sizeof (prefix->fp_addr.ip4));
135     }
136   else
137     {
138       prefix->fp_len = 128;
139       prefix->fp_proto = FIB_PROTOCOL_IP6;
140       memcpy (&prefix->fp_addr.ip6, &addr->ip, sizeof (prefix->fp_addr.ip6));
141     }
142 }
143
144 /**
145  * convert from a LISP to a FIB prefix
146  */
147 void
148 ip_prefix_to_fib_prefix (const ip_prefix_t * ip_prefix,
149                          fib_prefix_t * fib_prefix)
150 {
151   ip_address_to_fib_prefix (&ip_prefix->addr, fib_prefix);
152   fib_prefix->fp_len = ip_prefix->len;
153 }
154
155 /**
156  * Find the sw_if_index of the interface that would be used to egress towards
157  * dst.
158  */
159 u32
160 ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
161 {
162   fib_node_index_t fei;
163   fib_prefix_t prefix;
164
165   ip_address_to_fib_prefix (dst, &prefix);
166
167   fei = fib_table_lookup (0, &prefix);
168
169   return (fib_entry_get_resolving_interface (fei));
170 }
171
172 /**
173  * Find first IP of the interface that would be used to egress towards dst.
174  * Returns 1 if the address is found 0 otherwise.
175  */
176 int
177 ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
178                                     ip_address_t * result)
179 {
180   u32 si;
181   ip_lookup_main_t *lm;
182   void *addr = 0;
183   u8 ipver;
184
185   ASSERT (result != 0);
186
187   ipver = ip_addr_version (dst);
188
189   lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
190   si = ip_fib_get_egress_iface_for_dst (lcm, dst);
191
192   if ((u32) ~ 0 == si)
193     return 0;
194
195   /* find the first ip address */
196   addr = ip_interface_get_first_address (lm, si, ipver);
197   if (0 == addr)
198     return 0;
199
200   ip_address_set (result, addr, ipver);
201   return 1;
202 }
203
204 static int
205 dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_l2, u8 is_add)
206 {
207   uword *dp_table;
208
209   if (!is_l2)
210     {
211       dp_table = hash_get (lcm->table_id_by_vni, vni);
212
213       if (!dp_table)
214         {
215           clib_warning ("vni %d not associated to a vrf!", vni);
216           return VNET_API_ERROR_INVALID_VALUE;
217         }
218     }
219   else
220     {
221       dp_table = hash_get (lcm->bd_id_by_vni, vni);
222       if (!dp_table)
223         {
224           clib_warning ("vni %d not associated to a bridge domain!", vni);
225           return VNET_API_ERROR_INVALID_VALUE;
226         }
227     }
228
229   /* enable/disable data-plane interface */
230   if (is_add)
231     {
232       if (is_l2)
233         lisp_gpe_tenant_l2_iface_add_or_lock (vni, dp_table[0]);
234       else
235         lisp_gpe_tenant_l3_iface_add_or_lock (vni, dp_table[0]);
236     }
237   else
238     {
239       if (is_l2)
240         lisp_gpe_tenant_l2_iface_unlock (vni);
241       else
242         lisp_gpe_tenant_l3_iface_unlock (vni);
243     }
244
245   return 0;
246 }
247
248 static void
249 dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
250 {
251   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
252   fwd_entry_t *fe = 0;
253   uword *feip = 0;
254   memset (a, 0, sizeof (*a));
255
256   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
257   if (!feip)
258     return;
259
260   fe = pool_elt_at_index (lcm->fwd_entry_pool, feip[0]);
261
262   /* delete dp fwd entry */
263   u32 sw_if_index;
264   a->is_add = 0;
265   a->locator_pairs = fe->locator_pairs;
266   a->vni = gid_address_vni (&fe->reid);
267   gid_address_copy (&a->rmt_eid, &fe->reid);
268   if (fe->is_src_dst)
269     gid_address_copy (&a->lcl_eid, &fe->leid);
270
271   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
272
273   /* delete entry in fwd table */
274   hash_unset (lcm->fwd_entry_by_mapping_index, dst_map_index);
275   vec_free (fe->locator_pairs);
276   pool_put (lcm->fwd_entry_pool, fe);
277 }
278
279 /**
280  * Finds first remote locator with best (lowest) priority that has a local
281  * peer locator with an underlying route to it.
282  *
283  */
284 static u32
285 get_locator_pairs (lisp_cp_main_t * lcm, mapping_t * lcl_map,
286                    mapping_t * rmt_map, locator_pair_t ** locator_pairs)
287 {
288   u32 i, limitp = 0, li, found = 0, esi;
289   locator_set_t *rmt_ls, *lcl_ls;
290   ip_address_t _lcl_addr, *lcl_addr = &_lcl_addr;
291   locator_t *lp, *rmt = 0;
292   uword *checked = 0;
293   locator_pair_t pair;
294
295   rmt_ls =
296     pool_elt_at_index (lcm->locator_set_pool, rmt_map->locator_set_index);
297   lcl_ls =
298     pool_elt_at_index (lcm->locator_set_pool, lcl_map->locator_set_index);
299
300   if (!rmt_ls || vec_len (rmt_ls->locator_indices) == 0)
301     return 0;
302
303   while (1)
304     {
305       rmt = 0;
306
307       /* find unvisited remote locator with best priority */
308       for (i = 0; i < vec_len (rmt_ls->locator_indices); i++)
309         {
310           if (0 != hash_get (checked, i))
311             continue;
312
313           li = vec_elt (rmt_ls->locator_indices, i);
314           lp = pool_elt_at_index (lcm->locator_pool, li);
315
316           /* we don't support non-IP locators for now */
317           if (gid_address_type (&lp->address) != GID_ADDR_IP_PREFIX)
318             continue;
319
320           if ((found && lp->priority == limitp)
321               || (!found && lp->priority >= limitp))
322             {
323               rmt = lp;
324
325               /* don't search for locators with lower priority and don't
326                * check this locator again*/
327               limitp = lp->priority;
328               hash_set (checked, i, 1);
329               break;
330             }
331         }
332       /* check if a local locator with a route to remote locator exists */
333       if (rmt != 0)
334         {
335           /* find egress sw_if_index for rmt locator */
336           esi =
337             ip_fib_get_egress_iface_for_dst (lcm,
338                                              &gid_address_ip (&rmt->address));
339           if ((u32) ~ 0 == esi)
340             continue;
341
342           for (i = 0; i < vec_len (lcl_ls->locator_indices); i++)
343             {
344               li = vec_elt (lcl_ls->locator_indices, i);
345               locator_t *sl = pool_elt_at_index (lcm->locator_pool, li);
346
347               /* found local locator with the needed sw_if_index */
348               if (sl->sw_if_index == esi)
349                 {
350                   /* and it has an address */
351                   if (0 == ip_interface_get_first_ip_address (lcm,
352                                                               sl->sw_if_index,
353                                                               gid_address_ip_version
354                                                               (&rmt->address),
355                                                               lcl_addr))
356                     continue;
357
358                   memset (&pair, 0, sizeof (pair));
359                   ip_address_copy (&pair.rmt_loc,
360                                    &gid_address_ip (&rmt->address));
361                   ip_address_copy (&pair.lcl_loc, lcl_addr);
362                   pair.weight = rmt->weight;
363                   vec_add1 (locator_pairs[0], pair);
364                   found = 1;
365                 }
366             }
367         }
368       else
369         break;
370     }
371
372   hash_free (checked);
373   return found;
374 }
375
376 static void
377 gid_address_sd_to_flat (gid_address_t * dst, gid_address_t * src,
378                         fid_address_t * fid)
379 {
380   ASSERT (GID_ADDR_SRC_DST == gid_address_type (src));
381
382   dst[0] = src[0];
383
384   switch (fid_addr_type (fid))
385     {
386     case FID_ADDR_IP_PREF:
387       gid_address_type (dst) = GID_ADDR_IP_PREFIX;
388       gid_address_ippref (dst) = fid_addr_ippref (fid);
389       break;
390     case FID_ADDR_MAC:
391       gid_address_type (dst) = GID_ADDR_MAC;
392       mac_copy (gid_address_mac (dst), fid_addr_mac (fid));
393       break;
394     default:
395       clib_warning ("Unsupported fid type %d!", fid_addr_type (fid));
396       break;
397     }
398 }
399
400 u8
401 vnet_lisp_map_register_state_get (void)
402 {
403   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
404   return lcm->map_registering;
405 }
406
407 u8
408 vnet_lisp_rloc_probe_state_get (void)
409 {
410   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
411   return lcm->rloc_probing;
412 }
413
414 static void
415 dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
416 {
417   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
418   mapping_t *src_map, *dst_map;
419   u32 sw_if_index;
420   uword *feip = 0, *dpid;
421   fwd_entry_t *fe;
422   u8 type, is_src_dst = 0;
423
424   memset (a, 0, sizeof (*a));
425
426   /* remove entry if it already exists */
427   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
428   if (feip)
429     dp_del_fwd_entry (lcm, src_map_index, dst_map_index);
430
431   if (lcm->lisp_pitr)
432     src_map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
433   else
434     src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
435   dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
436
437   /* insert data plane forwarding entry */
438   a->is_add = 1;
439
440   if (MR_MODE_SRC_DST == lcm->map_request_mode)
441     {
442       if (GID_ADDR_SRC_DST == gid_address_type (&dst_map->eid))
443         {
444           gid_address_sd_to_flat (&a->rmt_eid, &dst_map->eid,
445                                   &gid_address_sd_dst (&dst_map->eid));
446           gid_address_sd_to_flat (&a->lcl_eid, &dst_map->eid,
447                                   &gid_address_sd_src (&dst_map->eid));
448         }
449       else
450         {
451           gid_address_copy (&a->rmt_eid, &dst_map->eid);
452           gid_address_copy (&a->lcl_eid, &src_map->eid);
453         }
454       is_src_dst = 1;
455     }
456   else
457     gid_address_copy (&a->rmt_eid, &dst_map->eid);
458
459   a->vni = gid_address_vni (&a->rmt_eid);
460
461   /* get vrf or bd_index associated to vni */
462   type = gid_address_type (&a->rmt_eid);
463   if (GID_ADDR_IP_PREFIX == type)
464     {
465       dpid = hash_get (lcm->table_id_by_vni, a->vni);
466       if (!dpid)
467         {
468           clib_warning ("vni %d not associated to a vrf!", a->vni);
469           return;
470         }
471       a->table_id = dpid[0];
472     }
473   else if (GID_ADDR_MAC == type)
474     {
475       dpid = hash_get (lcm->bd_id_by_vni, a->vni);
476       if (!dpid)
477         {
478           clib_warning ("vni %d not associated to a bridge domain !", a->vni);
479           return;
480         }
481       a->bd_id = dpid[0];
482     }
483
484   /* find best locator pair that 1) verifies LISP policy 2) are connected */
485   if (0 == get_locator_pairs (lcm, src_map, dst_map, &a->locator_pairs))
486     {
487       /* negative entry */
488       a->is_negative = 1;
489       a->action = dst_map->action;
490     }
491
492   /* TODO remove */
493   u8 ipver = ip_prefix_version (&gid_address_ippref (&a->rmt_eid));
494   a->decap_next_index = (ipver == IP4) ?
495     LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
496
497   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
498
499   /* add tunnel to fwd entry table XXX check return value from DP insertion */
500   pool_get (lcm->fwd_entry_pool, fe);
501   fe->locator_pairs = a->locator_pairs;
502   gid_address_copy (&fe->reid, &a->rmt_eid);
503   gid_address_copy (&fe->leid, &src_map->eid);
504   fe->is_src_dst = is_src_dst;
505   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
506             fe - lcm->fwd_entry_pool);
507 }
508
509 /**
510  * Returns vector of adjacencies.
511  *
512  * The caller must free the vector returned by this function.
513  *
514  * @param vni virtual network identifier
515  * @return vector of adjacencies
516  */
517 lisp_adjacency_t *
518 vnet_lisp_adjacencies_get_by_vni (u32 vni)
519 {
520   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
521   fwd_entry_t *fwd;
522   lisp_adjacency_t *adjs = 0, adj;
523
524   /* *INDENT-OFF* */
525   pool_foreach(fwd, lcm->fwd_entry_pool,
526   ({
527     if (gid_address_vni (&fwd->reid) != vni)
528       continue;
529
530     gid_address_copy (&adj.reid, &fwd->reid);
531     gid_address_copy (&adj.leid, &fwd->leid);
532     vec_add1 (adjs, adj);
533   }));
534   /* *INDENT-ON* */
535
536   return adjs;
537 }
538
539 static clib_error_t *
540 lisp_show_adjacencies_command_fn (vlib_main_t * vm,
541                                   unformat_input_t * input,
542                                   vlib_cli_command_t * cmd)
543 {
544   lisp_adjacency_t *adjs, *adj;
545   vlib_cli_output (vm, "%s %40s\n", "leid", "reid");
546   unformat_input_t _line_input, *line_input = &_line_input;
547   u32 vni = ~0;
548
549   /* Get a line of input. */
550   if (!unformat_user (input, unformat_line_input, line_input))
551     return 0;
552
553   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
554     {
555       if (unformat (line_input, "vni %d", &vni))
556         ;
557       else
558         {
559           vlib_cli_output (vm, "parse error: '%U'",
560                            format_unformat_error, line_input);
561           return 0;
562         }
563     }
564
565   if (~0 == vni)
566     {
567       vlib_cli_output (vm, "error: no vni specified!");
568       return 0;
569     }
570
571   adjs = vnet_lisp_adjacencies_get_by_vni (vni);
572
573   vec_foreach (adj, adjs)
574   {
575     vlib_cli_output (vm, "%U %40U\n", format_gid_address, &adj->leid,
576                      format_gid_address, &adj->reid);
577   }
578   vec_free (adjs);
579
580   return 0;
581 }
582
583 /* *INDENT-OFF* */
584 VLIB_CLI_COMMAND (lisp_show_adjacencies_command) = {
585     .path = "show lisp adjacencies",
586     .short_help = "show lisp adjacencies",
587     .function = lisp_show_adjacencies_command_fn,
588 };
589 /* *INDENT-ON* */
590
591 static lisp_msmr_t *
592 get_map_server (ip_address_t * a)
593 {
594   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
595   lisp_msmr_t *m;
596
597   vec_foreach (m, lcm->map_servers)
598   {
599     if (!ip_address_cmp (&m->address, a))
600       {
601         return m;
602       }
603   }
604   return 0;
605 }
606
607 static lisp_msmr_t *
608 get_map_resolver (ip_address_t * a)
609 {
610   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
611   lisp_msmr_t *m;
612
613   vec_foreach (m, lcm->map_resolvers)
614   {
615     if (!ip_address_cmp (&m->address, a))
616       {
617         return m;
618       }
619   }
620   return 0;
621 }
622
623 int
624 vnet_lisp_add_del_map_server (ip_address_t * addr, u8 is_add)
625 {
626   u32 i;
627   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
628   lisp_msmr_t _ms, *ms = &_ms;
629
630   if (vnet_lisp_enable_disable_status () == 0)
631     {
632       clib_warning ("LISP is disabled!");
633       return VNET_API_ERROR_LISP_DISABLED;
634     }
635
636   if (is_add)
637     {
638       if (get_map_server (addr))
639         {
640           clib_warning ("map-server %U already exists!", format_ip_address,
641                         addr);
642           return -1;
643         }
644
645       memset (ms, 0, sizeof (*ms));
646       ip_address_copy (&ms->address, addr);
647       vec_add1 (lcm->map_servers, ms[0]);
648     }
649   else
650     {
651       for (i = 0; i < vec_len (lcm->map_servers); i++)
652         {
653           ms = vec_elt_at_index (lcm->map_servers, i);
654           if (!ip_address_cmp (&ms->address, addr))
655             {
656               vec_del1 (lcm->map_servers, i);
657               break;
658             }
659         }
660     }
661
662   return 0;
663 }
664
665 static clib_error_t *
666 lisp_add_del_map_server_command_fn (vlib_main_t * vm,
667                                     unformat_input_t * input,
668                                     vlib_cli_command_t * cmd)
669 {
670   int rv = 0;
671   u8 is_add = 1, ip_set = 0;
672   ip_address_t ip;
673   unformat_input_t _line_input, *line_input = &_line_input;
674
675   /* Get a line of input. */
676   if (!unformat_user (input, unformat_line_input, line_input))
677     return 0;
678
679   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
680     {
681       if (unformat (line_input, "add"))
682         is_add = 1;
683       else if (unformat (line_input, "del"))
684         is_add = 0;
685       else if (unformat (line_input, "%U", unformat_ip_address, &ip))
686         ip_set = 1;
687       else
688         {
689           vlib_cli_output (vm, "parse error: '%U'",
690                            format_unformat_error, line_input);
691           return 0;
692         }
693     }
694
695   if (!ip_set)
696     {
697       vlib_cli_output (vm, "map-server ip address not set!");
698       return 0;
699     }
700
701   rv = vnet_lisp_add_del_map_server (&ip, is_add);
702   if (!rv)
703     vlib_cli_output (vm, "failed to %s map-server!",
704                      is_add ? "add" : "delete");
705
706   return 0;
707 }
708
709 /* *INDENT-OFF* */
710 VLIB_CLI_COMMAND (lisp_add_del_map_server_command) = {
711     .path = "lisp map-server",
712     .short_help = "lisp map-server add|del <ip>",
713     .function = lisp_add_del_map_server_command_fn,
714 };
715 /* *INDENT-ON* */
716
717 /**
718  * Add/remove mapping to/from map-cache. Overwriting not allowed.
719  */
720 int
721 vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a,
722                              u32 * map_index_result)
723 {
724   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
725   u32 mi, *map_indexp, map_index, i;
726   mapping_t *m, *old_map;
727   u32 **eid_indexes;
728
729   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid);
730   old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
731   if (a->is_add)
732     {
733       /* TODO check if overwriting and take appropriate actions */
734       if (mi != GID_LOOKUP_MISS && !gid_address_cmp (&old_map->eid, &a->eid))
735         {
736           clib_warning ("eid %U found in the eid-table", format_gid_address,
737                         &a->eid);
738           return VNET_API_ERROR_VALUE_EXIST;
739         }
740
741       pool_get (lcm->mapping_pool, m);
742       gid_address_copy (&m->eid, &a->eid);
743       m->locator_set_index = a->locator_set_index;
744       m->ttl = a->ttl;
745       m->action = a->action;
746       m->local = a->local;
747       m->is_static = a->is_static;
748       m->key = vec_dup (a->key);
749       m->key_id = a->key_id;
750
751       map_index = m - lcm->mapping_pool;
752       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, map_index,
753                               1);
754
755       if (pool_is_free_index (lcm->locator_set_pool, a->locator_set_index))
756         {
757           clib_warning ("Locator set with index %d doesn't exist",
758                         a->locator_set_index);
759           return VNET_API_ERROR_INVALID_VALUE;
760         }
761
762       /* add eid to list of eids supported by locator-set */
763       vec_validate (lcm->locator_set_to_eids, a->locator_set_index);
764       eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
765                                       a->locator_set_index);
766       vec_add1 (eid_indexes[0], map_index);
767
768       if (a->local)
769         {
770           /* mark as local */
771           vec_add1 (lcm->local_mappings_indexes, map_index);
772         }
773       map_index_result[0] = map_index;
774     }
775   else
776     {
777       if (mi == GID_LOOKUP_MISS)
778         {
779           clib_warning ("eid %U not found in the eid-table",
780                         format_gid_address, &a->eid);
781           return VNET_API_ERROR_INVALID_VALUE;
782         }
783
784       /* clear locator-set to eids binding */
785       eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
786                                       a->locator_set_index);
787       for (i = 0; i < vec_len (eid_indexes[0]); i++)
788         {
789           map_indexp = vec_elt_at_index (eid_indexes[0], i);
790           if (map_indexp[0] == mi)
791             break;
792         }
793       vec_del1 (eid_indexes[0], i);
794
795       /* remove local mark if needed */
796       m = pool_elt_at_index (lcm->mapping_pool, mi);
797       if (m->local)
798         {
799           u32 k, *lm_indexp;
800           for (k = 0; k < vec_len (lcm->local_mappings_indexes); k++)
801             {
802               lm_indexp = vec_elt_at_index (lcm->local_mappings_indexes, k);
803               if (lm_indexp[0] == mi)
804                 break;
805             }
806           vec_del1 (lcm->local_mappings_indexes, k);
807         }
808
809       /* remove mapping from dictionary */
810       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, 0, 0);
811       gid_address_free (&m->eid);
812       pool_put_index (lcm->mapping_pool, mi);
813     }
814
815   return 0;
816 }
817
818 /**
819  *  Add/update/delete mapping to/in/from map-cache.
820  */
821 int
822 vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
823                                  u32 * map_index_result)
824 {
825   uword *dp_table = 0;
826   u32 vni;
827   u8 type;
828
829   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
830
831   if (vnet_lisp_enable_disable_status () == 0)
832     {
833       clib_warning ("LISP is disabled!");
834       return VNET_API_ERROR_LISP_DISABLED;
835     }
836
837   vni = gid_address_vni (&a->eid);
838   type = gid_address_type (&a->eid);
839   if (GID_ADDR_IP_PREFIX == type)
840     dp_table = hash_get (lcm->table_id_by_vni, vni);
841   else if (GID_ADDR_MAC == type)
842     dp_table = hash_get (lcm->bd_id_by_vni, vni);
843
844   if (!dp_table)
845     {
846       clib_warning ("vni %d not associated to a %s!", vni,
847                     GID_ADDR_IP_PREFIX == type ? "vrf" : "bd");
848       return VNET_API_ERROR_INVALID_VALUE;
849     }
850
851   /* store/remove mapping from map-cache */
852   return vnet_lisp_map_cache_add_del (a, map_index_result);
853 }
854
855 static clib_error_t *
856 lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
857                                    vlib_cli_command_t * cmd)
858 {
859   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
860   unformat_input_t _line_input, *line_input = &_line_input;
861   u8 is_add = 1;
862   gid_address_t eid;
863   gid_address_t *eids = 0;
864   clib_error_t *error = 0;
865   u8 *locator_set_name = 0;
866   u32 locator_set_index = 0, map_index = 0;
867   uword *p;
868   vnet_lisp_add_del_mapping_args_t _a, *a = &_a;
869   int rv = 0;
870   u32 vni = 0;
871   u8 *key = 0;
872   u32 key_id = 0;
873
874   memset (&eid, 0, sizeof (eid));
875   memset (a, 0, sizeof (*a));
876
877   /* Get a line of input. */
878   if (!unformat_user (input, unformat_line_input, line_input))
879     return 0;
880
881   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
882     {
883       if (unformat (line_input, "add"))
884         is_add = 1;
885       else if (unformat (line_input, "del"))
886         is_add = 0;
887       else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
888         ;
889       else if (unformat (line_input, "vni %d", &vni))
890         gid_address_vni (&eid) = vni;
891       else if (unformat (line_input, "secret-key %_%v%_", &key))
892         ;
893       else if (unformat (line_input, "key-id %U", unformat_hmac_key_id,
894                          &key_id))
895         ;
896       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
897         {
898           p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
899           if (!p)
900             {
901               error = clib_error_return (0, "locator-set %s doesn't exist",
902                                          locator_set_name);
903               goto done;
904             }
905           locator_set_index = p[0];
906         }
907       else
908         {
909           error = unformat_parse_error (line_input);
910           goto done;
911         }
912     }
913   /* XXX treat batch configuration */
914
915   if (GID_ADDR_SRC_DST == gid_address_type (&eid))
916     {
917       error =
918         clib_error_return (0, "src/dst is not supported for local EIDs!");
919       goto done;
920     }
921
922   if (key && (0 == key_id))
923     {
924       vlib_cli_output (vm, "invalid key_id!");
925       return 0;
926     }
927
928   gid_address_copy (&a->eid, &eid);
929   a->is_add = is_add;
930   a->locator_set_index = locator_set_index;
931   a->local = 1;
932   a->key = key;
933   a->key_id = key_id;
934
935   rv = vnet_lisp_add_del_local_mapping (a, &map_index);
936   if (0 != rv)
937     {
938       error = clib_error_return (0, "failed to %s local mapping!",
939                                  is_add ? "add" : "delete");
940     }
941 done:
942   vec_free (eids);
943   if (locator_set_name)
944     vec_free (locator_set_name);
945   gid_address_free (&a->eid);
946   vec_free (a->key);
947   return error;
948 }
949
950 /* *INDENT-OFF* */
951 VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = {
952     .path = "lisp eid-table",
953     .short_help = "lisp eid-table add/del [vni <vni>] eid <eid> "
954       "locator-set <locator-set> [key <secret-key> key-id sha1|sha256 ]",
955     .function = lisp_add_del_local_eid_command_fn,
956 };
957 /* *INDENT-ON* */
958
959 int
960 vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add)
961 {
962   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
963   uword *dp_idp, *vnip, **dp_table_by_vni, **vni_by_dp_table;
964
965   if (vnet_lisp_enable_disable_status () == 0)
966     {
967       clib_warning ("LISP is disabled!");
968       return -1;
969     }
970
971   dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni;
972   vni_by_dp_table = is_l2 ? &lcm->vni_by_bd_id : &lcm->vni_by_table_id;
973
974   if (!is_l2 && (vni == 0 || dp_id == 0))
975     {
976       clib_warning ("can't add/del default vni-vrf mapping!");
977       return -1;
978     }
979
980   dp_idp = hash_get (dp_table_by_vni[0], vni);
981   vnip = hash_get (vni_by_dp_table[0], dp_id);
982
983   if (is_add)
984     {
985       if (dp_idp || vnip)
986         {
987           clib_warning ("vni %d or vrf %d already used in vrf/vni "
988                         "mapping!", vni, dp_id);
989           return -1;
990         }
991       hash_set (dp_table_by_vni[0], vni, dp_id);
992       hash_set (vni_by_dp_table[0], dp_id, vni);
993
994       /* create dp iface */
995       dp_add_del_iface (lcm, vni, is_l2, 1);
996     }
997   else
998     {
999       if (!dp_idp || !vnip)
1000         {
1001           clib_warning ("vni %d or vrf %d not used in any vrf/vni! "
1002                         "mapping!", vni, dp_id);
1003           return -1;
1004         }
1005       hash_unset (dp_table_by_vni[0], vni);
1006       hash_unset (vni_by_dp_table[0], dp_id);
1007
1008       /* remove dp iface */
1009       dp_add_del_iface (lcm, vni, is_l2, 0);
1010     }
1011   return 0;
1012
1013 }
1014
1015 static clib_error_t *
1016 lisp_eid_table_map_command_fn (vlib_main_t * vm,
1017                                unformat_input_t * input,
1018                                vlib_cli_command_t * cmd)
1019 {
1020   u8 is_add = 1, is_l2 = 0;
1021   u32 vni = 0, dp_id = 0;
1022   unformat_input_t _line_input, *line_input = &_line_input;
1023
1024   /* Get a line of input. */
1025   if (!unformat_user (input, unformat_line_input, line_input))
1026     return 0;
1027
1028   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1029     {
1030       if (unformat (line_input, "del"))
1031         is_add = 0;
1032       else if (unformat (line_input, "vni %d", &vni))
1033         ;
1034       else if (unformat (line_input, "vrf %d", &dp_id))
1035         ;
1036       else if (unformat (line_input, "bd %d", &dp_id))
1037         is_l2 = 1;
1038       else
1039         {
1040           return unformat_parse_error (line_input);
1041         }
1042     }
1043   vnet_lisp_eid_table_map (vni, dp_id, is_l2, is_add);
1044   return 0;
1045 }
1046
1047 /* *INDENT-OFF* */
1048 VLIB_CLI_COMMAND (lisp_eid_table_map_command) = {
1049     .path = "lisp eid-table map",
1050     .short_help = "lisp eid-table map [del] vni <vni> vrf <vrf> | bd <bdi>",
1051     .function = lisp_eid_table_map_command_fn,
1052 };
1053 /* *INDENT-ON* */
1054
1055 /* return 0 if the two locator sets are identical 1 otherwise */
1056 static u8
1057 compare_locators (lisp_cp_main_t * lcm, u32 * old_ls_indexes,
1058                   locator_t * new_locators)
1059 {
1060   u32 i, old_li;
1061   locator_t *old_loc, *new_loc;
1062
1063   if (vec_len (old_ls_indexes) != vec_len (new_locators))
1064     return 1;
1065
1066   for (i = 0; i < vec_len (new_locators); i++)
1067     {
1068       old_li = vec_elt (old_ls_indexes, i);
1069       old_loc = pool_elt_at_index (lcm->locator_pool, old_li);
1070
1071       new_loc = vec_elt_at_index (new_locators, i);
1072
1073       if (locator_cmp (old_loc, new_loc))
1074         return 1;
1075     }
1076   return 0;
1077 }
1078
1079 typedef struct
1080 {
1081   u8 is_negative;
1082   void *lcm;
1083   gid_address_t *eids_to_be_deleted;
1084 } remove_mapping_args_t;
1085
1086 /**
1087  * Callback invoked when a sub-prefix is found
1088  */
1089 static void
1090 remove_mapping_if_needed (u32 mi, void *arg)
1091 {
1092   u8 delete = 0;
1093   remove_mapping_args_t *a = arg;
1094   lisp_cp_main_t *lcm = a->lcm;
1095   mapping_t *m;
1096   locator_set_t *ls;
1097
1098   m = pool_elt_at_index (lcm->mapping_pool, mi);
1099   if (!m)
1100     return;
1101
1102   ls = pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
1103
1104   if (a->is_negative)
1105     {
1106       if (0 != vec_len (ls->locator_indices))
1107         delete = 1;
1108     }
1109   else
1110     {
1111       if (0 == vec_len (ls->locator_indices))
1112         delete = 1;
1113     }
1114
1115   if (delete)
1116     vec_add1 (a->eids_to_be_deleted, m->eid);
1117 }
1118
1119 /**
1120  * This function searches map cache and looks for IP prefixes that are subset
1121  * of the provided one. If such prefix is found depending on 'is_negative'
1122  * it does follows:
1123  *
1124  * 1) if is_negative is true and found prefix points to positive mapping,
1125  *    then the mapping is removed
1126  * 2) if is_negative is false and found prefix points to negative mapping,
1127  *    then the mapping is removed
1128  */
1129 static void
1130 remove_overlapping_sub_prefixes (lisp_cp_main_t * lcm, gid_address_t * eid,
1131                                  u8 is_negative)
1132 {
1133   gid_address_t *e;
1134   remove_mapping_args_t a;
1135   memset (&a, 0, sizeof (a));
1136
1137   /* do this only in src/dst mode ... */
1138   if (MR_MODE_SRC_DST != lcm->map_request_mode)
1139     return;
1140
1141   /* ... and  only for IP prefix */
1142   if (GID_ADDR_SRC_DST != gid_address_type (eid)
1143       || (FID_ADDR_IP_PREF != gid_address_sd_dst_type (eid)))
1144     return;
1145
1146   a.is_negative = is_negative;
1147   a.lcm = lcm;
1148
1149   gid_dict_foreach_subprefix (&lcm->mapping_index_by_gid, eid,
1150                               remove_mapping_if_needed, &a);
1151
1152   vec_foreach (e, a.eids_to_be_deleted)
1153     vnet_lisp_add_del_mapping (e, 0, 0, 0, 0, 0 /* is add */ , 0, 0);
1154
1155   vec_free (a.eids_to_be_deleted);
1156 }
1157
1158 /**
1159  * Adds/removes/updates mapping. Does not program forwarding.
1160  *
1161  * @param eid end-host identifier
1162  * @param rlocs vector of remote locators
1163  * @param action action for negative map-reply
1164  * @param is_add add mapping if non-zero, delete otherwise
1165  * @param res_map_index the map-index that was created/updated/removed. It is
1166  *                      set to ~0 if no action is taken.
1167  * @param is_static used for distinguishing between statically learned
1168                     remote mappings and mappings obtained from MR
1169  * @return return code
1170  */
1171 int
1172 vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
1173                            u8 authoritative, u32 ttl, u8 is_add, u8 is_static,
1174                            u32 * res_map_index)
1175 {
1176   vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args;
1177   vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
1178   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1179   u32 mi, ls_index = 0, dst_map_index;
1180   mapping_t *old_map;
1181
1182   if (vnet_lisp_enable_disable_status () == 0)
1183     {
1184       clib_warning ("LISP is disabled!");
1185       return VNET_API_ERROR_LISP_DISABLED;
1186     }
1187
1188   if (res_map_index)
1189     res_map_index[0] = ~0;
1190
1191   memset (m_args, 0, sizeof (m_args[0]));
1192   memset (ls_args, 0, sizeof (ls_args[0]));
1193
1194   ls_args->locators = rlocs;
1195
1196   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid);
1197   old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
1198
1199   if (is_add)
1200     {
1201       /* overwrite: if mapping already exists, decide if locators should be
1202        * updated and be done */
1203       if (old_map && gid_address_cmp (&old_map->eid, eid) == 0)
1204         {
1205           if (!is_static && (old_map->is_static || old_map->local))
1206             {
1207               /* do not overwrite local or static remote mappings */
1208               clib_warning ("mapping %U rejected due to collision with local "
1209                             "or static remote mapping!", format_gid_address,
1210                             eid);
1211               return 0;
1212             }
1213
1214           locator_set_t *old_ls;
1215
1216           /* update mapping attributes */
1217           old_map->action = action;
1218           old_map->authoritative = authoritative;
1219           old_map->ttl = ttl;
1220
1221           old_ls = pool_elt_at_index (lcm->locator_set_pool,
1222                                       old_map->locator_set_index);
1223           if (compare_locators (lcm, old_ls->locator_indices,
1224                                 ls_args->locators))
1225             {
1226               /* set locator-set index to overwrite */
1227               ls_args->is_add = 1;
1228               ls_args->index = old_map->locator_set_index;
1229               vnet_lisp_add_del_locator_set (ls_args, 0);
1230               if (res_map_index)
1231                 res_map_index[0] = mi;
1232             }
1233         }
1234       /* new mapping */
1235       else
1236         {
1237           remove_overlapping_sub_prefixes (lcm, eid, 0 == ls_args->locators);
1238
1239           ls_args->is_add = 1;
1240           ls_args->index = ~0;
1241
1242           vnet_lisp_add_del_locator_set (ls_args, &ls_index);
1243
1244           /* add mapping */
1245           gid_address_copy (&m_args->eid, eid);
1246           m_args->is_add = 1;
1247           m_args->action = action;
1248           m_args->locator_set_index = ls_index;
1249           m_args->is_static = is_static;
1250           vnet_lisp_map_cache_add_del (m_args, &dst_map_index);
1251
1252           if (res_map_index)
1253             res_map_index[0] = dst_map_index;
1254         }
1255     }
1256   else
1257     {
1258       if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0)
1259         {
1260           clib_warning ("cannot delete mapping for eid %U",
1261                         format_gid_address, eid);
1262           return -1;
1263         }
1264
1265       m_args->is_add = 0;
1266       gid_address_copy (&m_args->eid, eid);
1267       m_args->locator_set_index = old_map->locator_set_index;
1268
1269       /* delete mapping associated from map-cache */
1270       vnet_lisp_map_cache_add_del (m_args, 0);
1271
1272       ls_args->is_add = 0;
1273       ls_args->index = old_map->locator_set_index;
1274       /* delete locator set */
1275       vnet_lisp_add_del_locator_set (ls_args, 0);
1276
1277       /* return old mapping index */
1278       if (res_map_index)
1279         res_map_index[0] = mi;
1280     }
1281
1282   /* success */
1283   return 0;
1284 }
1285
1286 int
1287 vnet_lisp_clear_all_remote_adjacencies (void)
1288 {
1289   int rv = 0;
1290   u32 mi, *map_indices = 0, *map_indexp;
1291   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1292   vnet_lisp_add_del_mapping_args_t _dm_args, *dm_args = &_dm_args;
1293   vnet_lisp_add_del_locator_set_args_t _ls, *ls = &_ls;
1294
1295   /* *INDENT-OFF* */
1296   pool_foreach_index (mi, lcm->mapping_pool,
1297   ({
1298     vec_add1 (map_indices, mi);
1299   }));
1300   /* *INDENT-ON* */
1301
1302   vec_foreach (map_indexp, map_indices)
1303   {
1304     mapping_t *map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
1305     if (!map->local)
1306       {
1307         dp_del_fwd_entry (lcm, 0, map_indexp[0]);
1308
1309         dm_args->is_add = 0;
1310         gid_address_copy (&dm_args->eid, &map->eid);
1311         dm_args->locator_set_index = map->locator_set_index;
1312
1313         /* delete mapping associated to fwd entry */
1314         vnet_lisp_map_cache_add_del (dm_args, 0);
1315
1316         ls->is_add = 0;
1317         ls->local = 0;
1318         ls->index = map->locator_set_index;
1319         /* delete locator set */
1320         rv = vnet_lisp_add_del_locator_set (ls, 0);
1321         if (rv != 0)
1322           goto cleanup;
1323       }
1324   }
1325
1326 cleanup:
1327   if (map_indices)
1328     vec_free (map_indices);
1329   return rv;
1330 }
1331
1332 /**
1333  * Adds adjacency or removes forwarding entry associated to remote mapping.
1334  * Note that adjacencies are not stored, they only result in forwarding entries
1335  * being created.
1336  */
1337 int
1338 lisp_add_del_adjacency (lisp_cp_main_t * lcm, gid_address_t * local_eid,
1339                         gid_address_t * remote_eid, u8 is_add)
1340 {
1341   u32 local_mi, remote_mi = ~0;
1342
1343   if (vnet_lisp_enable_disable_status () == 0)
1344     {
1345       clib_warning ("LISP is disabled!");
1346       return VNET_API_ERROR_LISP_DISABLED;
1347     }
1348
1349   remote_mi = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid,
1350                                         remote_eid, local_eid);
1351   if (GID_LOOKUP_MISS == remote_mi)
1352     {
1353       clib_warning ("Remote eid %U not found. Cannot add adjacency!",
1354                     format_gid_address, remote_eid);
1355
1356       return -1;
1357     }
1358
1359   if (is_add)
1360     {
1361       /* TODO 1) check if src/dst 2) once we have src/dst working, use it in
1362        * delete*/
1363
1364       /* check if source eid has an associated mapping. If pitr mode is on,
1365        * just use the pitr's mapping */
1366       local_mi = lcm->lisp_pitr ? lcm->pitr_map_index :
1367         gid_dictionary_lookup (&lcm->mapping_index_by_gid, local_eid);
1368
1369
1370       if (GID_LOOKUP_MISS == local_mi)
1371         {
1372           clib_warning ("Local eid %U not found. Cannot add adjacency!",
1373                         format_gid_address, local_eid);
1374
1375           return -1;
1376         }
1377
1378       /* update forwarding */
1379       dp_add_fwd_entry (lcm, local_mi, remote_mi);
1380     }
1381   else
1382     dp_del_fwd_entry (lcm, 0, remote_mi);
1383
1384   return 0;
1385 }
1386
1387 int
1388 vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a)
1389 {
1390   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1391   return lisp_add_del_adjacency (lcm, &a->leid, &a->reid, a->is_add);
1392 }
1393
1394 /**
1395  * Handler for add/del remote mapping CLI.
1396  *
1397  * @param vm vlib context
1398  * @param input input from user
1399  * @param cmd cmd
1400  * @return pointer to clib error structure
1401  */
1402 static clib_error_t *
1403 lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
1404                                         unformat_input_t * input,
1405                                         vlib_cli_command_t * cmd)
1406 {
1407   clib_error_t *error = 0;
1408   unformat_input_t _line_input, *line_input = &_line_input;
1409   u8 is_add = 1, del_all = 0;
1410   locator_t rloc, *rlocs = 0, *curr_rloc = 0;
1411   gid_address_t eid;
1412   u8 eid_set = 0;
1413   u32 vni, action = ~0, p, w;
1414   int rv;
1415
1416   /* Get a line of input. */
1417   if (!unformat_user (input, unformat_line_input, line_input))
1418     return 0;
1419
1420   memset (&eid, 0, sizeof (eid));
1421   memset (&rloc, 0, sizeof (rloc));
1422
1423   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1424     {
1425       if (unformat (line_input, "del-all"))
1426         del_all = 1;
1427       else if (unformat (line_input, "del"))
1428         is_add = 0;
1429       else if (unformat (line_input, "add"))
1430         ;
1431       else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
1432         eid_set = 1;
1433       else if (unformat (line_input, "vni %u", &vni))
1434         {
1435           gid_address_vni (&eid) = vni;
1436         }
1437       else if (unformat (line_input, "p %d w %d", &p, &w))
1438         {
1439           if (!curr_rloc)
1440             {
1441               clib_warning
1442                 ("No RLOC configured for setting priority/weight!");
1443               goto done;
1444             }
1445           curr_rloc->priority = p;
1446           curr_rloc->weight = w;
1447         }
1448       else if (unformat (line_input, "rloc %U", unformat_ip_address,
1449                          &gid_address_ip (&rloc.address)))
1450         {
1451           /* since rloc is stored in ip prefix we need to set prefix length */
1452           ip_prefix_t *pref = &gid_address_ippref (&rloc.address);
1453
1454           u8 version = gid_address_ip_version (&rloc.address);
1455           ip_prefix_len (pref) = ip_address_max_len (version);
1456
1457           vec_add1 (rlocs, rloc);
1458           curr_rloc = &rlocs[vec_len (rlocs) - 1];
1459         }
1460       else if (unformat (line_input, "action %U",
1461                          unformat_negative_mapping_action, &action))
1462         ;
1463       else
1464         {
1465           clib_warning ("parse error");
1466           goto done;
1467         }
1468     }
1469
1470   if (!eid_set)
1471     {
1472       clib_warning ("missing eid!");
1473       goto done;
1474     }
1475
1476   if (!del_all)
1477     {
1478       if (is_add && (~0 == action) && 0 == vec_len (rlocs))
1479         {
1480           clib_warning ("no action set for negative map-reply!");
1481           goto done;
1482         }
1483     }
1484   else
1485     {
1486       vnet_lisp_clear_all_remote_adjacencies ();
1487       goto done;
1488     }
1489
1490   /* TODO build src/dst with seid */
1491
1492   /* if it's a delete, clean forwarding */
1493   if (!is_add)
1494     {
1495       lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1496       rv = lisp_add_del_adjacency (lcm, 0, &eid, /* is_add */ 0);
1497       if (rv)
1498         {
1499           goto done;
1500         }
1501     }
1502
1503   /* add as static remote mapping, i.e., not authoritative and infinite
1504    * ttl */
1505   rv = vnet_lisp_add_del_mapping (&eid, rlocs, action, 0, ~0, is_add,
1506                                   1 /* is_static */ , 0);
1507
1508   if (rv)
1509     clib_warning ("failed to %s remote mapping!", is_add ? "add" : "delete");
1510
1511 done:
1512   vec_free (rlocs);
1513   unformat_free (line_input);
1514   return error;
1515 }
1516
1517 VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) =
1518 {
1519 .path = "lisp remote-mapping",.short_help =
1520     "lisp remote-mapping add|del [del-all] vni <vni> "
1521     "eid <est-eid> [action <no-action|natively-forward|"
1522     "send-map-request|drop>] rloc <dst-locator> p <prio> w <weight> "
1523     "[rloc <dst-locator> ... ]",.function =
1524     lisp_add_del_remote_mapping_command_fn,};
1525
1526 /**
1527  * Handler for add/del adjacency CLI.
1528  */
1529 static clib_error_t *
1530 lisp_add_del_adjacency_command_fn (vlib_main_t * vm, unformat_input_t * input,
1531                                    vlib_cli_command_t * cmd)
1532 {
1533   clib_error_t *error = 0;
1534   unformat_input_t _line_input, *line_input = &_line_input;
1535   vnet_lisp_add_del_adjacency_args_t _a, *a = &_a;
1536   u8 is_add = 1;
1537   ip_prefix_t *reid_ippref, *leid_ippref;
1538   gid_address_t leid, reid;
1539   u8 *dmac = gid_address_mac (&reid);
1540   u8 *smac = gid_address_mac (&leid);
1541   u8 reid_set = 0, leid_set = 0;
1542   u32 vni;
1543   int rv;
1544
1545   /* Get a line of input. */
1546   if (!unformat_user (input, unformat_line_input, line_input))
1547     return 0;
1548
1549   memset (&reid, 0, sizeof (reid));
1550   memset (&leid, 0, sizeof (leid));
1551
1552   leid_ippref = &gid_address_ippref (&leid);
1553   reid_ippref = &gid_address_ippref (&reid);
1554
1555   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1556     {
1557       if (unformat (line_input, "del"))
1558         is_add = 0;
1559       else if (unformat (line_input, "add"))
1560         ;
1561       else if (unformat (line_input, "reid %U",
1562                          unformat_ip_prefix, reid_ippref))
1563         {
1564           gid_address_type (&reid) = GID_ADDR_IP_PREFIX;
1565           reid_set = 1;
1566         }
1567       else if (unformat (line_input, "reid %U", unformat_mac_address, dmac))
1568         {
1569           gid_address_type (&reid) = GID_ADDR_MAC;
1570           reid_set = 1;
1571         }
1572       else if (unformat (line_input, "vni %u", &vni))
1573         {
1574           gid_address_vni (&leid) = vni;
1575           gid_address_vni (&reid) = vni;
1576         }
1577       else if (unformat (line_input, "leid %U",
1578                          unformat_ip_prefix, leid_ippref))
1579         {
1580           gid_address_type (&leid) = GID_ADDR_IP_PREFIX;
1581           leid_set = 1;
1582         }
1583       else if (unformat (line_input, "leid %U", unformat_mac_address, smac))
1584         {
1585           gid_address_type (&leid) = GID_ADDR_MAC;
1586           leid_set = 1;
1587         }
1588       else
1589         {
1590           clib_warning ("parse error");
1591           goto done;
1592         }
1593     }
1594
1595   if (!reid_set || !leid_set)
1596     {
1597       clib_warning ("missing remote or local eid!");
1598       goto done;
1599     }
1600
1601   if ((gid_address_type (&leid) != gid_address_type (&reid))
1602       || (gid_address_type (&reid) == GID_ADDR_IP_PREFIX
1603           && ip_prefix_version (reid_ippref)
1604           != ip_prefix_version (leid_ippref)))
1605     {
1606       clib_warning ("remote and local EIDs are of different types!");
1607       return error;
1608     }
1609
1610   memset (a, 0, sizeof (a[0]));
1611   gid_address_copy (&a->leid, &leid);
1612   gid_address_copy (&a->reid, &reid);
1613
1614   a->is_add = is_add;
1615   rv = vnet_lisp_add_del_adjacency (a);
1616
1617   if (rv)
1618     clib_warning ("failed to %s adjacency!", is_add ? "add" : "delete");
1619
1620 done:
1621   unformat_free (line_input);
1622   return error;
1623 }
1624
1625 /* *INDENT-OFF* */
1626 VLIB_CLI_COMMAND (lisp_add_del_adjacency_command) = {
1627     .path = "lisp adjacency",
1628     .short_help = "lisp adjacency add|del vni <vni> reid <remote-eid> "
1629       "leid <local-eid>",
1630     .function = lisp_add_del_adjacency_command_fn,
1631 };
1632 /* *INDENT-ON* */
1633
1634 int
1635 vnet_lisp_set_map_request_mode (u8 mode)
1636 {
1637   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1638
1639   if (vnet_lisp_enable_disable_status () == 0)
1640     {
1641       clib_warning ("LISP is disabled!");
1642       return VNET_API_ERROR_LISP_DISABLED;
1643     }
1644
1645   if (mode >= _MR_MODE_MAX)
1646     {
1647       clib_warning ("Invalid LISP map request mode %d!", mode);
1648       return VNET_API_ERROR_INVALID_ARGUMENT;
1649     }
1650
1651   lcm->map_request_mode = mode;
1652   return 0;
1653 }
1654
1655 static clib_error_t *
1656 lisp_map_request_mode_command_fn (vlib_main_t * vm,
1657                                   unformat_input_t * input,
1658                                   vlib_cli_command_t * cmd)
1659 {
1660   unformat_input_t _i, *i = &_i;
1661   map_request_mode_t mr_mode = _MR_MODE_MAX;
1662
1663   /* Get a line of input. */
1664   if (!unformat_user (input, unformat_line_input, i))
1665     return 0;
1666
1667   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
1668     {
1669       if (unformat (i, "dst-only"))
1670         mr_mode = MR_MODE_DST_ONLY;
1671       else if (unformat (i, "src-dst"))
1672         mr_mode = MR_MODE_SRC_DST;
1673       else
1674         {
1675           clib_warning ("parse error '%U'", format_unformat_error, i);
1676           goto done;
1677         }
1678     }
1679
1680   if (_MR_MODE_MAX == mr_mode)
1681     {
1682       clib_warning ("No LISP map request mode entered!");
1683       return 0;
1684     }
1685
1686   vnet_lisp_set_map_request_mode (mr_mode);
1687 done:
1688   return 0;
1689 }
1690
1691 /* *INDENT-OFF* */
1692 VLIB_CLI_COMMAND (lisp_map_request_mode_command) = {
1693     .path = "lisp map-request mode",
1694     .short_help = "lisp map-request mode dst-only|src-dst",
1695     .function = lisp_map_request_mode_command_fn,
1696 };
1697 /* *INDENT-ON* */
1698
1699 static u8 *
1700 format_lisp_map_request_mode (u8 * s, va_list * args)
1701 {
1702   u32 mode = va_arg (*args, u32);
1703
1704   switch (mode)
1705     {
1706     case 0:
1707       return format (0, "dst-only");
1708     case 1:
1709       return format (0, "src-dst");
1710     }
1711   return 0;
1712 }
1713
1714 static clib_error_t *
1715 lisp_show_map_request_mode_command_fn (vlib_main_t * vm,
1716                                        unformat_input_t * input,
1717                                        vlib_cli_command_t * cmd)
1718 {
1719   vlib_cli_output (vm, "map-request mode: %U", format_lisp_map_request_mode,
1720                    vnet_lisp_get_map_request_mode ());
1721   return 0;
1722 }
1723
1724 /* *INDENT-OFF* */
1725 VLIB_CLI_COMMAND (lisp_show_map_request_mode_command) = {
1726     .path = "show lisp map-request mode",
1727     .short_help = "show lisp map-request mode",
1728     .function = lisp_show_map_request_mode_command_fn,
1729 };
1730 /* *INDENT-ON* */
1731
1732 static clib_error_t *
1733 lisp_show_map_resolvers_command_fn (vlib_main_t * vm,
1734                                     unformat_input_t * input,
1735                                     vlib_cli_command_t * cmd)
1736 {
1737   lisp_msmr_t *mr;
1738   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1739
1740   vec_foreach (mr, lcm->map_resolvers)
1741   {
1742     vlib_cli_output (vm, "%U", format_ip_address, &mr->address);
1743   }
1744   return 0;
1745 }
1746
1747 /* *INDENT-OFF* */
1748 VLIB_CLI_COMMAND (lisp_show_map_resolvers_command) = {
1749     .path = "show lisp map-resolvers",
1750     .short_help = "show lisp map-resolvers",
1751     .function = lisp_show_map_resolvers_command_fn,
1752 };
1753 /* *INDENT-ON* */
1754
1755 int
1756 vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
1757 {
1758   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1759   u32 locator_set_index = ~0;
1760   mapping_t *m;
1761   uword *p;
1762
1763   if (vnet_lisp_enable_disable_status () == 0)
1764     {
1765       clib_warning ("LISP is disabled!");
1766       return VNET_API_ERROR_LISP_DISABLED;
1767     }
1768
1769   p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1770   if (!p)
1771     {
1772       clib_warning ("locator-set %v doesn't exist", locator_set_name);
1773       return -1;
1774     }
1775   locator_set_index = p[0];
1776
1777   if (is_add)
1778     {
1779       pool_get (lcm->mapping_pool, m);
1780       m->locator_set_index = locator_set_index;
1781       m->local = 1;
1782       lcm->pitr_map_index = m - lcm->mapping_pool;
1783
1784       /* enable pitr mode */
1785       lcm->lisp_pitr = 1;
1786     }
1787   else
1788     {
1789       /* remove pitr mapping */
1790       pool_put_index (lcm->mapping_pool, lcm->pitr_map_index);
1791
1792       /* disable pitr mode */
1793       lcm->lisp_pitr = 0;
1794     }
1795   return 0;
1796 }
1797
1798 static clib_error_t *
1799 lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm,
1800                                       unformat_input_t * input,
1801                                       vlib_cli_command_t * cmd)
1802 {
1803   u8 locator_name_set = 0;
1804   u8 *locator_set_name = 0;
1805   u8 is_add = 1;
1806   unformat_input_t _line_input, *line_input = &_line_input;
1807   clib_error_t *error = 0;
1808   int rv = 0;
1809
1810   /* Get a line of input. */
1811   if (!unformat_user (input, unformat_line_input, line_input))
1812     return 0;
1813
1814   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1815     {
1816       if (unformat (line_input, "ls %_%v%_", &locator_set_name))
1817         locator_name_set = 1;
1818       else if (unformat (line_input, "disable"))
1819         is_add = 0;
1820       else
1821         return clib_error_return (0, "parse error");
1822     }
1823
1824   if (!locator_name_set)
1825     {
1826       clib_warning ("No locator set specified!");
1827       goto done;
1828     }
1829   rv = vnet_lisp_pitr_set_locator_set (locator_set_name, is_add);
1830   if (0 != rv)
1831     {
1832       error = clib_error_return (0, "failed to %s pitr!",
1833                                  is_add ? "add" : "delete");
1834     }
1835
1836 done:
1837   if (locator_set_name)
1838     vec_free (locator_set_name);
1839   return error;
1840 }
1841
1842 /* *INDENT-OFF* */
1843 VLIB_CLI_COMMAND (lisp_pitr_set_locator_set_command) = {
1844     .path = "lisp pitr",
1845     .short_help = "lisp pitr [disable] ls <locator-set-name>",
1846     .function = lisp_pitr_set_locator_set_command_fn,
1847 };
1848 /* *INDENT-ON* */
1849
1850 static clib_error_t *
1851 lisp_show_pitr_command_fn (vlib_main_t * vm,
1852                            unformat_input_t * input, vlib_cli_command_t * cmd)
1853 {
1854   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1855   mapping_t *m;
1856   locator_set_t *ls;
1857   u8 *tmp_str = 0;
1858
1859   vlib_cli_output (vm, "%=20s%=16s",
1860                    "pitr", lcm->lisp_pitr ? "locator-set" : "");
1861
1862   if (!lcm->lisp_pitr)
1863     {
1864       vlib_cli_output (vm, "%=20s", "disable");
1865       return 0;
1866     }
1867
1868   if (~0 == lcm->pitr_map_index)
1869     {
1870       tmp_str = format (0, "N/A");
1871     }
1872   else
1873     {
1874       m = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
1875       if (~0 != m->locator_set_index)
1876         {
1877           ls =
1878             pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
1879           tmp_str = format (0, "%s", ls->name);
1880         }
1881       else
1882         {
1883           tmp_str = format (0, "N/A");
1884         }
1885     }
1886   vec_add1 (tmp_str, 0);
1887
1888   vlib_cli_output (vm, "%=20s%=16s", "enable", tmp_str);
1889
1890   vec_free (tmp_str);
1891
1892   return 0;
1893 }
1894
1895 /* *INDENT-OFF* */
1896 VLIB_CLI_COMMAND (lisp_show_pitr_command) = {
1897     .path = "show lisp pitr",
1898     .short_help = "Show pitr",
1899     .function = lisp_show_pitr_command_fn,
1900 };
1901 /* *INDENT-ON* */
1902
1903 static u8 *
1904 format_eid_entry (u8 * s, va_list * args)
1905 {
1906   vnet_main_t *vnm = va_arg (*args, vnet_main_t *);
1907   lisp_cp_main_t *lcm = va_arg (*args, lisp_cp_main_t *);
1908   mapping_t *mapit = va_arg (*args, mapping_t *);
1909   locator_set_t *ls = va_arg (*args, locator_set_t *);
1910   gid_address_t *gid = &mapit->eid;
1911   u32 ttl = mapit->ttl;
1912   u8 aut = mapit->authoritative;
1913   u32 *loc_index;
1914   u8 first_line = 1;
1915   u8 *loc;
1916
1917   u8 *type = ls->local ? format (0, "local(%s)", ls->name)
1918     : format (0, "remote");
1919
1920   if (vec_len (ls->locator_indices) == 0)
1921     {
1922       s = format (s, "%-35U%-30s%-20u%-u", format_gid_address, gid,
1923                   type, ttl, aut);
1924     }
1925   else
1926     {
1927       vec_foreach (loc_index, ls->locator_indices)
1928       {
1929         locator_t *l = pool_elt_at_index (lcm->locator_pool, loc_index[0]);
1930         if (l->local)
1931           loc = format (0, "%U", format_vnet_sw_if_index_name, vnm,
1932                         l->sw_if_index);
1933         else
1934           loc = format (0, "%U", format_ip_address,
1935                         &gid_address_ip (&l->address));
1936
1937         if (first_line)
1938           {
1939             s = format (s, "%-35U%-20s%-30v%-20u%-u\n", format_gid_address,
1940                         gid, type, loc, ttl, aut);
1941             first_line = 0;
1942           }
1943         else
1944           s = format (s, "%55s%v\n", "", loc);
1945       }
1946     }
1947   return s;
1948 }
1949
1950 static clib_error_t *
1951 lisp_show_eid_table_command_fn (vlib_main_t * vm,
1952                                 unformat_input_t * input,
1953                                 vlib_cli_command_t * cmd)
1954 {
1955   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1956   mapping_t *mapit;
1957   unformat_input_t _line_input, *line_input = &_line_input;
1958   u32 mi;
1959   gid_address_t eid;
1960   u8 print_all = 1;
1961   u8 filter = 0;
1962
1963   memset (&eid, 0, sizeof (eid));
1964
1965   /* Get a line of input. */
1966   if (!unformat_user (input, unformat_line_input, line_input))
1967     return 0;
1968
1969   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1970     {
1971       if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
1972         print_all = 0;
1973       else if (unformat (line_input, "local"))
1974         filter = 1;
1975       else if (unformat (line_input, "remote"))
1976         filter = 2;
1977       else
1978         return clib_error_return (0, "parse error: '%U'",
1979                                   format_unformat_error, line_input);
1980     }
1981
1982   vlib_cli_output (vm, "%-35s%-20s%-30s%-20s%-s",
1983                    "EID", "type", "locators", "ttl", "autoritative");
1984
1985   if (print_all)
1986     {
1987       /* *INDENT-OFF* */
1988       pool_foreach (mapit, lcm->mapping_pool,
1989       ({
1990         locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
1991                                                 mapit->locator_set_index);
1992         if (filter && !((1 == filter && ls->local) ||
1993           (2 == filter && !ls->local)))
1994           {
1995             continue;
1996           }
1997         vlib_cli_output (vm, "%U", format_eid_entry, lcm->vnet_main,
1998                          lcm, mapit, ls);
1999       }));
2000       /* *INDENT-ON* */
2001     }
2002   else
2003     {
2004       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &eid);
2005       if ((u32) ~ 0 == mi)
2006         return 0;
2007
2008       mapit = pool_elt_at_index (lcm->mapping_pool, mi);
2009       locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool,
2010                                              mapit->locator_set_index);
2011
2012       if (filter && !((1 == filter && ls->local) ||
2013                       (2 == filter && !ls->local)))
2014         {
2015           return 0;
2016         }
2017
2018       vlib_cli_output (vm, "%U,", format_eid_entry, lcm->vnet_main,
2019                        lcm, mapit, ls);
2020     }
2021
2022   return 0;
2023 }
2024
2025 /* *INDENT-OFF* */
2026 VLIB_CLI_COMMAND (lisp_cp_show_eid_table_command) = {
2027     .path = "show lisp eid-table",
2028     .short_help = "Shows EID table",
2029     .function = lisp_show_eid_table_command_fn,
2030 };
2031 /* *INDENT-ON* */
2032
2033 /* cleans locator to locator-set data and removes locators not part of
2034  * any locator-set */
2035 static void
2036 clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
2037 {
2038   u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
2039   locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool, lsi);
2040   for (i = 0; i < vec_len (ls->locator_indices); i++)
2041     {
2042       loc_indexp = vec_elt_at_index (ls->locator_indices, i);
2043       ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
2044                                      loc_indexp[0]);
2045       for (j = 0; j < vec_len (ls_indexes[0]); j++)
2046         {
2047           ls_indexp = vec_elt_at_index (ls_indexes[0], j);
2048           if (ls_indexp[0] == lsi)
2049             break;
2050         }
2051
2052       /* delete index for removed locator-set */
2053       vec_del1 (ls_indexes[0], j);
2054
2055       /* delete locator if it's part of no locator-set */
2056       if (vec_len (ls_indexes[0]) == 0)
2057         {
2058           pool_put_index (lcm->locator_pool, loc_indexp[0]);
2059           vec_add1 (to_be_deleted, i);
2060         }
2061     }
2062
2063   if (to_be_deleted)
2064     {
2065       for (i = 0; i < vec_len (to_be_deleted); i++)
2066         {
2067           loc_indexp = vec_elt_at_index (to_be_deleted, i);
2068           vec_del1 (ls->locator_indices, loc_indexp[0]);
2069         }
2070       vec_free (to_be_deleted);
2071     }
2072 }
2073
2074 static inline uword *
2075 get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p)
2076 {
2077   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2078
2079   ASSERT (a != NULL);
2080   ASSERT (p != NULL);
2081
2082   /* find locator-set */
2083   if (a->local)
2084     {
2085       p = hash_get_mem (lcm->locator_set_index_by_name, a->name);
2086     }
2087   else
2088     {
2089       *p = a->index;
2090     }
2091
2092   return p;
2093 }
2094
2095 static inline int
2096 is_locator_in_locator_set (lisp_cp_main_t * lcm, locator_set_t * ls,
2097                            locator_t * loc)
2098 {
2099   locator_t *itloc;
2100   u32 *locit;
2101
2102   ASSERT (ls != NULL);
2103   ASSERT (loc != NULL);
2104
2105   vec_foreach (locit, ls->locator_indices)
2106   {
2107     itloc = pool_elt_at_index (lcm->locator_pool, locit[0]);
2108     if ((ls->local && itloc->sw_if_index == loc->sw_if_index) ||
2109         (!ls->local && !gid_address_cmp (&itloc->address, &loc->address)))
2110       {
2111         clib_warning ("Duplicate locator");
2112         return VNET_API_ERROR_VALUE_EXIST;
2113       }
2114   }
2115
2116   return 0;
2117 }
2118
2119 static inline void
2120 remove_locator_from_locator_set (locator_set_t * ls, u32 * locit,
2121                                  u32 ls_index, u32 loc_id)
2122 {
2123   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2124   u32 **ls_indexes = NULL;
2125
2126   ASSERT (ls != NULL);
2127   ASSERT (locit != NULL);
2128
2129   ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets, locit[0]);
2130   pool_put_index (lcm->locator_pool, locit[0]);
2131   vec_del1 (ls->locator_indices, loc_id);
2132   vec_del1 (ls_indexes[0], ls_index);
2133 }
2134
2135 int
2136 vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
2137                            locator_set_t * ls, u32 * ls_result)
2138 {
2139   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2140   locator_t *loc = NULL, *itloc = NULL;
2141   uword _p = (u32) ~ 0, *p = &_p;
2142   u32 loc_index = ~0, ls_index = ~0, *locit = NULL, **ls_indexes = NULL;
2143   u32 loc_id = ~0;
2144   int ret = 0;
2145
2146   ASSERT (a != NULL);
2147
2148   if (vnet_lisp_enable_disable_status () == 0)
2149     {
2150       clib_warning ("LISP is disabled!");
2151       return VNET_API_ERROR_LISP_DISABLED;
2152     }
2153
2154   p = get_locator_set_index (a, p);
2155   if (!p)
2156     {
2157       clib_warning ("locator-set %v doesn't exist", a->name);
2158       return VNET_API_ERROR_INVALID_ARGUMENT;
2159     }
2160
2161   if (ls == 0)
2162     {
2163       ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
2164       if (!ls)
2165         {
2166           clib_warning ("locator-set %d to be overwritten doesn't exist!",
2167                         p[0]);
2168           return VNET_API_ERROR_INVALID_ARGUMENT;
2169         }
2170     }
2171
2172   if (a->is_add)
2173     {
2174       if (ls_result)
2175         ls_result[0] = p[0];
2176
2177       /* allocate locators */
2178       vec_foreach (itloc, a->locators)
2179       {
2180         ret = is_locator_in_locator_set (lcm, ls, itloc);
2181         if (0 != ret)
2182           {
2183             return ret;
2184           }
2185
2186         pool_get (lcm->locator_pool, loc);
2187         loc[0] = itloc[0];
2188         loc_index = loc - lcm->locator_pool;
2189
2190         vec_add1 (ls->locator_indices, loc_index);
2191
2192         vec_validate (lcm->locator_to_locator_sets, loc_index);
2193         ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
2194                                        loc_index);
2195         vec_add1 (ls_indexes[0], p[0]);
2196       }
2197     }
2198   else
2199     {
2200       ls_index = p[0];
2201
2202       itloc = a->locators;
2203       loc_id = 0;
2204       vec_foreach (locit, ls->locator_indices)
2205       {
2206         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
2207
2208         if (loc->local && loc->sw_if_index == itloc->sw_if_index)
2209           {
2210             remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
2211           }
2212         if (0 == loc->local &&
2213             !gid_address_cmp (&loc->address, &itloc->address))
2214           {
2215             remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
2216           }
2217
2218         loc_id++;
2219       }
2220     }
2221
2222   return 0;
2223 }
2224
2225 int
2226 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
2227                                u32 * ls_result)
2228 {
2229   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2230   locator_set_t *ls;
2231   uword _p = (u32) ~ 0, *p = &_p;
2232   u32 ls_index;
2233   u32 **eid_indexes;
2234   int ret = 0;
2235
2236   if (vnet_lisp_enable_disable_status () == 0)
2237     {
2238       clib_warning ("LISP is disabled!");
2239       return VNET_API_ERROR_LISP_DISABLED;
2240     }
2241
2242   if (a->is_add)
2243     {
2244       p = get_locator_set_index (a, p);
2245
2246       /* overwrite */
2247       if (p && p[0] != (u32) ~ 0)
2248         {
2249           ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
2250           if (!ls)
2251             {
2252               clib_warning ("locator-set %d to be overwritten doesn't exist!",
2253                             p[0]);
2254               return -1;
2255             }
2256
2257           /* clean locator to locator-set vectors and remove locators if
2258            * they're not part of another locator-set */
2259           clean_locator_to_locator_set (lcm, p[0]);
2260
2261           /* remove locator indices from locator set */
2262           vec_free (ls->locator_indices);
2263
2264           ls_index = p[0];
2265
2266           if (ls_result)
2267             ls_result[0] = p[0];
2268         }
2269       /* new locator-set */
2270       else
2271         {
2272           pool_get (lcm->locator_set_pool, ls);
2273           memset (ls, 0, sizeof (*ls));
2274           ls_index = ls - lcm->locator_set_pool;
2275
2276           if (a->local)
2277             {
2278               ls->name = vec_dup (a->name);
2279
2280               if (!lcm->locator_set_index_by_name)
2281                 lcm->locator_set_index_by_name = hash_create_vec (
2282                                                                    /* size */
2283                                                                    0,
2284                                                                    sizeof
2285                                                                    (ls->name
2286                                                                     [0]),
2287                                                                    sizeof
2288                                                                    (uword));
2289               hash_set_mem (lcm->locator_set_index_by_name, ls->name,
2290                             ls_index);
2291
2292               /* mark as local locator-set */
2293               vec_add1 (lcm->local_locator_set_indexes, ls_index);
2294             }
2295           ls->local = a->local;
2296           if (ls_result)
2297             ls_result[0] = ls_index;
2298         }
2299
2300       ret = vnet_lisp_add_del_locator (a, ls, NULL);
2301       if (0 != ret)
2302         {
2303           return ret;
2304         }
2305     }
2306   else
2307     {
2308       p = get_locator_set_index (a, p);
2309       if (!p)
2310         {
2311           clib_warning ("locator-set %v doesn't exists", a->name);
2312           return -1;
2313         }
2314
2315       ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
2316       if (!ls)
2317         {
2318           clib_warning ("locator-set with index %d doesn't exists", p[0]);
2319           return -1;
2320         }
2321
2322       if (lcm->mreq_itr_rlocs == p[0])
2323         {
2324           clib_warning ("Can't delete the locator-set used to constrain "
2325                         "the itr-rlocs in map-requests!");
2326           return -1;
2327         }
2328
2329       if (vec_len (lcm->locator_set_to_eids) != 0)
2330         {
2331           eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids, p[0]);
2332           if (vec_len (eid_indexes[0]) != 0)
2333             {
2334               clib_warning
2335                 ("Can't delete a locator that supports a mapping!");
2336               return -1;
2337             }
2338         }
2339
2340       /* clean locator to locator-sets data */
2341       clean_locator_to_locator_set (lcm, p[0]);
2342
2343       if (ls->local)
2344         {
2345           u32 it, lsi;
2346
2347           vec_foreach_index (it, lcm->local_locator_set_indexes)
2348           {
2349             lsi = vec_elt (lcm->local_locator_set_indexes, it);
2350             if (lsi == p[0])
2351               {
2352                 vec_del1 (lcm->local_locator_set_indexes, it);
2353                 break;
2354               }
2355           }
2356           hash_unset_mem (lcm->locator_set_index_by_name, ls->name);
2357         }
2358       vec_free (ls->name);
2359       vec_free (ls->locator_indices);
2360       pool_put (lcm->locator_set_pool, ls);
2361     }
2362   return 0;
2363 }
2364
2365 int
2366 vnet_lisp_rloc_probe_enable_disable (u8 is_enable)
2367 {
2368   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2369
2370   lcm->rloc_probing = is_enable;
2371   return 0;
2372 }
2373
2374 int
2375 vnet_lisp_map_register_enable_disable (u8 is_enable)
2376 {
2377   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2378
2379   lcm->map_registering = is_enable;
2380   return 0;
2381 }
2382
2383 clib_error_t *
2384 vnet_lisp_enable_disable (u8 is_enable)
2385 {
2386   u32 vni, dp_table;
2387   clib_error_t *error = 0;
2388   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2389   vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a;
2390
2391   a->is_en = is_enable;
2392   error = vnet_lisp_gpe_enable_disable (a);
2393   if (error)
2394     {
2395       return clib_error_return (0, "failed to %s data-plane!",
2396                                 a->is_en ? "enable" : "disable");
2397     }
2398
2399   if (is_enable)
2400     {
2401       /* enable all l2 and l3 ifaces */
2402
2403       /* *INDENT-OFF* */
2404       hash_foreach(vni, dp_table, lcm->table_id_by_vni, ({
2405         dp_add_del_iface(lcm, vni, 0, 1);
2406       }));
2407       hash_foreach(vni, dp_table, lcm->bd_id_by_vni, ({
2408         dp_add_del_iface(lcm, vni, /* is_l2 */ 1, 1);
2409       }));
2410       /* *INDENT-ON* */
2411     }
2412   else
2413     {
2414       /* clear interface table */
2415       hash_free (lcm->fwd_entry_by_mapping_index);
2416       pool_free (lcm->fwd_entry_pool);
2417     }
2418
2419   /* update global flag */
2420   lcm->is_enabled = is_enable;
2421
2422   return 0;
2423 }
2424
2425 static clib_error_t *
2426 lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
2427                                 vlib_cli_command_t * cmd)
2428 {
2429   unformat_input_t _line_input, *line_input = &_line_input;
2430   u8 is_enabled = 0;
2431   u8 is_set = 0;
2432
2433   /* Get a line of input. */
2434   if (!unformat_user (input, unformat_line_input, line_input))
2435     return 0;
2436
2437   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2438     {
2439       if (unformat (line_input, "enable"))
2440         {
2441           is_set = 1;
2442           is_enabled = 1;
2443         }
2444       else if (unformat (line_input, "disable"))
2445         is_set = 1;
2446       else
2447         {
2448           return clib_error_return (0, "parse error: '%U'",
2449                                     format_unformat_error, line_input);
2450         }
2451     }
2452
2453   if (!is_set)
2454     return clib_error_return (0, "state not set");
2455
2456   vnet_lisp_enable_disable (is_enabled);
2457   return 0;
2458 }
2459
2460 /* *INDENT-OFF* */
2461 VLIB_CLI_COMMAND (lisp_cp_enable_disable_command) = {
2462     .path = "lisp",
2463     .short_help = "lisp [enable|disable]",
2464     .function = lisp_enable_disable_command_fn,
2465 };
2466 /* *INDENT-ON* */
2467
2468 static clib_error_t *
2469 lisp_map_register_enable_disable_command_fn (vlib_main_t * vm,
2470                                              unformat_input_t * input,
2471                                              vlib_cli_command_t * cmd)
2472 {
2473   unformat_input_t _line_input, *line_input = &_line_input;
2474   u8 is_enabled = 0;
2475   u8 is_set = 0;
2476
2477   /* Get a line of input. */
2478   if (!unformat_user (input, unformat_line_input, line_input))
2479     return 0;
2480
2481   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2482     {
2483       if (unformat (line_input, "enable"))
2484         {
2485           is_set = 1;
2486           is_enabled = 1;
2487         }
2488       else if (unformat (line_input, "disable"))
2489         is_set = 1;
2490       else
2491         {
2492           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
2493                            line_input);
2494           return 0;
2495         }
2496     }
2497
2498   if (!is_set)
2499     {
2500       vlib_cli_output (vm, "state not set!");
2501       return 0;
2502     }
2503
2504   vnet_lisp_map_register_enable_disable (is_enabled);
2505   return 0;
2506 }
2507
2508 /* *INDENT-OFF* */
2509 VLIB_CLI_COMMAND (lisp_map_register_enable_disable_command) = {
2510     .path = "lisp map-register",
2511     .short_help = "lisp map-register [enable|disable]",
2512     .function = lisp_map_register_enable_disable_command_fn,
2513 };
2514 /* *INDENT-ON* */
2515
2516 static clib_error_t *
2517 lisp_rloc_probe_enable_disable_command_fn (vlib_main_t * vm,
2518                                            unformat_input_t * input,
2519                                            vlib_cli_command_t * cmd)
2520 {
2521   unformat_input_t _line_input, *line_input = &_line_input;
2522   u8 is_enabled = 0;
2523   u8 is_set = 0;
2524
2525   /* Get a line of input. */
2526   if (!unformat_user (input, unformat_line_input, line_input))
2527     return 0;
2528
2529   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2530     {
2531       if (unformat (line_input, "enable"))
2532         {
2533           is_set = 1;
2534           is_enabled = 1;
2535         }
2536       else if (unformat (line_input, "disable"))
2537         is_set = 1;
2538       else
2539         {
2540           vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
2541                            line_input);
2542           return 0;
2543         }
2544     }
2545
2546   if (!is_set)
2547     {
2548       vlib_cli_output (vm, "state not set!");
2549       return 0;
2550     }
2551
2552   vnet_lisp_rloc_probe_enable_disable (is_enabled);
2553   return 0;
2554 }
2555
2556 /* *INDENT-OFF* */
2557 VLIB_CLI_COMMAND (lisp_rloc_probe_enable_disable_command) = {
2558     .path = "lisp rloc-probe",
2559     .short_help = "lisp rloc-probe [enable|disable]",
2560     .function = lisp_rloc_probe_enable_disable_command_fn,
2561 };
2562 /* *INDENT-ON* */
2563
2564 u8
2565 vnet_lisp_enable_disable_status (void)
2566 {
2567   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2568   return lcm->is_enabled;
2569 }
2570
2571 static u8 *
2572 format_lisp_status (u8 * s, va_list * args)
2573 {
2574   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2575   return format (s, "%s", lcm->is_enabled ? "enabled" : "disabled");
2576 }
2577
2578 static clib_error_t *
2579 lisp_show_status_command_fn (vlib_main_t * vm, unformat_input_t * input,
2580                              vlib_cli_command_t * cmd)
2581 {
2582   u8 *msg = 0;
2583   msg = format (msg, "feature: %U\ngpe: %U\n",
2584                 format_lisp_status, format_vnet_lisp_gpe_status);
2585   vlib_cli_output (vm, "%v", msg);
2586   vec_free (msg);
2587   return 0;
2588 }
2589
2590 /* *INDENT-OFF* */
2591 VLIB_CLI_COMMAND (lisp_show_status_command) = {
2592     .path = "show lisp status",
2593     .short_help = "show lisp status",
2594     .function = lisp_show_status_command_fn,
2595 };
2596 /* *INDENT-ON* */
2597
2598 static clib_error_t *
2599 lisp_show_eid_table_map_command_fn (vlib_main_t * vm,
2600                                     unformat_input_t * input,
2601                                     vlib_cli_command_t * cmd)
2602 {
2603   hash_pair_t *p;
2604   unformat_input_t _line_input, *line_input = &_line_input;
2605   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2606   uword *vni_table = 0;
2607   u8 is_l2 = 0;
2608
2609   /* Get a line of input. */
2610   if (!unformat_user (input, unformat_line_input, line_input))
2611     return 0;
2612
2613   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2614     {
2615       if (unformat (line_input, "l2"))
2616         {
2617           vni_table = lcm->bd_id_by_vni;
2618           is_l2 = 1;
2619         }
2620       else if (unformat (line_input, "l3"))
2621         {
2622           vni_table = lcm->table_id_by_vni;
2623           is_l2 = 0;
2624         }
2625       else
2626         return clib_error_return (0, "parse error: '%U'",
2627                                   format_unformat_error, line_input);
2628     }
2629
2630   if (!vni_table)
2631     {
2632       vlib_cli_output (vm, "Error: expected l2|l3 param!\n");
2633       return 0;
2634     }
2635
2636   vlib_cli_output (vm, "%=10s%=10s", "VNI", is_l2 ? "BD" : "VRF");
2637
2638   /* *INDENT-OFF* */
2639   hash_foreach_pair (p, vni_table,
2640   ({
2641     vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
2642   }));
2643   /* *INDENT-ON* */
2644
2645   return 0;
2646 }
2647
2648 /* *INDENT-OFF* */
2649 VLIB_CLI_COMMAND (lisp_show_eid_table_map_command) = {
2650     .path = "show lisp eid-table map",
2651     .short_help = "show lisp eid-table l2|l3",
2652     .function = lisp_show_eid_table_map_command_fn,
2653 };
2654 /* *INDENT-ON* */
2655
2656 static clib_error_t *
2657 lisp_add_del_locator_set_command_fn (vlib_main_t * vm,
2658                                      unformat_input_t * input,
2659                                      vlib_cli_command_t * cmd)
2660 {
2661   lisp_gpe_main_t *lgm = &lisp_gpe_main;
2662   vnet_main_t *vnm = lgm->vnet_main;
2663   unformat_input_t _line_input, *line_input = &_line_input;
2664   u8 is_add = 1;
2665   clib_error_t *error = 0;
2666   u8 *locator_set_name = 0;
2667   locator_t locator, *locators = 0;
2668   vnet_lisp_add_del_locator_set_args_t _a, *a = &_a;
2669   u32 ls_index = 0;
2670   int rv = 0;
2671
2672   memset (&locator, 0, sizeof (locator));
2673   memset (a, 0, sizeof (a[0]));
2674
2675   /* Get a line of input. */
2676   if (!unformat_user (input, unformat_line_input, line_input))
2677     return 0;
2678
2679   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2680     {
2681       if (unformat (line_input, "add %_%v%_", &locator_set_name))
2682         is_add = 1;
2683       else if (unformat (line_input, "del %_%v%_", &locator_set_name))
2684         is_add = 0;
2685       else if (unformat (line_input, "iface %U p %d w %d",
2686                          unformat_vnet_sw_interface, vnm,
2687                          &locator.sw_if_index, &locator.priority,
2688                          &locator.weight))
2689         {
2690           locator.local = 1;
2691           vec_add1 (locators, locator);
2692         }
2693       else
2694         {
2695           error = unformat_parse_error (line_input);
2696           goto done;
2697         }
2698     }
2699
2700   a->name = locator_set_name;
2701   a->locators = locators;
2702   a->is_add = is_add;
2703   a->local = 1;
2704
2705   rv = vnet_lisp_add_del_locator_set (a, &ls_index);
2706   if (0 != rv)
2707     {
2708       error = clib_error_return (0, "failed to %s locator-set!",
2709                                  is_add ? "add" : "delete");
2710     }
2711
2712 done:
2713   vec_free (locators);
2714   if (locator_set_name)
2715     vec_free (locator_set_name);
2716   return error;
2717 }
2718
2719 /* *INDENT-OFF* */
2720 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
2721     .path = "lisp locator-set",
2722     .short_help = "lisp locator-set add/del <name> [iface <iface-name> "
2723         "p <priority> w <weight>]",
2724     .function = lisp_add_del_locator_set_command_fn,
2725 };
2726 /* *INDENT-ON* */
2727
2728 static clib_error_t *
2729 lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm,
2730                                         unformat_input_t * input,
2731                                         vlib_cli_command_t * cmd)
2732 {
2733   lisp_gpe_main_t *lgm = &lisp_gpe_main;
2734   vnet_main_t *vnm = lgm->vnet_main;
2735   unformat_input_t _line_input, *line_input = &_line_input;
2736   u8 is_add = 1;
2737   clib_error_t *error = 0;
2738   u8 *locator_set_name = 0;
2739   u8 locator_set_name_set = 0;
2740   locator_t locator, *locators = 0;
2741   vnet_lisp_add_del_locator_set_args_t _a, *a = &_a;
2742   u32 ls_index = 0;
2743
2744   memset (&locator, 0, sizeof (locator));
2745   memset (a, 0, sizeof (a[0]));
2746
2747   /* Get a line of input. */
2748   if (!unformat_user (input, unformat_line_input, line_input))
2749     return 0;
2750
2751   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2752     {
2753       if (unformat (line_input, "add"))
2754         is_add = 1;
2755       else if (unformat (line_input, "del"))
2756         is_add = 0;
2757       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
2758         locator_set_name_set = 1;
2759       else if (unformat (line_input, "iface %U p %d w %d",
2760                          unformat_vnet_sw_interface, vnm,
2761                          &locator.sw_if_index, &locator.priority,
2762                          &locator.weight))
2763         {
2764           locator.local = 1;
2765           vec_add1 (locators, locator);
2766         }
2767       else
2768         {
2769           error = unformat_parse_error (line_input);
2770           goto done;
2771         }
2772     }
2773
2774   if (!locator_set_name_set)
2775     {
2776       error = clib_error_return (0, "locator_set name not set!");
2777       goto done;
2778     }
2779
2780   a->name = locator_set_name;
2781   a->locators = locators;
2782   a->is_add = is_add;
2783   a->local = 1;
2784
2785   vnet_lisp_add_del_locator (a, 0, &ls_index);
2786
2787 done:
2788   vec_free (locators);
2789   vec_free (locator_set_name);
2790   return error;
2791 }
2792
2793 /* *INDENT-OFF* */
2794 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_in_set_command) = {
2795     .path = "lisp locator",
2796     .short_help = "lisp locator add/del locator-set <name> iface <iface-name> "
2797                   "p <priority> w <weight>",
2798     .function = lisp_add_del_locator_in_set_command_fn,
2799 };
2800 /* *INDENT-ON* */
2801
2802 static clib_error_t *
2803 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
2804                                       unformat_input_t * input,
2805                                       vlib_cli_command_t * cmd)
2806 {
2807   locator_set_t *lsit;
2808   locator_t *loc;
2809   u32 *locit;
2810   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2811
2812   vlib_cli_output (vm, "%s%=16s%=16s%=16s", "Locator-set", "Locator",
2813                    "Priority", "Weight");
2814
2815   /* *INDENT-OFF* */
2816   pool_foreach (lsit, lcm->locator_set_pool,
2817   ({
2818     u8 * msg = 0;
2819     int next_line = 0;
2820     if (lsit->local)
2821       {
2822         msg = format (msg, "%v", lsit->name);
2823       }
2824     else
2825       {
2826         msg = format (msg, "<%s-%d>", "remote", lsit - lcm->locator_set_pool);
2827       }
2828     vec_foreach (locit, lsit->locator_indices)
2829       {
2830         if (next_line)
2831           {
2832             msg = format (msg, "%16s", " ");
2833           }
2834         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
2835         if (loc->local)
2836           msg = format (msg, "%16d%16d%16d\n", loc->sw_if_index, loc->priority,
2837                         loc->weight);
2838         else
2839           msg = format (msg, "%16U%16d%16d\n", format_ip_address,
2840                         &gid_address_ip(&loc->address), loc->priority,
2841                         loc->weight);
2842         next_line = 1;
2843       }
2844     vlib_cli_output (vm, "%v", msg);
2845     vec_free (msg);
2846   }));
2847   /* *INDENT-ON* */
2848   return 0;
2849 }
2850
2851 /* *INDENT-OFF* */
2852 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
2853     .path = "show lisp locator-set",
2854     .short_help = "Shows locator-sets",
2855     .function = lisp_cp_show_locator_sets_command_fn,
2856 };
2857 /* *INDENT-ON* */
2858
2859 int
2860 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
2861 {
2862   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2863   u32 i;
2864   lisp_msmr_t _mr, *mr = &_mr;
2865
2866   if (vnet_lisp_enable_disable_status () == 0)
2867     {
2868       clib_warning ("LISP is disabled!");
2869       return VNET_API_ERROR_LISP_DISABLED;
2870     }
2871
2872   if (a->is_add)
2873     {
2874
2875       if (get_map_resolver (&a->address))
2876         {
2877           clib_warning ("map-resolver %U already exists!", format_ip_address,
2878                         &a->address);
2879           return -1;
2880         }
2881
2882       memset (mr, 0, sizeof (*mr));
2883       ip_address_copy (&mr->address, &a->address);
2884       vec_add1 (lcm->map_resolvers, *mr);
2885
2886       if (vec_len (lcm->map_resolvers) == 1)
2887         lcm->do_map_resolver_election = 1;
2888     }
2889   else
2890     {
2891       for (i = 0; i < vec_len (lcm->map_resolvers); i++)
2892         {
2893           mr = vec_elt_at_index (lcm->map_resolvers, i);
2894           if (!ip_address_cmp (&mr->address, &a->address))
2895             {
2896               if (!ip_address_cmp (&mr->address, &lcm->active_map_resolver))
2897                 lcm->do_map_resolver_election = 1;
2898
2899               vec_del1 (lcm->map_resolvers, i);
2900               break;
2901             }
2902         }
2903     }
2904   return 0;
2905 }
2906
2907 static clib_error_t *
2908 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
2909                                       unformat_input_t * input,
2910                                       vlib_cli_command_t * cmd)
2911 {
2912   unformat_input_t _line_input, *line_input = &_line_input;
2913   u8 is_add = 1, addr_set = 0;
2914   ip_address_t ip_addr;
2915   clib_error_t *error = 0;
2916   int rv = 0;
2917   vnet_lisp_add_del_map_resolver_args_t _a, *a = &_a;
2918
2919   /* Get a line of input. */
2920   if (!unformat_user (input, unformat_line_input, line_input))
2921     return 0;
2922
2923   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2924     {
2925       if (unformat (line_input, "add"))
2926         is_add = 1;
2927       else if (unformat (line_input, "del"))
2928         is_add = 0;
2929       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
2930         addr_set = 1;
2931       else
2932         {
2933           error = unformat_parse_error (line_input);
2934           goto done;
2935         }
2936     }
2937
2938   if (!addr_set)
2939     {
2940       error = clib_error_return (0, "Map-resolver address must be set!");
2941       goto done;
2942     }
2943
2944   a->is_add = is_add;
2945   a->address = ip_addr;
2946   rv = vnet_lisp_add_del_map_resolver (a);
2947   if (0 != rv)
2948     {
2949       error = clib_error_return (0, "failed to %s map-resolver!",
2950                                  is_add ? "add" : "delete");
2951     }
2952
2953 done:
2954   return error;
2955 }
2956
2957 /* *INDENT-OFF* */
2958 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
2959     .path = "lisp map-resolver",
2960     .short_help = "lisp map-resolver add/del <ip_address>",
2961     .function = lisp_add_del_map_resolver_command_fn,
2962 };
2963 /* *INDENT-ON* */
2964
2965 int
2966 vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
2967 {
2968   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2969   uword *p = 0;
2970
2971   if (vnet_lisp_enable_disable_status () == 0)
2972     {
2973       clib_warning ("LISP is disabled!");
2974       return VNET_API_ERROR_LISP_DISABLED;
2975     }
2976
2977   if (a->is_add)
2978     {
2979       p = hash_get_mem (lcm->locator_set_index_by_name, a->locator_set_name);
2980       if (!p)
2981         {
2982           clib_warning ("locator-set %v doesn't exist", a->locator_set_name);
2983           return VNET_API_ERROR_INVALID_ARGUMENT;
2984         }
2985
2986       lcm->mreq_itr_rlocs = p[0];
2987     }
2988   else
2989     {
2990       lcm->mreq_itr_rlocs = ~0;
2991     }
2992
2993   return 0;
2994 }
2995
2996 static clib_error_t *
2997 lisp_add_del_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
2998                                         unformat_input_t * input,
2999                                         vlib_cli_command_t * cmd)
3000 {
3001   unformat_input_t _line_input, *line_input = &_line_input;
3002   u8 is_add = 1;
3003   u8 *locator_set_name = 0;
3004   clib_error_t *error = 0;
3005   int rv = 0;
3006   vnet_lisp_add_del_mreq_itr_rloc_args_t _a, *a = &_a;
3007
3008   /* Get a line of input. */
3009   if (!unformat_user (input, unformat_line_input, line_input))
3010     return 0;
3011
3012   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
3013     {
3014       if (unformat (line_input, "del"))
3015         is_add = 0;
3016       else if (unformat (line_input, "add %_%v%_", &locator_set_name))
3017         is_add = 1;
3018       else
3019         {
3020           error = unformat_parse_error (line_input);
3021           goto done;
3022         }
3023     }
3024
3025   a->is_add = is_add;
3026   a->locator_set_name = locator_set_name;
3027   rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
3028   if (0 != rv)
3029     {
3030       error = clib_error_return (0, "failed to %s map-request itr-rlocs!",
3031                                  is_add ? "add" : "delete");
3032     }
3033
3034   vec_free (locator_set_name);
3035
3036 done:
3037   return error;
3038
3039 }
3040
3041 /* *INDENT-OFF* */
3042 VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
3043     .path = "lisp map-request itr-rlocs",
3044     .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
3045     .function = lisp_add_del_mreq_itr_rlocs_command_fn,
3046 };
3047 /* *INDENT-ON* */
3048
3049 static clib_error_t *
3050 lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
3051                                      unformat_input_t * input,
3052                                      vlib_cli_command_t * cmd)
3053 {
3054   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3055   locator_set_t *loc_set;
3056
3057   vlib_cli_output (vm, "%=20s", "itr-rlocs");
3058
3059   if (~0 == lcm->mreq_itr_rlocs)
3060     {
3061       return 0;
3062     }
3063
3064   loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
3065
3066   vlib_cli_output (vm, "%=20s", loc_set->name);
3067
3068   return 0;
3069 }
3070
3071 /* *INDENT-OFF* */
3072 VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
3073     .path = "show lisp map-request itr-rlocs",
3074     .short_help = "Shows map-request itr-rlocs",
3075     .function = lisp_show_mreq_itr_rlocs_command_fn,
3076 };
3077 /* *INDENT-ON* */
3078
3079 /* Statistics (not really errors) */
3080 #define foreach_lisp_cp_lookup_error           \
3081 _(DROP, "drop")                                \
3082 _(MAP_REQUESTS_SENT, "map-request sent")
3083
3084 static char *lisp_cp_lookup_error_strings[] = {
3085 #define _(sym,string) string,
3086   foreach_lisp_cp_lookup_error
3087 #undef _
3088 };
3089
3090 typedef enum
3091 {
3092 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
3093   foreach_lisp_cp_lookup_error
3094 #undef _
3095     LISP_CP_LOOKUP_N_ERROR,
3096 } lisp_cp_lookup_error_t;
3097
3098 typedef enum
3099 {
3100   LISP_CP_LOOKUP_NEXT_DROP,
3101   LISP_CP_LOOKUP_N_NEXT,
3102 } lisp_cp_lookup_next_t;
3103
3104 typedef struct
3105 {
3106   gid_address_t dst_eid;
3107   ip_address_t map_resolver_ip;
3108 } lisp_cp_lookup_trace_t;
3109
3110 u8 *
3111 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
3112 {
3113   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
3114   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
3115   lisp_cp_lookup_trace_t *t = va_arg (*args, lisp_cp_lookup_trace_t *);
3116
3117   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
3118               format_ip_address, &t->map_resolver_ip, format_gid_address,
3119               &t->dst_eid);
3120   return s;
3121 }
3122
3123 int
3124 get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
3125                            ip_address_t * sloc)
3126 {
3127   lisp_msmr_t *mrit;
3128   ip_address_t *a;
3129
3130   if (vec_len (lcm->map_resolvers) == 0)
3131     {
3132       clib_warning ("No map-resolver configured");
3133       return 0;
3134     }
3135
3136   /* find the first mr ip we have a route to and the ip of the
3137    * iface that has a route to it */
3138   vec_foreach (mrit, lcm->map_resolvers)
3139   {
3140     a = &mrit->address;
3141     if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, a, sloc))
3142       {
3143         ip_address_copy (mr_ip, a);
3144
3145         /* also update globals */
3146         return 1;
3147       }
3148   }
3149
3150   clib_warning ("Can't find map-resolver and local interface ip!");
3151   return 0;
3152 }
3153
3154 static gid_address_t *
3155 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
3156 {
3157   void *addr;
3158   u32 i;
3159   locator_t *loc;
3160   u32 *loc_indexp;
3161   ip_interface_address_t *ia = 0;
3162   gid_address_t gid_data, *gid = &gid_data;
3163   gid_address_t *rlocs = 0;
3164   ip_prefix_t *ippref = &gid_address_ippref (gid);
3165   ip_address_t *rloc = &ip_prefix_addr (ippref);
3166
3167   memset (gid, 0, sizeof (gid[0]));
3168   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
3169   for (i = 0; i < vec_len (loc_set->locator_indices); i++)
3170     {
3171       loc_indexp = vec_elt_at_index (loc_set->locator_indices, i);
3172       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
3173
3174       /* Add ipv4 locators first TODO sort them */
3175
3176       /* *INDENT-OFF* */
3177       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
3178                                     loc->sw_if_index, 1 /* unnumbered */,
3179       ({
3180         addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
3181         ip_address_set (rloc, addr, IP4);
3182         ip_prefix_len (ippref) = 32;
3183         ip_prefix_normalize (ippref);
3184         vec_add1 (rlocs, gid[0]);
3185       }));
3186
3187       /* Add ipv6 locators */
3188       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
3189                                     loc->sw_if_index, 1 /* unnumbered */,
3190       ({
3191         addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
3192         ip_address_set (rloc, addr, IP6);
3193         ip_prefix_len (ippref) = 128;
3194         ip_prefix_normalize (ippref);
3195         vec_add1 (rlocs, gid[0]);
3196       }));
3197       /* *INDENT-ON* */
3198
3199     }
3200   return rlocs;
3201 }
3202
3203 static vlib_buffer_t *
3204 build_map_request (lisp_cp_main_t * lcm, gid_address_t * deid,
3205                    ip_address_t * sloc, ip_address_t * rloc,
3206                    gid_address_t * itr_rlocs, u64 * nonce_res, u32 * bi_res)
3207 {
3208   vlib_buffer_t *b;
3209   u32 bi;
3210   vlib_main_t *vm = lcm->vlib_main;
3211
3212   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
3213     {
3214       clib_warning ("Can't allocate buffer for Map-Request!");
3215       return 0;
3216     }
3217
3218   b = vlib_get_buffer (vm, bi);
3219
3220   /* leave some space for the encap headers */
3221   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
3222
3223   /* put lisp msg */
3224   lisp_msg_put_mreq (lcm, b, NULL, deid, itr_rlocs, 0 /* smr invoked */ ,
3225                      1 /* rloc probe */ , nonce_res);
3226
3227   /* push outer ip header */
3228   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
3229                        rloc);
3230
3231   bi_res[0] = bi;
3232
3233   return b;
3234 }
3235
3236 static vlib_buffer_t *
3237 build_encapsulated_map_request (lisp_cp_main_t * lcm,
3238                                 gid_address_t * seid, gid_address_t * deid,
3239                                 locator_set_t * loc_set, ip_address_t * mr_ip,
3240                                 ip_address_t * sloc, u8 is_smr_invoked,
3241                                 u64 * nonce_res, u32 * bi_res)
3242 {
3243   vlib_buffer_t *b;
3244   u32 bi;
3245   gid_address_t *rlocs = 0;
3246   vlib_main_t *vm = lcm->vlib_main;
3247
3248   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
3249     {
3250       clib_warning ("Can't allocate buffer for Map-Request!");
3251       return 0;
3252     }
3253
3254   b = vlib_get_buffer (vm, bi);
3255
3256   /* leave some space for the encap headers */
3257   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
3258
3259   /* get rlocs */
3260   rlocs = build_itr_rloc_list (lcm, loc_set);
3261
3262   if (MR_MODE_SRC_DST == lcm->map_request_mode
3263       && GID_ADDR_SRC_DST != gid_address_type (deid))
3264     {
3265       gid_address_t sd;
3266       memset (&sd, 0, sizeof (sd));
3267       build_src_dst (&sd, seid, deid);
3268       lisp_msg_put_mreq (lcm, b, seid, &sd, rlocs, is_smr_invoked,
3269                          0 /* rloc probe */ , nonce_res);
3270     }
3271   else
3272     {
3273       /* put lisp msg */
3274       lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked,
3275                          0 /* rloc probe */ , nonce_res);
3276     }
3277
3278   /* push ecm: udp-ip-lisp */
3279   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
3280
3281   /* push outer ip header */
3282   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
3283                        mr_ip);
3284
3285   bi_res[0] = bi;
3286
3287   vec_free (rlocs);
3288   return b;
3289 }
3290
3291 static void
3292 reset_pending_mr_counters (pending_map_request_t * r)
3293 {
3294   r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
3295   r->retries_num = 0;
3296 }
3297
3298 static int
3299 elect_map_resolver (lisp_cp_main_t * lcm)
3300 {
3301   lisp_msmr_t *mr;
3302
3303   vec_foreach (mr, lcm->map_resolvers)
3304   {
3305     if (!mr->is_down)
3306       {
3307         ip_address_copy (&lcm->active_map_resolver, &mr->address);
3308         lcm->do_map_resolver_election = 0;
3309         return 1;
3310       }
3311   }
3312   return 0;
3313 }
3314
3315 static void
3316 free_map_register_records (mapping_t * maps)
3317 {
3318   mapping_t *map;
3319   vec_foreach (map, maps) vec_free (map->locators);
3320
3321   vec_free (maps);
3322 }
3323
3324 static void
3325 add_locators (lisp_cp_main_t * lcm, mapping_t * m, u32 locator_set_index,
3326               ip_address_t * probed_loc)
3327 {
3328   u32 *li;
3329   locator_t *loc, new;
3330   ip_interface_address_t *ia = 0;
3331   void *addr;
3332   ip_address_t *new_ip = &gid_address_ip (&new.address);
3333
3334   m->locators = 0;
3335   locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool,
3336                                          locator_set_index);
3337   vec_foreach (li, ls->locator_indices)
3338   {
3339     loc = pool_elt_at_index (lcm->locator_pool, li[0]);
3340     new = loc[0];
3341     if (loc->local)
3342       {
3343           /* *INDENT-OFF* */
3344           foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
3345                                         loc->sw_if_index, 1 /* unnumbered */,
3346           ({
3347             addr = ip_interface_address_get_address (&lcm->im4->lookup_main,
3348                                                      ia);
3349             ip_address_set (new_ip, addr, IP4);
3350           }));
3351
3352           /* Add ipv6 locators */
3353           foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
3354                                         loc->sw_if_index, 1 /* unnumbered */,
3355           ({
3356             addr = ip_interface_address_get_address (&lcm->im6->lookup_main,
3357                                                      ia);
3358             ip_address_set (new_ip, addr, IP6);
3359           }));
3360           /* *INDENT-ON* */
3361
3362         if (probed_loc && ip_address_cmp (probed_loc, new_ip) == 0)
3363           new.probed = 1;
3364       }
3365     vec_add1 (m->locators, new);
3366   }
3367 }
3368
3369 static mapping_t *
3370 build_map_register_record_list (lisp_cp_main_t * lcm)
3371 {
3372   mapping_t *recs = 0, rec, *m;
3373
3374   /* *INDENT-OFF* */
3375   pool_foreach(m, lcm->mapping_pool,
3376   {
3377     /* for now build only local mappings */
3378     if (!m->local)
3379       continue;
3380
3381     rec = m[0];
3382     add_locators (lcm, &rec, m->locator_set_index, NULL);
3383     vec_add1 (recs, rec);
3384   });
3385   /* *INDENT-ON* */
3386
3387   return recs;
3388 }
3389
3390 static int
3391 update_map_register_auth_data (map_register_hdr_t * map_reg_hdr,
3392                                lisp_key_type_t key_id, u8 * key,
3393                                u16 auth_data_len, u32 msg_len)
3394 {
3395   MREG_KEY_ID (map_reg_hdr) = clib_host_to_net_u16 (key_id);
3396   MREG_AUTH_DATA_LEN (map_reg_hdr) = clib_host_to_net_u16 (auth_data_len);
3397
3398   unsigned char *result = HMAC (get_encrypt_fcn (key_id), key, vec_len (key),
3399                                 (unsigned char *) map_reg_hdr, msg_len, NULL,
3400                                 NULL);
3401   clib_memcpy (MREG_DATA (map_reg_hdr), result, auth_data_len);
3402
3403   return 0;
3404 }
3405
3406 static vlib_buffer_t *
3407 build_map_register (lisp_cp_main_t * lcm, ip_address_t * sloc,
3408                     ip_address_t * ms_ip, u64 * nonce_res, u8 want_map_notif,
3409                     mapping_t * records, lisp_key_type_t key_id, u8 * key,
3410                     u32 * bi_res)
3411 {
3412   void *map_reg_hdr;
3413   vlib_buffer_t *b;
3414   u32 bi, auth_data_len = 0, msg_len = 0;
3415   vlib_main_t *vm = lcm->vlib_main;
3416
3417   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
3418     {
3419       clib_warning ("Can't allocate buffer for Map-Register!");
3420       return 0;
3421     }
3422
3423   b = vlib_get_buffer (vm, bi);
3424
3425   /* leave some space for the encap headers */
3426   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
3427
3428   auth_data_len = auth_data_len_by_key_id (key_id);
3429   map_reg_hdr = lisp_msg_put_map_register (b, records, want_map_notif,
3430                                            auth_data_len, nonce_res,
3431                                            &msg_len);
3432
3433   update_map_register_auth_data (map_reg_hdr, key_id, key, auth_data_len,
3434                                  msg_len);
3435
3436   /* push outer ip header */
3437   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
3438                        ms_ip);
3439
3440   bi_res[0] = bi;
3441   return b;
3442 }
3443
3444 static int
3445 get_egress_map_resolver_ip (lisp_cp_main_t * lcm, ip_address_t * ip)
3446 {
3447   lisp_msmr_t *mr;
3448   while (lcm->do_map_resolver_election
3449          | (0 == ip_fib_get_first_egress_ip_for_dst (lcm,
3450                                                      &lcm->active_map_resolver,
3451                                                      ip)))
3452     {
3453       if (0 == elect_map_resolver (lcm))
3454         /* all map resolvers are down */
3455         {
3456           /* restart MR checking by marking all of them up */
3457           vec_foreach (mr, lcm->map_resolvers) mr->is_down = 0;
3458           return -1;
3459         }
3460     }
3461   return 0;
3462 }
3463
3464 static int
3465 send_rloc_probe (lisp_cp_main_t * lcm, gid_address_t * deid,
3466                  u32 local_locator_set_index, ip_address_t * sloc,
3467                  ip_address_t * rloc)
3468 {
3469   locator_set_t *ls;
3470   u32 bi;
3471   vlib_buffer_t *b;
3472   vlib_frame_t *f;
3473   u64 nonce = 0;
3474   u32 next_index, *to_next;
3475   gid_address_t *itr_rlocs;
3476
3477   ls = pool_elt_at_index (lcm->locator_set_pool, local_locator_set_index);
3478   itr_rlocs = build_itr_rloc_list (lcm, ls);
3479
3480   b = build_map_request (lcm, deid, sloc, rloc, itr_rlocs, &nonce, &bi);
3481   vec_free (itr_rlocs);
3482   if (!b)
3483     return -1;
3484
3485   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
3486
3487   next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
3488     ip4_lookup_node.index : ip6_lookup_node.index;
3489
3490   f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
3491
3492   /* Enqueue the packet */
3493   to_next = vlib_frame_vector_args (f);
3494   to_next[0] = bi;
3495   f->n_vectors = 1;
3496   vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
3497
3498   hash_set (lcm->map_register_messages_by_nonce, nonce, 0);
3499   return 0;
3500 }
3501
3502 static int
3503 send_rloc_probes (lisp_cp_main_t * lcm)
3504 {
3505   mapping_t *lm;
3506   fwd_entry_t *e;
3507   u32 si;
3508
3509   /* *INDENT-OFF* */
3510   pool_foreach (e, lcm->fwd_entry_pool,
3511   {
3512     si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &e->leid);
3513     if (~0 == si)
3514       {
3515         clib_warning ("internal error: cannot find local eid %U in "
3516                       "map-cache!", format_gid_address, &e->leid);
3517         continue;
3518       }
3519     lm = pool_elt_at_index (lcm->mapping_pool, si);
3520
3521     if (vec_len (e->locator_pairs) == 0)
3522       continue;
3523
3524     /* TODO send rloc-probe for each pair? for now assume there is only one
3525       pair at a time */
3526     locator_pair_t *lp = &e->locator_pairs[0];
3527
3528     /* get first remote locator */
3529     send_rloc_probe (lcm, &e->reid, lm->locator_set_index, &lp->lcl_loc,
3530                      &lp->rmt_loc);
3531   });
3532   /* *INDENT-ON* */
3533
3534   return 0;
3535 }
3536
3537 static int
3538 send_map_register (lisp_cp_main_t * lcm, u8 want_map_notif)
3539 {
3540   u32 bi;
3541   vlib_buffer_t *b;
3542   ip_address_t sloc;
3543   vlib_frame_t *f;
3544   u64 nonce = 0;
3545   u32 next_index, *to_next;
3546   ip_address_t *ms = 0;
3547
3548   // TODO: support multiple map servers and do election
3549   if (0 == vec_len (lcm->map_servers))
3550     return -1;
3551
3552   ms = &lcm->map_servers[0].address;
3553
3554   if (0 == ip_fib_get_first_egress_ip_for_dst (lcm, ms, &sloc))
3555     {
3556       clib_warning ("no eligible interface address found for %U!",
3557                     format_ip_address, &lcm->map_servers[0]);
3558       return -1;
3559     }
3560
3561   /* TODO build mapping records grouped by secret key and send one map-register
3562      per group. Currently only one secret key per vpp is supported  */
3563   mapping_t *records = build_map_register_record_list (lcm);
3564   if (!records)
3565     return -1;
3566
3567   u8 *key = records[0].key;
3568   u8 key_id = records[0].key_id;
3569
3570   if (!key)
3571     return 0;                   /* no secret key -> map-register cannot be sent */
3572
3573   b = build_map_register (lcm, &sloc, ms, &nonce, want_map_notif, records,
3574                           key_id, key, &bi);
3575   if (!b)
3576     return -1;
3577   free_map_register_records (records);
3578
3579   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
3580
3581   next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
3582     ip4_lookup_node.index : ip6_lookup_node.index;
3583
3584   f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
3585
3586   /* Enqueue the packet */
3587   to_next = vlib_frame_vector_args (f);
3588   to_next[0] = bi;
3589   f->n_vectors = 1;
3590   vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
3591
3592   hash_set (lcm->map_register_messages_by_nonce, nonce, 0);
3593   return 0;
3594 }
3595
3596 #define send_encapsulated_map_request(lcm, seid, deid, smr) \
3597   _send_encapsulated_map_request(lcm, seid, deid, smr, 0)
3598
3599 #define resend_encapsulated_map_request(lcm, seid, deid, smr) \
3600   _send_encapsulated_map_request(lcm, seid, deid, smr, 1)
3601
3602 static int
3603 _send_encapsulated_map_request (lisp_cp_main_t * lcm,
3604                                 gid_address_t * seid, gid_address_t * deid,
3605                                 u8 is_smr_invoked, u8 is_resend)
3606 {
3607   u32 next_index, bi = 0, *to_next, map_index;
3608   vlib_buffer_t *b;
3609   vlib_frame_t *f;
3610   u64 nonce = 0;
3611   locator_set_t *loc_set;
3612   mapping_t *map;
3613   pending_map_request_t *pmr, *duplicate_pmr = 0;
3614   ip_address_t sloc;
3615   u32 ls_index;
3616
3617   ASSERT (*lcm->pending_map_request_lock);
3618
3619   /* if there is already a pending request remember it */
3620
3621   /* *INDENT-OFF* */
3622   pool_foreach(pmr, lcm->pending_map_requests_pool,
3623   ({
3624     if (!gid_address_cmp (&pmr->src, seid)
3625         && !gid_address_cmp (&pmr->dst, deid))
3626       {
3627         duplicate_pmr = pmr;
3628         break;
3629       }
3630   }));
3631   /* *INDENT-ON* */
3632
3633   if (!is_resend && duplicate_pmr)
3634     {
3635       /* don't send the request if there is a pending map request already */
3636       return 0;
3637     }
3638
3639   /* get locator-set for seid */
3640   if (!lcm->lisp_pitr)
3641     {
3642       map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
3643       if (map_index == ~0)
3644         {
3645           clib_warning ("No local mapping found in eid-table for %U!",
3646                         format_gid_address, seid);
3647           return -1;
3648         }
3649
3650       map = pool_elt_at_index (lcm->mapping_pool, map_index);
3651
3652       if (!map->local)
3653         {
3654           clib_warning
3655             ("Mapping found for src eid %U is not marked as local!",
3656              format_gid_address, seid);
3657           return -1;
3658         }
3659       ls_index = map->locator_set_index;
3660     }
3661   else
3662     {
3663       map_index = lcm->pitr_map_index;
3664       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
3665       ls_index = map->locator_set_index;
3666     }
3667
3668   /* overwrite locator set if map-request itr-rlocs configured */
3669   if (~0 != lcm->mreq_itr_rlocs)
3670     {
3671       ls_index = lcm->mreq_itr_rlocs;
3672     }
3673
3674   loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
3675
3676   if (get_egress_map_resolver_ip (lcm, &sloc) < 0)
3677     {
3678       if (duplicate_pmr)
3679         duplicate_pmr->to_be_removed = 1;
3680       return -1;
3681     }
3682
3683   /* build the encapsulated map request */
3684   b = build_encapsulated_map_request (lcm, seid, deid, loc_set,
3685                                       &lcm->active_map_resolver,
3686                                       &sloc, is_smr_invoked, &nonce, &bi);
3687
3688   if (!b)
3689     return -1;
3690
3691   /* set fib index to default and lookup node */
3692   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
3693   next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
3694     ip4_lookup_node.index : ip6_lookup_node.index;
3695
3696   f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
3697
3698   /* Enqueue the packet */
3699   to_next = vlib_frame_vector_args (f);
3700   to_next[0] = bi;
3701   f->n_vectors = 1;
3702   vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
3703
3704   if (duplicate_pmr)
3705     /* if there is a pending request already update it */
3706     {
3707       if (clib_fifo_elts (duplicate_pmr->nonces) >= PENDING_MREQ_QUEUE_LEN)
3708         {
3709           /* remove the oldest nonce */
3710           u64 CLIB_UNUSED (tmp), *nonce_del;
3711           nonce_del = clib_fifo_head (duplicate_pmr->nonces);
3712           hash_unset (lcm->pending_map_requests_by_nonce, nonce_del[0]);
3713           clib_fifo_sub1 (duplicate_pmr->nonces, tmp);
3714         }
3715
3716       clib_fifo_add1 (duplicate_pmr->nonces, nonce);
3717       hash_set (lcm->pending_map_requests_by_nonce, nonce,
3718                 duplicate_pmr - lcm->pending_map_requests_pool);
3719     }
3720   else
3721     {
3722       /* add map-request to pending requests table */
3723       pool_get (lcm->pending_map_requests_pool, pmr);
3724       memset (pmr, 0, sizeof (*pmr));
3725       gid_address_copy (&pmr->src, seid);
3726       gid_address_copy (&pmr->dst, deid);
3727       clib_fifo_add1 (pmr->nonces, nonce);
3728       pmr->is_smr_invoked = is_smr_invoked;
3729       reset_pending_mr_counters (pmr);
3730       hash_set (lcm->pending_map_requests_by_nonce, nonce,
3731                 pmr - lcm->pending_map_requests_pool);
3732     }
3733
3734   return 0;
3735 }
3736
3737 static void
3738 get_src_and_dst_ip (void *hdr, ip_address_t * src, ip_address_t * dst)
3739 {
3740   ip4_header_t *ip4 = hdr;
3741   ip6_header_t *ip6;
3742
3743   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
3744     {
3745       ip_address_set (src, &ip4->src_address, IP4);
3746       ip_address_set (dst, &ip4->dst_address, IP4);
3747     }
3748   else
3749     {
3750       ip6 = hdr;
3751       ip_address_set (src, &ip6->src_address, IP6);
3752       ip_address_set (dst, &ip6->dst_address, IP6);
3753     }
3754 }
3755
3756 static u32
3757 lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b,
3758                              u8 version)
3759 {
3760   uword *vnip;
3761   u32 vni = ~0, table_id = ~0;
3762
3763   table_id = fib_table_get_table_id_for_sw_if_index ((version ==
3764                                                       IP4 ? FIB_PROTOCOL_IP4 :
3765                                                       FIB_PROTOCOL_IP6),
3766                                                      vnet_buffer
3767                                                      (b)->sw_if_index
3768                                                      [VLIB_RX]);
3769
3770   vnip = hash_get (lcm->vni_by_table_id, table_id);
3771   if (vnip)
3772     vni = vnip[0];
3773   else
3774     clib_warning ("vrf %d is not mapped to any vni!", table_id);
3775
3776   return vni;
3777 }
3778
3779 always_inline u32
3780 lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b)
3781 {
3782   uword *vnip;
3783   u32 vni = ~0;
3784   u32 sw_if_index0;
3785
3786   l2input_main_t *l2im = &l2input_main;
3787   l2_input_config_t *config;
3788   l2_bridge_domain_t *bd_config;
3789
3790   sw_if_index0 = vnet_buffer (b)->sw_if_index[VLIB_RX];
3791   config = vec_elt_at_index (l2im->configs, sw_if_index0);
3792   bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index);
3793
3794   vnip = hash_get (lcm->vni_by_bd_id, bd_config->bd_id);
3795   if (vnip)
3796     vni = vnip[0];
3797   else
3798     clib_warning ("bridge domain %d is not mapped to any vni!",
3799                   config->bd_index);
3800
3801   return vni;
3802 }
3803
3804 always_inline void
3805 get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
3806                                   gid_address_t * src, gid_address_t * dst)
3807 {
3808   u32 vni = 0;
3809   u16 type;
3810
3811   memset (src, 0, sizeof (*src));
3812   memset (dst, 0, sizeof (*dst));
3813   type = vnet_buffer (b)->lisp.overlay_afi;
3814
3815   if (LISP_AFI_IP == type || LISP_AFI_IP6 == type)
3816     {
3817       ip4_header_t *ip;
3818       u8 version, preflen;
3819
3820       gid_address_type (src) = GID_ADDR_IP_PREFIX;
3821       gid_address_type (dst) = GID_ADDR_IP_PREFIX;
3822
3823       ip = vlib_buffer_get_current (b);
3824       get_src_and_dst_ip (ip, &gid_address_ip (src), &gid_address_ip (dst));
3825
3826       version = gid_address_ip_version (src);
3827       preflen = ip_address_max_len (version);
3828       gid_address_ippref_len (src) = preflen;
3829       gid_address_ippref_len (dst) = preflen;
3830
3831       vni = lisp_get_vni_from_buffer_ip (lcm, b, version);
3832       gid_address_vni (dst) = vni;
3833       gid_address_vni (src) = vni;
3834     }
3835   else if (LISP_AFI_MAC == type)
3836     {
3837       ethernet_header_t *eh;
3838
3839       eh = vlib_buffer_get_current (b);
3840
3841       gid_address_type (src) = GID_ADDR_MAC;
3842       gid_address_type (dst) = GID_ADDR_MAC;
3843       mac_copy (&gid_address_mac (src), eh->src_address);
3844       mac_copy (&gid_address_mac (dst), eh->dst_address);
3845
3846       /* get vni */
3847       vni = lisp_get_vni_from_buffer_eth (lcm, b);
3848
3849       gid_address_vni (dst) = vni;
3850       gid_address_vni (src) = vni;
3851     }
3852 }
3853
3854 static uword
3855 lisp_cp_lookup_inline (vlib_main_t * vm,
3856                        vlib_node_runtime_t * node,
3857                        vlib_frame_t * from_frame, int overlay)
3858 {
3859   u32 *from, *to_next_drop, di, si;
3860   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3861   u32 pkts_mapped = 0;
3862   uword n_left_from, n_left_to_next_drop;
3863
3864   from = vlib_frame_vector_args (from_frame);
3865   n_left_from = from_frame->n_vectors;
3866
3867   while (n_left_from > 0)
3868     {
3869       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
3870                            to_next_drop, n_left_to_next_drop);
3871
3872       while (n_left_from > 0 && n_left_to_next_drop > 0)
3873         {
3874           u32 pi0;
3875           vlib_buffer_t *b0;
3876           gid_address_t src, dst;
3877
3878           pi0 = from[0];
3879           from += 1;
3880           n_left_from -= 1;
3881           to_next_drop[0] = pi0;
3882           to_next_drop += 1;
3883           n_left_to_next_drop -= 1;
3884
3885           b0 = vlib_get_buffer (vm, pi0);
3886           b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
3887           vnet_buffer (b0)->lisp.overlay_afi = overlay;
3888
3889           /* src/dst eid pair */
3890           get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst);
3891
3892           /* if we have remote mapping for destination already in map-chache
3893              add forwarding tunnel directly. If not send a map-request */
3894           di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst,
3895                                          &src);
3896           if (~0 != di)
3897             {
3898               mapping_t *m = vec_elt_at_index (lcm->mapping_pool, di);
3899               /* send a map-request also in case of negative mapping entry
3900                  with corresponding action */
3901               if (m->action == LISP_SEND_MAP_REQUEST)
3902                 {
3903                   /* send map-request */
3904                   queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3905                                      0 /* is_resend */ );
3906                   pkts_mapped++;
3907                 }
3908               else
3909                 {
3910                   si = gid_dictionary_lookup (&lcm->mapping_index_by_gid,
3911                                               &src);
3912                   if (~0 != si)
3913                     {
3914                       dp_add_fwd_entry (lcm, si, di);
3915                     }
3916                 }
3917             }
3918           else
3919             {
3920               /* send map-request */
3921               queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3922                                  0 /* is_resend */ );
3923               pkts_mapped++;
3924             }
3925
3926           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3927             {
3928               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
3929                                                            sizeof (*tr));
3930
3931               memset (tr, 0, sizeof (*tr));
3932               gid_address_copy (&tr->dst_eid, &dst);
3933               ip_address_copy (&tr->map_resolver_ip,
3934                                &lcm->active_map_resolver);
3935             }
3936           gid_address_free (&dst);
3937           gid_address_free (&src);
3938         }
3939
3940       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
3941                            n_left_to_next_drop);
3942     }
3943   vlib_node_increment_counter (vm, node->node_index,
3944                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
3945                                pkts_mapped);
3946   return from_frame->n_vectors;
3947 }
3948
3949 static uword
3950 lisp_cp_lookup_ip4 (vlib_main_t * vm,
3951                     vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3952 {
3953   return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP));
3954 }
3955
3956 static uword
3957 lisp_cp_lookup_ip6 (vlib_main_t * vm,
3958                     vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3959 {
3960   return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP6));
3961 }
3962
3963 static uword
3964 lisp_cp_lookup_l2 (vlib_main_t * vm,
3965                    vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3966 {
3967   return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_MAC));
3968 }
3969
3970 /* *INDENT-OFF* */
3971 VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = {
3972   .function = lisp_cp_lookup_ip4,
3973   .name = "lisp-cp-lookup-ip4",
3974   .vector_size = sizeof (u32),
3975   .format_trace = format_lisp_cp_lookup_trace,
3976   .type = VLIB_NODE_TYPE_INTERNAL,
3977
3978   .n_errors = LISP_CP_LOOKUP_N_ERROR,
3979   .error_strings = lisp_cp_lookup_error_strings,
3980
3981   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3982
3983   .next_nodes = {
3984       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
3985   },
3986 };
3987 /* *INDENT-ON* */
3988
3989 /* *INDENT-OFF* */
3990 VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = {
3991   .function = lisp_cp_lookup_ip6,
3992   .name = "lisp-cp-lookup-ip6",
3993   .vector_size = sizeof (u32),
3994   .format_trace = format_lisp_cp_lookup_trace,
3995   .type = VLIB_NODE_TYPE_INTERNAL,
3996
3997   .n_errors = LISP_CP_LOOKUP_N_ERROR,
3998   .error_strings = lisp_cp_lookup_error_strings,
3999
4000   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
4001
4002   .next_nodes = {
4003       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
4004   },
4005 };
4006 /* *INDENT-ON* */
4007
4008 /* *INDENT-OFF* */
4009 VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
4010   .function = lisp_cp_lookup_l2,
4011   .name = "lisp-cp-lookup-l2",
4012   .vector_size = sizeof (u32),
4013   .format_trace = format_lisp_cp_lookup_trace,
4014   .type = VLIB_NODE_TYPE_INTERNAL,
4015
4016   .n_errors = LISP_CP_LOOKUP_N_ERROR,
4017   .error_strings = lisp_cp_lookup_error_strings,
4018
4019   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
4020
4021   .next_nodes = {
4022       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
4023   },
4024 };
4025 /* *INDENT-ON* */
4026
4027 /* lisp_cp_input statistics */
4028 #define foreach_lisp_cp_input_error                     \
4029 _(DROP, "drop")                                         \
4030 _(MAP_REPLIES_RECEIVED, "map-replies received")
4031
4032 static char *lisp_cp_input_error_strings[] = {
4033 #define _(sym,string) string,
4034   foreach_lisp_cp_input_error
4035 #undef _
4036 };
4037
4038 typedef enum
4039 {
4040 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
4041   foreach_lisp_cp_input_error
4042 #undef _
4043     LISP_CP_INPUT_N_ERROR,
4044 } lisp_cp_input_error_t;
4045
4046 typedef enum
4047 {
4048   LISP_CP_INPUT_NEXT_DROP,
4049   LISP_CP_INPUT_N_NEXT,
4050 } lisp_cp_input_next_t;
4051
4052 typedef struct
4053 {
4054   gid_address_t dst_eid;
4055   ip4_address_t map_resolver_ip;
4056 } lisp_cp_input_trace_t;
4057
4058 u8 *
4059 format_lisp_cp_input_trace (u8 * s, va_list * args)
4060 {
4061   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
4062   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
4063   CLIB_UNUSED (lisp_cp_input_trace_t * t) =
4064     va_arg (*args, lisp_cp_input_trace_t *);
4065
4066   s = format (s, "LISP-CP-INPUT: TODO");
4067   return s;
4068 }
4069
4070 void *
4071 process_map_reply (void *arg)
4072 {
4073   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4074   vlib_buffer_t *b = arg;
4075   u32 len = 0, i, ttl, dst_map_index = 0;
4076   void *h;
4077   pending_map_request_t *pmr;
4078   locator_t probed;
4079   map_reply_hdr_t *mrep_hdr;
4080   u64 nonce, *noncep;
4081   gid_address_t deid;
4082   uword *pmr_index;
4083   u8 authoritative, action;
4084   locator_t *locators = 0, *loc;
4085
4086   mrep_hdr = vlib_buffer_get_current (b);
4087
4088   lisp_pending_map_request_lock (lcm);
4089
4090   /* Check pending requests table and nonce */
4091   nonce = MREP_NONCE (mrep_hdr);
4092   pmr_index = hash_get (lcm->pending_map_requests_by_nonce, nonce);
4093   if (!pmr_index)
4094     {
4095       clib_warning ("No pending map-request entry with nonce %lu!", nonce);
4096       goto done;
4097     }
4098   pmr = pool_elt_at_index (lcm->pending_map_requests_pool, pmr_index[0]);
4099
4100   vlib_buffer_pull (b, sizeof (*mrep_hdr));
4101
4102   for (i = 0; i < MREP_REC_COUNT (mrep_hdr); i++)
4103     {
4104       h = vlib_buffer_get_current (b);
4105       ttl = clib_net_to_host_u32 (MAP_REC_TTL (h));
4106       action = MAP_REC_ACTION (h);
4107       authoritative = MAP_REC_AUTH (h);
4108
4109       len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
4110       if (len == ~0)
4111         {
4112           clib_warning ("Failed to parse mapping record!");
4113           vec_foreach (loc, locators)
4114           {
4115             locator_free (loc);
4116           }
4117           vec_free (locators);
4118           goto done;
4119         }
4120
4121       /* insert/update mappings cache */
4122       vnet_lisp_add_del_mapping (&deid, locators, action, authoritative, ttl,
4123                                  1, 0 /* is_static */ , &dst_map_index);
4124
4125       /* try to program forwarding only if mapping saved or updated */
4126       if ((u32) ~ 0 != dst_map_index)
4127         lisp_add_del_adjacency (lcm, &pmr->src, &deid, 1);
4128
4129       vec_free (locators);
4130     }
4131
4132   /* remove pending map request entry */
4133
4134   /* *INDENT-OFF* */
4135   clib_fifo_foreach (noncep, pmr->nonces, ({
4136     hash_unset(lcm->pending_map_requests_by_nonce, noncep[0]);
4137   }));
4138   /* *INDENT-ON* */
4139
4140   clib_fifo_free (pmr->nonces);
4141   pool_put (lcm->pending_map_requests_pool, pmr);
4142
4143 done:
4144   lisp_pending_map_request_unlock (lcm);
4145   return 0;
4146 }
4147
4148 static int
4149 is_auth_data_valid (map_notify_hdr_t * h, u32 msg_len,
4150                     lisp_key_type_t key_id, u8 * key)
4151 {
4152   u8 *auth_data = 0;
4153   u16 auth_data_len;
4154   int result;
4155
4156   auth_data_len = auth_data_len_by_key_id (key_id);
4157   if ((u16) ~ 0 == auth_data_len)
4158     {
4159       clib_warning ("invalid length for key_id %d!", key_id);
4160       return 0;
4161     }
4162
4163   /* save auth data */
4164   vec_validate (auth_data, auth_data_len - 1);
4165   clib_memcpy (auth_data, MNOTIFY_DATA (h), auth_data_len);
4166
4167   /* clear auth data */
4168   memset (MNOTIFY_DATA (h), 0, auth_data_len);
4169
4170   /* get hash of the message */
4171   unsigned char *code = HMAC (get_encrypt_fcn (key_id), key, vec_len (key),
4172                               (unsigned char *) h, msg_len, NULL, NULL);
4173
4174   result = memcmp (code, auth_data, auth_data_len);
4175
4176   vec_free (auth_data);
4177
4178   return !result;
4179 }
4180
4181 static void
4182 process_map_notify (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
4183 {
4184   lisp_key_type_t key_id;
4185   gid_address_t deid;
4186   mapping_t *m;
4187   u32 i, mi, len;
4188   map_notify_hdr_t *mnotif_hdr;
4189   u64 nonce;
4190   uword *pmr_index;
4191   locator_t *locators = 0, *loc;
4192   u16 auth_data_len = 0;
4193
4194   mnotif_hdr = vlib_buffer_get_current (b);
4195   vlib_buffer_pull (b, sizeof (*mnotif_hdr));
4196   memset (&deid, 0, sizeof (deid));
4197
4198   nonce = MNOTIFY_NONCE (mnotif_hdr);
4199   key_id = clib_net_to_host_u16 (MNOTIFY_KEY_ID (mnotif_hdr));
4200   auth_data_len = auth_data_len_by_key_id (key_id);
4201
4202   pmr_index = hash_get (lcm->map_register_messages_by_nonce, nonce);
4203   if (!pmr_index)
4204     {
4205       clib_warning ("No pending map-register entry with nonce %lu!", nonce);
4206       return;
4207     }
4208
4209   /* advance buffer by authentication data */
4210   vlib_buffer_pull (b, auth_data_len);
4211
4212   /* parse record eid */
4213   for (i = 0; i < MNOTIFY_REC_COUNT (mnotif_hdr); i++)
4214     {
4215       len = lisp_msg_parse_mapping_record (b, &deid, &locators, NULL);
4216       if (len == ~0)
4217         {
4218           clib_warning ("Failed to parse mapping record!");
4219           vec_foreach (loc, locators)
4220           {
4221             locator_free (loc);
4222           }
4223           vec_free (locators);
4224           return;
4225         }
4226
4227       vec_free (locators);
4228     }
4229
4230   /* lookup eid in map-cache */
4231   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &deid);
4232   if (~0 == mi)
4233     {
4234       clib_warning ("eid %U not found in map-cache!", unformat_gid_address,
4235                     &deid);
4236       return;
4237     }
4238
4239   m = pool_elt_at_index (lcm->mapping_pool, mi);
4240   if (!m->key)
4241     {
4242       clib_warning ("There is no secret key assigned to %U!",
4243                     format_gid_address, &deid);
4244       goto done;
4245     }
4246
4247   /* verify authentication data */
4248   if (!is_auth_data_valid (mnotif_hdr, vlib_buffer_get_tail (b)
4249                            - (u8 *) mnotif_hdr, m->key_id, m->key))
4250     {
4251       clib_warning ("Map-notify auth data verification failed for nonce %lu!",
4252                     nonce);
4253       goto done;
4254     }
4255
4256 done:
4257   hash_unset (lcm->map_register_messages_by_nonce, nonce);
4258   gid_address_free (&deid);
4259 }
4260
4261 static vlib_buffer_t *
4262 build_map_reply (lisp_cp_main_t * lcm, ip_address_t * sloc,
4263                  ip_address_t * dst, u64 nonce, u8 probe_bit,
4264                  mapping_t * records, u16 dst_port, u32 * bi_res)
4265 {
4266   vlib_buffer_t *b;
4267   u32 bi;
4268   vlib_main_t *vm = lcm->vlib_main;
4269
4270   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
4271     {
4272       clib_warning ("Can't allocate buffer for Map-Register!");
4273       return 0;
4274     }
4275
4276   b = vlib_get_buffer (vm, bi);
4277
4278   /* leave some space for the encap headers */
4279   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
4280
4281   lisp_msg_put_map_reply (b, records, nonce, probe_bit);
4282
4283   /* push outer ip header */
4284   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, dst_port, sloc, dst);
4285
4286   bi_res[0] = bi;
4287   return b;
4288 }
4289
4290 static int
4291 send_map_reply (lisp_cp_main_t * lcm, u32 mi, ip_address_t * dst,
4292                 u8 probe_bit, u64 nonce, u16 dst_port,
4293                 ip_address_t * probed_loc)
4294 {
4295   ip_address_t src;
4296   u32 bi;
4297   vlib_buffer_t *b;
4298   vlib_frame_t *f;
4299   u32 next_index, *to_next;
4300   mapping_t *records = 0, *m;
4301
4302   m = pool_elt_at_index (lcm->mapping_pool, mi);
4303   if (!m)
4304     return -1;
4305
4306   vec_add1 (records, m[0]);
4307   add_locators (lcm, &records[0], m->locator_set_index, probed_loc);
4308   memset (&src, 0, sizeof (src));
4309
4310   if (!ip_fib_get_first_egress_ip_for_dst (lcm, dst, &src))
4311     {
4312       clib_warning ("can't find inteface address for %U", format_ip_address,
4313                     dst);
4314       return -1;
4315     }
4316
4317   b = build_map_reply (lcm, &src, dst, nonce, probe_bit, records, dst_port,
4318                        &bi);
4319   if (!b)
4320     return -1;
4321   free_map_register_records (records);
4322
4323   vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
4324   next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
4325     ip4_lookup_node.index : ip6_lookup_node.index;
4326
4327   f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
4328
4329   /* Enqueue the packet */
4330   to_next = vlib_frame_vector_args (f);
4331   to_next[0] = bi;
4332   f->n_vectors = 1;
4333   vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
4334   return 0;
4335 }
4336
4337 void
4338 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
4339                      vlib_buffer_t * b)
4340 {
4341   u8 *ip_hdr = 0, *udp_hdr;
4342   ip4_header_t *ip4;
4343   ip6_header_t *ip6;
4344   ip_address_t *dst_loc = 0, probed_loc, src_loc;
4345   mapping_t m;
4346   map_request_hdr_t *mreq_hdr;
4347   gid_address_t src, dst;
4348   u64 nonce;
4349   u32 i, len = 0;
4350   gid_address_t *itr_rlocs = 0, *rloc;
4351
4352   mreq_hdr = vlib_buffer_get_current (b);
4353
4354   // TODO ugly workaround to find out whether LISP is carried by ip4 or 6
4355   // and needs to be fixed
4356   udp_hdr = (u8 *) vlib_buffer_get_current (b) - sizeof (udp_header_t);
4357   ip4 = (ip4_header_t *) (udp_hdr - sizeof (ip4_header_t));
4358   ip6 = (ip6_header_t *) (udp_hdr - sizeof (ip6_header_t));
4359
4360   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
4361     ip_hdr = (u8 *) ip4;
4362   else
4363     {
4364       u32 flags = clib_net_to_host_u32
4365         (ip6->ip_version_traffic_class_and_flow_label);
4366       if ((flags & 0xF0000000) == 0x60000000)
4367         ip_hdr = (u8 *) ip6;
4368       else
4369         {
4370           clib_warning ("internal error: cannot determine whether packet "
4371                         "is ip4 or 6!");
4372           return;
4373         }
4374     }
4375
4376   vlib_buffer_pull (b, sizeof (*mreq_hdr));
4377
4378   nonce = MREQ_NONCE (mreq_hdr);
4379
4380   if (!MREQ_SMR (mreq_hdr) && !MREQ_RLOC_PROBE (mreq_hdr))
4381     {
4382       clib_warning
4383         ("Only SMR Map-Requests and RLOC probe supported for now!");
4384       return;
4385     }
4386
4387   /* parse src eid */
4388   len = lisp_msg_parse_addr (b, &src);
4389   if (len == ~0)
4390     return;
4391
4392   /* for now we don't do anything with the itr's rlocs */
4393   len =
4394     lisp_msg_parse_itr_rlocs (b, &itr_rlocs,
4395                               MREQ_ITR_RLOC_COUNT (mreq_hdr) + 1);
4396   if (len == ~0)
4397     return;
4398
4399   /* parse eid records and send SMR-invoked map-requests */
4400   for (i = 0; i < MREQ_REC_COUNT (mreq_hdr); i++)
4401     {
4402       memset (&dst, 0, sizeof (dst));
4403       len = lisp_msg_parse_eid_rec (b, &dst);
4404       if (len == ~0)
4405         {
4406           clib_warning ("Can't parse map-request EID-record");
4407           goto done;
4408         }
4409
4410       if (MREQ_SMR (mreq_hdr))
4411         {
4412           /* send SMR-invoked map-requests */
4413           queue_map_request (&dst, &src, 1 /* invoked */ , 0 /* resend */ );
4414         }
4415       else if (MREQ_RLOC_PROBE (mreq_hdr))
4416         {
4417           memset (&m, 0, sizeof (m));
4418           u32 mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
4419
4420           // TODO: select best locator; for now use the first one
4421           dst_loc = &gid_address_ip (&itr_rlocs[0]);
4422
4423           /* get src/dst IP addresses */
4424           get_src_and_dst_ip (ip_hdr, &src_loc, &probed_loc);
4425
4426           // TODO get source port from buffer
4427           u16 src_port = LISP_CONTROL_PORT;
4428
4429           send_map_reply (lcm, mi, dst_loc, 1 /* probe-bit */ , nonce,
4430                           src_port, &probed_loc);
4431         }
4432     }
4433
4434 done:
4435   vec_foreach (rloc, itr_rlocs)
4436   {
4437     gid_address_free (rloc);
4438   }
4439 }
4440
4441 static void
4442 queue_map_reply (vlib_buffer_t * b)
4443 {
4444   vlib_buffer_t *a = clib_mem_alloc (sizeof (a[0]) + b->current_length);
4445
4446   clib_memcpy (a->data, b->data + b->current_data, b->current_length);
4447   a->current_length = b->current_length;
4448   a->current_data = 0;
4449
4450   vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (a[0])
4451                                + a->current_length);
4452   clib_mem_free (a);
4453 }
4454
4455 static uword
4456 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
4457                vlib_frame_t * from_frame)
4458 {
4459   u32 n_left_from, *from, *to_next_drop;
4460   lisp_msg_type_e type;
4461   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4462
4463   from = vlib_frame_vector_args (from_frame);
4464   n_left_from = from_frame->n_vectors;
4465
4466
4467   while (n_left_from > 0)
4468     {
4469       u32 n_left_to_next_drop;
4470
4471       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
4472                            to_next_drop, n_left_to_next_drop);
4473       while (n_left_from > 0 && n_left_to_next_drop > 0)
4474         {
4475           u32 bi0;
4476           vlib_buffer_t *b0;
4477
4478           bi0 = from[0];
4479           from += 1;
4480           n_left_from -= 1;
4481           to_next_drop[0] = bi0;
4482           to_next_drop += 1;
4483           n_left_to_next_drop -= 1;
4484
4485           b0 = vlib_get_buffer (vm, bi0);
4486
4487           type = lisp_msg_type (vlib_buffer_get_current (b0));
4488           switch (type)
4489             {
4490             case LISP_MAP_REPLY:
4491               queue_map_reply (b0);
4492               break;
4493             case LISP_MAP_REQUEST:
4494               process_map_request (vm, lcm, b0);
4495               break;
4496             case LISP_MAP_NOTIFY:
4497               process_map_notify (vm, lcm, b0);
4498               break;
4499             default:
4500               clib_warning ("Unsupported LISP message type %d", type);
4501               break;
4502             }
4503
4504           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
4505
4506           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
4507             {
4508
4509             }
4510         }
4511
4512       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
4513                            n_left_to_next_drop);
4514     }
4515   return from_frame->n_vectors;
4516 }
4517
4518 /* *INDENT-OFF* */
4519 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
4520   .function = lisp_cp_input,
4521   .name = "lisp-cp-input",
4522   .vector_size = sizeof (u32),
4523   .format_trace = format_lisp_cp_input_trace,
4524   .type = VLIB_NODE_TYPE_INTERNAL,
4525
4526   .n_errors = LISP_CP_INPUT_N_ERROR,
4527   .error_strings = lisp_cp_input_error_strings,
4528
4529   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
4530
4531   .next_nodes = {
4532       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
4533   },
4534 };
4535 /* *INDENT-ON* */
4536
4537 clib_error_t *
4538 lisp_cp_init (vlib_main_t * vm)
4539 {
4540   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4541   clib_error_t *error = 0;
4542
4543   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
4544     return error;
4545
4546   lcm->im4 = &ip4_main;
4547   lcm->im6 = &ip6_main;
4548   lcm->vlib_main = vm;
4549   lcm->vnet_main = vnet_get_main ();
4550   lcm->mreq_itr_rlocs = ~0;
4551   lcm->lisp_pitr = 0;
4552   memset (&lcm->active_map_resolver, 0, sizeof (lcm->active_map_resolver));
4553
4554   lcm->pending_map_request_lock =
4555     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
4556
4557   lcm->pending_map_request_lock[0] = 0;
4558   gid_dictionary_init (&lcm->mapping_index_by_gid);
4559   lcm->do_map_resolver_election = 1;
4560   lcm->map_request_mode = MR_MODE_DST_ONLY;
4561
4562   /* default vrf mapped to vni 0 */
4563   hash_set (lcm->table_id_by_vni, 0, 0);
4564   hash_set (lcm->vni_by_table_id, 0, 0);
4565
4566   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
4567                          lisp_cp_input_node.index, 1 /* is_ip4 */ );
4568   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
4569                          lisp_cp_input_node.index, 0 /* is_ip4 */ );
4570
4571   return 0;
4572 }
4573
4574 static void *
4575 send_map_request_thread_fn (void *arg)
4576 {
4577   map_request_args_t *a = arg;
4578   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4579
4580   if (a->is_resend)
4581     /* if resending, we already have the lock */
4582     resend_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
4583   else
4584     {
4585       /* get lock before sending map-request */
4586       lisp_pending_map_request_lock (lcm);
4587       send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
4588       lisp_pending_map_request_unlock (lcm);
4589     }
4590
4591
4592   return 0;
4593 }
4594
4595 static int
4596 queue_map_request (gid_address_t * seid, gid_address_t * deid,
4597                    u8 smr_invoked, u8 is_resend)
4598 {
4599   map_request_args_t a;
4600
4601   a.is_resend = is_resend;
4602   gid_address_copy (&a.seid, seid);
4603   gid_address_copy (&a.deid, deid);
4604   a.smr_invoked = smr_invoked;
4605
4606   vl_api_rpc_call_main_thread (send_map_request_thread_fn,
4607                                (u8 *) & a, sizeof (a));
4608   return 0;
4609 }
4610
4611 /**
4612  * Take an action with a pending map request depending on expiration time
4613  * and re-try counters.
4614  */
4615 static void
4616 update_pending_request (pending_map_request_t * r, f64 dt)
4617 {
4618   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4619   lisp_msmr_t *mr;
4620
4621   if (r->time_to_expire - dt < 0)
4622     /* it's time to decide what to do with this pending request */
4623     {
4624       if (r->retries_num >= NUMBER_OF_RETRIES)
4625         /* too many retries -> assume current map resolver is not available */
4626         {
4627           mr = get_map_resolver (&lcm->active_map_resolver);
4628           if (!mr)
4629             {
4630               clib_warning ("Map resolver %U not found - probably deleted "
4631                             "by the user recently.", format_ip_address,
4632                             &lcm->active_map_resolver);
4633             }
4634           else
4635             {
4636               clib_warning ("map resolver %U is unreachable, ignoring",
4637                             format_ip_address, &lcm->active_map_resolver);
4638
4639               /* mark current map resolver unavailable so it won't be
4640                * selected next time */
4641               mr->is_down = 1;
4642               mr->last_update = vlib_time_now (lcm->vlib_main);
4643             }
4644
4645           reset_pending_mr_counters (r);
4646           elect_map_resolver (lcm);
4647
4648           /* try to find a next eligible map resolver and re-send */
4649           queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
4650                              1 /* resend */ );
4651         }
4652       else
4653         {
4654           /* try again */
4655           queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
4656                              1 /* resend */ );
4657           r->retries_num++;
4658           r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
4659         }
4660     }
4661   else
4662     r->time_to_expire -= dt;
4663 }
4664
4665 static void
4666 remove_dead_pending_map_requests (lisp_cp_main_t * lcm)
4667 {
4668   u64 *nonce;
4669   pending_map_request_t *pmr;
4670   u32 *to_be_removed = 0, *pmr_index;
4671
4672   ASSERT (*lcm->pending_map_request_lock);
4673
4674   /* *INDENT-OFF* */
4675   pool_foreach (pmr, lcm->pending_map_requests_pool,
4676   ({
4677     if (pmr->to_be_removed)
4678       {
4679         clib_fifo_foreach (nonce, pmr->nonces, ({
4680           hash_unset (lcm->pending_map_requests_by_nonce, nonce[0]);
4681         }));
4682
4683         vec_add1 (to_be_removed, pmr - lcm->pending_map_requests_pool);
4684       }
4685   }));
4686   /* *INDENT-ON* */
4687
4688   vec_foreach (pmr_index, to_be_removed)
4689     pool_put_index (lcm->pending_map_requests_by_nonce, pmr_index[0]);
4690
4691   vec_free (to_be_removed);
4692 }
4693
4694 static void
4695 update_rloc_probing (lisp_cp_main_t * lcm, f64 dt)
4696 {
4697   static f64 time_left = RLOC_PROBING_INTERVAL;
4698
4699   if (!lcm->is_enabled || !lcm->rloc_probing)
4700     return;
4701
4702   time_left -= dt;
4703   if (time_left <= 0)
4704     {
4705       time_left = RLOC_PROBING_INTERVAL;
4706       send_rloc_probes (lcm);
4707     }
4708 }
4709
4710 static void
4711 update_map_register (lisp_cp_main_t * lcm, f64 dt)
4712 {
4713   static f64 time_left = QUICK_MAP_REGISTER_INTERVAL;
4714   static u64 mreg_sent_counter = 0;
4715
4716   if (!lcm->is_enabled || !lcm->map_registering)
4717     return;
4718
4719   time_left -= dt;
4720   if (time_left <= 0)
4721     {
4722       if (mreg_sent_counter >= QUICK_MAP_REGISTER_MSG_COUNT)
4723         time_left = MAP_REGISTER_INTERVAL;
4724       else
4725         {
4726           mreg_sent_counter++;
4727           time_left = QUICK_MAP_REGISTER_INTERVAL;
4728         }
4729       send_map_register (lcm, 1 /* want map notify */ );
4730     }
4731 }
4732
4733 static uword
4734 send_map_resolver_service (vlib_main_t * vm,
4735                            vlib_node_runtime_t * rt, vlib_frame_t * f)
4736 {
4737   f64 period = 2.0;
4738   pending_map_request_t *pmr;
4739   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4740
4741   while (1)
4742     {
4743       vlib_process_wait_for_event_or_clock (vm, period);
4744
4745       /* currently no signals are expected - just wait for clock */
4746       (void) vlib_process_get_events (vm, 0);
4747
4748       lisp_pending_map_request_lock (lcm);
4749
4750       /* *INDENT-OFF* */
4751       pool_foreach (pmr, lcm->pending_map_requests_pool,
4752       ({
4753         if (!pmr->to_be_removed)
4754           update_pending_request (pmr, period);
4755       }));
4756       /* *INDENT-ON* */
4757
4758       remove_dead_pending_map_requests (lcm);
4759       lisp_pending_map_request_unlock (lcm);
4760
4761       update_map_register (lcm, period);
4762       update_rloc_probing (lcm, period);
4763     }
4764
4765   /* unreachable */
4766   return 0;
4767 }
4768
4769 /* *INDENT-OFF* */
4770 VLIB_REGISTER_NODE (lisp_retry_service_node,static) = {
4771     .function = send_map_resolver_service,
4772     .type = VLIB_NODE_TYPE_PROCESS,
4773     .name = "lisp-retry-service",
4774     .process_log2_n_stack_bytes = 16,
4775 };
4776 /* *INDENT-ON* */
4777
4778 VLIB_INIT_FUNCTION (lisp_cp_init);
4779
4780 /*
4781  * fd.io coding-style-patch-verification: ON
4782  *
4783  * Local Variables:
4784  * eval: (c-set-style "gnu")
4785  * End:
4786  */