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