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