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