Edit eid table dump
[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 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 eid end-host identifier
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  * @param res_map_index the map-index that was created/updated/removed. It is
700  *                      set to ~0 if no action is taken.
701  * @return return code
702  */
703 int
704 vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
705                            u8 authoritative, u32 ttl, u8 is_add,
706                            u32 * res_map_index)
707 {
708   vnet_lisp_add_del_mapping_args_t _m_args, * m_args = &_m_args;
709   vnet_lisp_add_del_locator_set_args_t _ls_args, * ls_args = &_ls_args;
710   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
711   u32 mi, ls_index = 0, dst_map_index;
712   mapping_t * old_map;
713
714   if (vnet_lisp_enable_disable_status() == 0)
715     {
716       clib_warning ("LISP is disabled!");
717       return VNET_API_ERROR_LISP_DISABLED;
718     }
719
720   if (res_map_index)
721     res_map_index[0] = ~0;
722
723   memset (m_args, 0, sizeof (m_args[0]));
724   memset (ls_args, 0, sizeof (ls_args[0]));
725
726   ls_args->locators = rlocs;
727
728   mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid);
729   old_map = ((u32) ~0 != mi) ? pool_elt_at_index(lcm->mapping_pool, mi) : 0;
730
731   if (is_add)
732     {
733       /* overwrite: if mapping already exists, decide if locators should be
734        * updated and be done */
735       if (old_map && gid_address_cmp (&old_map->eid, eid) == 0)
736         {
737           locator_set_t * old_ls;
738
739           /* update mapping attributes */
740           old_map->action = action;
741           old_map->authoritative = authoritative;
742           old_map->ttl = ttl;
743
744           old_ls = pool_elt_at_index(lcm->locator_set_pool,
745                                      old_map->locator_set_index);
746           if (compare_locators (lcm, old_ls->locator_indices,
747                                 ls_args->locators))
748             {
749               /* set locator-set index to overwrite */
750               ls_args->is_add = 1;
751               ls_args->index = old_map->locator_set_index;
752               vnet_lisp_add_del_locator_set (ls_args, 0);
753               if (res_map_index)
754                 res_map_index[0] = mi;
755             }
756         }
757       /* new mapping */
758       else
759         {
760           ls_args->is_add = 1;
761           ls_args->index = ~0;
762
763           vnet_lisp_add_del_locator_set (ls_args, &ls_index);
764
765           /* add mapping */
766           gid_address_copy (&m_args->eid, eid);
767           m_args->is_add = 1;
768           m_args->action = action;
769           m_args->locator_set_index = ls_index;
770           vnet_lisp_map_cache_add_del (m_args, &dst_map_index);
771
772           if (res_map_index)
773             res_map_index[0] = dst_map_index;
774         }
775     }
776   else
777     {
778       if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0)
779         {
780           clib_warning("cannot delete mapping for eid %U", format_gid_address,
781                        eid);
782           return -1;
783         }
784
785       m_args->is_add = 0;
786       gid_address_copy (&m_args->eid, eid);
787       m_args->locator_set_index = old_map->locator_set_index;
788
789       /* delete mapping associated from map-cache */
790       vnet_lisp_map_cache_add_del (m_args, 0);
791
792       ls_args->is_add = 0;
793       ls_args->index = old_map->locator_set_index;
794       /* delete locator set */
795       vnet_lisp_add_del_locator_set (ls_args, 0);
796
797       /* return old mapping index */
798       if (res_map_index)
799         res_map_index[0] = mi;
800     }
801
802   /* success */
803   return 0;
804 }
805
806 int
807 vnet_lisp_clear_all_remote_adjacencies (void)
808 {
809   int rv = 0;
810   u32 mi, * map_indices = 0, * map_indexp;
811   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
812   vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args;
813   vnet_lisp_add_del_locator_set_args_t _ls, * ls = &_ls;
814
815   pool_foreach_index (mi, lcm->mapping_pool,
816     ({
817       vec_add1 (map_indices, mi);
818     }));
819
820   vec_foreach (map_indexp, map_indices)
821     {
822       mapping_t * map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
823       if (!map->local)
824         {
825           dp_del_fwd_entry (lcm, 0, map_indexp[0]);
826
827           dm_args->is_add = 0;
828           gid_address_copy (&dm_args->eid, &map->eid);
829           dm_args->locator_set_index = map->locator_set_index;
830
831           /* delete mapping associated to fwd entry */
832           vnet_lisp_map_cache_add_del (dm_args, 0);
833
834           ls->is_add = 0;
835           ls->local = 0;
836           ls->index = map->locator_set_index;
837           /* delete locator set */
838           rv = vnet_lisp_add_del_locator_set (ls, 0);
839           if (rv != 0)
840             goto cleanup;
841         }
842     }
843
844 cleanup:
845   if (map_indices)
846     vec_free (map_indices);
847   return rv;
848 }
849
850 /**
851  * Adds adjacency or removes forwarding entry associated to remote mapping.
852  * Note that adjacencies are not stored, they only result in forwarding entries
853  * being created.
854  */
855 int
856 lisp_add_del_adjacency (lisp_cp_main_t * lcm, gid_address_t * local_eid,
857                         gid_address_t * remote_eid, u8 is_add)
858 {
859   u32 local_mi, remote_mi = ~0;
860
861   if (vnet_lisp_enable_disable_status () == 0)
862     {
863       clib_warning ("LISP is disabled!");
864       return VNET_API_ERROR_LISP_DISABLED;
865     }
866
867   remote_mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, remote_eid);
868   if (GID_LOOKUP_MISS == remote_mi)
869     {
870       clib_warning("Remote eid %U not found. Cannot add adjacency!",
871                    format_gid_address, remote_eid);
872
873       return -1;
874     }
875
876   if (is_add)
877     {
878       /* TODO 1) check if src/dst 2) once we have src/dst working, use it in
879        * delete*/
880
881       /* check if source eid has an associated mapping. If pitr mode is on,
882        * just use the pitr's mapping */
883       local_mi = lcm->lisp_pitr ? lcm->pitr_map_index :
884               gid_dictionary_lookup (&lcm->mapping_index_by_gid, local_eid);
885
886
887       if (GID_LOOKUP_MISS == local_mi)
888         {
889           clib_warning("Local eid %U not found. Cannot add adjacency!",
890                        format_gid_address, local_eid);
891
892           return -1;
893         }
894
895       /* update forwarding */
896       dp_add_fwd_entry (lcm, local_mi, remote_mi);
897     }
898   else
899     dp_del_fwd_entry (lcm, 0, remote_mi);
900
901   return 0;
902 }
903
904 int
905 vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a)
906 {
907   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
908   return lisp_add_del_adjacency(lcm, &a->seid, &a->deid, a->is_add);
909 }
910
911 /**
912  * Handler for add/del remote mapping CLI.
913  *
914  * @param vm vlib context
915  * @param input input from user
916  * @param cmd cmd
917  * @return pointer to clib error structure
918  */
919 static clib_error_t *
920 lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm,
921                                         unformat_input_t * input,
922                                         vlib_cli_command_t * cmd)
923 {
924   clib_error_t * error = 0;
925   unformat_input_t _line_input, * line_input = &_line_input;
926   u8 is_add = 1, del_all = 0;
927   locator_t rloc, * rlocs = 0, * curr_rloc = 0;
928   ip_prefix_t * eid_ippref;
929   gid_address_t eid;
930   u8 * dmac = gid_address_mac (&eid);
931   u8 eid_set = 0;
932   u8 * s = 0;
933   u32 vni, action = ~0, p, w;
934   int rv;
935
936   /* Get a line of input. */
937   if (! unformat_user (input, unformat_line_input, line_input))
938     return 0;
939
940   memset(&eid, 0, sizeof(eid));
941   memset(&rloc, 0, sizeof(rloc));
942
943   eid_ippref = &gid_address_ippref(&eid);
944
945   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
946     {
947       if (unformat (line_input, "del-all"))
948         del_all = 1;
949       else if (unformat (line_input, "del"))
950         is_add = 0;
951       else if (unformat (line_input, "add"))
952         ;
953       else if (unformat (line_input, "eid %U",
954                          unformat_ip_prefix, eid_ippref))
955         {
956           gid_address_type (&eid) = GID_ADDR_IP_PREFIX;
957           eid_set = 1;
958         }
959       else if (unformat (line_input, "eid %U",
960                          unformat_mac_address, dmac))
961         {
962           gid_address_type (&eid) = GID_ADDR_MAC;
963           eid_set = 1;
964         }
965       else if (unformat (line_input, "vni %u", &vni))
966         {
967           gid_address_vni (&eid) = vni;
968         }
969       else if (unformat (line_input, "p %d w %d", &p, &w))
970         {
971           if (!curr_rloc)
972             {
973               clib_warning ("No RLOC configured for setting priority/weight!");
974               goto done;
975             }
976           curr_rloc->priority = p;
977           curr_rloc->weight = w;
978         }
979       else if (unformat (line_input, "rloc %U", unformat_ip_address,
980                          &rloc.address))
981         {
982           vec_add1 (rlocs, rloc);
983           curr_rloc = &rlocs[vec_len (rlocs) - 1];
984         }
985       else if (unformat (line_input, "action %s", &s))
986         {
987           if (!strcmp ((char *)s, "no-action"))
988             action = ACTION_NONE;
989           if (!strcmp ((char *)s, "natively-forward"))
990             action = ACTION_NATIVELY_FORWARDED;
991           if (!strcmp ((char *)s, "send-map-request"))
992             action = ACTION_SEND_MAP_REQUEST;
993           else if (!strcmp ((char *)s, "drop"))
994             action = ACTION_DROP;
995           else
996             {
997               clib_warning ("invalid action: '%s'", s);
998               goto done;
999             }
1000         }
1001       else
1002         {
1003           clib_warning ("parse error");
1004           goto done;
1005         }
1006     }
1007
1008   if (!eid_set)
1009     {
1010       clib_warning ("missing eid!");
1011       goto done;
1012     }
1013
1014   if (!del_all)
1015     {
1016
1017
1018       if (is_add && (~0 == action)
1019           && 0 == vec_len (rlocs))
1020         {
1021           clib_warning ("no action set for negative map-reply!");
1022           goto done;
1023         }
1024     }
1025   else
1026     {
1027       vnet_lisp_clear_all_remote_adjacencies ();
1028       goto done;
1029     }
1030
1031   /* TODO build src/dst with seid*/
1032
1033   /* if it's a delete, clean forwarding */
1034   if (!is_add)
1035     {
1036       lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1037       rv = lisp_add_del_adjacency (lcm, 0, &eid, /* is_add */ 0);
1038       if (rv)
1039         {
1040           goto done;
1041         }
1042     }
1043
1044   /* add as static remote mapping, i.e., not authoritative and infinite
1045    * ttl */
1046   rv = vnet_lisp_add_del_mapping (&eid, rlocs, action, 0, ~0, is_add, 0);
1047
1048   if (rv)
1049     clib_warning("failed to %s remote mapping!", is_add ? "add" : "delete");
1050
1051 done:
1052   vec_free (rlocs);
1053   unformat_free (line_input);
1054   if (s)
1055     vec_free (s);
1056   return error;
1057 }
1058
1059 VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) = {
1060     .path = "lisp remote-mapping",
1061     .short_help = "lisp remote-mapping add|del [del-all] vni <vni> "
1062      "eid <est-eid> [action <no-action|natively-forward|"
1063      "send-map-request|drop>] rloc <dst-locator> [rloc <dst-locator> ... ]",
1064     .function = lisp_add_del_remote_mapping_command_fn,
1065 };
1066
1067 /**
1068  * Handler for add/del adjacency CLI.
1069  */
1070 static clib_error_t *
1071 lisp_add_del_adjacency_command_fn (vlib_main_t * vm, unformat_input_t * input,
1072                                    vlib_cli_command_t * cmd)
1073 {
1074   clib_error_t * error = 0;
1075   unformat_input_t _line_input, * line_input = &_line_input;
1076   vnet_lisp_add_del_adjacency_args_t _a, * a = &_a;
1077   u8 is_add = 1;
1078   locator_t rloc, * rlocs = 0;
1079   ip_prefix_t * deid_ippref, * seid_ippref;
1080   gid_address_t seid, deid;
1081   u8 * dmac = gid_address_mac (&deid);
1082   u8 * smac = gid_address_mac (&seid);
1083   u8 deid_set = 0, seid_set = 0;
1084   u8 * s = 0;
1085   u32 vni, action = ~0;
1086   int rv;
1087
1088   /* Get a line of input. */
1089   if (! unformat_user (input, unformat_line_input, line_input))
1090     return 0;
1091
1092   memset(&deid, 0, sizeof(deid));
1093   memset(&seid, 0, sizeof(seid));
1094   memset(&rloc, 0, sizeof(rloc));
1095
1096   seid_ippref = &gid_address_ippref(&seid);
1097   deid_ippref = &gid_address_ippref(&deid);
1098
1099   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1100     {
1101       if (unformat (line_input, "del"))
1102         is_add = 0;
1103       else if (unformat (line_input, "add"))
1104         ;
1105       else if (unformat (line_input, "deid %U",
1106                          unformat_ip_prefix, deid_ippref))
1107         {
1108           gid_address_type (&deid) = GID_ADDR_IP_PREFIX;
1109           deid_set = 1;
1110         }
1111       else if (unformat (line_input, "deid %U",
1112                          unformat_mac_address, dmac))
1113         {
1114           gid_address_type (&deid) = GID_ADDR_MAC;
1115           deid_set = 1;
1116         }
1117       else if (unformat (line_input, "vni %u", &vni))
1118         {
1119           gid_address_vni (&seid) = vni;
1120           gid_address_vni (&deid) = vni;
1121         }
1122       else if (unformat (line_input, "seid %U",
1123                          unformat_ip_prefix, seid_ippref))
1124         {
1125           gid_address_type (&seid) = GID_ADDR_IP_PREFIX;
1126           seid_set = 1;
1127         }
1128       else if (unformat (line_input, "seid %U",
1129                          unformat_mac_address, smac))
1130         {
1131           gid_address_type (&seid) = GID_ADDR_MAC;
1132           seid_set = 1;
1133         }
1134       else
1135         {
1136           clib_warning ("parse error");
1137           goto done;
1138         }
1139     }
1140
1141   if (!deid_set)
1142     {
1143       clib_warning ("missing deid!");
1144       goto done;
1145     }
1146
1147   if (GID_ADDR_IP_PREFIX == gid_address_type (&deid))
1148     {
1149       /* if seid not set, make sure the ip version is the same as that
1150        * of the deid. This ensures the seid to be configured will be
1151        * either 0/0 or ::/0 */
1152       if (!seid_set)
1153         ip_prefix_version(seid_ippref) = ip_prefix_version(deid_ippref);
1154
1155       if (is_add &&
1156           (ip_prefix_version (deid_ippref)
1157            != ip_prefix_version(seid_ippref)))
1158         {
1159           clib_warning ("source and destination EIDs are not"
1160                         " in the same IP family!");
1161           goto done;
1162         }
1163     }
1164
1165   if (is_add && (~0 == action)
1166       && 0 == vec_len (rlocs))
1167     {
1168       clib_warning ("no action set for negative map-reply!");
1169       goto done;
1170     }
1171
1172   memset(a, 0, sizeof(a[0]));
1173   gid_address_copy (&a->seid, &deid);
1174   gid_address_copy (&a->deid, &seid);
1175
1176   a->is_add = is_add;
1177   rv = vnet_lisp_add_del_adjacency (a);
1178
1179   if (rv)
1180     clib_warning("failed to %s adjacency!", is_add ? "add" : "delete");
1181
1182 done:
1183   unformat_free (line_input);
1184   if (s)
1185     vec_free (s);
1186   return error;
1187 }
1188
1189 VLIB_CLI_COMMAND (lisp_add_del_adjacency_command) = {
1190     .path = "lisp adjacency",
1191     .short_help = "lisp adjacency add|del vni <vni>"
1192      "deid <dest-eid> seid <src-eid> [action <no-action|natively-forward|"
1193      "send-map-request|drop>] rloc <dst-locator> [rloc <dst-locator> ... ]",
1194     .function = lisp_add_del_adjacency_command_fn,
1195 };
1196
1197
1198 static clib_error_t *
1199 lisp_show_map_resolvers_command_fn (vlib_main_t * vm,
1200                                     unformat_input_t * input,
1201                                     vlib_cli_command_t * cmd)
1202 {
1203   ip_address_t * addr;
1204   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1205
1206   vec_foreach (addr, lcm->map_resolvers)
1207     {
1208       vlib_cli_output (vm, "%U", format_ip_address, addr);
1209     }
1210   return 0;
1211 }
1212
1213 VLIB_CLI_COMMAND (lisp_show_map_resolvers_command) = {
1214     .path = "show lisp map-resolvers",
1215     .short_help = "show lisp map-resolvers",
1216     .function = lisp_show_map_resolvers_command_fn,
1217 };
1218
1219 int
1220 vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
1221 {
1222   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1223   u32 locator_set_index = ~0;
1224   mapping_t * m;
1225   uword * p;
1226
1227   if (vnet_lisp_enable_disable_status () == 0)
1228     {
1229       clib_warning ("LISP is disabled!");
1230       return VNET_API_ERROR_LISP_DISABLED;
1231     }
1232
1233   p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1234   if (!p)
1235     {
1236       clib_warning ("locator-set %v doesn't exist", locator_set_name);
1237       return -1;
1238     }
1239   locator_set_index = p[0];
1240
1241   if (is_add)
1242     {
1243       pool_get (lcm->mapping_pool, m);
1244       m->locator_set_index = locator_set_index;
1245       m->local = 1;
1246       lcm->pitr_map_index = m - lcm->mapping_pool;
1247
1248       /* enable pitr mode */
1249       lcm->lisp_pitr = 1;
1250     }
1251   else
1252     {
1253       /* remove pitr mapping */
1254       pool_put_index (lcm->mapping_pool, lcm->pitr_map_index);
1255
1256       /* disable pitr mode */
1257       lcm->lisp_pitr = 0;
1258     }
1259   return 0;
1260 }
1261
1262 static clib_error_t *
1263 lisp_pitr_set_locator_set_command_fn (vlib_main_t * vm,
1264                                       unformat_input_t * input,
1265                                       vlib_cli_command_t * cmd)
1266 {
1267   u8 locator_name_set = 0;
1268   u8 * locator_set_name = 0;
1269   u8 is_add = 1;
1270   unformat_input_t _line_input, * line_input = &_line_input;
1271   clib_error_t * error = 0;
1272   int rv = 0;
1273
1274   /* Get a line of input. */
1275   if (! unformat_user (input, unformat_line_input, line_input))
1276     return 0;
1277
1278   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1279     {
1280       if (unformat (line_input, "ls %_%v%_", &locator_set_name))
1281         locator_name_set = 1;
1282       else if (unformat (line_input, "disable"))
1283         is_add = 0;
1284       else
1285         return clib_error_return (0, "parse error");
1286     }
1287
1288   if (!locator_name_set)
1289     {
1290       clib_warning ("No locator set specified!");
1291       goto done;
1292     }
1293   rv = vnet_lisp_pitr_set_locator_set (locator_set_name, is_add);
1294   if (0 != rv)
1295     {
1296       error = clib_error_return(0, "failed to %s pitr!",
1297                                 is_add ? "add" : "delete");
1298     }
1299
1300 done:
1301   if (locator_set_name)
1302     vec_free (locator_set_name);
1303   return error;
1304 }
1305
1306 VLIB_CLI_COMMAND (lisp_pitr_set_locator_set_command) = {
1307     .path = "lisp pitr",
1308     .short_help = "lisp pitr [disable] ls <locator-set-name>",
1309     .function = lisp_pitr_set_locator_set_command_fn,
1310 };
1311
1312 static clib_error_t *
1313 lisp_show_pitr_command_fn (vlib_main_t * vm,
1314                            unformat_input_t * input,
1315                            vlib_cli_command_t * cmd)
1316 {
1317   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1318   mapping_t * m;
1319   locator_set_t * ls;
1320   u8 * tmp_str = 0;
1321
1322   vlib_cli_output (vm, "%=20s%=16s",
1323                    "pitr", lcm->lisp_pitr ? "locator-set" : "");
1324
1325   if (!lcm->lisp_pitr) {
1326     vlib_cli_output (vm, "%=20s", "disable");
1327     return 0;
1328   }
1329
1330   if (~0 == lcm->pitr_map_index) {
1331     tmp_str = format(0, "N/A");
1332   } else {
1333     m = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
1334     if (~0 != m->locator_set_index) {
1335       ls = pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
1336       tmp_str = format(0, "%s", ls->name);
1337     } else {
1338       tmp_str = format(0, "N/A");
1339     }
1340   }
1341   vec_add1(tmp_str, 0);
1342
1343   vlib_cli_output (vm, "%=20s%=16s",
1344                    "enable", tmp_str);
1345
1346   vec_free(tmp_str);
1347
1348   return 0;
1349 }
1350
1351 VLIB_CLI_COMMAND (lisp_show_pitr_command) = {
1352     .path = "show lisp pitr",
1353     .short_help = "Show pitr",
1354     .function = lisp_show_pitr_command_fn,
1355 };
1356
1357 static u8 *
1358 format_eid_entry (u8 * s, va_list * args)
1359 {
1360   vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
1361   lisp_cp_main_t * lcm = va_arg (*args, lisp_cp_main_t *);
1362   mapping_t * mapit = va_arg (*args, mapping_t *);
1363   locator_set_t * ls = va_arg (*args, locator_set_t *);
1364   gid_address_t * gid = &mapit->eid;
1365   u32 ttl = mapit->ttl;
1366   u8 aut = mapit->authoritative;
1367   u32 * loc_index;
1368   u8 first_line = 1;
1369   u8 * loc;
1370
1371   u8 * type = ls->local ? format(0, "local(%s)", ls->name)
1372                         : format(0, "remote");
1373
1374   if (vec_len (ls->locator_indices) == 0)
1375     {
1376       s = format (s, "%-35U%-30s%-20u%-u", format_gid_address, gid,
1377                                            type, ttl, aut);
1378     }
1379   else
1380     {
1381       vec_foreach (loc_index, ls->locator_indices)
1382         {
1383           locator_t * l = pool_elt_at_index (lcm->locator_pool, loc_index[0]);
1384           if (l->local)
1385             loc = format (0, "%U", format_vnet_sw_if_index_name, vnm,
1386                           l->sw_if_index);
1387           else
1388             loc = format (0, "%U", format_ip_address,
1389                           &gid_address_ip (&l->address));
1390
1391           if (first_line)
1392             {
1393               s = format (s, "%-35U%-20s%-30v%-20u%-u\n", format_gid_address,
1394                           gid, type, loc, ttl, aut);
1395               first_line = 0;
1396             }
1397           else
1398             s = format (s, "%55s%v\n", "", loc);
1399         }
1400     }
1401   return s;
1402 }
1403
1404 static clib_error_t *
1405 lisp_show_eid_table_command_fn (vlib_main_t * vm,
1406                                 unformat_input_t * input,
1407                                 vlib_cli_command_t * cmd)
1408 {
1409   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1410   mapping_t * mapit;
1411   unformat_input_t _line_input, * line_input = &_line_input;
1412   u32 mi;
1413   gid_address_t eid;
1414   u8 print_all = 1;
1415   u8 filter = 0;
1416
1417   memset (&eid, 0, sizeof(eid));
1418
1419   /* Get a line of input. */
1420   if (!unformat_user (input, unformat_line_input, line_input))
1421     return 0;
1422
1423   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1424     {
1425       if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
1426         print_all = 0;
1427       else if (unformat (line_input, "local"))
1428         filter = 1;
1429       else if (unformat(line_input, "remote"))
1430         filter = 2;
1431       else
1432         return clib_error_return (0, "parse error: '%U'",
1433                                   format_unformat_error, line_input);
1434     }
1435
1436   vlib_cli_output (vm, "%-35s%-20s%-30s%-20s%-s",
1437                    "EID", "type", "locators", "ttl", "autoritative");
1438
1439   if (print_all)
1440     {
1441       pool_foreach (mapit, lcm->mapping_pool,
1442       ({
1443         locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
1444                                                 mapit->locator_set_index);
1445         if (filter && !((1 == filter && ls->local) ||
1446           (2 == filter && !ls->local)))
1447           {
1448             continue;
1449           }
1450         vlib_cli_output (vm, "%U", format_eid_entry, lcm->vnet_main,
1451                          lcm, mapit, ls);
1452       }));
1453     }
1454   else
1455     {
1456       mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &eid);
1457       if ((u32)~0 == mi)
1458         return 0;
1459
1460       mapit = pool_elt_at_index (lcm->mapping_pool, mi);
1461       locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
1462                                               mapit->locator_set_index);
1463
1464       if (filter && !((1 == filter && ls->local) ||
1465         (2 == filter && !ls->local)))
1466         {
1467           return 0;
1468         }
1469
1470       vlib_cli_output (vm, "%U,", format_eid_entry, lcm->vnet_main,
1471                        lcm, mapit, ls);
1472     }
1473
1474   return 0;
1475 }
1476
1477 VLIB_CLI_COMMAND (lisp_cp_show_eid_table_command) = {
1478     .path = "show lisp eid-table",
1479     .short_help = "Shows EID table",
1480     .function = lisp_show_eid_table_command_fn,
1481 };
1482
1483 /* cleans locator to locator-set data and removes locators not part of
1484  * any locator-set */
1485 static void
1486 clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
1487 {
1488   u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
1489   locator_set_t * ls = pool_elt_at_index(lcm->locator_set_pool, lsi);
1490   for (i = 0; i < vec_len(ls->locator_indices); i++)
1491     {
1492       loc_indexp = vec_elt_at_index(ls->locator_indices, i);
1493       ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1494                                     loc_indexp[0]);
1495       for (j = 0; j < vec_len(ls_indexes[0]); j++)
1496         {
1497           ls_indexp = vec_elt_at_index(ls_indexes[0], j);
1498           if (ls_indexp[0] == lsi)
1499             break;
1500         }
1501
1502       /* delete index for removed locator-set*/
1503       vec_del1(ls_indexes[0], j);
1504
1505       /* delete locator if it's part of no locator-set */
1506       if (vec_len (ls_indexes[0]) == 0)
1507         {
1508           pool_put_index (lcm->locator_pool, loc_indexp[0]);
1509           vec_add1 (to_be_deleted, i);
1510         }
1511     }
1512
1513   if (to_be_deleted)
1514     {
1515       for (i = 0; i < vec_len (to_be_deleted); i++)
1516         {
1517           loc_indexp = vec_elt_at_index (to_be_deleted, i);
1518           vec_del1 (ls->locator_indices, loc_indexp[0]);
1519         }
1520       vec_free (to_be_deleted);
1521     }
1522 }
1523
1524 static inline uword *
1525 get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p)
1526 {
1527   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1528
1529   ASSERT(a != NULL);
1530   ASSERT(p != NULL);
1531
1532   /* find locator-set */
1533   if (a->local)
1534     {
1535       p = hash_get_mem(lcm->locator_set_index_by_name, a->name);
1536     }
1537   else
1538     {
1539       *p = a->index;
1540     }
1541
1542   return p;
1543 }
1544
1545 static inline int
1546 is_locator_in_locator_set (lisp_cp_main_t * lcm, locator_set_t * ls,
1547                            locator_t * loc)
1548 {
1549   locator_t * itloc;
1550   u32 * locit;
1551
1552   ASSERT(ls != NULL);
1553   ASSERT(loc != NULL);
1554
1555   vec_foreach(locit, ls->locator_indices)
1556     {
1557       itloc = pool_elt_at_index(lcm->locator_pool, locit[0]);
1558       if ((ls->local && itloc->sw_if_index == loc->sw_if_index) ||
1559           (!ls->local && !gid_address_cmp(&itloc->address, &loc->address)))
1560         {
1561           clib_warning("Duplicate locator");
1562           return VNET_API_ERROR_VALUE_EXIST;
1563         }
1564     }
1565
1566   return 0;
1567 }
1568
1569 static inline void
1570 remove_locator_from_locator_set (locator_set_t * ls, u32 * locit, u32 ls_index,
1571                                  u32 loc_id)
1572 {
1573   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1574   u32 ** ls_indexes = NULL;
1575
1576   ASSERT(ls != NULL);
1577   ASSERT(locit != NULL);
1578
1579   ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1580                                 locit[0]);
1581   pool_put_index(lcm->locator_pool, locit[0]);
1582   vec_del1(ls->locator_indices, loc_id);
1583   vec_del1(ls_indexes[0], ls_index);
1584 }
1585
1586 int
1587 vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
1588                            locator_set_t * ls, u32 * ls_result)
1589 {
1590   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1591   locator_t * loc = NULL, *itloc = NULL;
1592   uword _p = (u32)~0, * p = &_p;
1593   u32 loc_index = ~0, ls_index = ~0, * locit = NULL, ** ls_indexes = NULL;
1594   u32 loc_id = ~0;
1595   int ret = 0;
1596
1597   ASSERT(a != NULL);
1598
1599   if (vnet_lisp_enable_disable_status () == 0)
1600     {
1601       clib_warning ("LISP is disabled!");
1602       return VNET_API_ERROR_LISP_DISABLED;
1603     }
1604
1605   p = get_locator_set_index(a, p);
1606   if (!p)
1607     {
1608       clib_warning("locator-set %v doesn't exist", a->name);
1609       return VNET_API_ERROR_INVALID_ARGUMENT;
1610     }
1611
1612   if (ls == 0)
1613     {
1614       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1615       if (!ls)
1616         {
1617           clib_warning("locator-set %d to be overwritten doesn't exist!",
1618                        p[0]);
1619           return VNET_API_ERROR_INVALID_ARGUMENT;
1620         }
1621     }
1622
1623   if (a->is_add)
1624     {
1625
1626         if (ls_result)
1627           ls_result[0] = p[0];
1628
1629         /* allocate locators */
1630         vec_foreach (itloc, a->locators)
1631           {
1632             ret = is_locator_in_locator_set(lcm, ls, itloc);
1633             if (0 != ret)
1634               {
1635                 return ret;
1636               }
1637
1638             pool_get(lcm->locator_pool, loc);
1639             loc[0] = itloc[0];
1640             loc_index = loc - lcm->locator_pool;
1641
1642             vec_add1(ls->locator_indices, loc_index);
1643
1644             vec_validate (lcm->locator_to_locator_sets, loc_index);
1645             ls_indexes = vec_elt_at_index(lcm->locator_to_locator_sets,
1646                                           loc_index);
1647             vec_add1(ls_indexes[0], ls_index);
1648           }
1649       }
1650     else
1651       {
1652         ls_index = p[0];
1653
1654         itloc = a->locators;
1655         loc_id = 0;
1656         vec_foreach (locit, ls->locator_indices)
1657           {
1658             loc = pool_elt_at_index(lcm->locator_pool, locit[0]);
1659
1660             if (loc->local && loc->sw_if_index == itloc->sw_if_index)
1661               {
1662                 remove_locator_from_locator_set(ls, locit,
1663                                                 ls_index, loc_id);
1664               }
1665             if (0 == loc->local &&
1666                 !gid_address_cmp(&loc->address, &itloc->address))
1667               {
1668                 remove_locator_from_locator_set(ls, locit,
1669                                                 ls_index, loc_id);
1670               }
1671
1672             loc_id++;
1673           }
1674       }
1675
1676   return 0;
1677 }
1678
1679 int
1680 vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
1681                                u32 * ls_result)
1682 {
1683   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
1684   locator_set_t * ls;
1685   uword _p = (u32)~0, * p = &_p;
1686   u32 ls_index;
1687   u32 ** eid_indexes;
1688   int ret = 0;
1689
1690   if (vnet_lisp_enable_disable_status () == 0)
1691     {
1692       clib_warning ("LISP is disabled!");
1693       return VNET_API_ERROR_LISP_DISABLED;
1694     }
1695
1696   if (a->is_add)
1697     {
1698       p = get_locator_set_index(a, p);
1699
1700       /* overwrite */
1701       if (p && p[0] != (u32)~0)
1702         {
1703           ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1704           if (!ls)
1705             {
1706               clib_warning("locator-set %d to be overwritten doesn't exist!",
1707                            p[0]);
1708               return -1;
1709             }
1710
1711           /* clean locator to locator-set vectors and remove locators if
1712            * they're not part of another locator-set */
1713           clean_locator_to_locator_set (lcm, p[0]);
1714
1715           /* remove locator indices from locator set */
1716           vec_free(ls->locator_indices);
1717
1718           ls_index = p[0];
1719
1720           if (ls_result)
1721             ls_result[0] = p[0];
1722         }
1723       /* new locator-set */
1724       else
1725         {
1726           pool_get(lcm->locator_set_pool, ls);
1727           memset(ls, 0, sizeof(*ls));
1728           ls_index = ls - lcm->locator_set_pool;
1729
1730           if (a->local)
1731             {
1732               ls->name = vec_dup(a->name);
1733
1734               if (!lcm->locator_set_index_by_name)
1735                 lcm->locator_set_index_by_name = hash_create_vec(
1736                     /* size */0, sizeof(ls->name[0]), sizeof(uword));
1737               hash_set_mem(lcm->locator_set_index_by_name, ls->name, ls_index);
1738
1739               /* mark as local locator-set */
1740               vec_add1(lcm->local_locator_set_indexes, ls_index);
1741             }
1742           ls->local = a->local;
1743           if (ls_result)
1744             ls_result[0] = ls_index;
1745         }
1746
1747       ret = vnet_lisp_add_del_locator(a, ls, NULL);
1748       if (0 != ret)
1749         {
1750           return ret;
1751         }
1752     }
1753   else
1754     {
1755       p = get_locator_set_index(a, p);
1756       if (!p)
1757         {
1758           clib_warning("locator-set %v doesn't exists", a->name);
1759           return -1;
1760         }
1761
1762       ls = pool_elt_at_index(lcm->locator_set_pool, p[0]);
1763       if (!ls)
1764         {
1765           clib_warning("locator-set with index %d doesn't exists", p[0]);
1766           return -1;
1767         }
1768
1769       if (lcm->mreq_itr_rlocs == p[0])
1770         {
1771           clib_warning ("Can't delete the locator-set used to constrain "
1772                         "the itr-rlocs in map-requests!");
1773           return -1;
1774         }
1775
1776       if (vec_len(lcm->locator_set_to_eids) != 0)
1777       {
1778           eid_indexes = vec_elt_at_index(lcm->locator_set_to_eids, p[0]);
1779           if (vec_len(eid_indexes[0]) != 0)
1780           {
1781               clib_warning ("Can't delete a locator that supports a mapping!");
1782               return -1;
1783           }
1784       }
1785
1786       /* clean locator to locator-sets data */
1787       clean_locator_to_locator_set (lcm, p[0]);
1788
1789       if (ls->local)
1790         {
1791           u32 it, lsi;
1792
1793           vec_foreach_index(it, lcm->local_locator_set_indexes)
1794           {
1795             lsi = vec_elt(lcm->local_locator_set_indexes, it);
1796             if (lsi == p[0])
1797               {
1798                 vec_del1(lcm->local_locator_set_indexes, it);
1799                 break;
1800               }
1801           }
1802           hash_unset_mem(lcm->locator_set_index_by_name, ls->name);
1803         }
1804       vec_free(ls->name);
1805       vec_free(ls->locator_indices);
1806       pool_put(lcm->locator_set_pool, ls);
1807     }
1808   return 0;
1809 }
1810
1811 clib_error_t *
1812 vnet_lisp_enable_disable (u8 is_enable)
1813 {
1814   u32 vni, table_id;
1815   clib_error_t * error = 0;
1816   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1817   vnet_lisp_gpe_enable_disable_args_t _a, * a = &_a;
1818
1819   a->is_en = is_enable;
1820   error = vnet_lisp_gpe_enable_disable (a);
1821   if (error)
1822     {
1823       return clib_error_return (0, "failed to %s data-plane!",
1824                                 a->is_en ? "enable" : "disable");
1825     }
1826
1827   if (is_enable)
1828     {
1829       /* enable all ifaces */
1830       hash_foreach(vni, table_id, lcm->table_id_by_vni, ({
1831         dp_add_del_iface(lcm, vni, 1);
1832       }));
1833     }
1834   else
1835     {
1836       /* clear interface table */
1837       hash_free(lcm->dp_intf_by_vni);
1838       hash_free(lcm->fwd_entry_by_mapping_index);
1839       pool_free(lcm->fwd_entry_pool);
1840     }
1841
1842   /* update global flag */
1843   lcm->is_enabled = is_enable;
1844
1845   return 0;
1846 }
1847
1848 static clib_error_t *
1849 lisp_enable_disable_command_fn (vlib_main_t * vm, unformat_input_t * input,
1850                                 vlib_cli_command_t * cmd)
1851 {
1852   unformat_input_t _line_input, * line_input = &_line_input;
1853   u8 is_enabled = 0;
1854   u8 is_set = 0;
1855
1856   /* Get a line of input. */
1857   if (! unformat_user (input, unformat_line_input, line_input))
1858     return 0;
1859
1860   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1861     {
1862       if (unformat (line_input, "enable"))
1863         {
1864           is_set = 1;
1865           is_enabled = 1;
1866         }
1867       else if (unformat (line_input, "disable"))
1868         is_set = 1;
1869       else
1870         {
1871           return clib_error_return (0, "parse error: '%U'",
1872                                    format_unformat_error, line_input);
1873         }
1874     }
1875
1876   if (!is_set)
1877       return clib_error_return (0, "state not set");
1878
1879   return vnet_lisp_enable_disable (is_enabled);
1880 }
1881
1882 VLIB_CLI_COMMAND (lisp_cp_enable_disable_command) = {
1883     .path = "lisp",
1884     .short_help = "lisp [enable|disable]",
1885     .function = lisp_enable_disable_command_fn,
1886 };
1887
1888 u8
1889 vnet_lisp_enable_disable_status (void)
1890 {
1891   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1892   return lcm->is_enabled;
1893 }
1894
1895 static u8 *
1896 format_lisp_status (u8 * s, va_list * args)
1897 {
1898   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1899   return format (s, "%s", lcm->is_enabled ? "enabled" : "disabled");
1900 }
1901
1902 static clib_error_t *
1903 lisp_show_status_command_fn (vlib_main_t * vm, unformat_input_t * input,
1904                              vlib_cli_command_t * cmd)
1905 {
1906   u8 * msg = 0;
1907   msg = format (msg, "feature: %U\ngpe: %U\n",
1908                 format_lisp_status, format_vnet_lisp_gpe_status);
1909   vlib_cli_output (vm, "%v", msg);
1910   vec_free (msg);
1911   return 0;
1912 }
1913
1914 VLIB_CLI_COMMAND (lisp_show_status_command) = {
1915     .path = "show lisp status",
1916     .short_help = "show lisp status",
1917     .function = lisp_show_status_command_fn,
1918 };
1919
1920 static clib_error_t *
1921 lisp_show_eid_table_map_command_fn (vlib_main_t * vm, unformat_input_t * input,
1922                                     vlib_cli_command_t * cmd)
1923 {
1924   hash_pair_t * p;
1925   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
1926
1927   vlib_cli_output (vm, "%=10s%=10s", "VNI", "VRF");
1928   hash_foreach_pair (p, lcm->table_id_by_vni,
1929     {
1930       vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
1931     });
1932   return 0;
1933 }
1934
1935 VLIB_CLI_COMMAND (lisp_show_eid_table_map_command) = {
1936     .path = "show lisp eid-table map",
1937     .short_help = "show lisp eid-table vni to vrf mappings",
1938     .function = lisp_show_eid_table_map_command_fn,
1939 };
1940
1941 static clib_error_t *
1942 lisp_add_del_locator_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
1943                                      vlib_cli_command_t * cmd)
1944 {
1945   lisp_gpe_main_t * lgm = &lisp_gpe_main;
1946   vnet_main_t * vnm = lgm->vnet_main;
1947   unformat_input_t _line_input, * line_input = &_line_input;
1948   u8 is_add = 1;
1949   clib_error_t * error = 0;
1950   u8 * locator_set_name = 0;
1951   locator_t locator, * locators = 0;
1952   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
1953   u32 ls_index = 0;
1954   int rv = 0;
1955
1956   memset(&locator, 0, sizeof(locator));
1957   memset(a, 0, sizeof(a[0]));
1958
1959   /* Get a line of input. */
1960   if (! unformat_user (input, unformat_line_input, line_input))
1961     return 0;
1962
1963   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1964     {
1965       if (unformat (line_input, "add %_%v%_", &locator_set_name))
1966         is_add = 1;
1967       else if (unformat (line_input, "del %_%v%_", &locator_set_name))
1968         is_add = 0;
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   a->name = locator_set_name;
1984   a->locators = locators;
1985   a->is_add = is_add;
1986   a->local = 1;
1987
1988   rv = vnet_lisp_add_del_locator_set(a, &ls_index);
1989   if (0 != rv)
1990     {
1991       error = clib_error_return(0, "failed to %s locator-set!",
1992                                 is_add ? "add" : "delete");
1993     }
1994
1995  done:
1996   vec_free(locators);
1997   if (locator_set_name)
1998     vec_free (locator_set_name);
1999   return error;
2000 }
2001
2002 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_set_command) = {
2003     .path = "lisp locator-set",
2004     .short_help = "lisp locator-set add/del <name> [iface <iface-name> "
2005         "p <priority> w <weight>]",
2006     .function = lisp_add_del_locator_set_command_fn,
2007 };
2008
2009 static clib_error_t *
2010 lisp_add_del_locator_in_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
2011                                      vlib_cli_command_t * cmd)
2012 {
2013   lisp_gpe_main_t * lgm = &lisp_gpe_main;
2014   vnet_main_t * vnm = lgm->vnet_main;
2015   unformat_input_t _line_input, * line_input = &_line_input;
2016   u8 is_add = 1;
2017   clib_error_t * error = 0;
2018   u8 * locator_set_name = 0;
2019   u8 locator_set_name_set = 0;
2020   locator_t locator, * locators = 0;
2021   vnet_lisp_add_del_locator_set_args_t _a, * a = &_a;
2022   u32 ls_index = 0;
2023
2024   memset(&locator, 0, sizeof(locator));
2025   memset(a, 0, sizeof(a[0]));
2026
2027   /* Get a line of input. */
2028   if (! unformat_user (input, unformat_line_input, line_input))
2029     return 0;
2030
2031   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2032     {
2033       if (unformat (line_input, "add"))
2034         is_add = 1;
2035       else if (unformat (line_input, "del"))
2036         is_add = 0;
2037       else if (unformat(line_input, "locator-set %_%v%_", &locator_set_name))
2038         locator_set_name_set = 1;
2039       else if (unformat (line_input, "iface %U p %d w %d",
2040                          unformat_vnet_sw_interface, vnm, &locator.sw_if_index,
2041                          &locator.priority, &locator.weight))
2042         {
2043           locator.local = 1;
2044           vec_add1(locators, locator);
2045         }
2046       else
2047         {
2048           error = unformat_parse_error(line_input);
2049           goto done;
2050         }
2051     }
2052
2053   if (!locator_set_name_set)
2054     {
2055       error = clib_error_return(0, "locator_set name not set!");
2056       goto done;
2057   }
2058
2059   a->name = locator_set_name;
2060   a->locators = locators;
2061   a->is_add = is_add;
2062   a->local = 1;
2063
2064   vnet_lisp_add_del_locator(a, 0, &ls_index);
2065
2066  done:
2067   vec_free(locators);
2068   vec_free (locator_set_name);
2069   return error;
2070 }
2071
2072 VLIB_CLI_COMMAND (lisp_cp_add_del_locator_in_set_command) = {
2073     .path = "lisp locator",
2074     .short_help = "lisp locator add/del locator-set <name> iface <iface-name> "
2075                   "p <priority> w <weight>",
2076     .function = lisp_add_del_locator_in_set_command_fn,
2077 };
2078
2079 static clib_error_t *
2080 lisp_cp_show_locator_sets_command_fn (vlib_main_t * vm,
2081                                       unformat_input_t * input,
2082                                       vlib_cli_command_t * cmd)
2083 {
2084   locator_set_t * lsit;
2085   locator_t * loc;
2086   u32 * locit;
2087   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2088
2089   vlib_cli_output (vm, "%=20s%=16s%=16s%=16s", "Locator-set", "Locator",
2090                    "Priority", "Weight");
2091   pool_foreach (lsit, lcm->locator_set_pool,
2092   ({
2093     u8 * msg = 0;
2094     int next_line = 0;
2095     if (lsit->local)
2096       {
2097         msg = format (msg, "%=16v", lsit->name);
2098       }
2099     else
2100       {
2101         msg = format (msg, "%=16s", "remote");
2102       }
2103     vec_foreach (locit, lsit->locator_indices)
2104       {
2105         if (next_line)
2106           {
2107             msg = format (msg, "%16s", " ");
2108           }
2109         loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
2110         if (loc->local)
2111           msg = format (msg, "%16d%16d%16d\n", loc->sw_if_index, loc->priority,
2112                         loc->weight);
2113         else
2114           msg = format (msg, "%16U%16d%16d\n", format_ip_address,
2115                         &gid_address_ip(&loc->address), loc->priority,
2116                         loc->weight);
2117         next_line = 1;
2118       }
2119     vlib_cli_output (vm, "%v", msg);
2120     vec_free (msg);
2121   }));
2122   return 0;
2123 }
2124
2125 VLIB_CLI_COMMAND (lisp_cp_show_locator_sets_command) = {
2126     .path = "show lisp locator-set",
2127     .short_help = "Shows locator-sets",
2128     .function = lisp_cp_show_locator_sets_command_fn,
2129 };
2130
2131 int
2132 vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
2133 {
2134   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2135   ip_address_t * addr;
2136   u32 i;
2137
2138   if (vnet_lisp_enable_disable_status () == 0)
2139     {
2140       clib_warning ("LISP is disabled!");
2141       return VNET_API_ERROR_LISP_DISABLED;
2142     }
2143
2144   if (a->is_add)
2145     {
2146       vec_foreach(addr, lcm->map_resolvers)
2147         {
2148           if (!ip_address_cmp (addr, &a->address))
2149             {
2150               clib_warning("map-resolver %U already exists!", format_ip_address,
2151                            &a->address);
2152               return -1;
2153             }
2154         }
2155       vec_add1(lcm->map_resolvers, a->address);
2156     }
2157   else
2158     {
2159       for (i = 0; i < vec_len(lcm->map_resolvers); i++)
2160         {
2161           addr = vec_elt_at_index(lcm->map_resolvers, i);
2162           if (!ip_address_cmp (addr, &a->address))
2163             {
2164               vec_delete(lcm->map_resolvers, 1, i);
2165               break;
2166             }
2167         }
2168     }
2169   return 0;
2170 }
2171
2172 static clib_error_t *
2173 lisp_add_del_map_resolver_command_fn (vlib_main_t * vm,
2174                                       unformat_input_t * input,
2175                                       vlib_cli_command_t * cmd)
2176 {
2177   unformat_input_t _line_input, * line_input = &_line_input;
2178   u8 is_add = 1, addr_set = 0;
2179   ip_address_t ip_addr;
2180   clib_error_t * error = 0;
2181   int rv = 0;
2182   vnet_lisp_add_del_map_resolver_args_t _a, * a = &_a;
2183
2184   /* Get a line of input. */
2185   if (! unformat_user (input, unformat_line_input, line_input))
2186     return 0;
2187
2188   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2189     {
2190       if (unformat (line_input, "add"))
2191         is_add = 1;
2192       else if (unformat (line_input, "del"))
2193         is_add = 0;
2194       else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
2195         addr_set = 1;
2196       else
2197         {
2198           error = unformat_parse_error(line_input);
2199           goto done;
2200         }
2201     }
2202
2203   if (!addr_set)
2204     {
2205       error = clib_error_return(0, "Map-resolver address must be set!");
2206       goto done;
2207     }
2208
2209   a->is_add = is_add;
2210   a->address = ip_addr;
2211   rv = vnet_lisp_add_del_map_resolver (a);
2212   if (0 != rv)
2213     {
2214       error = clib_error_return(0, "failed to %s map-resolver!",
2215                                 is_add ? "add" : "delete");
2216     }
2217
2218  done:
2219   return error;
2220 }
2221
2222 VLIB_CLI_COMMAND (lisp_add_del_map_resolver_command) = {
2223     .path = "lisp map-resolver",
2224     .short_help = "lisp map-resolver add/del <ip_address>",
2225     .function = lisp_add_del_map_resolver_command_fn,
2226 };
2227
2228 int
2229 vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
2230 {
2231   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2232   uword * p = 0;
2233
2234   if (vnet_lisp_enable_disable_status () == 0)
2235     {
2236       clib_warning("LISP is disabled!");
2237       return VNET_API_ERROR_LISP_DISABLED;
2238     }
2239
2240   if (a->is_add)
2241     {
2242       p = hash_get_mem(lcm->locator_set_index_by_name, a->locator_set_name);
2243       if (!p)
2244         {
2245           clib_warning("locator-set %v doesn't exist", a->locator_set_name);
2246           return VNET_API_ERROR_INVALID_ARGUMENT;
2247         }
2248
2249       lcm->mreq_itr_rlocs = p[0];
2250     }
2251   else
2252     {
2253       lcm->mreq_itr_rlocs = ~0;
2254     }
2255
2256   return 0;
2257 }
2258
2259 static clib_error_t *
2260 lisp_add_del_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
2261                                         unformat_input_t * input,
2262                                         vlib_cli_command_t * cmd)
2263 {
2264   unformat_input_t _line_input, * line_input = &_line_input;
2265   u8 is_add = 1;
2266   u8 * locator_set_name = 0;
2267   clib_error_t * error = 0;
2268   int rv = 0;
2269   vnet_lisp_add_del_mreq_itr_rloc_args_t _a, * a = &_a;
2270
2271   /* Get a line of input. */
2272   if (! unformat_user (input, unformat_line_input, line_input))
2273     return 0;
2274
2275   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
2276     {
2277       if (unformat (line_input, "del"))
2278         is_add = 0;
2279       else if (unformat (line_input, "add %s", &locator_set_name))
2280         is_add = 1;
2281       else
2282         {
2283           error = unformat_parse_error(line_input);
2284           goto done;
2285         }
2286     }
2287
2288   a->is_add = is_add;
2289   a->locator_set_name = locator_set_name;
2290   rv = vnet_lisp_add_del_mreq_itr_rlocs (a);
2291   if (0 != rv)
2292     {
2293       error = clib_error_return(0, "failed to %s map-request itr-rlocs!",
2294                                 is_add ? "add" : "delete");
2295     }
2296
2297   vec_free(locator_set_name);
2298
2299  done:
2300   return error;
2301
2302 }
2303
2304 VLIB_CLI_COMMAND (lisp_add_del_map_request_command) = {
2305     .path = "lisp map-request itr-rlocs",
2306     .short_help = "lisp map-request itr-rlocs add/del <locator_set_name>",
2307     .function = lisp_add_del_mreq_itr_rlocs_command_fn,
2308 };
2309
2310 static clib_error_t *
2311 lisp_show_mreq_itr_rlocs_command_fn (vlib_main_t * vm,
2312                                     unformat_input_t * input,
2313                                     vlib_cli_command_t * cmd)
2314 {
2315   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2316   locator_set_t * loc_set;
2317
2318   vlib_cli_output (vm, "%=20s", "itr-rlocs");
2319
2320   if (~0 == lcm->mreq_itr_rlocs)
2321     {
2322       return 0;
2323     }
2324
2325   loc_set = pool_elt_at_index (lcm->locator_set_pool, lcm->mreq_itr_rlocs);
2326
2327   vlib_cli_output (vm, "%=20s", loc_set->name);
2328
2329   return 0;
2330 }
2331
2332 VLIB_CLI_COMMAND (lisp_show_map_request_command) = {
2333     .path = "show lisp map-request itr-rlocs",
2334     .short_help = "Shows map-request itr-rlocs",
2335     .function = lisp_show_mreq_itr_rlocs_command_fn,
2336 };
2337
2338 /* Statistics (not really errors) */
2339 #define foreach_lisp_cp_lookup_error           \
2340 _(DROP, "drop")                                \
2341 _(MAP_REQUESTS_SENT, "map-request sent")
2342
2343 static char * lisp_cp_lookup_error_strings[] = {
2344 #define _(sym,string) string,
2345   foreach_lisp_cp_lookup_error
2346 #undef _
2347 };
2348
2349 typedef enum
2350 {
2351 #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
2352     foreach_lisp_cp_lookup_error
2353 #undef _
2354     LISP_CP_LOOKUP_N_ERROR,
2355 } lisp_cp_lookup_error_t;
2356
2357 typedef enum
2358 {
2359   LISP_CP_LOOKUP_NEXT_DROP,
2360   LISP_CP_LOOKUP_NEXT_IP4_LOOKUP,
2361   LISP_CP_LOOKUP_NEXT_IP6_LOOKUP,
2362   LISP_CP_LOOKUP_N_NEXT,
2363 } lisp_cp_lookup_next_t;
2364
2365 typedef struct
2366 {
2367   gid_address_t dst_eid;
2368   ip_address_t map_resolver_ip;
2369 } lisp_cp_lookup_trace_t;
2370
2371 u8 *
2372 format_lisp_cp_lookup_trace (u8 * s, va_list * args)
2373 {
2374   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2375   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2376   lisp_cp_lookup_trace_t * t = va_arg (*args, lisp_cp_lookup_trace_t *);
2377
2378   s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
2379               format_ip_address, &t->map_resolver_ip, format_gid_address,
2380               &t->dst_eid);
2381   return s;
2382 }
2383
2384 int
2385 get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
2386                            ip_address_t * sloc)
2387 {
2388   ip_address_t * mrit;
2389
2390   if (vec_len(lcm->map_resolvers) == 0)
2391     {
2392       clib_warning("No map-resolver configured");
2393       return 0;
2394     }
2395
2396   /* find the first mr ip we have a route to and the ip of the
2397    * iface that has a route to it */
2398   vec_foreach(mrit, lcm->map_resolvers)
2399     {
2400       if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, mrit, sloc)) {
2401           ip_address_copy(mr_ip, mrit);
2402           return 1;
2403       }
2404     }
2405
2406   clib_warning("Can't find map-resolver and local interface ip!");
2407   return 0;
2408 }
2409
2410 static gid_address_t *
2411 build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
2412 {
2413   void * addr;
2414   u32 i;
2415   locator_t * loc;
2416   u32 * loc_indexp;
2417   ip_interface_address_t * ia = 0;
2418   gid_address_t gid_data, * gid = &gid_data;
2419   gid_address_t * rlocs = 0;
2420   ip_prefix_t * ippref = &gid_address_ippref (gid);
2421   ip_address_t * rloc = &ip_prefix_addr (ippref);
2422
2423   memset (gid, 0, sizeof (gid[0]));
2424   gid_address_type (gid) = GID_ADDR_IP_PREFIX;
2425   for (i = 0; i < vec_len(loc_set->locator_indices); i++)
2426     {
2427       loc_indexp = vec_elt_at_index(loc_set->locator_indices, i);
2428       loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
2429
2430       /* Add ipv4 locators first TODO sort them */
2431       foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2432                                     loc->sw_if_index, 1 /* unnumbered */,
2433       ({
2434         addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
2435         ip_address_set (rloc, addr, IP4);
2436         ip_prefix_len (ippref) = 32;
2437         ip_prefix_normalize (ippref);
2438         vec_add1 (rlocs, gid[0]);
2439       }));
2440
2441       /* Add ipv6 locators */
2442       foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2443                                     loc->sw_if_index, 1 /* unnumbered */,
2444       ({
2445         addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
2446         ip_address_set (rloc, addr, IP6);
2447         ip_prefix_len (ippref) = 128;
2448         ip_prefix_normalize (ippref);
2449         vec_add1 (rlocs, gid[0]);
2450       }));
2451     }
2452   return rlocs;
2453 }
2454
2455 static vlib_buffer_t *
2456 build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
2457                                 gid_address_t * seid, gid_address_t * deid,
2458                                 locator_set_t * loc_set, ip_address_t * mr_ip,
2459                                 ip_address_t * sloc, u8 is_smr_invoked,
2460                                 u64 *nonce_res, u32 * bi_res)
2461 {
2462   vlib_buffer_t * b;
2463   u32 bi;
2464   gid_address_t * rlocs = 0;
2465
2466   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2467     {
2468       clib_warning ("Can't allocate buffer for Map-Request!");
2469       return 0;
2470     }
2471
2472   b = vlib_get_buffer (vm, bi);
2473
2474   /* leave some space for the encap headers */
2475   vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2476
2477   /* get rlocs */
2478   rlocs = build_itr_rloc_list (lcm, loc_set);
2479
2480   /* put lisp msg */
2481   lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked, nonce_res);
2482
2483   /* push ecm: udp-ip-lisp */
2484   lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
2485
2486   /* push outer ip header */
2487   pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
2488                        mr_ip);
2489
2490   bi_res[0] = bi;
2491
2492   vec_free(rlocs);
2493   return b;
2494 }
2495
2496 static void
2497 send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
2498                                gid_address_t * seid, gid_address_t * deid,
2499                                u8 is_smr_invoked)
2500 {
2501   u32 next_index, bi = 0, * to_next, map_index;
2502   vlib_buffer_t * b;
2503   vlib_frame_t * f;
2504   u64 nonce = 0;
2505   locator_set_t * loc_set;
2506   mapping_t * map;
2507   pending_map_request_t * pmr;
2508   ip_address_t mr_ip, sloc;
2509   u32 ls_index;
2510
2511   /* get locator-set for seid */
2512   if (!lcm->lisp_pitr)
2513     {
2514       map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
2515       if (map_index == ~0)
2516         {
2517           clib_warning("No local mapping found in eid-table for %U!",
2518                        format_gid_address, seid);
2519           return;
2520         }
2521
2522       map = pool_elt_at_index (lcm->mapping_pool, map_index);
2523
2524       if (!map->local)
2525         {
2526           clib_warning("Mapping found for src eid %U is not marked as local!",
2527                        format_gid_address, seid);
2528           return;
2529         }
2530       ls_index = map->locator_set_index;
2531     }
2532   else
2533     {
2534       map_index = lcm->pitr_map_index;
2535       map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
2536       ls_index = map->locator_set_index;
2537     }
2538
2539   /* overwrite locator set if map-request itr-rlocs configured */
2540   if (~0 != lcm->mreq_itr_rlocs)
2541     {
2542       ls_index = lcm->mreq_itr_rlocs;
2543     }
2544
2545   loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
2546
2547   /* get local iface ip to use in map-request */
2548   if (0 == get_mr_and_local_iface_ip (lcm, &mr_ip, &sloc))
2549     return;
2550
2551   /* build the encapsulated map request */
2552   b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set, &mr_ip,
2553                                       &sloc, is_smr_invoked, &nonce, &bi);
2554
2555   if (!b)
2556     return;
2557
2558   /* set fib index to default and lookup node */
2559   vnet_buffer(b)->sw_if_index[VLIB_TX] = 0;
2560   next_index = (ip_addr_version(&mr_ip) == IP4) ?
2561       ip4_lookup_node.index : ip6_lookup_node.index;
2562
2563   f = vlib_get_frame_to_node (vm, next_index);
2564
2565   /* Enqueue the packet */
2566   to_next = vlib_frame_vector_args (f);
2567   to_next[0] = bi;
2568   f->n_vectors = 1;
2569   vlib_put_frame_to_node (vm, next_index, f);
2570
2571   /* add map-request to pending requests table */
2572   pool_get(lcm->pending_map_requests_pool, pmr);
2573   gid_address_copy (&pmr->src, seid);
2574   gid_address_copy (&pmr->dst, deid);
2575   hash_set(lcm->pending_map_requests_by_nonce, nonce,
2576            pmr - lcm->pending_map_requests_pool);
2577 }
2578
2579 static void
2580 get_src_and_dst (void *hdr, ip_address_t * src, ip_address_t *dst)
2581 {
2582   ip4_header_t * ip4 = hdr;
2583   ip6_header_t * ip6;
2584
2585   if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
2586     {
2587       ip_address_set(src, &ip4->src_address, IP4);
2588       ip_address_set(dst, &ip4->dst_address, IP4);
2589     }
2590   else
2591     {
2592       ip6 = hdr;
2593       ip_address_set(src, &ip6->src_address, IP6);
2594       ip_address_set(dst, &ip6->dst_address, IP6);
2595     }
2596 }
2597
2598 static u32
2599 lisp_get_vni_from_buffer (vlib_buffer_t * b, u8 version)
2600 {
2601   uword * vnip;
2602   u32 vni = ~0, table_id = ~0, fib_index;
2603   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
2604
2605   if (version == IP4)
2606     {
2607       ip4_fib_t * fib;
2608       ip4_main_t * im4 = &ip4_main;
2609       fib_index = vec_elt (im4->fib_index_by_sw_if_index,
2610                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2611       fib = find_ip4_fib_by_table_index_or_id (im4, fib_index,
2612                                                IP4_ROUTE_FLAG_FIB_INDEX);
2613       table_id = fib->table_id;
2614     }
2615   else
2616     {
2617       ip6_fib_t * fib;
2618       ip6_main_t * im6 = &ip6_main;
2619       fib_index = vec_elt (im6->fib_index_by_sw_if_index,
2620                            vnet_buffer (b)->sw_if_index[VLIB_RX]);
2621       fib = find_ip6_fib_by_table_index_or_id (im6, fib_index,
2622                                                IP6_ROUTE_FLAG_FIB_INDEX);
2623       table_id = fib->table_id;
2624     }
2625
2626   vnip = hash_get (lcm->vni_by_table_id, table_id);
2627   if (vnip)
2628     vni = vnip[0];
2629   else
2630     clib_warning ("vrf %d is not mapped to any vni!", table_id);
2631
2632   return vni;
2633 }
2634
2635 static uword
2636 lisp_cp_lookup (vlib_main_t * vm, vlib_node_runtime_t * node,
2637               vlib_frame_t * from_frame)
2638 {
2639   u32 * from, * to_next_drop, di, si;
2640   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main();
2641   u32 pkts_mapped = 0;
2642   uword n_left_from, n_left_to_next_drop;
2643
2644   from = vlib_frame_vector_args (from_frame);
2645   n_left_from = from_frame->n_vectors;
2646
2647   while (n_left_from > 0)
2648     {
2649       vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
2650                            to_next_drop, n_left_to_next_drop);
2651
2652       while (n_left_from > 0 && n_left_to_next_drop > 0)
2653         {
2654           u32 pi0, vni;
2655           vlib_buffer_t * p0;
2656           ip4_header_t * ip0;
2657           gid_address_t src, dst;
2658           ip_prefix_t * spref, * dpref;
2659
2660           gid_address_type (&src) = GID_ADDR_IP_PREFIX;
2661           spref = &gid_address_ippref(&src);
2662           gid_address_type (&dst) = GID_ADDR_IP_PREFIX;
2663           dpref = &gid_address_ippref(&dst);
2664
2665           pi0 = from[0];
2666           from += 1;
2667           n_left_from -= 1;
2668           to_next_drop[0] = pi0;
2669           to_next_drop += 1;
2670           n_left_to_next_drop -= 1;
2671
2672           p0 = vlib_get_buffer (vm, pi0);
2673           p0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
2674
2675           /* src/dst eid pair */
2676           ip0 = vlib_buffer_get_current (p0);
2677           get_src_and_dst (ip0, &ip_prefix_addr(spref), &ip_prefix_addr(dpref));
2678           ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref));
2679           ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref));
2680
2681           vni = lisp_get_vni_from_buffer (p0, ip_prefix_version (spref));
2682           gid_address_vni (&dst) = vni;
2683           gid_address_vni (&src) = vni;
2684
2685           /* if we have remote mapping for destination already in map-chache
2686              add forwarding tunnel directly. If not send a map-request */
2687           di = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
2688           if (~0 != di)
2689             {
2690               mapping_t * m =  vec_elt_at_index (lcm->mapping_pool, di);
2691               /* send a map-request also in case of negative mapping entry
2692                 with corresponding action */
2693               if (m->action == ACTION_SEND_MAP_REQUEST)
2694                 {
2695                   /* send map-request */
2696                   send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2697                   pkts_mapped++;
2698                 }
2699               else
2700                 {
2701                   si =  gid_dictionary_lookup (&lcm->mapping_index_by_gid,
2702                                                &src);
2703                   if (~0 != si)
2704                     {
2705                       dp_add_fwd_entry (lcm, si, di);
2706                     }
2707                 }
2708             }
2709           else
2710             {
2711               /* send map-request */
2712               send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
2713               pkts_mapped++;
2714             }
2715
2716           if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
2717             {
2718               lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, p0,
2719                                                           sizeof(*tr));
2720
2721               memset(tr, 0, sizeof(*tr));
2722               gid_address_copy (&tr->dst_eid, &dst);
2723               if (vec_len(lcm->map_resolvers) > 0)
2724                 {
2725                   clib_memcpy (&tr->map_resolver_ip,
2726                                vec_elt_at_index(lcm->map_resolvers, 0),
2727                                sizeof(ip_address_t));
2728                 }
2729             }
2730           gid_address_free (&dst);
2731           gid_address_free (&src);
2732         }
2733
2734       vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP, n_left_to_next_drop);
2735     }
2736   vlib_node_increment_counter (vm, node->node_index,
2737                                LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
2738                                pkts_mapped);
2739   return from_frame->n_vectors;
2740 }
2741
2742 VLIB_REGISTER_NODE (lisp_cp_lookup_node) = {
2743   .function = lisp_cp_lookup,
2744   .name = "lisp-cp-lookup",
2745   .vector_size = sizeof (u32),
2746   .format_trace = format_lisp_cp_lookup_trace,
2747   .type = VLIB_NODE_TYPE_INTERNAL,
2748
2749   .n_errors = LISP_CP_LOOKUP_N_ERROR,
2750   .error_strings = lisp_cp_lookup_error_strings,
2751
2752   .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
2753
2754   .next_nodes = {
2755       [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
2756       [LISP_CP_LOOKUP_NEXT_IP4_LOOKUP] = "ip4-lookup",
2757       [LISP_CP_LOOKUP_NEXT_IP6_LOOKUP] = "ip6-lookup",
2758   },
2759 };
2760
2761 /* lisp_cp_input statistics */
2762 #define foreach_lisp_cp_input_error                     \
2763 _(DROP, "drop")                                         \
2764 _(MAP_REPLIES_RECEIVED, "map-replies received")
2765
2766 static char * lisp_cp_input_error_strings[] = {
2767 #define _(sym,string) string,
2768   foreach_lisp_cp_input_error
2769 #undef _
2770 };
2771
2772 typedef enum
2773 {
2774 #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
2775     foreach_lisp_cp_input_error
2776 #undef _
2777     LISP_CP_INPUT_N_ERROR,
2778 } lisp_cp_input_error_t;
2779
2780 typedef enum
2781 {
2782   LISP_CP_INPUT_NEXT_DROP,
2783   LISP_CP_INPUT_N_NEXT,
2784 } lisp_cp_input_next_t;
2785
2786 typedef struct
2787 {
2788   gid_address_t dst_eid;
2789   ip4_address_t map_resolver_ip;
2790 } lisp_cp_input_trace_t;
2791
2792 u8 *
2793 format_lisp_cp_input_trace (u8 * s, va_list * args)
2794 {
2795   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2796   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2797   CLIB_UNUSED(lisp_cp_input_trace_t * t) = va_arg (*args, lisp_cp_input_trace_t *);
2798
2799   s = format (s, "LISP-CP-INPUT: TODO");
2800   return s;
2801 }
2802
2803 void
2804 process_map_reply (lisp_cp_main_t * lcm, vlib_buffer_t * b)
2805 {
2806   u32 len = 0, i, ttl, dst_map_index = 0;
2807   void * h;
2808   pending_map_request_t * pmr;
2809   locator_t probed;
2810   map_reply_hdr_t * mrep_hdr;
2811   u64 nonce;
2812   gid_address_t deid;
2813   uword * pmr_index;
2814   u8 authoritative, action;
2815   locator_t * locators = 0, * loc;
2816
2817   mrep_hdr = vlib_buffer_get_current (b);
2818
2819   /* Check pending requests table and nonce */
2820   nonce = MREP_NONCE(mrep_hdr);
2821   pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce);
2822   if (!pmr_index)
2823     {
2824       clib_warning("No pending map-request entry with nonce %lu!", nonce);
2825       return;
2826     }
2827   pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]);
2828
2829   vlib_buffer_pull (b, sizeof(*mrep_hdr));
2830
2831   for (i = 0; i < MREP_REC_COUNT(mrep_hdr); i++)
2832     {
2833
2834       h = vlib_buffer_get_current (b);
2835       ttl = clib_net_to_host_u32 (MAP_REC_TTL(h));
2836       action = MAP_REC_ACTION(h);
2837       authoritative = MAP_REC_AUTH(h);
2838
2839       len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
2840       if (len == ~0)
2841         {
2842           clib_warning ("Failed to parse mapping record!");
2843           vec_foreach (loc, locators)
2844             {
2845               locator_free (loc);
2846             }
2847           vec_free(locators);
2848           return;
2849         }
2850
2851       /* insert/update mappings cache */
2852       vnet_lisp_add_del_mapping (&deid, locators, action, authoritative, ttl, 1,
2853                                  &dst_map_index);
2854
2855       /* try to program forwarding only if mapping saved or updated*/
2856       if ((u32) ~0 != dst_map_index)
2857         lisp_add_del_adjacency (lcm, &pmr->src, &deid, 1);
2858
2859       vec_free(locators);
2860     }
2861
2862   /* remove pending map request entry */
2863   hash_unset(lcm->pending_map_requests_by_nonce, nonce);
2864   pool_put(lcm->pending_map_requests_pool, pmr);
2865 }
2866
2867 void
2868 process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
2869 {
2870   map_request_hdr_t * mreq_hdr;
2871   gid_address_t src, dst;
2872 //  u64 nonce;
2873   u32 i, len = 0;
2874   gid_address_t * itr_rlocs = 0, * rloc;
2875
2876   mreq_hdr = vlib_buffer_get_current (b);
2877   vlib_buffer_pull (b, sizeof(*mreq_hdr));
2878
2879 //  nonce = MREQ_NONCE(mreq_hdr);
2880
2881   if (!MREQ_SMR(mreq_hdr)) {
2882       clib_warning("Only SMR Map-Requests supported for now!");
2883       return;
2884   }
2885
2886   /* parse src eid */
2887   len = lisp_msg_parse_addr (b, &src);
2888   if (len == ~0)
2889     return;
2890
2891   /* for now we don't do anything with the itr's rlocs */
2892   len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs, MREQ_ITR_RLOC_COUNT(mreq_hdr) + 1);
2893   if (len == ~0)
2894     return;
2895
2896   /* TODO: RLOCs are currently unused, so free them for now */
2897   vec_foreach (rloc, itr_rlocs)
2898     {
2899       gid_address_free (rloc);
2900     }
2901
2902   /* parse eid records and send SMR-invoked map-requests */
2903   for (i = 0; i < MREQ_REC_COUNT(mreq_hdr); i++)
2904     {
2905       memset(&dst, 0, sizeof(dst));
2906       len = lisp_msg_parse_eid_rec (b, &dst);
2907       if (len == ~0)
2908         {
2909           clib_warning("Can't parse map-request EID-record");
2910           return;
2911         }
2912       /* send SMR-invoked map-requests */
2913       send_encapsulated_map_request (vm, lcm, &dst, &src, /* invoked */ 1);
2914     }
2915 }
2916
2917 static uword
2918 lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
2919                vlib_frame_t * from_frame)
2920 {
2921   u32 n_left_from, * from, * to_next_drop;
2922   lisp_msg_type_e type;
2923   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2924
2925   from = vlib_frame_vector_args (from_frame);
2926   n_left_from = from_frame->n_vectors;
2927
2928
2929   while (n_left_from > 0)
2930     {
2931       u32 n_left_to_next_drop;
2932
2933       vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
2934                            to_next_drop, n_left_to_next_drop);
2935       while (n_left_from > 0 && n_left_to_next_drop > 0)
2936         {
2937           u32 bi0;
2938           vlib_buffer_t * b0;
2939
2940           bi0 = from[0];
2941           from += 1;
2942           n_left_from -= 1;
2943           to_next_drop[0] = bi0;
2944           to_next_drop += 1;
2945           n_left_to_next_drop -= 1;
2946
2947           b0 = vlib_get_buffer (vm, bi0);
2948
2949           type = lisp_msg_type(vlib_buffer_get_current (b0));
2950           switch (type)
2951             {
2952             case LISP_MAP_REPLY:
2953               process_map_reply (lcm, b0);
2954               break;
2955             case LISP_MAP_REQUEST:
2956               process_map_request(vm, lcm, b0);
2957               break;
2958             default:
2959               clib_warning("Unsupported LISP message type %d", type);
2960               break;
2961             }
2962
2963           b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
2964
2965           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
2966             {
2967
2968             }
2969         }
2970
2971       vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP, n_left_to_next_drop);
2972     }
2973   return from_frame->n_vectors;
2974 }
2975
2976 VLIB_REGISTER_NODE (lisp_cp_input_node) = {
2977   .function = lisp_cp_input,
2978   .name = "lisp-cp-input",
2979   .vector_size = sizeof (u32),
2980   .format_trace = format_lisp_cp_input_trace,
2981   .type = VLIB_NODE_TYPE_INTERNAL,
2982
2983   .n_errors = LISP_CP_INPUT_N_ERROR,
2984   .error_strings = lisp_cp_input_error_strings,
2985
2986   .n_next_nodes = LISP_CP_INPUT_N_NEXT,
2987
2988   .next_nodes = {
2989       [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
2990   },
2991 };
2992
2993 clib_error_t *
2994 lisp_cp_init (vlib_main_t *vm)
2995 {
2996   lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
2997   clib_error_t * error = 0;
2998
2999   if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
3000     return error;
3001
3002   lcm->im4 = &ip4_main;
3003   lcm->im6 = &ip6_main;
3004   lcm->vlib_main = vm;
3005   lcm->vnet_main = vnet_get_main();
3006   lcm->mreq_itr_rlocs = ~0;
3007   lcm->lisp_pitr = 0;
3008
3009   gid_dictionary_init (&lcm->mapping_index_by_gid);
3010
3011   /* default vrf mapped to vni 0 */
3012   hash_set(lcm->table_id_by_vni, 0, 0);
3013   hash_set(lcm->vni_by_table_id, 0, 0);
3014
3015   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
3016                          lisp_cp_input_node.index, 1 /* is_ip4 */);
3017   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
3018                          lisp_cp_input_node.index, 0 /* is_ip4 */);
3019
3020   return 0;
3021 }
3022
3023 VLIB_INIT_FUNCTION(lisp_cp_init);