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