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