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