VPP-198: LISP map-resolver failover algorithm
[vpp.git] / vnet / vnet / lisp-cp / control.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vlibmemory/api.h>
17 #include <vnet/lisp-cp/control.h>
18 #include <vnet/lisp-cp/packets.h>
19 #include <vnet/lisp-cp/lisp_msg_serdes.h>
20 #include <vnet/lisp-gpe/lisp_gpe.h>
21
22 typedef struct
23 {
24   u8 is_resend;
25   gid_address_t seid;
26   gid_address_t deid;
27   u8 smr_invoked;
28 } map_request_args_t;
29
30 static int
31 queue_map_request (gid_address_t * seid, gid_address_t * deid,
32                    u8 smr_invoked, u8 is_resend);
33
34 ip_interface_address_t *
35 ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
36                                           u8 loop)
37 {
38   vnet_main_t *vnm = vnet_get_main ();
39   vnet_sw_interface_t * swif = vnet_get_sw_interface (vnm, sw_if_index);
40   if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
41     sw_if_index = swif->unnumbered_sw_if_index;
42   u32 ia =
43       (vec_len((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
44           vec_elt((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
45           (u32) ~0;
46   return pool_elt_at_index((lm)->if_address_pool, ia);
47 }
48
49 void *
50 ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
51                                 u8 version)
52 {
53   ip_interface_address_t * ia;
54
55   ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
56   if (!ia)
57     return 0;
58   return ip_interface_address_get_address (lm, ia);
59 }
60
61 int
62 ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
63                                    u8 version, ip_address_t * result)
64 {
65   ip_lookup_main_t * lm;
66   void * addr;
67
68   lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
69   addr = ip_interface_get_first_address (lm, sw_if_index, version);
70   if (!addr)
71     return 0;
72
73   ip_address_set (result, addr, version);
74   return 1;
75 }
76
77 static u32
78 ip_fib_lookup_with_table (lisp_cp_main_t * lcm, u32 fib_index,
79                           ip_address_t * dst)
80 {
81   if (ip_addr_version (dst) == IP4)
82       return ip4_fib_lookup_with_table (lcm->im4, fib_index, &ip_addr_v4(dst),
83                                         0);
84   else
85       return ip6_fib_lookup_with_table (lcm->im6, fib_index, &ip_addr_v6(dst));
86 }
87
88 u32
89 ip_fib_get_egress_iface_for_dst_with_lm (lisp_cp_main_t * lcm,
90                                          ip_address_t * dst,
91                                          ip_lookup_main_t * lm)
92 {
93   u32 adj_index;
94   ip_adjacency_t * adj;
95
96   adj_index = ip_fib_lookup_with_table (lcm, 0, dst);
97   adj = ip_get_adjacency (lm, adj_index);
98
99   if (adj == 0)
100     return ~0;
101
102   /* we only want outgoing routes */
103   if (adj->lookup_next_index != IP_LOOKUP_NEXT_ARP
104       && adj->lookup_next_index != IP_LOOKUP_NEXT_REWRITE)
105     return ~0;
106
107   return adj->rewrite_header.sw_if_index;
108 }
109
110 /**
111  * Find the sw_if_index of the interface that would be used to egress towards
112  * dst.
113  */
114 u32
115 ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
116 {
117   ip_lookup_main_t * lm;
118
119   lm = ip_addr_version (dst) == IP4 ?
120       &lcm->im4->lookup_main : &lcm->im6->lookup_main;
121
122   return ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
123 }
124
125 /**
126  * Find first IP of the interface that would be used to egress towards dst.
127  * Returns 1 if the address is found 0 otherwise.
128  */
129 int
130 ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
131                                     ip_address_t * result)
132 {
133   u32 si;
134   ip_lookup_main_t * lm;
135   void * addr = 0;
136   u8 ipver;
137
138   ASSERT(result != 0);
139
140   ipver = ip_addr_version(dst);
141
142   lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
143   si = ip_fib_get_egress_iface_for_dst_with_lm (lcm, dst, lm);
144
145   if ((u32) ~0 == si)
146     return 0;
147
148   /* find the first ip address */
149   addr = ip_interface_get_first_address (lm, si, ipver);
150   if (0 == addr)
151     return 0;
152
153   ip_address_set (result, addr, ipver);
154   return 1;
155 }
156
157 static int
158 dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_l2, u8 is_add)
159 {
160   uword * dp_table, * intf;
161   vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
162
163   if (!is_l2)
164     {
165       dp_table = hash_get(lcm->table_id_by_vni, vni);
166
167       if (!dp_table)
168         {
169           clib_warning("vni %d not associated to a vrf!", vni);
170           return VNET_API_ERROR_INVALID_VALUE;
171         }
172     }
173   else
174     {
175       dp_table = hash_get(lcm->bd_id_by_vni, vni);
176       if (!dp_table)
177         {
178           clib_warning("vni %d not associated to a bridge domain!", vni);
179           return VNET_API_ERROR_INVALID_VALUE;
180         }
181     }
182
183   intf = hash_get(is_l2 ? lcm->l2_dp_intf_by_vni :lcm->dp_intf_by_vni, vni);
184
185   /* enable/disable data-plane interface */
186   if (is_add)
187     {
188       /* create interface */
189       if (!intf)
190         {
191           ai->is_add = 1;
192           ai->vni = vni;
193           ai->is_l2 = is_l2;
194           ai->dp_table = dp_table[0];
195
196           vnet_lisp_gpe_add_del_iface (ai, 0);
197
198           /* keep track of vnis for which interfaces have been created */
199           hash_set(lcm->dp_intf_by_vni, vni, 1);
200         }
201     }
202   else
203     {
204       if (intf == 0)
205         {
206           clib_warning("interface for vni %d doesn't exist!", vni);
207           return VNET_API_ERROR_INVALID_VALUE;
208         }
209
210       ai->is_add = 0;
211       ai->vni = vni;
212       ai->dp_table = dp_table[0];
213       vnet_lisp_gpe_add_del_iface (ai, 0);
214       hash_unset(lcm->dp_intf_by_vni, vni);
215     }
216
217   return 0;
218 }
219
220 static void
221 dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
222 {
223   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
224   fwd_entry_t * fe = 0;
225   uword * feip = 0;
226   memset(a, 0, sizeof(*a));
227
228   feip = hash_get(lcm->fwd_entry_by_mapping_index, dst_map_index);
229   if (!feip)
230     return;
231
232   fe = pool_elt_at_index(lcm->fwd_entry_pool, feip[0]);
233
234   /* delete dp fwd entry */
235   u32 sw_if_index;
236   a->is_add = 0;
237   a->locator_pairs = fe->locator_pairs;
238   a->vni = gid_address_vni(&a->rmt_eid);
239   gid_address_copy(&a->rmt_eid, &fe->deid);
240
241   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
242
243   /* delete entry in fwd table */
244   hash_unset(lcm->fwd_entry_by_mapping_index, dst_map_index);
245   vec_free(fe->locator_pairs);
246   pool_put(lcm->fwd_entry_pool, fe);
247 }
248
249 /**
250  * Finds first remote locator with best (lowest) priority that has a local
251  * peer locator with an underlying route to it.
252  *
253  */
254 static u32
255 get_locator_pairs (lisp_cp_main_t* lcm, mapping_t * lcl_map,
256                    mapping_t * rmt_map, locator_pair_t ** locator_pairs)
257 {
258   u32 i, limitp = 0, li, found = 0, esi;
259   locator_set_t * rmt_ls, * lcl_ls;
260   ip_address_t _lcl_addr, * lcl_addr = &_lcl_addr;
261   locator_t * lp, * rmt = 0;
262   uword * checked = 0;
263   locator_pair_t pair;
264
265   rmt_ls = pool_elt_at_index(lcm->locator_set_pool, rmt_map->locator_set_index);
266   lcl_ls = pool_elt_at_index(lcm->locator_set_pool, lcl_map->locator_set_index);
267
268   if (!rmt_ls || vec_len(rmt_ls->locator_indices) == 0)
269     return 0;
270
271   while (1)
272     {
273       rmt = 0;
274
275       /* find unvisited remote locator with best priority */
276       for (i = 0; i < vec_len(rmt_ls->locator_indices); i++)
277         {
278           if (0 != hash_get(checked, i))
279             continue;
280
281           li = vec_elt(rmt_ls->locator_indices, i);
282           lp = pool_elt_at_index(lcm->locator_pool, li);
283
284           /* we don't support non-IP locators for now */
285           if (gid_address_type(&lp->address) != GID_ADDR_IP_PREFIX)
286             continue;
287
288           if ((found && lp->priority == limitp)
289               || (!found && lp->priority >= limitp))
290             {
291               rmt = lp;
292
293               /* don't search for locators with lower priority and don't
294                * check this locator again*/
295               limitp = lp->priority;
296               hash_set(checked, i, 1);
297               break;
298             }
299         }
300       /* check if a local locator with a route to remote locator exists */
301       if (rmt != 0)
302         {
303           /* find egress sw_if_index for rmt locator */
304           esi = ip_fib_get_egress_iface_for_dst (
305               lcm, &gid_address_ip(&rmt->address));
306           if ((u32) ~0 == esi)
307             continue;
308
309           for (i = 0; i < vec_len(lcl_ls->locator_indices); i++)
310             {
311               li = vec_elt (lcl_ls->locator_indices, i);
312               locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
313
314               /* found local locator with the needed sw_if_index*/
315               if (sl->sw_if_index == esi)
316                 {
317                   /* and it has an address */
318                   if (0 == ip_interface_get_first_ip_address (lcm,
319                              sl->sw_if_index,
320                              gid_address_ip_version(&rmt->address), lcl_addr))
321                     continue;
322
323                   memset(&pair, 0, sizeof(pair));
324                   ip_address_copy (&pair.rmt_loc,
325                                    &gid_address_ip(&rmt->address));
326                   ip_address_copy(&pair.lcl_loc, lcl_addr);
327                   pair.weight = rmt->weight;
328                   vec_add1(locator_pairs[0], pair);
329                   found = 1;
330                 }
331             }
332         }
333       else
334         break;
335     }
336
337   hash_free(checked);
338   return found;
339 }
340
341 static void
342 dp_add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index)
343 {
344   vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
345   mapping_t * src_map, * dst_map;
346   u32 sw_if_index;
347   uword * feip = 0, * dpid;
348   fwd_entry_t* fe;
349   u8 type;
350
351   memset (a, 0, sizeof(*a));
352
353   /* remove entry if it already exists */
354   feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
355   if (feip)
356     dp_del_fwd_entry (lcm, src_map_index, dst_map_index);
357
358   src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
359   dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
360
361   /* insert data plane forwarding entry */
362   a->is_add = 1;
363
364   gid_address_copy (&a->rmt_eid, &dst_map->eid);
365   a->vni = gid_address_vni(&a->rmt_eid);
366
367   /* get vrf or bd_index associated to vni */
368   type = gid_address_type(&dst_map->eid);
369   if (GID_ADDR_IP_PREFIX == type)
370     {
371       dpid = hash_get(lcm->table_id_by_vni, a->vni);
372       if (!dpid)
373         {
374           clib_warning("vni %d not associated to a vrf!", a->vni);
375           return;
376         }
377       a->table_id = dpid[0];
378     }
379   else if (GID_ADDR_MAC == type)
380     {
381       dpid = hash_get(lcm->bd_id_by_vni, a->vni);
382       if (!dpid)
383         {
384           clib_warning("vni %d not associated to a bridge domain !", a->vni);
385           return;
386         }
387       a->bd_id = dpid[0];
388     }
389
390   /* find best locator pair that 1) verifies LISP policy 2) are connected */
391   if (0 == get_locator_pairs (lcm, src_map, dst_map, &a->locator_pairs))
392     {
393       /* negative entry */
394       a->is_negative = 1;
395       a->action = dst_map->action;
396     }
397
398   /* TODO remove */
399   u8 ipver = ip_prefix_version(&gid_address_ippref(&a->rmt_eid));
400   a->decap_next_index = (ipver == IP4) ?
401           LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
402
403   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
404
405   /* add tunnel to fwd entry table XXX check return value from DP insertion */
406   pool_get (lcm->fwd_entry_pool, fe);
407   fe->locator_pairs = a->locator_pairs;
408   gid_address_copy (&fe->deid, &a->rmt_eid);
409   hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
410             fe - lcm->fwd_entry_pool);
411 }
412
413 /**
414  * Add/remove mapping to/from map-cache. Overwriting not allowed.
415  */
416 int
417 vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a,
418                              u32 * map_index_result)
419 {
420   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
421   u32 mi, * map_indexp, map_index, i;
422   mapping_t * m, * old_map;
423   u32 ** eid_indexes;
424
425   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid);
426   old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
427   if (a->is_add)
428     {
429       /* TODO check if overwriting and take appropriate actions */
430       if (mi != GID_LOOKUP_MISS && !gid_address_cmp (&old_map->eid,
431                                                      &a->eid))
432         {
433           clib_warning ("eid %U found in the eid-table", format_gid_address,
434                        &a->eid);
435           return VNET_API_ERROR_VALUE_EXIST;
436         }
437
438       pool_get(lcm->mapping_pool, m);
439       gid_address_copy (&m->eid, &a->eid);
440       m->locator_set_index = a->locator_set_index;
441       m->ttl = a->ttl;
442       m->action = a->action;
443       m->local = a->local;
444
445       map_index = m - lcm->mapping_pool;
446       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, map_index,
447                               1);
448
449       if (pool_is_free_index(lcm->locator_set_pool, a->locator_set_index))
450         {
451           clib_warning("Locator set with index %d doesn't exist",
452                        a->locator_set_index);
453           return VNET_API_ERROR_INVALID_VALUE;
454         }
455
456       /* add eid to list of eids supported by locator-set */
457       vec_validate (lcm->locator_set_to_eids, a->locator_set_index);
458       eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
459                                      a->locator_set_index);
460       vec_add1(eid_indexes[0], map_index);
461
462       if (a->local)
463         {
464           /* mark as local */
465           vec_add1(lcm->local_mappings_indexes, map_index);
466         }
467       map_index_result[0] = map_index;
468     }
469   else
470     {
471       if (mi == GID_LOOKUP_MISS)
472         {
473           clib_warning("eid %U not found in the eid-table", format_gid_address,
474                        &a->eid);
475           return VNET_API_ERROR_INVALID_VALUE;
476         }
477
478       /* clear locator-set to eids binding */
479       eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids,
480                                      a->locator_set_index);
481       for (i = 0; i < vec_len(eid_indexes[0]); i++)
482         {
483           map_indexp = vec_elt_at_index(eid_indexes[0], i);
484           if (map_indexp[0] == mi)
485               break;
486         }
487       vec_del1(eid_indexes[0], i);
488
489       /* remove local mark if needed */
490       m = pool_elt_at_index(lcm->mapping_pool, mi);
491       if (m->local)
492         {
493           u32 k, * lm_indexp;
494           for (k = 0; k < vec_len(lcm->local_mappings_indexes); k++)
495             {
496               lm_indexp = vec_elt_at_index(lcm->local_mappings_indexes, k);
497               if (lm_indexp[0] == mi)
498                 break;
499             }
500           vec_del1(lcm->local_mappings_indexes, k);
501         }
502
503       /* remove mapping from dictionary */
504       gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, 0, 0);
505       gid_address_free (&m->eid);
506       pool_put_index (lcm->mapping_pool, mi);
507     }
508
509   return 0;
510 }
511
512 /**
513  *  Add/update/delete mapping to/in/from map-cache.
514  */
515 int
516 vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
517                                  u32 * map_index_result)
518 {
519   uword * dp_table = 0;
520   u32 vni;
521   u8 type;
522
523   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
524
525   if (vnet_lisp_enable_disable_status () == 0)
526     {
527       clib_warning ("LISP is disabled!");
528       return VNET_API_ERROR_LISP_DISABLED;
529     }
530
531   vni = gid_address_vni(&a->eid);
532   type = gid_address_type(&a->eid);
533   if (GID_ADDR_IP_PREFIX == type)
534     dp_table = hash_get(lcm->table_id_by_vni, vni);
535   else if (GID_ADDR_MAC == type)
536     dp_table = hash_get(lcm->bd_id_by_vni, vni);
537
538   if (!dp_table)
539     {
540       clib_warning("vni %d not associated to a %s!", vni,
541                    GID_ADDR_IP_PREFIX == type ? "vrf" : "bd");
542       return VNET_API_ERROR_INVALID_VALUE;
543     }
544
545   /* store/remove mapping from map-cache */
546   return vnet_lisp_map_cache_add_del (a, map_index_result);
547 }
548
549 static clib_error_t *
550 lisp_add_del_local_eid_command_fn (vlib_main_t * vm, unformat_input_t * input,
551                                    vlib_cli_command_t * cmd)
552 {
553   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
554   unformat_input_t _line_input, * line_input = &_line_input;
555   u8 is_add = 1;
556   gid_address_t eid;
557   gid_address_t * eids = 0;
558   clib_error_t * error = 0;
559   u8 * locator_set_name = 0;
560   u32 locator_set_index = 0, map_index = 0;
561   uword * p;
562   vnet_lisp_add_del_mapping_args_t _a, * a = &_a;
563   int rv = 0;
564   u32 vni = 0;
565
566   memset (&eid, 0, sizeof (eid));
567   memset (a, 0, sizeof (*a));
568
569   /* Get a line of input. */
570   if (! unformat_user (input, unformat_line_input, line_input))
571     return 0;
572
573   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
574     {
575       if (unformat (line_input, "add"))
576         is_add = 1;
577       else if (unformat (line_input, "del"))
578         is_add = 0;
579       else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
580         ;
581       else if (unformat (line_input, "vni %d", &vni))
582         gid_address_vni (&eid) = vni;
583       else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
584         {
585           p = hash_get_mem(lcm->locator_set_index_by_name, locator_set_name);
586           if (!p)
587             {
588               error = clib_error_return(0, "locator-set %s doesn't exist",
589                                         locator_set_name);
590               goto done;
591             }
592           locator_set_index = p[0];
593         }
594       else
595         {
596           error = unformat_parse_error(line_input);
597           goto done;
598         }
599     }
600   /* XXX treat batch configuration */
601
602   if (GID_ADDR_SRC_DST == gid_address_type(&eid))
603     {
604       error = clib_error_return(0, "src/dst is not supported for local EIDs!");
605       goto done;
606     }
607
608   gid_address_copy(&a->eid, &eid);
609   a->is_add = is_add;
610   a->locator_set_index = locator_set_index;
611   a->local = 1;
612
613   rv = vnet_lisp_add_del_local_mapping (a, &map_index);
614   if (0 != rv)
615    {
616       error = clib_error_return(0, "failed to %s local mapping!",
617                                 is_add ? "add" : "delete");
618    }
619  done:
620   vec_free(eids);
621   if (locator_set_name)
622     vec_free (locator_set_name);
623   gid_address_free (&a->eid);
624   return error;
625 }
626
627 VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = {
628     .path = "lisp eid-table",
629     .short_help = "lisp eid-table add/del [vni <vni>] eid <eid> "
630       "locator-set <locator-set>",
631     .function = lisp_add_del_local_eid_command_fn,
632 };
633
634 int
635 vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add)
636 {
637   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
638   uword * dp_idp, * vnip, ** dp_table_by_vni, ** vni_by_dp_table;
639
640   if (vnet_lisp_enable_disable_status () == 0)
641     {
642       clib_warning ("LISP is disabled!");
643       return -1;
644     }
645
646   dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni;
647   vni_by_dp_table = is_l2 ? &lcm->vni_by_bd_id : &lcm->vni_by_table_id;
648
649   if (!is_l2 && (vni == 0 || dp_id == 0))
650     {
651       clib_warning ("can't add/del default vni-vrf mapping!");
652       return -1;
653     }
654
655   dp_idp = hash_get (dp_table_by_vni[0], vni);
656   vnip = hash_get (vni_by_dp_table[0], dp_id);
657
658   if (is_add)
659     {
660       if (dp_idp || vnip)
661         {
662           clib_warning ("vni %d or vrf %d already used in vrf/vni "
663                         "mapping!", vni, dp_id);
664           return -1;
665         }
666       hash_set (dp_table_by_vni[0], vni, dp_id);
667       hash_set (vni_by_dp_table[0], dp_id, vni);
668
669       /* create dp iface */
670       dp_add_del_iface (lcm, vni, is_l2, 1);
671     }
672   else
673     {
674       if (!dp_idp || !vnip)
675         {
676           clib_warning ("vni %d or vrf %d not used in any vrf/vni! "
677                         "mapping!", vni, dp_id);
678           return -1;
679         }
680       hash_unset (dp_table_by_vni[0], vni);
681       hash_unset (vni_by_dp_table[0], dp_id);
682
683       /* remove dp iface */
684       dp_add_del_iface (lcm, vni, is_l2, 0);
685     }
686   return 0;
687
688 }
689
690 static clib_error_t *
691 lisp_eid_table_map_command_fn (vlib_main_t * vm,
692                                unformat_input_t * input,
693                                vlib_cli_command_t * cmd)
694 {
695   u8 is_add = 1, is_l2 = 0;
696   u32 vni = 0, dp_id = 0;
697   unformat_input_t _line_input, * line_input = &_line_input;
698
699   /* Get a line of input. */
700   if (! unformat_user (input, unformat_line_input, line_input))
701     return 0;
702
703   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
704     {
705       if (unformat (line_input, "del"))
706         is_add = 0;
707       else if (unformat (line_input, "vni %d", &vni))
708         ;
709       else if (unformat (line_input, "vrf %d", &dp_id))
710         ;
711       else if (unformat (line_input, "bd %d", &dp_id))
712         is_l2 = 1;
713       else
714         {
715           return unformat_parse_error (line_input);
716         }
717     }
718   vnet_lisp_eid_table_map (vni, dp_id, is_l2, is_add);
719   return 0;
720 }
721
722 VLIB_CLI_COMMAND (lisp_eid_table_map_command) = {
723     .path = "lisp eid-table map",
724     .short_help = "lisp eid-table map [del] vni <vni> vrf <vrf> | bd <bdi>",
725     .function = lisp_eid_table_map_command_fn,
726 };
727
728
729 /* return 0 if the two locator sets are identical 1 otherwise */
730 static u8
731 compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes,
732                   locator_t * new_locators)
733 {
734   u32 i, old_li;
735   locator_t * old_loc, * new_loc;
736
737   if (vec_len (old_ls_indexes) != vec_len(new_locators))
738     return 1;
739
740   for (i = 0; i < vec_len(new_locators); i++)
741     {
742       old_li = vec_elt(old_ls_indexes, i);
743       old_loc = pool_elt_at_index(lcm->locator_pool, old_li);
744
745       new_loc = vec_elt_at_index(new_locators, i);
746
747       if (locator_cmp (old_loc, new_loc))
748         return 1;
749     }
750   return 0;
751 }
752
753 /**
754  * Adds/removes/updates mapping. Does not program forwarding.
755  *
756  * @param eid end-host identifier
757  * @param rlocs vector of remote locators
758  * @param action action for negative map-reply
759  * @param is_add add mapping if non-zero, delete otherwise
760  * @param res_map_index the map-index that was created/updated/removed. It is
761  *                      set to ~0 if no action is taken.
762  * @return return code
763  */
764 int
765 vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
766                            u8 authoritative, u32 ttl, u8 is_add,
767                            u32 * res_map_index)
768 {
769   vnet_lisp_add_del_mapping_args_t _m_args, * m_args = &_m_args;
770   vnet_lisp_add_del_locator_set_args_t _ls_args, * ls_args = &_ls_args;
771   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
772   u32 mi, ls_index = 0, dst_map_index;
773   mapping_t * old_map;
774
775   if (vnet_lisp_enable_disable_status() == 0)
776     {
777       clib_warning ("LISP is disabled!");
778       return VNET_API_ERROR_LISP_DISABLED;
779     }
780
781   if (res_map_index)
782     res_map_index[0] = ~0;
783
784   memset (m_args, 0, sizeof (m_args[0]));
785   memset (ls_args, 0, sizeof (ls_args[0]));
786
787   ls_args->locators = rlocs;
788
789   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid);
790   old_map = ((u32) ~0 != mi) ? pool_elt_at_index(lcm->mapping_pool, mi) : 0;
791
792   if (is_add)
793     {
794       /* overwrite: if mapping already exists, decide if locators should be
795        * updated and be done */
796       if (old_map && gid_address_cmp (&old_map->eid, eid) == 0)
797         {
798           locator_set_t * old_ls;
799
800           /* update mapping attributes */
801           old_map->action = action;
802           old_map->authoritative = authoritative;
803           old_map->ttl = ttl;
804
805           old_ls = pool_elt_at_index(lcm->locator_set_pool,
806                                      old_map->locator_set_index);
807           if (compare_locators (lcm, old_ls->locator_indices,
808                                 ls_args->locators))
809             {
810               /* set locator-set index to overwrite */
811               ls_args->is_add = 1;
812               ls_args->index = old_map->locator_set_index;
813               vnet_lisp_add_del_locator_set (ls_args, 0);
814               if (res_map_index)
815                 res_map_index[0] = mi;
816             }
817         }
818       /* new mapping */
819       else
820         {
821           ls_args->is_add = 1;
822           ls_args->index = ~0;
823
824           vnet_lisp_add_del_locator_set (ls_args, &ls_index);
825
826           /* add mapping */
827           gid_address_copy (&m_args->eid, eid);
828           m_args->is_add = 1;
829           m_args->action = action;
830           m_args->locator_set_index = ls_index;
831           vnet_lisp_map_cache_add_del (m_args, &dst_map_index);
832
833           if (res_map_index)
834             res_map_index[0] = dst_map_index;
835         }
836     }
837   else
838     {
839       if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0)
840         {
841           clib_warning("cannot delete mapping for eid %U", format_gid_address,
842                        eid);
843           return -1;
844         }
845
846       m_args->is_add = 0;
847       gid_address_copy (&m_args->eid, eid);
848       m_args->locator_set_index = old_map->locator_set_index;
849
850       /* delete mapping associated from map-cache */
851       vnet_lisp_map_cache_add_del (m_args, 0);
852
853       ls_args->is_add = 0;
854       ls_args->index = old_map->locator_set_index;
855       /* delete locator set */
856       vnet_lisp_add_del_locator_set (ls_args, 0);
857
858       /* return old mapping index */
859       if (res_map_index)
860         res_map_index[0] = mi;
861     }
862
863   /* success */
864   return 0;
865 }
866
867 int
868 vnet_lisp_clear_all_remote_adjacencies (void)
869 {
870   int rv = 0;
871   u32 mi, * map_indices = 0, * map_indexp;
872   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
873   vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args;
874   vnet_lisp_add_del_locator_set_args_t _ls, * ls = &_ls;
875
876   pool_foreach_index (mi, lcm->mapping_pool,
877     ({
878       vec_add1 (map_indices, mi);
879     }));
880
881   vec_foreach (map_indexp, map_indices)
882     {
883       mapping_t * map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
884       if (!map->local)
885         {
886           dp_del_fwd_entry (lcm, 0, map_indexp[0]);
887
888           dm_args->is_add = 0;
889           gid_address_copy (&dm_args->eid, &map->eid);
890           dm_args->locator_set_index = map->locator_set_index;
891
892           /* delete mapping associated to fwd entry */
893           vnet_lisp_map_cache_add_del (dm_args, 0);
894
895           ls->is_add = 0;
896           ls->local = 0;
897           ls->index = map->locator_set_index;
898           /* delete locator set */
899           rv = vnet_lisp_add_del_locator_set (ls, 0);
900           if (rv != 0)
901             goto cleanup;
902         }
903     }
904
905 cleanup:
906   if (map_indices)
907     vec_free (map_indices);
908   return rv;
909 }
910
911 /**
912  * Adds adjacency or removes forwarding entry associated to remote mapping.
913  * Note that adjacencies are not stored, they only result in forwarding entries
914  * being created.
915  */
916 int
917 lisp_add_del_adjacency (lisp_cp_main_t * lcm, gid_address_t * local_eid,
918                         gid_address_t * remote_eid, u8 is_add)
919 {
920   u32 local_mi, remote_mi = ~0;
921
922   if (vnet_lisp_enable_disable_status () == 0)
923     {
924       clib_warning ("LISP is disabled!");
925       return VNET_API_ERROR_LISP_DISABLED;
926     }
927
928   remote_mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, remote_eid);
929   if (GID_LOOKUP_MISS == remote_mi)
930     {
931       clib_warning("Remote eid %U not found. Cannot add adjacency!",
932                    format_gid_address, remote_eid);
933
934       return -1;
935     }
936
937   if (is_add)
938     {
939       /* TODO 1) check if src/dst 2) once we have src/dst working, use it in
940        * delete*/
941
942       /* check if source eid has an associated mapping. If pitr mode is on,
943        * just use the pitr's mapping */
944       local_mi = lcm->lisp_pitr ? lcm->pitr_map_index :
945               gid_dictionary_lookup (&lcm->mapping_index_by_gid, local_eid);
946
947
948       if (GID_LOOKUP_MISS == local_mi)
949         {
950           clib_warning("Local eid %U not found. Cannot add adjacency!",
951                        format_gid_address, local_eid);
952
953           return -1;
954         }
955
956       /* update forwarding */
957       dp_add_fwd_entry (lcm, local_mi, remote_mi);
958     }
959   else
960     dp_del_fwd_entry (lcm, 0, remote_mi);
961
962   return 0;
963 }
964
965 int
966 vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a)
967 {
968   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
969   return lisp_add_del_adjacency(lcm, &a->seid, &a->deid, a->is_add);
970 }
971
972 /**
973  * Handler for add/del remote mapping CLI.
974  *
975  * @param vm vlib context
976  * @param input input from user
977  * @param cmd cmd
978  * @return pointer to clib error structure
979  */
980 static clib_error_t *
981 lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
982                                         unformat_input_t * input,
983                                         vlib_cli_command_t * cmd)
984 {
985   clib_error_t * error = 0;
986   unformat_input_t _line_input, * line_input = &_line_input;
987   u8 is_add = 1, del_all = 0;
988   locator_t rloc, * rlocs = 0, * curr_rloc = 0;
989   gid_address_t eid;
990   u8 eid_set = 0;
991   u32 vni, action = ~0, p, w;
992   int rv;
993
994   /* Get a line of input. */
995   if (! unformat_user (input, unformat_line_input, line_input))
996     return 0;
997
998   memset(&eid, 0, sizeof(eid));
999   memset(&rloc, 0, sizeof(rloc));
1000
1001   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1002     {
1003       if (unformat (line_input, "del-all"))
1004         del_all = 1;
1005       else if (unformat (line_input, "del"))
1006         is_add = 0;
1007       else if (unformat (line_input, "add"))
1008         ;
1009       else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
1010         eid_set = 1;
1011       else if (unformat (line_input, "vni %u", &vni))
1012         {
1013           gid_address_vni (&eid) = vni;
1014         }
1015       else if (unformat (line_input, "p %d w %d", &p, &w))
1016         {
1017           if (!curr_rloc)
1018             {
1019               clib_warning ("No RLOC configured for setting priority/weight!");
1020               goto done;
1021             }
1022           curr_rloc->priority = p;
1023           curr_rloc->weight = w;
1024         }
1025       else if (unformat (line_input, "rloc %U", unformat_ip_address,
1026                          &gid_address_ip(&rloc.address)))
1027         {
1028           vec_add1 (rlocs, rloc);
1029           curr_rloc = &rlocs[vec_len (rlocs) - 1];
1030         }
1031       else if (unformat (line_input, "action %U",
1032                          unformat_negative_mapping_action, &action))
1033         ;
1034       else
1035         {
1036           clib_warning ("parse error");
1037           goto done;
1038         }
1039     }
1040
1041   if (!eid_set)
1042     {
1043       clib_warning ("missing eid!");
1044       goto done;
1045     }
1046
1047   if (!del_all)
1048     {
1049       if (is_add && (~0 == action)
1050           && 0 == vec_len (rlocs))
1051         {
1052           clib_warning ("no action set for negative map-reply!");
1053           goto done;
1054         }
1055     }
1056   else
1057     {
1058       vnet_lisp_clear_all_remote_adjacencies ();
1059       goto done;
1060     }
1061
1062   /* TODO build src/dst with seid*/
1063
1064   /* if it's a delete, clean forwarding */
1065   if (!is_add)
1066     {
1067       lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1068       rv = lisp_add_del_adjacency (lcm, 0, &eid, /* is_add */ 0);
1069       if (rv)
1070         {
1071           goto done;
1072         }
1073     }
1074
1075   /* add as static remote mapping, i.e., not authoritative and infinite
1076    * ttl */
1077   rv = vnet_lisp_add_del_mapping (&eid, rlocs, action, 0, ~0, is_add, 0);
1078
1079   if (rv)
1080     clib_warning("failed to %s remote mapping!", is_add ? "add" : "delete");
1081
1082 done:
1083   vec_free (rlocs);
1084   unformat_free (line_input);
1085   return error;
1086 }
1087
1088 VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) = {
1089     .path = "lisp remote-mapping",
1090     .short_help = "lisp remote-mapping add|del [del-all] vni <vni> "
1091      "eid <est-eid> [action <no-action|natively-forward|"
1092      "send-map-request|drop>] rloc <dst-locator> p <prio> w <weight> "
1093      "[rloc <dst-locator> ... ]",
1094     .function = lisp_add_del_remote_mapping_command_fn,
1095 };
1096
1097 /**
1098  * Handler for add/del adjacency CLI.
1099  */
1100 static clib_error_t *
1101 lisp_add_del_adjacency_command_fn (vlib_main_t * vm, unformat_input_t * input,
1102                                    vlib_cli_command_t * cmd)
1103 {
1104   clib_error_t * error = 0;
1105   unformat_input_t _line_input, * line_input = &_line_input;
1106   vnet_lisp_add_del_adjacency_args_t _a, * a = &_a;
1107   u8 is_add = 1;
1108   locator_t rloc, * rlocs = 0;
1109   ip_prefix_t * deid_ippref, * seid_ippref;
1110   gid_address_t seid, deid;
1111   u8 * dmac = gid_address_mac (&deid);
1112   u8 * smac = gid_address_mac (&seid);
1113   u8 deid_set = 0, seid_set = 0;
1114   u8 * s = 0;
1115   u32 vni, action = ~0;
1116   int rv;
1117
1118   /* Get a line of input. */
1119   if (! unformat_user (input, unformat_line_input, line_input))
1120     return 0;
1121
1122   memset(&deid, 0, sizeof(deid));
1123   memset(&seid, 0, sizeof(seid));
1124   memset(&rloc, 0, sizeof(rloc));
1125
1126   seid_ippref = &gid_address_ippref(&seid);
1127   deid_ippref = &gid_address_ippref(&deid);
1128
1129   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1130     {
1131       if (unformat (line_input, "del"))
1132         is_add = 0;
1133       else if (unformat (line_input, "add"))
1134         ;
1135       else if (unformat (line_input, "deid %U",
1136                          unformat_ip_prefix, deid_ippref))
1137         {
1138           gid_address_type (&deid) = GID_ADDR_IP_PREFIX;
1139           deid_set = 1;
1140         }
1141       else if (unformat (line_input, "deid %U",
1142                          unformat_mac_address, dmac))
1143         {
1144           gid_address_type (&deid) = GID_ADDR_MAC;
1145           deid_set = 1;
1146         }
1147       else if (unformat (line_input, "vni %u", &vni))
1148         {
1149           gid_address_vni (&seid) = vni;
1150           gid_address_vni (&deid) = vni;
1151         }
1152       else if (unformat (line_input, "seid %U",
1153                          unformat_ip_prefix, seid_ippref))
1154         {
1155           gid_address_type (&seid) = GID_ADDR_IP_PREFIX;
1156           seid_set = 1;
1157         }
1158       else if (unformat (line_input, "seid %U",
1159                          unformat_mac_address, smac))
1160         {
1161           gid_address_type (&seid) = GID_ADDR_MAC;
1162           seid_set = 1;
1163         }
1164       else
1165         {
1166           clib_warning ("parse error");
1167           goto done;
1168         }
1169     }
1170
1171   if (!deid_set)
1172     {
1173       clib_warning ("missing deid!");
1174       goto done;
1175     }
1176
1177   if (GID_ADDR_IP_PREFIX == gid_address_type (&deid))
1178     {
1179       /* if seid not set, make sure the ip version is the same as that
1180        * of the deid. This ensures the seid to be configured will be
1181        * either 0/0 or ::/0 */
1182       if (!seid_set)
1183         ip_prefix_version(seid_ippref) = ip_prefix_version(deid_ippref);
1184
1185       if (is_add &&
1186           (ip_prefix_version (deid_ippref)
1187            != ip_prefix_version(seid_ippref)))
1188         {
1189           clib_warning ("source and destination EIDs are not"
1190                         " in the same IP family!");
1191           goto done;
1192         }
1193     }
1194
1195   if (is_add && (~0 == action)
1196       && 0 == vec_len (rlocs))
1197     {
1198       clib_warning ("no action set for negative map-reply!");
1199       goto done;
1200     }
1201
1202   memset(a, 0, sizeof(a[0]));
1203   gid_address_copy (&a->seid, &deid);
1204   gid_address_copy (&a->deid, &seid);
1205
1206   a->is_add = is_add;
1207   rv = vnet_lisp_add_del_adjacency (a);
1208
1209   if (rv)
1210     clib_warning("failed to %s adjacency!", is_add ? "add" : "delete");
1211
1212 done:
1213   unformat_free (line_input);
1214   if (s)
1215     vec_free (s);
1216   return error;
1217 }
1218
1219 VLIB_CLI_COMMAND (lisp_add_del_adjacency_command) = {
1220     .path = "lisp adjacency",
1221     .short_help = "lisp adjacency add|del vni <vni>"
1222      "deid <dest-eid> seid <src-eid> [action <no-action|natively-forward|"
1223      "send-map-request|drop>] rloc <dst-locator> [rloc <dst-locator> ... ]",
1224     .function = lisp_add_del_adjacency_command_fn,
1225 };
1226
1227
1228 static clib_error_t *
1229 lisp_show_map_resolvers_command_fn (vlib_main_t * vm,
1230                                     unformat_input_t * input,
1231                                     vlib_cli_command_t * cmd)
1232 {
1233   map_resolver_t * mr;
1234   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1235
1236   vec_foreach (mr, lcm->map_resolvers)
1237     {
1238       vlib_cli_output (vm, "%U", format_ip_address, &mr->address);
1239     }
1240   return 0;
1241 }
1242
1243 VLIB_CLI_COMMAND (lisp_show_map_resolvers_command) = {
1244     .path = "show lisp map-resolvers",
1245     .short_help = "show lisp map-resolvers",
1246     .function = lisp_show_map_resolvers_command_fn,
1247 };
1248
1249 int
1250 vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
1251 {
1252   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1253   u32 locator_set_index = ~0;
1254   mapping_t * m;
1255   uword * p;
1256
1257   if (vnet_lisp_enable_disable_status () == 0)
1258     {
1259       clib_warning ("LISP is disabled!");
1260       return VNET_API_ERROR_LISP_DISABLED;
1261     }
1262
1263   p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1264   if (!p)
1265     {
1266       clib_warning ("locator-set %v doesn't exist", locator_set_name);
1267       return -1;
1268     }
1269   locator_set_index = p[0];
1270
1271   if (is_add)
1272     {
1273       pool_get (lcm->mapping_pool, m);
1274       m->locator_set_index = locator_set_index;
1275       m->local = 1;
1276       lcm->pitr_map_index = m - lcm->mapping_pool;
1277
1278       /* enable pitr mode */
1279       lcm->lisp_pitr = 1;
1280     }
1281   else
1282     {
1283       /* remove pitr mapping */
1284       pool_put_index (lcm->mapping_pool, lcm->pitr_map_index);
1285
1286       /* disable pitr mode */
1287       lcm->lisp_pitr = 0;
1288     }
1289   return 0;
1290 }
1291
1292 static clib_error_t *
1293 lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm,
1294                                       unformat_input_t * input,
1295                                       vlib_cli_command_t * cmd)
1296 {
1297   u8 locator_name_set = 0;
1298   u8 * locator_set_name = 0;
1299   u8 is_add = 1;
1300   unformat_input_t _line_input, * line_input = &_line_input;
1301   clib_error_t * error = 0;
1302   int rv = 0;
1303
1304   /* Get a line of input. */
1305   if (! unformat_user (input, unformat_line_input, line_input))
1306     return 0;
1307
1308   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1309     {
1310       if (unformat (line_input, "ls %_%v%_", &locator_set_name))
1311         locator_name_set = 1;
1312       else if (unformat (line_input, "disable"))
1313         is_add = 0;
1314       else
1315         return clib_error_return (0, "parse error");
1316     }
1317
1318   if (!locator_name_set)
1319     {
1320       clib_warning ("No locator set specified!");
1321       goto done;
1322     }
1323   rv = vnet_lisp_pitr_set_locator_set (locator_set_name, is_add);
1324   if (0 != rv)
1325     {
1326       error = clib_error_return(0, "failed to %s pitr!",
1327                                 is_add ? "add" : "delete");
1328     }
1329
1330 done:
1331   if (locator_set_name)
1332     vec_free (locator_set_name);
1333   return error;
1334 }
1335
1336 VLIB_CLI_COMMAND (lisp_pitr_set_locator_set_command) = {
1337     .path = "lisp pitr",
1338     .short_help = "lisp pitr [disable] ls <locator-set-name>",
1339     .function = lisp_pitr_set_locator_set_command_fn,
1340 };
1341
1342 static clib_error_t *
1343 lisp_show_pitr_command_fn (vlib_main_t * vm,
1344                            unformat_input_t * input,
1345                            vlib_cli_command_t * cmd)
1346 {
1347   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1348   mapping_t * m;
1349   locator_set_t * ls;
1350   u8 * tmp_str = 0;
1351
1352   vlib_cli_output (vm, "%=20s%=16s",
1353                    "pitr", lcm->lisp_pitr ? "locator-set" : "");
1354
1355   if (!lcm->lisp_pitr) {
1356     vlib_cli_output (vm, "%=20s", "disable");
1357     return 0;
1358   }
1359
1360   if (~0 == lcm->pitr_map_index) {
1361     tmp_str = format(0, "N/A");
1362   } else {
1363     m = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
1364     if (~0 != m->locator_set_index) {
1365       ls = pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
1366       tmp_str = format(0, "%s", ls->name);
1367     } else {
1368       tmp_str = format(0, "N/A");
1369     }
1370   }
1371   vec_add1(tmp_str, 0);
1372
1373   vlib_cli_output (vm, "%=20s%=16s",
1374                    "enable", tmp_str);
1375
1376   vec_free(tmp_str);
1377
1378   return 0;
1379 }
1380
1381 VLIB_CLI_COMMAND (lisp_show_pitr_command) = {
1382     .path = "show lisp pitr",
1383     .short_help = "Show pitr",
1384     .function = lisp_show_pitr_command_fn,
1385 };
1386
1387 static u8 *
1388 format_eid_entry (u8 * s, va_list * args)
1389 {
1390   vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
1391   lisp_cp_main_t * lcm = va_arg (*args, lisp_cp_main_t *);
1392   mapping_t * mapit = va_arg (*args, mapping_t *);
1393   locator_set_t * ls = va_arg (*args, locator_set_t *);
1394   gid_address_t * gid = &mapit->eid;
1395   u32 ttl = mapit->ttl;
1396   u8 aut = mapit->authoritative;
1397   u32 * loc_index;
1398   u8 first_line = 1;
1399   u8 * loc;
1400
1401   u8 * type = ls->local ? format(0, "local(%s)", ls->name)
1402                         : format(0, "remote");
1403
1404   if (vec_len (ls->locator_indices) == 0)
1405     {
1406       s = format (s, "%-35U%-30s%-20u%-u", format_gid_address, gid,
1407                                            type, ttl, aut);
1408     }
1409   else
1410     {
1411       vec_foreach (loc_index, ls->locator_indices)
1412         {
1413           locator_t * l = pool_elt_at_index (lcm->locator_pool, loc_index[0]);
1414           if (l->local)
1415             loc = format (0, "%U", format_vnet_sw_if_index_name, vnm,
1416                           l->sw_if_index);
1417           else
1418             loc = format (0, "%U", format_ip_address,
1419                           &gid_address_ip (&l->address));
1420
1421           if (first_line)
1422             {
1423               s = format (s, "%-35U%-20s%-30v%-20u%-u\n", format_gid_address,
1424                           gid, type, loc, ttl, aut);
1425               first_line = 0;
1426             }
1427           else
1428             s = format (s, "%55s%v\n", "", loc);
1429         }
1430     }
1431   return s;
1432 }
1433
1434 static clib_error_t *
1435 lisp_show_eid_table_command_fn (vlib_main_t * vm,
1436                                 unformat_input_t * input,
1437                                 vlib_cli_command_t * cmd)
1438 {
1439   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1440   mapping_t * mapit;
1441   unformat_input_t _line_input, * line_input = &_line_input;
1442   u32 mi;
1443   gid_address_t eid;
1444   u8 print_all = 1;
1445   u8 filter = 0;
1446
1447   memset (&eid, 0, sizeof(eid));
1448
1449   /* Get a line of input. */
1450   if (!unformat_user (input, unformat_line_input, line_input))
1451     return 0;
1452
1453   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1454     {
1455       if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
1456         print_all = 0;
1457       else if (unformat (line_input, "local"))
1458         filter = 1;
1459       else if (unformat(line_input, "remote"))
1460         filter = 2;
1461       else
1462         return clib_error_return (0, "parse error: '%U'",
1463                                   format_unformat_error, line_input);
1464     }
1465
1466   vlib_cli_output (vm, "%-35s%-20s%-30s%-20s%-s",
1467                    "EID", "type", "locators", "ttl", "autoritative");
1468
1469   if (print_all)
1470     {
1471       pool_foreach (mapit, lcm->mapping_pool,
1472       ({
1473         locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
1474                                                 mapit->locator_set_index);
1475         if (filter && !((1 == filter && ls->local) ||
1476           (2 == filter && !ls->local)))
1477           {
1478             continue;
1479           }
1480         vlib_cli_output (vm, "%U", format_eid_entry, lcm->vnet_main,
1481                          lcm, mapit, ls);
1482       }));
1483     }
1484   else
1485     {
1486       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &eid);
1487       if ((u32)~0 == mi)
1488         return 0;
1489
1490       mapit = pool_elt_at_index (lcm->mapping_pool, mi);
1491       locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
1492                                               mapit->locator_set_index);
1493
1494       if (filter && !((1 == filter && ls->local) ||
1495         (2 == filter && !ls->local)))
1496         {
1497           return 0;
1498         }
1499
1500       vlib_cli_output (vm, "%U,", format_eid_entry, lcm->vnet_main,
1501                        lcm, mapit, ls);
1502     }
1503
1504   return 0;
1505 }
1506
1507 VLIB_CLI_COMMAND (lisp_cp_show_eid_table_command) = {
1508     .path = "show lisp eid-table",
1509     .short_help = "Shows EID table",
1510     .function = lisp_show_eid_table_command_fn,
1511 };
1512
1513 /* cleans locator to locator-set data and removes locators not part of
1514  * any locator-set */
1515 static void
1516 clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
1517 {
1518   u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
1519   locator_set_t * ls = pool_elt_at_index(lcm->locator_set_pool, lsi);
1520   for (i = 0; i < vec_len(ls->locator_indices); i++)
1521     {
1522       loc_indexp = vec_elt_at_index(ls->locator_indices, i);
1523       ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1524                                     loc_indexp[0]);
1525       for (j = 0; j < vec_len(ls_indexes[0]); j++)
1526         {
1527           ls_indexp = vec_elt_at_index(ls_indexes[0], j);
1528           if (ls_indexp[0] == lsi)
1529             break;
1530         }
1531
1532       /* delete index for removed locator-set*/
1533       vec_del1(ls_indexes[0], j);
1534
1535       /* delete locator if it's part of no locator-set */
1536       if (vec_len (ls_indexes[0]) == 0)
1537         {
1538           pool_put_index (lcm->locator_pool, loc_indexp[0]);
1539           vec_add1 (to_be_deleted, i);
1540         }
1541     }
1542
1543   if (to_be_deleted)
1544     {
1545       for (i = 0; i < vec_len (to_be_deleted); i++)
1546         {
1547           loc_indexp = vec_elt_at_index (to_be_deleted, i);
1548           vec_del1 (ls->locator_indices, loc_indexp[0]);
1549         }
1550       vec_free (to_be_deleted);
1551     }
1552 }
1553
1554 static inline uword *
1555 get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p)
1556 {
1557   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1558
1559   ASSERT(a != NULL);
1560   ASSERT(p != NULL);
1561
1562   /* find locator-set */
1563   if (a->local)
1564     {
1565       p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
1566     }
1567   else
1568     {
1569       *p = a->index;
1570     }
1571
1572   return p;
1573 }
1574
1575 static inline int
1576 is_locator_in_locator_set (lisp_cp_main_t * lcm, locator_set_t * ls,
1577                            locator_t * loc)
1578 {
1579   locator_t * itloc;
1580   u32 * locit;
1581
1582   ASSERT(ls != NULL);
1583   ASSERT(loc != NULL);
1584
1585   vec_foreach(locit, ls->locator_indices)
1586     {
1587       itloc = pool_elt_at_index(lcm->locator_pool, locit[0]);
1588       if ((ls->local && itloc->sw_if_index == loc->sw_if_index) ||
1589           (!ls->local && !gid_address_cmp(&itloc->address, &loc->address)))
1590         {
1591           clib_warning("Duplicate locator");
1592           return VNET_API_ERROR_VALUE_EXIST;
1593         }
1594     }
1595
1596   return 0;
1597 }
1598
1599 static inline void
1600 remove_locator_from_locator_set (locator_set_t * ls, u32 * locit, u32 ls_index,
1601                                  u32 loc_id)
1602 {
1603   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1604   u32 ** ls_indexes = NULL;
1605
1606   ASSERT(ls != NULL);
1607   ASSERT(locit != NULL);
1608
1609   ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1610                                 locit[0]);
1611   pool_put_index(lcm->locator_pool, locit[0]);
1612   vec_del1(ls->locator_indices, loc_id);
1613   vec_del1(ls_indexes[0], ls_index);
1614 }
1615
1616 int
1617 vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
1618                            locator_set_t * ls, u32 * ls_result)
1619 {
1620   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1621   locator_t * loc = NULL, *itloc = NULL;
1622   uword _p = (u32)~0, * p = &_p;
1623   u32 loc_index = ~0, ls_index = ~0, * locit = NULL, ** ls_indexes = NULL;
1624   u32 loc_id = ~0;
1625   int ret = 0;
1626
1627   ASSERT(a != NULL);
1628
1629   if (vnet_lisp_enable_disable_status () == 0)
1630     {
1631       clib_warning ("LISP is disabled!");
1632       return VNET_API_ERROR_LISP_DISABLED;
1633     }
1634
1635   p = get_locator_set_index(a, p);
1636   if (!p)
1637     {
1638       clib_warning("locator-set %v doesn't exist", a->name);
1639       return VNET_API_ERROR_INVALID_ARGUMENT;
1640     }
1641
1642   if (ls == 0)
1643     {
1644       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1645       if (!ls)
1646         {
1647           clib_warning("locator-set %d to be overwritten doesn't exist!",
1648                        p[0]);
1649           return VNET_API_ERROR_INVALID_ARGUMENT;
1650         }
1651     }
1652
1653   if (a->is_add)
1654     {
1655
1656         if (ls_result)
1657           ls_result[0] = p[0];
1658
1659         /* allocate locators */
1660         vec_foreach (itloc, a->locators)
1661           {
1662             ret = is_locator_in_locator_set(lcm, ls, itloc);
1663             if (0 != ret)
1664               {
1665                 return ret;
1666               }
1667
1668             pool_get(lcm->locator_pool, loc);
1669             loc[0] = itloc[0];
1670             loc_index = loc - lcm->locator_pool;
1671
1672             vec_add1(ls->locator_indices, loc_index);
1673
1674             vec_validate (lcm->locator_to_locator_sets, loc_index);
1675             ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1676                                           loc_index);
1677             vec_add1(ls_indexes[0], ls_index);
1678           }
1679       }
1680     else
1681       {
1682         ls_index = p[0];
1683
1684         itloc = a->locators;
1685         loc_id = 0;
1686         vec_foreach (locit, ls->locator_indices)
1687           {
1688             loc = pool_elt_at_index(lcm->locator_pool, locit[0]);
1689
1690             if (loc->local && loc->sw_if_index == itloc->sw_if_index)
1691               {
1692                 remove_locator_from_locator_set(ls, locit,
1693                                                 ls_index, loc_id);
1694               }
1695             if (0 == loc->local &&
1696                 !gid_address_cmp(&loc->address, &itloc->address))
1697               {
1698                 remove_locator_from_locator_set(ls, locit,
1699                                                 ls_index, loc_id);
1700               }
1701
1702             loc_id++;
1703           }
1704       }
1705
1706   return 0;
1707 }
1708
1709 int
1710 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
1711                                u32 * ls_result)
1712 {
1713   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1714   locator_set_t * ls;
1715   uword _p = (u32)~0, * p = &_p;
1716   u32 ls_index;
1717   u32 ** eid_indexes;
1718   int ret = 0;
1719
1720   if (vnet_lisp_enable_disable_status () == 0)
1721     {
1722       clib_warning ("LISP is disabled!");
1723       return VNET_API_ERROR_LISP_DISABLED;
1724     }
1725
1726   if (a->is_add)
1727     {
1728       p = get_locator_set_index(a, p);
1729
1730       /* overwrite */
1731       if (p && p[0] != (u32)~0)
1732         {
1733           ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1734           if (!ls)
1735             {
1736               clib_warning("locator-set %d to be overwritten doesn't exist!",
1737                            p[0]);
1738               return -1;
1739             }
1740
1741           /* clean locator to locator-set vectors and remove locators if
1742            * they're not part of another locator-set */
1743           clean_locator_to_locator_set (lcm, p[0]);
1744
1745           /* remove locator indices from locator set */
1746           vec_free(ls->locator_indices);
1747
1748           ls_index = p[0];
1749
1750           if (ls_result)
1751             ls_result[0] = p[0];
1752         }
1753       /* new locator-set */
1754       else
1755         {
1756           pool_get(lcm->locator_set_pool, ls);
1757           memset(ls, 0, sizeof(*ls));
1758           ls_index = ls - lcm->locator_set_pool;
1759
1760           if (a->local)
1761             {
1762               ls->name = vec_dup(a->name);
1763
1764               if (!lcm->locator_set_index_by_name)
1765                 lcm->locator_set_index_by_name = hash_create_vec(
1766                     /* size */0, sizeof(ls->name[0]), sizeof(uword));
1767               hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index);
1768
1769               /* mark as local locator-set */
1770               vec_add1(lcm->local_locator_set_indexes, ls_index);
1771             }
1772           ls->local = a->local;
1773           if (ls_result)
1774             ls_result[0] = ls_index;
1775         }
1776
1777       ret = vnet_lisp_add_del_locator(a, ls, NULL);
1778       if (0 != ret)
1779         {
1780           return ret;
1781         }
1782     }
1783   else
1784     {
1785       p = get_locator_set_index(a, p);
1786       if (!p)
1787         {
1788           clib_warning("locator-set %v doesn't exists", a->name);
1789           return -1;
1790         }
1791
1792       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1793       if (!ls)
1794         {
1795           clib_warning("locator-set with index %d doesn't exists", p[0]);
1796           return -1;
1797         }
1798
1799       if (lcm->mreq_itr_rlocs == p[0])
1800         {
1801           clib_warning ("Can't delete the locator-set used to constrain "
1802                         "the itr-rlocs in map-requests!");
1803           return -1;
1804         }
1805
1806       if (vec_len(lcm->locator_set_to_eids) != 0)
1807       {
1808           eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, p[0]);
1809           if (vec_len(eid_indexes[0]) != 0)
1810           {
1811               clib_warning ("Can't delete a locator that supports a mapping!");
1812               return -1;
1813           }
1814       }
1815
1816       /* clean locator to locator-sets data */
1817       clean_locator_to_locator_set (lcm, p[0]);
1818
1819       if (ls->local)
1820         {
1821           u32 it, lsi;
1822
1823           vec_foreach_index(it, lcm->local_locator_set_indexes)
1824           {
1825             lsi = vec_elt(lcm->local_locator_set_indexes, it);
1826             if (lsi == p[0])
1827               {
1828                 vec_del1(lcm->local_locator_set_indexes, it);
1829                 break;
1830               }
1831           }
1832           hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
1833         }
1834       vec_free(ls->name);
1835       vec_free(ls->locator_indices);
1836       pool_put(lcm->locator_set_pool, ls);
1837     }
1838   return 0;
1839 }
1840
1841 clib_error_t *
1842 vnet_lisp_enable_disable (u8 is_enable)
1843 {
1844   u32 vni, dp_table;
1845   clib_error_t * error = 0;
1846   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1847   vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
1848
1849   a->is_en = is_enable;
1850   error = vnet_lisp_gpe_enable_disable (a);
1851   if (error)
1852     {
1853       return clib_error_return (0, "failed to %s data-plane!",
1854                                 a->is_en ? "enable" : "disable");
1855     }
1856
1857   if (is_enable)
1858     {
1859       /* enable all l2 and l3 ifaces */
1860       hash_foreach(vni, dp_table, lcm->table_id_by_vni, ({
1861         dp_add_del_iface(lcm, vni, 0, 1);
1862       }));
1863
1864       hash_foreach(vni, dp_table, lcm->bd_id_by_vni, ({
1865         dp_add_del_iface(lcm, vni, /* is_l2 */ 1, 1);
1866       }));
1867     }
1868   else
1869     {
1870       /* clear interface table */
1871       hash_free(lcm->dp_intf_by_vni);
1872       hash_free(lcm->fwd_entry_by_mapping_index);
1873       pool_free(lcm->fwd_entry_pool);
1874     }
1875
1876   /* update global flag */
1877   lcm->is_enabled = is_enable;
1878
1879   return 0;
1880 }
1881
1882 static clib_error_t *
1883 lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
1884                                 vlib_cli_command_t * cmd)
1885 {
1886   unformat_input_t _line_input, * line_input = &_line_input;
1887   u8 is_enabled = 0;
1888   u8 is_set = 0;
1889
1890   /* Get a line of input. */
1891   if (! unformat_user (input, unformat_line_input, line_input))
1892     return 0;
1893
1894   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1895     {
1896       if (unformat (line_input, "enable"))
1897         {
1898           is_set = 1;
1899           is_enabled = 1;
1900         }
1901       else if (unformat (line_input, "disable"))
1902         is_set = 1;
1903       else
1904         {
1905           return clib_error_return (0, "parse error: '%U'",
1906                                    format_unformat_error, line_input);
1907         }
1908     }
1909
1910   if (!is_set)
1911       return clib_error_return (0, "state not set");
1912
1913   return vnet_lisp_enable_disable (is_enabled);
1914 }
1915
1916 VLIB_CLI_COMMAND (lisp_cp_enable_disable_command) = {
1917     .path = "lisp",
1918     .short_help = "lisp [enable|disable]",
1919     .function = lisp_enable_disable_command_fn,
1920 };
1921
1922 u8
1923 vnet_lisp_enable_disable_status (void)
1924 {
1925   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1926   return lcm->is_enabled;
1927 }
1928
1929 static u8 *
1930 format_lisp_status (u8 * s, va_list * args)
1931 {
1932   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1933   return format (s, "%s", lcm->is_enabled ? "enabled" : "disabled");
1934 }
1935
1936 static clib_error_t *
1937 lisp_show_status_command_fn (vlib_main_t * vm, unformat_input_t * input,
1938                              vlib_cli_command_t * cmd)
1939 {
1940   u8 * msg = 0;
1941   msg = format (msg, "feature: %U\ngpe: %U\n",
1942                 format_lisp_status, format_vnet_lisp_gpe_status);
1943   vlib_cli_output (vm, "%v", msg);
1944   vec_free (msg);
1945   return 0;
1946 }
1947
1948 VLIB_CLI_COMMAND (lisp_show_status_command) = {
1949     .path = "show lisp status",
1950     .short_help = "show lisp status",
1951     .function = lisp_show_status_command_fn,
1952 };
1953
1954 static clib_error_t *
1955 lisp_show_eid_table_map_command_fn (vlib_main_t * vm, unformat_input_t * input,
1956                                     vlib_cli_command_t * cmd)
1957 {
1958   hash_pair_t * p;
1959   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1960
1961   vlib_cli_output (vm, "%=10s%=10s", "VNI", "VRF");
1962   hash_foreach_pair (p, lcm->table_id_by_vni,
1963     {
1964       vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
1965     });
1966   return 0;
1967 }
1968
1969 VLIB_CLI_COMMAND (lisp_show_eid_table_map_command) = {
1970     .path = "show lisp eid-table map",
1971     .short_help = "show lisp eid-table vni to vrf mappings",
1972     .function = lisp_show_eid_table_map_command_fn,
1973 };
1974
1975 static clib_error_t *
1976 lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
1977                                      vlib_cli_command_t * cmd)
1978 {
1979   lisp_gpe_main_t * lgm = &lisp_gpe_main;
1980   vnet_main_t * vnm = lgm->vnet_main;
1981   unformat_input_t _line_input, * line_input = &_line_input;
1982   u8 is_add = 1;
1983   clib_error_t * error = 0;
1984   u8 * locator_set_name = 0;
1985   locator_t locator, * locators = 0;
1986   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
1987   u32 ls_index = 0;
1988   int rv = 0;
1989
1990   memset(&locator, 0, sizeof(locator));
1991   memset(a, 0, sizeof(a[0]));
1992
1993   /* Get a line of input. */
1994   if (! unformat_user (input, unformat_line_input, line_input))
1995     return 0;
1996
1997   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1998     {
1999       if (unformat (line_input, "add %_%v%_", &locator_set_name))
2000         is_add = 1;
2001       else if (unformat (line_input, "del %_%v%_", &locator_set_name))
2002         is_add = 0;
2003       else if (unformat (line_input, "iface %U p %d w %d",
2004                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
2005                          &locator.priority, &locator.weight))
2006         {
2007           locator.local = 1;
2008           vec_add1(locators, locator);
2009         }
2010       else
2011         {
2012           error = unformat_parse_error(line_input);
2013           goto done;
2014         }
2015     }
2016
2017   a->name = locator_set_name;
2018   a->locators = locators;
2019   a->is_add = is_add;
2020   a->local = 1;
2021
2022   rv = vnet_lisp_add_del_locator_set(a, &ls_index);
2023   if (0 != rv)
2024     {
2025       error = clib_error_return(0, "failed to %s locator-set!",
2026                                 is_add ? "add" : "delete");
2027     }
2028
2029  done:
2030   vec_free(locators);
2031   if (locator_set_name)
2032     vec_free (locator_set_name);
2033   return error;
2034 }
2035
2036 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
2037     .path = "lisp locator-set",
2038     .short_help = "lisp locator-set add/del <name> [iface <iface-name> "
2039         "p <priority> w <weight>]",
2040     .function = lisp_add_del_locator_set_command_fn,
2041 };
2042
2043 static clib_error_t *
2044 lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
2045                                      vlib_cli_command_t * cmd)
2046 {
2047   lisp_gpe_main_t * lgm = &lisp_gpe_main;
2048   vnet_main_t * vnm = lgm->vnet_main;
2049   unformat_input_t _line_input, * line_input = &_line_input;
2050   u8 is_add = 1;
2051   clib_error_t * error = 0;
2052   u8 * locator_set_name = 0;
2053   u8 locator_set_name_set = 0;
2054   locator_t locator, * locators = 0;
2055   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
2056   u32 ls_index = 0;
2057
2058   memset(&locator, 0, sizeof(locator));
2059   memset(a, 0, sizeof(a[0]));
2060
2061   /* Get a line of input. */
2062   if (! unformat_user (input, unformat_line_input, line_input))
2063     return 0;
2064
2065   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2066     {
2067       if (unformat (line_input, "add"))
2068         is_add = 1;
2069       else if (unformat (line_input, "del"))
2070         is_add = 0;
2071       else if (unformat(line_input, "locator-set %_%v%_", &locator_set_name))
2072         locator_set_name_set = 1;
2073       else if (unformat (line_input, "iface %U p %d w %d",
2074                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
2075                          &locator.priority, &locator.weight))
2076         {
2077           locator.local = 1;
2078           vec_add1(locators, locator);
2079         }
2080       else
2081         {
2082           error = unformat_parse_error(line_input);
2083           goto done;
2084         }
2085     }
2086
2087   if (!locator_set_name_set)
2088     {
2089       error = clib_error_return(0, "locator_set name not set!");
2090       goto done;
2091   }
2092
2093   a->name = locator_set_name;
2094   a->locators = locators;
2095   a->is_add = is_add;
2096   a->local = 1;
2097
2098   vnet_lisp_add_del_locator(a, 0, &ls_index);
2099
2100  done:
2101   vec_free(locators);
2102   vec_free (locator_set_name);
2103   return error;
2104 }
2105
2106 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_in_set_command) = {
2107     .path = "lisp locator",
2108     .short_help = "lisp locator add/del locator-set <name> iface <iface-name> "
2109                   "p <priority> w <weight>",
2110     .function = lisp_add_del_locator_in_set_command_fn,
2111 };
2112
2113 static clib_error_t *
2114 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
2115                                       unformat_input_t * input,
2116                                       vlib_cli_command_t * cmd)
2117 {
2118   locator_set_t * lsit;
2119   locator_t * loc;
2120   u32 * locit;
2121   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2122
2123   vlib_cli_output (vm, "%=20s%=16s%=16s%=16s", "Locator-set", "Locator",
2124                    "Priority", "Weight");
2125   pool_foreach (lsit, lcm->locator_set_pool,
2126   ({
2127     u8 * msg = 0;
2128     int next_line = 0;
2129     if (lsit->local)
2130       {
2131         msg = format (msg, "%=16v", lsit->name);
2132       }
2133     else
2134       {
2135         msg = format (msg, "%=16s", "remote");
2136       }
2137     vec_foreach (locit, lsit->locator_indices)
2138       {
2139         if (next_line)
2140           {
2141             msg = format (msg, "%16s", " ");
2142           }
2143         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
2144         if (loc->local)
2145           msg = format (msg, "%16d%16d%16d\n", loc->sw_if_index, loc->priority,
2146                         loc->weight);
2147         else
2148           msg = format (msg, "%16U%16d%16d\n", format_ip_address,
2149                         &gid_address_ip(&loc->address), loc->priority,
2150                         loc->weight);
2151         next_line = 1;
2152       }
2153     vlib_cli_output (vm, "%v", msg);
2154     vec_free (msg);
2155   }));
2156   return 0;
2157 }
2158
2159 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
2160     .path = "show lisp locator-set",
2161     .short_help = "Shows locator-sets",
2162     .function = lisp_cp_show_locator_sets_command_fn,
2163 };
2164
2165 static map_resolver_t *
2166 get_map_resolver (ip_address_t * a)
2167 {
2168   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
2169   map_resolver_t * mr;
2170
2171   vec_foreach (mr, lcm->map_resolvers)
2172     {
2173       if (!ip_address_cmp (&mr->address, a))
2174         {
2175           return mr;
2176         }
2177     }
2178   return 0;
2179 }
2180
2181 int
2182 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
2183 {
2184   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2185   u32 i;
2186   map_resolver_t _mr, * mr = &_mr;
2187
2188   if (vnet_lisp_enable_disable_status () == 0)
2189     {
2190       clib_warning ("LISP is disabled!");
2191       return VNET_API_ERROR_LISP_DISABLED;
2192     }
2193
2194   if (a->is_add)
2195     {
2196
2197       if (get_map_resolver (&a->address))
2198         {
2199           clib_warning("map-resolver %U already exists!", format_ip_address,
2200                        &a->address);
2201           return -1;
2202         }
2203
2204       memset (mr, 0, sizeof (*mr));
2205       ip_address_copy(&mr->address, &a->address);
2206       vec_add1(lcm->map_resolvers, *mr);
2207
2208       if (vec_len (lcm->map_resolvers) == 1)
2209         lcm->do_map_resolver_election = 1;
2210     }
2211   else
2212     {
2213       for (i = 0; i < vec_len(lcm->map_resolvers); i++)
2214         {
2215           mr = vec_elt_at_index(lcm->map_resolvers, i);
2216           if (!ip_address_cmp (&mr->address, &a->address))
2217             {
2218               if (!ip_address_cmp (&mr->address, &lcm->active_map_resolver))
2219                 lcm->do_map_resolver_election = 1;
2220
2221               vec_del1 (lcm->map_resolvers, i);
2222               break;
2223             }
2224         }
2225     }
2226   return 0;
2227 }
2228
2229 static clib_error_t *
2230 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
2231                                       unformat_input_t * input,
2232                                       vlib_cli_command_t * cmd)
2233 {
2234   unformat_input_t _line_input, * line_input = &_line_input;
2235   u8 is_add = 1, addr_set = 0;
2236   ip_address_t ip_addr;
2237   clib_error_t * error = 0;
2238   int rv = 0;
2239   vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a;
2240
2241   /* Get a line of input. */
2242   if (! unformat_user (input, unformat_line_input, line_input))
2243     return 0;
2244
2245   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2246     {
2247       if (unformat (line_input, "add"))
2248         is_add = 1;
2249       else if (unformat (line_input, "del"))
2250         is_add = 0;
2251       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
2252         addr_set = 1;
2253       else
2254         {
2255           error = unformat_parse_error(line_input);
2256           goto done;
2257         }
2258     }
2259
2260   if (!addr_set)
2261     {
2262       error = clib_error_return(0, "Map-resolver address must be set!");
2263       goto done;
2264     }
2265
2266   a->is_add = is_add;
2267   a->address = ip_addr;
2268   rv = vnet_lisp_add_del_map_resolver (a);
2269   if (0 != rv)
2270     {
2271       error = clib_error_return(0, "failed to %s map-resolver!",
2272                                 is_add ? "add" : "delete");
2273     }
2274
2275  done:
2276   return error;
2277 }
2278
2279 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
2280     .path = "lisp map-resolver",
2281     .short_help = "lisp map-resolver add/del <ip_address>",
2282     .function = lisp_add_del_map_resolver_command_fn,
2283 };
2284
2285 int
2286 vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
2287 {
2288   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2289   uword * p = 0;
2290
2291   if (vnet_lisp_enable_disable_status () == 0)
2292     {
2293       clib_warning("LISP is disabled!");
2294       return VNET_API_ERROR_LISP_DISABLED;
2295     }
2296
2297   if (a->is_add)
2298     {
2299       p = hash_get_mem(lcm->locator_set_index_by_name, a->locator_set_name);
2300       if (!p)
2301         {
2302           clib_warning("locator-set %v doesn't exist", a->locator_set_name);
2303           return VNET_API_ERROR_INVALID_ARGUMENT;
2304         }
2305
2306       lcm->mreq_itr_rlocs = p[0];
2307     }
2308   else
2309     {
2310       lcm->mreq_itr_rlocs = ~0;
2311     }
2312
2313   return 0;
2314 }
2315
2316 static clib_error_t *
2317 lisp_add_del_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
2318                                         unformat_input_t * input,
2319                                         vlib_cli_command_t * cmd)
2320 {
2321   unformat_input_t _line_input, * line_input = &_line_input;
2322   u8 is_add = 1;
2323   u8 * locator_set_name = 0;
2324   clib_error_t * error = 0;
2325   int rv = 0;
2326   vnet_lisp_add_del_mreq_itr_rloc_args_t _a, * a = &_a;
2327
2328   /* Get a line of input. */
2329   if (! unformat_user (input, unformat_line_input, line_input))
2330     return 0;
2331
2332   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2333     {
2334       if (unformat (line_input, "del"))
2335         is_add = 0;
2336       else if (unformat (line_input, "add %s", &locator_set_name))
2337         is_add = 1;
2338       else
2339         {
2340           error = unformat_parse_error(line_input);
2341           goto done;
2342         }
2343     }
2344
2345   a->is_add = is_add;
2346   a->locator_set_name = locator_set_name;
2347   rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
2348   if (0 != rv)
2349     {
2350       error = clib_error_return(0, "failed to %s map-request itr-rlocs!",
2351                                 is_add ? "add" : "delete");
2352     }
2353
2354   vec_free(locator_set_name);
2355
2356  done:
2357   return error;
2358
2359 }
2360
2361 VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
2362     .path = "lisp map-request itr-rlocs",
2363     .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
2364     .function = lisp_add_del_mreq_itr_rlocs_command_fn,
2365 };
2366
2367 static clib_error_t *
2368 lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
2369                                     unformat_input_t * input,
2370                                     vlib_cli_command_t * cmd)
2371 {
2372   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2373   locator_set_t * loc_set;
2374
2375   vlib_cli_output (vm, "%=20s", "itr-rlocs");
2376
2377   if (~0 == lcm->mreq_itr_rlocs)
2378     {
2379       return 0;
2380     }
2381
2382   loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
2383
2384   vlib_cli_output (vm, "%=20s", loc_set->name);
2385
2386   return 0;
2387 }
2388
2389 VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
2390     .path = "show lisp map-request itr-rlocs",
2391     .short_help = "Shows map-request itr-rlocs",
2392     .function = lisp_show_mreq_itr_rlocs_command_fn,
2393 };
2394
2395 /* Statistics (not really errors) */
2396 #define foreach_lisp_cp_lookup_error           \
2397 _(DROP, "drop")                                \
2398 _(MAP_REQUESTS_SENT, "map-request sent")
2399
2400 static char * lisp_cp_lookup_error_strings[] = {
2401 #define _(sym,string) string,
2402   foreach_lisp_cp_lookup_error
2403 #undef _
2404 };
2405
2406 typedef enum
2407 {
2408 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
2409     foreach_lisp_cp_lookup_error
2410 #undef _
2411     LISP_CP_LOOKUP_N_ERROR,
2412 } lisp_cp_lookup_error_t;
2413
2414 typedef enum
2415 {
2416   LISP_CP_LOOKUP_NEXT_DROP,
2417   LISP_CP_LOOKUP_NEXT_IP4_LOOKUP,
2418   LISP_CP_LOOKUP_NEXT_IP6_LOOKUP,
2419   LISP_CP_LOOKUP_N_NEXT,
2420 } lisp_cp_lookup_next_t;
2421
2422 typedef struct
2423 {
2424   gid_address_t dst_eid;
2425   ip_address_t map_resolver_ip;
2426 } lisp_cp_lookup_trace_t;
2427
2428 u8 *
2429 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
2430 {
2431   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2432   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2433   lisp_cp_lookup_trace_t * t = va_arg (*args, lisp_cp_lookup_trace_t *);
2434
2435   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
2436               format_ip_address, &t->map_resolver_ip, format_gid_address,
2437               &t->dst_eid);
2438   return s;
2439 }
2440
2441 int
2442 get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
2443                            ip_address_t * sloc)
2444 {
2445   map_resolver_t * mrit;
2446   ip_address_t * a;
2447
2448   if (vec_len(lcm->map_resolvers) == 0)
2449     {
2450       clib_warning("No map-resolver configured");
2451       return 0;
2452     }
2453
2454   /* find the first mr ip we have a route to and the ip of the
2455    * iface that has a route to it */
2456   vec_foreach(mrit, lcm->map_resolvers)
2457     {
2458       a = &mrit->address;
2459       if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, a, sloc))
2460         {
2461           ip_address_copy(mr_ip, a);
2462
2463           /* also update globals */
2464           return 1;
2465         }
2466     }
2467
2468   clib_warning("Can't find map-resolver and local interface ip!");
2469   return 0;
2470 }
2471
2472 static gid_address_t *
2473 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
2474 {
2475   void * addr;
2476   u32 i;
2477   locator_t * loc;
2478   u32 * loc_indexp;
2479   ip_interface_address_t * ia = 0;
2480   gid_address_t gid_data, * gid = &gid_data;
2481   gid_address_t * rlocs = 0;
2482   ip_prefix_t * ippref = &gid_address_ippref (gid);
2483   ip_address_t * rloc = &ip_prefix_addr (ippref);
2484
2485   memset (gid, 0, sizeof (gid[0]));
2486   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
2487   for (i = 0; i < vec_len(loc_set->locator_indices); i++)
2488     {
2489       loc_indexp = vec_elt_at_index(loc_set->locator_indices, i);
2490       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
2491
2492       /* Add ipv4 locators first TODO sort them */
2493       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2494                                     loc->sw_if_index, 1 /* unnumbered */,
2495       ({
2496         addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
2497         ip_address_set (rloc, addr, IP4);
2498         ip_prefix_len (ippref) = 32;
2499         ip_prefix_normalize (ippref);
2500         vec_add1 (rlocs, gid[0]);
2501       }));
2502
2503       /* Add ipv6 locators */
2504       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2505                                     loc->sw_if_index, 1 /* unnumbered */,
2506       ({
2507         addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
2508         ip_address_set (rloc, addr, IP6);
2509         ip_prefix_len (ippref) = 128;
2510         ip_prefix_normalize (ippref);
2511         vec_add1 (rlocs, gid[0]);
2512       }));
2513     }
2514   return rlocs;
2515 }
2516
2517 static vlib_buffer_t *
2518 build_encapsulated_map_request (lisp_cp_main_t *lcm,
2519                                 gid_address_t * seid, gid_address_t * deid,
2520                                 locator_set_t * loc_set, ip_address_t * mr_ip,
2521                                 ip_address_t * sloc, u8 is_smr_invoked,
2522                                 u64 *nonce_res, u32 * bi_res)
2523 {
2524   vlib_buffer_t * b;
2525   u32 bi;
2526   gid_address_t * rlocs = 0;
2527   vlib_main_t * vm = lcm->vlib_main;
2528
2529   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2530     {
2531       clib_warning ("Can't allocate buffer for Map-Request!");
2532       return 0;
2533     }
2534
2535   b = vlib_get_buffer (vm, bi);
2536
2537   /* leave some space for the encap headers */
2538   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2539
2540   /* get rlocs */
2541   rlocs = build_itr_rloc_list (lcm, loc_set);
2542
2543   /* put lisp msg */
2544   lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked, nonce_res);
2545
2546   /* push ecm: udp-ip-lisp */
2547   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
2548
2549   /* push outer ip header */
2550   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
2551                        mr_ip);
2552
2553   bi_res[0] = bi;
2554
2555   vec_free(rlocs);
2556   return b;
2557 }
2558
2559 static void
2560 reset_pending_mr_counters (pending_map_request_t * r)
2561 {
2562   r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
2563   r->retries_num = 0;
2564 }
2565
2566 static int
2567 elect_map_resolver (lisp_cp_main_t * lcm)
2568 {
2569   map_resolver_t * mr;
2570
2571   vec_foreach (mr, lcm->map_resolvers)
2572     {
2573       if (!mr->is_down)
2574         {
2575           ip_address_copy (&lcm->active_map_resolver, &mr->address);
2576           lcm->do_map_resolver_election = 0;
2577           return 1;
2578         }
2579     }
2580   return 0;
2581 }
2582
2583 #define send_encapsulated_map_request(lcm, seid, deid, smr) \
2584   _send_encapsulated_map_request(lcm, seid, deid, smr, 0)
2585
2586 #define resend_encapsulated_map_request(lcm, seid, deid, smr) \
2587   _send_encapsulated_map_request(lcm, seid, deid, smr, 1)
2588
2589 static int
2590 _send_encapsulated_map_request (lisp_cp_main_t *lcm,
2591                                 gid_address_t * seid, gid_address_t * deid,
2592                                 u8 is_smr_invoked, u8 is_resend)
2593 {
2594   map_resolver_t * mr;
2595   u32 next_index, bi = 0, * to_next, map_index;
2596   vlib_buffer_t * b;
2597   vlib_frame_t * f;
2598   u64 nonce = 0;
2599   locator_set_t * loc_set;
2600   mapping_t * map;
2601   pending_map_request_t * pmr, * duplicate_pmr = 0;
2602   ip_address_t sloc;
2603   u32 ls_index;
2604
2605   ASSERT (*lcm->pending_map_request_lock);
2606
2607   /* if there is already a pending request remember it */
2608   pool_foreach(pmr, lcm->pending_map_requests_pool,
2609   ({
2610     if (!gid_address_cmp (&pmr->src, seid)
2611         && !gid_address_cmp (&pmr->dst, deid))
2612       {
2613         duplicate_pmr = pmr;
2614         break;
2615       }
2616   }));
2617
2618   if (!is_resend && duplicate_pmr)
2619     {
2620       /* don't send the request if there is a pending map request already */
2621       return 0;
2622     }
2623
2624   /* get locator-set for seid */
2625   if (!lcm->lisp_pitr)
2626     {
2627       map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
2628       if (map_index == ~0)
2629         {
2630           clib_warning("No local mapping found in eid-table for %U!",
2631                        format_gid_address, seid);
2632           return -1;
2633         }
2634
2635       map = pool_elt_at_index (lcm->mapping_pool, map_index);
2636
2637       if (!map->local)
2638         {
2639           clib_warning("Mapping found for src eid %U is not marked as local!",
2640                        format_gid_address, seid);
2641           return -1;
2642         }
2643       ls_index = map->locator_set_index;
2644     }
2645   else
2646     {
2647       map_index = lcm->pitr_map_index;
2648       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
2649       ls_index = map->locator_set_index;
2650     }
2651
2652   /* overwrite locator set if map-request itr-rlocs configured */
2653   if (~0 != lcm->mreq_itr_rlocs)
2654     {
2655       ls_index = lcm->mreq_itr_rlocs;
2656     }
2657
2658   loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
2659
2660   while (lcm->do_map_resolver_election
2661          | (0 == ip_fib_get_first_egress_ip_for_dst (lcm,
2662                                                      &lcm->active_map_resolver,
2663                                                      &sloc)))
2664     {
2665       if (0 == elect_map_resolver (lcm))
2666         /* all Mrs are down */
2667         {
2668           if (duplicate_pmr)
2669             duplicate_pmr->to_be_removed = 1;
2670
2671           /* restart MR checking by marking all of them up */
2672           vec_foreach (mr, lcm->map_resolvers)
2673           mr->is_down = 0;
2674
2675           return -1;
2676         }
2677     }
2678
2679   /* build the encapsulated map request */
2680   b = build_encapsulated_map_request (lcm, seid, deid, loc_set,
2681                                       &lcm->active_map_resolver,
2682                                       &sloc, is_smr_invoked, &nonce, &bi);
2683
2684   if (!b)
2685     return -1;
2686
2687   /* set fib index to default and lookup node */
2688   vnet_buffer(b)->sw_if_index[VLIB_TX] = 0;
2689   next_index = (ip_addr_version(&lcm->active_map_resolver) == IP4) ?
2690       ip4_lookup_node.index : ip6_lookup_node.index;
2691
2692   f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
2693
2694   /* Enqueue the packet */
2695   to_next = vlib_frame_vector_args (f);
2696   to_next[0] = bi;
2697   f->n_vectors = 1;
2698   vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
2699
2700   if (duplicate_pmr)
2701     /* if there is a pending request already update it */
2702     {
2703       if (vec_len (duplicate_pmr->nonces) >= PENDING_MREQ_QUEUE_LEN)
2704         {
2705           /* remove the oldest nonce */
2706           u64 * nonce_del = vec_elt_at_index (duplicate_pmr->nonces, 0);
2707           hash_unset (lcm->pending_map_requests_by_nonce, nonce_del[0]);
2708           vec_del1 (duplicate_pmr->nonces, 0);
2709         }
2710
2711       vec_add1 (duplicate_pmr->nonces, nonce);
2712       hash_set (lcm->pending_map_requests_by_nonce, nonce,
2713                 duplicate_pmr - lcm->pending_map_requests_pool);
2714     }
2715   else
2716     {
2717       /* add map-request to pending requests table */
2718       pool_get(lcm->pending_map_requests_pool, pmr);
2719       memset (pmr, 0, sizeof (*pmr));
2720       gid_address_copy (&pmr->src, seid);
2721       gid_address_copy (&pmr->dst, deid);
2722       vec_add1 (pmr->nonces, nonce);
2723       pmr->is_smr_invoked = is_smr_invoked;
2724       reset_pending_mr_counters (pmr);
2725       hash_set (lcm->pending_map_requests_by_nonce, nonce,
2726                 pmr - lcm->pending_map_requests_pool);
2727     }
2728
2729   return 0;
2730 }
2731
2732 static void
2733 get_src_and_dst_ip (void *hdr, ip_address_t * src, ip_address_t *dst)
2734 {
2735   ip4_header_t * ip4 = hdr;
2736   ip6_header_t * ip6;
2737
2738   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
2739     {
2740       ip_address_set(src, &ip4->src_address, IP4);
2741       ip_address_set(dst, &ip4->dst_address, IP4);
2742     }
2743   else
2744     {
2745       ip6 = hdr;
2746       ip_address_set(src, &ip6->src_address, IP6);
2747       ip_address_set(dst, &ip6->dst_address, IP6);
2748     }
2749 }
2750
2751 static u32
2752 lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b,
2753                              u8 version)
2754 {
2755   uword * vnip;
2756   u32 vni = ~0, table_id = ~0, fib_index;
2757
2758   if (version == IP4)
2759     {
2760       ip4_fib_t * fib;
2761       ip4_main_t * im4 = &ip4_main;
2762       fib_index = vec_elt (im4->fib_index_by_sw_if_index,
2763                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2764       fib = find_ip4_fib_by_table_index_or_id (im4, fib_index,
2765                                                IP4_ROUTE_FLAG_FIB_INDEX);
2766       table_id = fib->table_id;
2767     }
2768   else
2769     {
2770       ip6_fib_t * fib;
2771       ip6_main_t * im6 = &ip6_main;
2772       fib_index = vec_elt (im6->fib_index_by_sw_if_index,
2773                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2774       fib = find_ip6_fib_by_table_index_or_id (im6, fib_index,
2775                                                IP6_ROUTE_FLAG_FIB_INDEX);
2776       table_id = fib->table_id;
2777     }
2778
2779   vnip = hash_get (lcm->vni_by_table_id, table_id);
2780   if (vnip)
2781     vni = vnip[0];
2782   else
2783     clib_warning ("vrf %d is not mapped to any vni!", table_id);
2784
2785   return vni;
2786 }
2787
2788 always_inline u32
2789 lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b)
2790 {
2791   uword * vnip;
2792   u32 vni = ~0;
2793   u32 sw_if_index0;
2794
2795   l2input_main_t * l2im = &l2input_main;
2796   l2_input_config_t * config;
2797   l2_bridge_domain_t * bd_config;
2798
2799   sw_if_index0 = vnet_buffer(b)->sw_if_index[VLIB_RX];
2800   config = vec_elt_at_index(l2im->configs, sw_if_index0);
2801   bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index);
2802
2803   vnip = hash_get (lcm->vni_by_bd_id, bd_config->bd_id);
2804   if (vnip)
2805     vni = vnip[0];
2806   else
2807     clib_warning("bridge domain %d is not mapped to any vni!",
2808                  config->bd_index);
2809
2810   return vni;
2811 }
2812
2813 always_inline void
2814 get_src_and_dst_eids_from_buffer (lisp_cp_main_t *lcm, vlib_buffer_t * b,
2815                                   gid_address_t * src, gid_address_t * dst)
2816 {
2817   u32 vni = 0;
2818   u16 type;
2819
2820   memset (src, 0, sizeof (*src));
2821   memset (dst, 0, sizeof (*dst));
2822   type = vnet_buffer(b)->lisp.overlay_afi;
2823
2824   if (LISP_AFI_IP == type || LISP_AFI_IP6 == type)
2825     {
2826       ip4_header_t * ip;
2827       u8 version, preflen;
2828
2829       gid_address_type(src) = GID_ADDR_IP_PREFIX;
2830       gid_address_type(dst) = GID_ADDR_IP_PREFIX;
2831
2832       ip = vlib_buffer_get_current (b);
2833       get_src_and_dst_ip (ip, &gid_address_ip(src), &gid_address_ip(dst));
2834
2835       version = gid_address_ip_version(src);
2836       preflen = ip_address_max_len (version);
2837       gid_address_ippref_len(src) = preflen;
2838       gid_address_ippref_len(dst) = preflen;
2839
2840       vni = lisp_get_vni_from_buffer_ip (lcm, b, version);
2841       gid_address_vni (dst) = vni;
2842       gid_address_vni (src) = vni;
2843     }
2844   else if (LISP_AFI_MAC == type)
2845     {
2846       ethernet_header_t * eh;
2847
2848       eh = vlib_buffer_get_current (b);
2849
2850       gid_address_type(src) = GID_ADDR_MAC;
2851       gid_address_type(dst) = GID_ADDR_MAC;
2852       mac_copy(&gid_address_mac(src), eh->src_address);
2853       mac_copy(&gid_address_mac(dst), eh->dst_address);
2854
2855       /* get vni */
2856       vni = lisp_get_vni_from_buffer_eth (lcm, b);
2857
2858       gid_address_vni (dst) = vni;
2859       gid_address_vni (src) = vni;
2860     }
2861 }
2862
2863 static uword
2864 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
2865               vlib_frame_t * from_frame)
2866 {
2867   u32 * from, * to_next_drop, di, si;
2868   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main();
2869   u32 pkts_mapped = 0;
2870   uword n_left_from, n_left_to_next_drop;
2871
2872   from = vlib_frame_vector_args (from_frame);
2873   n_left_from = from_frame->n_vectors;
2874
2875   while (n_left_from > 0)
2876     {
2877       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
2878                            to_next_drop, n_left_to_next_drop);
2879
2880       while (n_left_from > 0 && n_left_to_next_drop > 0)
2881         {
2882           u32 pi0;
2883           vlib_buffer_t * b0;
2884           gid_address_t src, dst;
2885
2886           pi0 = from[0];
2887           from += 1;
2888           n_left_from -= 1;
2889           to_next_drop[0] = pi0;
2890           to_next_drop += 1;
2891           n_left_to_next_drop -= 1;
2892
2893           b0 = vlib_get_buffer (vm, pi0);
2894           b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
2895
2896           /* src/dst eid pair */
2897           get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst);
2898
2899           /* if we have remote mapping for destination already in map-chache
2900              add forwarding tunnel directly. If not send a map-request */
2901           di = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
2902           if (~0 != di)
2903             {
2904               mapping_t * m =  vec_elt_at_index (lcm->mapping_pool, di);
2905               /* send a map-request also in case of negative mapping entry
2906                 with corresponding action */
2907               if (m->action == LISP_SEND_MAP_REQUEST)
2908                 {
2909                   /* send map-request */
2910                   queue_map_request (&src, &dst, 0 /* smr_invoked */,
2911                                      0 /* is_resend */);
2912                   pkts_mapped++;
2913                 }
2914               else
2915                 {
2916                   si =  gid_dictionary_lookup (&lcm->mapping_index_by_gid,
2917                                                &src);
2918                   if (~0 != si)
2919                     {
2920                       dp_add_fwd_entry (lcm, si, di);
2921                     }
2922                 }
2923             }
2924           else
2925             {
2926               /* send map-request */
2927               queue_map_request (&src, &dst, 0 /* smr_invoked */,
2928                                  0 /* is_resend */);
2929               pkts_mapped++;
2930             }
2931
2932           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2933             {
2934               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
2935                                                           sizeof(*tr));
2936
2937               memset(tr, 0, sizeof(*tr));
2938               gid_address_copy (&tr->dst_eid, &dst);
2939               if (vec_len(lcm->map_resolvers) > 0)
2940                 {
2941                   clib_memcpy (&tr->map_resolver_ip,
2942                                vec_elt_at_index(lcm->map_resolvers, 0),
2943                                sizeof(ip_address_t));
2944                 }
2945             }
2946           gid_address_free (&dst);
2947           gid_address_free (&src);
2948         }
2949
2950       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop);
2951     }
2952   vlib_node_increment_counter (vm, node->node_index,
2953                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
2954                                pkts_mapped);
2955   return from_frame->n_vectors;
2956 }
2957
2958 VLIB_REGISTER_NODE (lisp_cp_lookup_node) = {
2959   .function = lisp_cp_lookup,
2960   .name = "lisp-cp-lookup",
2961   .vector_size = sizeof (u32),
2962   .format_trace = format_lisp_cp_lookup_trace,
2963   .type = VLIB_NODE_TYPE_INTERNAL,
2964
2965   .n_errors = LISP_CP_LOOKUP_N_ERROR,
2966   .error_strings = lisp_cp_lookup_error_strings,
2967
2968   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
2969
2970   .next_nodes = {
2971       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
2972       [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup",
2973       [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup",
2974   },
2975 };
2976
2977 /* lisp_cp_input statistics */
2978 #define foreach_lisp_cp_input_error                     \
2979 _(DROP, "drop")                                         \
2980 _(MAP_REPLIES_RECEIVED, "map-replies received")
2981
2982 static char * lisp_cp_input_error_strings[] = {
2983 #define _(sym,string) string,
2984   foreach_lisp_cp_input_error
2985 #undef _
2986 };
2987
2988 typedef enum
2989 {
2990 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
2991     foreach_lisp_cp_input_error
2992 #undef _
2993     LISP_CP_INPUT_N_ERROR,
2994 } lisp_cp_input_error_t;
2995
2996 typedef enum
2997 {
2998   LISP_CP_INPUT_NEXT_DROP,
2999   LISP_CP_INPUT_N_NEXT,
3000 } lisp_cp_input_next_t;
3001
3002 typedef struct
3003 {
3004   gid_address_t dst_eid;
3005   ip4_address_t map_resolver_ip;
3006 } lisp_cp_input_trace_t;
3007
3008 u8 *
3009 format_lisp_cp_input_trace (u8 * s, va_list * args)
3010 {
3011   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
3012   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
3013   CLIB_UNUSED(lisp_cp_input_trace_t * t) = va_arg (*args, lisp_cp_input_trace_t *);
3014
3015   s = format (s, "LISP-CP-INPUT: TODO");
3016   return s;
3017 }
3018
3019 void *
3020 process_map_reply (void * arg)
3021 {
3022   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
3023   vlib_buffer_t * b = arg;
3024   u32 len = 0, i, ttl, dst_map_index = 0;
3025   void * h;
3026   pending_map_request_t * pmr;
3027   locator_t probed;
3028   map_reply_hdr_t * mrep_hdr;
3029   u64 nonce, * noncep;
3030   gid_address_t deid;
3031   uword * pmr_index;
3032   u8 authoritative, action;
3033   locator_t * locators = 0, * loc;
3034
3035   mrep_hdr = vlib_buffer_get_current (b);
3036
3037   lisp_pending_map_request_lock (lcm);
3038
3039   /* Check pending requests table and nonce */
3040   nonce = MREP_NONCE(mrep_hdr);
3041   pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce);
3042   if (!pmr_index)
3043     {
3044       clib_warning("No pending map-request entry with nonce %lu!", nonce);
3045       goto done;
3046     }
3047   pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]);
3048
3049   vlib_buffer_pull (b, sizeof(*mrep_hdr));
3050
3051   for (i = 0; i < MREP_REC_COUNT(mrep_hdr); i++)
3052     {
3053       h = vlib_buffer_get_current (b);
3054       ttl = clib_net_to_host_u32 (MAP_REC_TTL(h));
3055       action = MAP_REC_ACTION(h);
3056       authoritative = MAP_REC_AUTH(h);
3057
3058       len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
3059       if (len == ~0)
3060         {
3061           clib_warning ("Failed to parse mapping record!");
3062           vec_foreach (loc, locators)
3063             {
3064               locator_free (loc);
3065             }
3066           vec_free(locators);
3067           goto done;
3068         }
3069
3070       /* insert/update mappings cache */
3071       vnet_lisp_add_del_mapping (&deid, locators, action, authoritative, ttl, 1,
3072                                  &dst_map_index);
3073
3074       /* try to program forwarding only if mapping saved or updated*/
3075       if ((u32) ~0 != dst_map_index)
3076         lisp_add_del_adjacency (lcm, &pmr->src, &deid, 1);
3077
3078       vec_free(locators);
3079     }
3080
3081   /* remove pending map request entry */
3082   vec_foreach (noncep, pmr->nonces)
3083     hash_unset(lcm->pending_map_requests_by_nonce, noncep[0]);
3084   vec_free(pmr->nonces);
3085   pool_put(lcm->pending_map_requests_pool, pmr);
3086
3087 done:
3088   lisp_pending_map_request_unlock (lcm);
3089   return 0;
3090 }
3091
3092 void
3093 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
3094 {
3095   map_request_hdr_t * mreq_hdr;
3096   gid_address_t src, dst;
3097 //  u64 nonce;
3098   u32 i, len = 0;
3099   gid_address_t * itr_rlocs = 0, * rloc;
3100
3101   mreq_hdr = vlib_buffer_get_current (b);
3102   vlib_buffer_pull (b, sizeof(*mreq_hdr));
3103
3104 //  nonce = MREQ_NONCE(mreq_hdr);
3105
3106   if (!MREQ_SMR(mreq_hdr)) {
3107       clib_warning("Only SMR Map-Requests supported for now!");
3108       return;
3109   }
3110
3111   /* parse src eid */
3112   len = lisp_msg_parse_addr (b, &src);
3113   if (len == ~0)
3114     return;
3115
3116   /* for now we don't do anything with the itr's rlocs */
3117   len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs, MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1);
3118   if (len == ~0)
3119     return;
3120
3121   /* TODO: RLOCs are currently unused, so free them for now */
3122   vec_foreach (rloc, itr_rlocs)
3123     {
3124       gid_address_free (rloc);
3125     }
3126
3127   /* parse eid records and send SMR-invoked map-requests */
3128   for (i = 0; i < MREQ_REC_COUNT(mreq_hdr); i++)
3129     {
3130       memset(&dst, 0, sizeof(dst));
3131       len = lisp_msg_parse_eid_rec (b, &dst);
3132       if (len == ~0)
3133         {
3134           clib_warning("Can't parse map-request EID-record");
3135           return;
3136         }
3137       /* send SMR-invoked map-requests */
3138       queue_map_request (&dst, &src, 1 /* invoked */, 0 /* resend */);
3139     }
3140 }
3141
3142 static void
3143 queue_map_reply (vlib_buffer_t * b)
3144 {
3145   vlib_buffer_t * a = clib_mem_alloc (sizeof (a[0]) + b->current_length);
3146
3147   clib_memcpy (a->data, b->data + b->current_data,
3148                b->current_length);
3149   a->current_length = b->current_length;
3150   a->current_data = 0;
3151
3152   vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (a[0])
3153                                 + a->current_length);
3154   clib_mem_free (a);
3155 }
3156
3157 static uword
3158 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
3159                vlib_frame_t * from_frame)
3160 {
3161   u32 n_left_from, * from, * to_next_drop;
3162   lisp_msg_type_e type;
3163   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
3164
3165   from = vlib_frame_vector_args (from_frame);
3166   n_left_from = from_frame->n_vectors;
3167
3168
3169   while (n_left_from > 0)
3170     {
3171       u32 n_left_to_next_drop;
3172
3173       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
3174                            to_next_drop, n_left_to_next_drop);
3175       while (n_left_from > 0 && n_left_to_next_drop > 0)
3176         {
3177           u32 bi0;
3178           vlib_buffer_t * b0;
3179
3180           bi0 = from[0];
3181           from += 1;
3182           n_left_from -= 1;
3183           to_next_drop[0] = bi0;
3184           to_next_drop += 1;
3185           n_left_to_next_drop -= 1;
3186
3187           b0 = vlib_get_buffer (vm, bi0);
3188
3189           type = lisp_msg_type(vlib_buffer_get_current (b0));
3190           switch (type)
3191             {
3192             case LISP_MAP_REPLY:
3193               queue_map_reply (b0);
3194               break;
3195             case LISP_MAP_REQUEST:
3196               process_map_request(vm, lcm, b0);
3197               break;
3198             default:
3199               clib_warning("Unsupported LISP message type %d", type);
3200               break;
3201             }
3202
3203           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
3204
3205           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
3206             {
3207
3208             }
3209         }
3210
3211       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, n_left_to_next_drop);
3212     }
3213   return from_frame->n_vectors;
3214 }
3215
3216 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
3217   .function = lisp_cp_input,
3218   .name = "lisp-cp-input",
3219   .vector_size = sizeof (u32),
3220   .format_trace = format_lisp_cp_input_trace,
3221   .type = VLIB_NODE_TYPE_INTERNAL,
3222
3223   .n_errors = LISP_CP_INPUT_N_ERROR,
3224   .error_strings = lisp_cp_input_error_strings,
3225
3226   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
3227
3228   .next_nodes = {
3229       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
3230   },
3231 };
3232
3233 clib_error_t *
3234 lisp_cp_init (vlib_main_t *vm)
3235 {
3236   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
3237   clib_error_t * error = 0;
3238
3239   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
3240     return error;
3241
3242   lcm->im4 = &ip4_main;
3243   lcm->im6 = &ip6_main;
3244   lcm->vlib_main = vm;
3245   lcm->vnet_main = vnet_get_main();
3246   lcm->mreq_itr_rlocs = ~0;
3247   lcm->lisp_pitr = 0;
3248
3249   lcm->pending_map_request_lock =
3250     clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
3251
3252   lcm->pending_map_request_lock[0] = 0;
3253   gid_dictionary_init (&lcm->mapping_index_by_gid);
3254   lcm->do_map_resolver_election = 1;
3255
3256   /* default vrf mapped to vni 0 */
3257   hash_set(lcm->table_id_by_vni, 0, 0);
3258   hash_set(lcm->vni_by_table_id, 0, 0);
3259
3260   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
3261                          lisp_cp_input_node.index, 1 /* is_ip4 */);
3262   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
3263                          lisp_cp_input_node.index, 0 /* is_ip4 */);
3264
3265   return 0;
3266 }
3267
3268 static void *
3269 send_map_request_thread_fn (void * arg)
3270 {
3271   map_request_args_t * a = arg;
3272   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
3273
3274   lisp_pending_map_request_lock (lcm);
3275
3276   if (a->is_resend)
3277     resend_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
3278   else
3279     send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
3280
3281   lisp_pending_map_request_unlock (lcm);
3282
3283   return 0;
3284 }
3285
3286 static int
3287 queue_map_request (gid_address_t * seid, gid_address_t * deid,
3288                    u8 smr_invoked, u8 is_resend)
3289 {
3290   map_request_args_t a;
3291
3292   a.is_resend = is_resend;
3293   gid_address_copy (&a.seid, seid);
3294   gid_address_copy (&a.deid, deid);
3295   a.smr_invoked = smr_invoked;
3296
3297   vl_api_rpc_call_main_thread (send_map_request_thread_fn,
3298                                (u8 *) &a, sizeof (a));
3299   return 0;
3300 }
3301
3302 /**
3303  * Take an action with a pending map request depending on expiration time
3304  * and re-try counters.
3305  */
3306 static void
3307 update_pending_request (pending_map_request_t * r, f64 dt)
3308 {
3309   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
3310   map_resolver_t * mr;
3311
3312   if (r->time_to_expire - dt < 0)
3313     /* it's time to decide what to do with this pending request */
3314     {
3315       if (r->retries_num >= NUMBER_OF_RETRIES)
3316         /* too many retries -> assume current map resolver is not available */
3317         {
3318           mr = get_map_resolver (&lcm->active_map_resolver);
3319           if (!mr)
3320             {
3321               clib_warning ("Map resolver %U not found - probably deleted "
3322                             "by the user recently.", format_ip_address,
3323                             &lcm->active_map_resolver);
3324             }
3325           else
3326             {
3327               clib_warning ("map resolver %U is unreachable, ignoring",
3328                             format_ip_address, &lcm->active_map_resolver);
3329
3330               /* mark current map resolver unavailable so it won't be
3331                * selected next time */
3332               mr->is_down = 1;
3333               mr->last_update = vlib_time_now (lcm->vlib_main);
3334             }
3335
3336           reset_pending_mr_counters (r);
3337           elect_map_resolver (lcm);
3338
3339           /* try to find a next eligible map resolver and re-send */
3340           queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
3341                              1 /* resend */);
3342         }
3343       else
3344         {
3345           /* try again */
3346           queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
3347                              1 /* resend */);
3348           r->retries_num++;
3349           r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
3350         }
3351     }
3352   else
3353     r->time_to_expire -= dt;
3354 }
3355
3356 static void
3357 remove_dead_pending_map_requests (lisp_cp_main_t * lcm)
3358 {
3359   u64 * nonce;
3360   pending_map_request_t * pmr;
3361   u32 * to_be_removed = 0, * pmr_index;
3362
3363   ASSERT (*lcm->pending_map_request_lock);
3364
3365   pool_foreach (pmr, lcm->pending_map_requests_pool,
3366     ({
3367       if (pmr->to_be_removed)
3368         {
3369           vec_foreach (nonce, pmr->nonces)
3370             hash_unset (lcm->pending_map_requests_by_nonce, nonce[0]);
3371
3372           vec_add1 (to_be_removed, pmr - lcm->pending_map_requests_pool);
3373         }
3374     }));
3375
3376   vec_foreach (pmr_index, to_be_removed)
3377     pool_put_index (lcm->pending_map_requests_by_nonce, pmr_index[0]);
3378
3379   vec_free (to_be_removed);
3380 }
3381
3382 static uword
3383 send_map_resolver_service (vlib_main_t * vm,
3384                            vlib_node_runtime_t * rt,
3385                            vlib_frame_t * f)
3386 {
3387   f64 period = 2.0;
3388   pending_map_request_t * pmr;
3389   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
3390
3391   while (1)
3392     {
3393       vlib_process_wait_for_event_or_clock (vm, period);
3394
3395       /* currently no signals are expected - just wait for clock */
3396       (void) vlib_process_get_events (vm, 0);
3397
3398       lisp_pending_map_request_lock (lcm);
3399       pool_foreach (pmr, lcm->pending_map_requests_pool,
3400         ({
3401           if (!pmr->to_be_removed)
3402             update_pending_request (pmr, period);
3403         }));
3404
3405       remove_dead_pending_map_requests (lcm);
3406
3407       lisp_pending_map_request_unlock (lcm);
3408     }
3409
3410   /* unreachable */
3411   return 0;
3412 }
3413
3414 VLIB_REGISTER_NODE (lisp_retry_service_node,static) = {
3415     .function = send_map_resolver_service,
3416     .type = VLIB_NODE_TYPE_PROCESS,
3417     .name = "lisp-retry-service",
3418     .process_log2_n_stack_bytes = 16,
3419 };
3420
3421 VLIB_INIT_FUNCTION(lisp_cp_init);