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