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