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