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