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