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