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