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