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