blob: 59a45ed8910f72b0aceda35168cbf8adee1118ff [file] [log] [blame]
Florin Corase127a7e2016-02-18 22:20:01 +01001/*
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
Filip Tehlara5abdeb2016-07-18 17:35:40 +020016#include <vlibmemory/api.h>
Florin Corase127a7e2016-02-18 22:20:01 +010017#include <vnet/lisp-cp/control.h>
18#include <vnet/lisp-cp/packets.h>
19#include <vnet/lisp-cp/lisp_msg_serdes.h>
Neale Ranns5e575b12016-10-03 09:40:25 +010020#include <vnet/lisp-gpe/lisp_gpe_fwd_entry.h>
21#include <vnet/lisp-gpe/lisp_gpe_tenant.h>
Filip Tehlar4868ff62017-03-09 16:48:39 +010022#include <vnet/lisp-gpe/lisp_gpe_tunnel.h>
Neale Ranns0bfe5d82016-08-25 15:29:12 +010023#include <vnet/fib/fib_entry.h>
24#include <vnet/fib/fib_table.h>
Filip Tehlard5a65db2017-05-17 17:21:10 +020025#include <vnet/ethernet/arp_packet.h>
26#include <vnet/ethernet/packet.h>
Florin Corase127a7e2016-02-18 22:20:01 +010027
Filip Tehlar397fd7d2016-10-26 14:31:24 +020028#include <openssl/evp.h>
29#include <openssl/hmac.h>
30
Filip Tehlaref2a5bf2017-05-30 07:14:46 +020031#define MAX_VALUE_U24 0xffffff
32
Florin Corasf3dc11a2017-01-24 03:13:43 -080033lisp_cp_main_t lisp_control_main;
34
Filip Tehlarcda70662017-01-16 10:30:03 +010035u8 *format_lisp_cp_input_trace (u8 * s, va_list * args);
36
37typedef enum
38{
39 LISP_CP_INPUT_NEXT_DROP,
40 LISP_CP_INPUT_N_NEXT,
41} lisp_cp_input_next_t;
42
Filip Tehlara5abdeb2016-07-18 17:35:40 +020043typedef struct
44{
45 u8 is_resend;
46 gid_address_t seid;
47 gid_address_t deid;
48 u8 smr_invoked;
49} map_request_args_t;
50
Florin Corasdca88042016-09-14 16:01:38 +020051u8
52vnet_lisp_get_map_request_mode (void)
53{
54 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
55 return lcm->map_request_mode;
56}
57
Filip Tehlar397fd7d2016-10-26 14:31:24 +020058static u16
59auth_data_len_by_key_id (lisp_key_type_t key_id)
60{
61 switch (key_id)
62 {
63 case HMAC_SHA_1_96:
64 return SHA1_AUTH_DATA_LEN;
65 case HMAC_SHA_256_128:
66 return SHA256_AUTH_DATA_LEN;
67 default:
68 clib_warning ("unsupported key type: %d!", key_id);
69 return (u16) ~ 0;
70 }
71 return (u16) ~ 0;
72}
73
74static const EVP_MD *
75get_encrypt_fcn (lisp_key_type_t key_id)
76{
77 switch (key_id)
78 {
79 case HMAC_SHA_1_96:
80 return EVP_sha1 ();
81 case HMAC_SHA_256_128:
82 return EVP_sha256 ();
83 default:
84 clib_warning ("unsupported encryption key type: %d!", key_id);
85 break;
86 }
87 return 0;
88}
89
Filip Tehlara5abdeb2016-07-18 17:35:40 +020090static int
91queue_map_request (gid_address_t * seid, gid_address_t * deid,
Florin Corasa2157cf2016-08-16 21:09:14 +020092 u8 smr_invoked, u8 is_resend);
Filip Tehlara5abdeb2016-07-18 17:35:40 +020093
Florin Corasf727db92016-06-23 15:01:58 +020094ip_interface_address_t *
Florin Corasa2157cf2016-08-16 21:09:14 +020095ip_interface_get_first_interface_address (ip_lookup_main_t * lm,
96 u32 sw_if_index, u8 loop)
Florin Corasf727db92016-06-23 15:01:58 +020097{
98 vnet_main_t *vnm = vnet_get_main ();
Florin Corasa2157cf2016-08-16 21:09:14 +020099 vnet_sw_interface_t *swif = vnet_get_sw_interface (vnm, sw_if_index);
Florin Corasf727db92016-06-23 15:01:58 +0200100 if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
101 sw_if_index = swif->unnumbered_sw_if_index;
102 u32 ia =
Florin Corasa2157cf2016-08-16 21:09:14 +0200103 (vec_len ((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
104 vec_elt ((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
105 (u32) ~ 0;
106 return pool_elt_at_index ((lm)->if_address_pool, ia);
Florin Corasf727db92016-06-23 15:01:58 +0200107}
Filip Tehlar215104e2016-05-10 16:58:29 +0200108
Florin Corasf727db92016-06-23 15:01:58 +0200109void *
110ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
Florin Corasa2157cf2016-08-16 21:09:14 +0200111 u8 version)
Florin Corasf727db92016-06-23 15:01:58 +0200112{
Florin Corasa2157cf2016-08-16 21:09:14 +0200113 ip_interface_address_t *ia;
Filip Tehlar195bcee2016-05-13 17:37:35 +0200114
Florin Corasf727db92016-06-23 15:01:58 +0200115 ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
116 if (!ia)
117 return 0;
118 return ip_interface_address_get_address (lm, ia);
119}
Filip Tehlar195bcee2016-05-13 17:37:35 +0200120
Florin Corase127a7e2016-02-18 22:20:01 +0100121int
Florin Corasf727db92016-06-23 15:01:58 +0200122ip_interface_get_first_ip_address (lisp_cp_main_t * lcm, u32 sw_if_index,
Florin Corasa2157cf2016-08-16 21:09:14 +0200123 u8 version, ip_address_t * result)
Florin Corasf727db92016-06-23 15:01:58 +0200124{
Florin Corasa2157cf2016-08-16 21:09:14 +0200125 ip_lookup_main_t *lm;
126 void *addr;
Florin Corasf727db92016-06-23 15:01:58 +0200127
128 lm = (version == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
129 addr = ip_interface_get_first_address (lm, sw_if_index, version);
130 if (!addr)
131 return 0;
132
133 ip_address_set (result, addr, version);
134 return 1;
135}
136
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100137/**
138 * convert from a LISP address to a FIB prefix
139 */
140void
141ip_address_to_fib_prefix (const ip_address_t * addr, fib_prefix_t * prefix)
Florin Corasf727db92016-06-23 15:01:58 +0200142{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100143 if (addr->version == IP4)
144 {
145 prefix->fp_len = 32;
146 prefix->fp_proto = FIB_PROTOCOL_IP4;
147 memset (&prefix->fp_addr.pad, 0, sizeof (prefix->fp_addr.pad));
148 memcpy (&prefix->fp_addr.ip4, &addr->ip, sizeof (prefix->fp_addr.ip4));
149 }
Florin Corasf727db92016-06-23 15:01:58 +0200150 else
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100151 {
152 prefix->fp_len = 128;
153 prefix->fp_proto = FIB_PROTOCOL_IP6;
154 memcpy (&prefix->fp_addr.ip6, &addr->ip, sizeof (prefix->fp_addr.ip6));
155 }
Florin Corasf727db92016-06-23 15:01:58 +0200156}
157
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100158/**
159 * convert from a LISP to a FIB prefix
160 */
161void
162ip_prefix_to_fib_prefix (const ip_prefix_t * ip_prefix,
163 fib_prefix_t * fib_prefix)
Florin Corasf727db92016-06-23 15:01:58 +0200164{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100165 ip_address_to_fib_prefix (&ip_prefix->addr, fib_prefix);
166 fib_prefix->fp_len = ip_prefix->len;
Florin Corasf727db92016-06-23 15:01:58 +0200167}
168
169/**
170 * Find the sw_if_index of the interface that would be used to egress towards
171 * dst.
172 */
173u32
174ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
175{
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100176 fib_node_index_t fei;
177 fib_prefix_t prefix;
Florin Corasf727db92016-06-23 15:01:58 +0200178
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100179 ip_address_to_fib_prefix (dst, &prefix);
Florin Corasf727db92016-06-23 15:01:58 +0200180
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100181 fei = fib_table_lookup (0, &prefix);
182
183 return (fib_entry_get_resolving_interface (fei));
Florin Corasf727db92016-06-23 15:01:58 +0200184}
185
186/**
187 * Find first IP of the interface that would be used to egress towards dst.
188 * Returns 1 if the address is found 0 otherwise.
189 */
190int
191ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
Florin Corasa2157cf2016-08-16 21:09:14 +0200192 ip_address_t * result)
Florin Corasf727db92016-06-23 15:01:58 +0200193{
194 u32 si;
Florin Corasa2157cf2016-08-16 21:09:14 +0200195 ip_lookup_main_t *lm;
196 void *addr = 0;
Florin Corasf727db92016-06-23 15:01:58 +0200197 u8 ipver;
198
Florin Corasa2157cf2016-08-16 21:09:14 +0200199 ASSERT (result != 0);
Florin Corasf727db92016-06-23 15:01:58 +0200200
Florin Corasa2157cf2016-08-16 21:09:14 +0200201 ipver = ip_addr_version (dst);
Florin Corasf727db92016-06-23 15:01:58 +0200202
203 lm = (ipver == IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
Neale Ranns0bfe5d82016-08-25 15:29:12 +0100204 si = ip_fib_get_egress_iface_for_dst (lcm, dst);
Florin Corasf727db92016-06-23 15:01:58 +0200205
Florin Corasa2157cf2016-08-16 21:09:14 +0200206 if ((u32) ~ 0 == si)
Florin Corasf727db92016-06-23 15:01:58 +0200207 return 0;
208
209 /* find the first ip address */
210 addr = ip_interface_get_first_address (lm, si, ipver);
211 if (0 == addr)
212 return 0;
213
214 ip_address_set (result, addr, ipver);
215 return 1;
216}
217
218static int
Florin Coras1a1adc72016-07-22 01:45:30 +0200219dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_l2, u8 is_add)
Florin Corasf727db92016-06-23 15:01:58 +0200220{
Neale Ranns5e575b12016-10-03 09:40:25 +0100221 uword *dp_table;
Florin Corasf727db92016-06-23 15:01:58 +0200222
Florin Coras1a1adc72016-07-22 01:45:30 +0200223 if (!is_l2)
Florin Corasf727db92016-06-23 15:01:58 +0200224 {
Florin Corasa2157cf2016-08-16 21:09:14 +0200225 dp_table = hash_get (lcm->table_id_by_vni, vni);
Florin Coras1a1adc72016-07-22 01:45:30 +0200226
227 if (!dp_table)
Florin Corasa2157cf2016-08-16 21:09:14 +0200228 {
229 clib_warning ("vni %d not associated to a vrf!", vni);
230 return VNET_API_ERROR_INVALID_VALUE;
231 }
Florin Coras1a1adc72016-07-22 01:45:30 +0200232 }
233 else
234 {
Florin Corasa2157cf2016-08-16 21:09:14 +0200235 dp_table = hash_get (lcm->bd_id_by_vni, vni);
Florin Coras1a1adc72016-07-22 01:45:30 +0200236 if (!dp_table)
Florin Corasa2157cf2016-08-16 21:09:14 +0200237 {
238 clib_warning ("vni %d not associated to a bridge domain!", vni);
239 return VNET_API_ERROR_INVALID_VALUE;
240 }
Florin Corasf727db92016-06-23 15:01:58 +0200241 }
242
Florin Corasf727db92016-06-23 15:01:58 +0200243 /* enable/disable data-plane interface */
244 if (is_add)
245 {
Neale Ranns5e575b12016-10-03 09:40:25 +0100246 if (is_l2)
247 lisp_gpe_tenant_l2_iface_add_or_lock (vni, dp_table[0]);
248 else
249 lisp_gpe_tenant_l3_iface_add_or_lock (vni, dp_table[0]);
Florin Corasf727db92016-06-23 15:01:58 +0200250 }
251 else
252 {
Neale Ranns5e575b12016-10-03 09:40:25 +0100253 if (is_l2)
254 lisp_gpe_tenant_l2_iface_unlock (vni);
255 else
256 lisp_gpe_tenant_l3_iface_unlock (vni);
Florin Corasf727db92016-06-23 15:01:58 +0200257 }
258
259 return 0;
260}
261
262static void
263dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
264{
Florin Corasa2157cf2016-08-16 21:09:14 +0200265 vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
266 fwd_entry_t *fe = 0;
267 uword *feip = 0;
268 memset (a, 0, sizeof (*a));
Florin Corasf727db92016-06-23 15:01:58 +0200269
Florin Corasa2157cf2016-08-16 21:09:14 +0200270 feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
Florin Corasf727db92016-06-23 15:01:58 +0200271 if (!feip)
272 return;
273
Florin Corasa2157cf2016-08-16 21:09:14 +0200274 fe = pool_elt_at_index (lcm->fwd_entry_pool, feip[0]);
Florin Corasf727db92016-06-23 15:01:58 +0200275
276 /* delete dp fwd entry */
277 u32 sw_if_index;
278 a->is_add = 0;
Florin Corasbb5c22f2016-08-02 02:31:03 +0200279 a->locator_pairs = fe->locator_pairs;
Filip Tehlar2fdaece2016-09-28 14:27:59 +0200280 a->vni = gid_address_vni (&fe->reid);
281 gid_address_copy (&a->rmt_eid, &fe->reid);
Filip Tehlard5fcc462016-10-17 16:20:18 +0200282 if (fe->is_src_dst)
283 gid_address_copy (&a->lcl_eid, &fe->leid);
Florin Corasf727db92016-06-23 15:01:58 +0200284
Filip Tehlar21511912017-04-07 10:41:42 +0200285 vnet_lisp_gpe_del_fwd_counters (a, feip[0]);
Florin Corasf727db92016-06-23 15:01:58 +0200286 vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
287
288 /* delete entry in fwd table */
Florin Corasa2157cf2016-08-16 21:09:14 +0200289 hash_unset (lcm->fwd_entry_by_mapping_index, dst_map_index);
290 vec_free (fe->locator_pairs);
291 pool_put (lcm->fwd_entry_pool, fe);
Florin Corasf727db92016-06-23 15:01:58 +0200292}
293
294/**
295 * Finds first remote locator with best (lowest) priority that has a local
296 * peer locator with an underlying route to it.
297 *
298 */
299static u32
Florin Corasa2157cf2016-08-16 21:09:14 +0200300get_locator_pairs (lisp_cp_main_t * lcm, mapping_t * lcl_map,
301 mapping_t * rmt_map, locator_pair_t ** locator_pairs)
Florin Corasf727db92016-06-23 15:01:58 +0200302{
Florin Coras3590ac52016-08-08 16:04:26 +0200303 u32 i, limitp = 0, li, found = 0, esi;
Florin Corasa2157cf2016-08-16 21:09:14 +0200304 locator_set_t *rmt_ls, *lcl_ls;
305 ip_address_t _lcl_addr, *lcl_addr = &_lcl_addr;
306 locator_t *lp, *rmt = 0;
307 uword *checked = 0;
Florin Corasbb5c22f2016-08-02 02:31:03 +0200308 locator_pair_t pair;
Florin Corasf727db92016-06-23 15:01:58 +0200309
Florin Corasa2157cf2016-08-16 21:09:14 +0200310 rmt_ls =
311 pool_elt_at_index (lcm->locator_set_pool, rmt_map->locator_set_index);
312 lcl_ls =
313 pool_elt_at_index (lcm->locator_set_pool, lcl_map->locator_set_index);
Florin Corasf727db92016-06-23 15:01:58 +0200314
Florin Corasa2157cf2016-08-16 21:09:14 +0200315 if (!rmt_ls || vec_len (rmt_ls->locator_indices) == 0)
Florin Corasf727db92016-06-23 15:01:58 +0200316 return 0;
317
Florin Coras3590ac52016-08-08 16:04:26 +0200318 while (1)
Florin Corasf727db92016-06-23 15:01:58 +0200319 {
320 rmt = 0;
321
322 /* find unvisited remote locator with best priority */
Florin Corasa2157cf2016-08-16 21:09:14 +0200323 for (i = 0; i < vec_len (rmt_ls->locator_indices); i++)
324 {
325 if (0 != hash_get (checked, i))
326 continue;
Florin Corasf727db92016-06-23 15:01:58 +0200327
Florin Corasa2157cf2016-08-16 21:09:14 +0200328 li = vec_elt (rmt_ls->locator_indices, i);
329 lp = pool_elt_at_index (lcm->locator_pool, li);
Florin Corasf727db92016-06-23 15:01:58 +0200330
Florin Corasa2157cf2016-08-16 21:09:14 +0200331 /* we don't support non-IP locators for now */
332 if (gid_address_type (&lp->address) != GID_ADDR_IP_PREFIX)
333 continue;
Florin Corasf727db92016-06-23 15:01:58 +0200334
Florin Corasa2157cf2016-08-16 21:09:14 +0200335 if ((found && lp->priority == limitp)
336 || (!found && lp->priority >= limitp))
337 {
338 rmt = lp;
Florin Coras3590ac52016-08-08 16:04:26 +0200339
Florin Corasa2157cf2016-08-16 21:09:14 +0200340 /* don't search for locators with lower priority and don't
341 * check this locator again*/
342 limitp = lp->priority;
343 hash_set (checked, i, 1);
344 break;
345 }
346 }
Florin Corasf727db92016-06-23 15:01:58 +0200347 /* check if a local locator with a route to remote locator exists */
348 if (rmt != 0)
Florin Corasa2157cf2016-08-16 21:09:14 +0200349 {
350 /* find egress sw_if_index for rmt locator */
351 esi =
352 ip_fib_get_egress_iface_for_dst (lcm,
353 &gid_address_ip (&rmt->address));
354 if ((u32) ~ 0 == esi)
355 continue;
Florin Corasf727db92016-06-23 15:01:58 +0200356
Florin Corasa2157cf2016-08-16 21:09:14 +0200357 for (i = 0; i < vec_len (lcl_ls->locator_indices); i++)
358 {
359 li = vec_elt (lcl_ls->locator_indices, i);
360 locator_t *sl = pool_elt_at_index (lcm->locator_pool, li);
Florin Corasf727db92016-06-23 15:01:58 +0200361
Florin Corasa2157cf2016-08-16 21:09:14 +0200362 /* found local locator with the needed sw_if_index */
363 if (sl->sw_if_index == esi)
364 {
365 /* and it has an address */
366 if (0 == ip_interface_get_first_ip_address (lcm,
367 sl->sw_if_index,
368 gid_address_ip_version
369 (&rmt->address),
370 lcl_addr))
371 continue;
Florin Corasf727db92016-06-23 15:01:58 +0200372
Florin Corasa2157cf2016-08-16 21:09:14 +0200373 memset (&pair, 0, sizeof (pair));
374 ip_address_copy (&pair.rmt_loc,
375 &gid_address_ip (&rmt->address));
376 ip_address_copy (&pair.lcl_loc, lcl_addr);
377 pair.weight = rmt->weight;
Filip Tehlarfb9931f2016-12-09 13:52:38 +0100378 pair.priority = rmt->priority;
Florin Corasa2157cf2016-08-16 21:09:14 +0200379 vec_add1 (locator_pairs[0], pair);
380 found = 1;
381 }
382 }
383 }
Florin Corasf727db92016-06-23 15:01:58 +0200384 else
Florin Corasa2157cf2016-08-16 21:09:14 +0200385 break;
Florin Corasf727db92016-06-23 15:01:58 +0200386 }
Florin Coras3590ac52016-08-08 16:04:26 +0200387
Florin Corasa2157cf2016-08-16 21:09:14 +0200388 hash_free (checked);
Florin Coras3590ac52016-08-08 16:04:26 +0200389 return found;
Florin Corasf727db92016-06-23 15:01:58 +0200390}
391
392static void
Florin Corasdca88042016-09-14 16:01:38 +0200393gid_address_sd_to_flat (gid_address_t * dst, gid_address_t * src,
394 fid_address_t * fid)
395{
396 ASSERT (GID_ADDR_SRC_DST == gid_address_type (src));
397
398 dst[0] = src[0];
399
400 switch (fid_addr_type (fid))
401 {
402 case FID_ADDR_IP_PREF:
403 gid_address_type (dst) = GID_ADDR_IP_PREFIX;
404 gid_address_ippref (dst) = fid_addr_ippref (fid);
405 break;
406 case FID_ADDR_MAC:
407 gid_address_type (dst) = GID_ADDR_MAC;
408 mac_copy (gid_address_mac (dst), fid_addr_mac (fid));
409 break;
410 default:
411 clib_warning ("Unsupported fid type %d!", fid_addr_type (fid));
412 break;
413 }
414}
415
Filip Tehlar397fd7d2016-10-26 14:31:24 +0200416u8
417vnet_lisp_map_register_state_get (void)
418{
419 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
420 return lcm->map_registering;
421}
422
423u8
424vnet_lisp_rloc_probe_state_get (void)
425{
426 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
427 return lcm->rloc_probing;
428}
429
Florin Corasdca88042016-09-14 16:01:38 +0200430static void
Florin Corasa2157cf2016-08-16 21:09:14 +0200431dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
Florin Corasf727db92016-06-23 15:01:58 +0200432{
Florin Corasa2157cf2016-08-16 21:09:14 +0200433 vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
Florin Corasba888e42017-01-24 11:38:18 -0800434 gid_address_t *rmt_eid, *lcl_eid;
435 mapping_t *lcl_map, *rmt_map;
Florin Corasf727db92016-06-23 15:01:58 +0200436 u32 sw_if_index;
Florin Corasa2157cf2016-08-16 21:09:14 +0200437 uword *feip = 0, *dpid;
438 fwd_entry_t *fe;
Filip Tehlar69a9b762016-09-23 10:00:52 +0200439 u8 type, is_src_dst = 0;
Florin Corasba888e42017-01-24 11:38:18 -0800440 int rv;
Florin Corasf727db92016-06-23 15:01:58 +0200441
Florin Corasa2157cf2016-08-16 21:09:14 +0200442 memset (a, 0, sizeof (*a));
Florin Corasf727db92016-06-23 15:01:58 +0200443
444 /* remove entry if it already exists */
445 feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
446 if (feip)
447 dp_del_fwd_entry (lcm, src_map_index, dst_map_index);
448
Florin Corasba888e42017-01-24 11:38:18 -0800449 /*
450 * Determine local mapping and eid
451 */
Filip Tehlarf3e3fd32016-09-30 12:47:59 +0200452 if (lcm->lisp_pitr)
Florin Corasba888e42017-01-24 11:38:18 -0800453 lcl_map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
Filip Tehlarf3e3fd32016-09-30 12:47:59 +0200454 else
Florin Corasba888e42017-01-24 11:38:18 -0800455 lcl_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
456 lcl_eid = &lcl_map->eid;
Florin Corasf727db92016-06-23 15:01:58 +0200457
Florin Corasba888e42017-01-24 11:38:18 -0800458 /*
459 * Determine remote mapping and eid
460 */
461 rmt_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
462 rmt_eid = &rmt_map->eid;
463
464 /*
465 * Build and insert data plane forwarding entry
466 */
Florin Corasf727db92016-06-23 15:01:58 +0200467 a->is_add = 1;
468
Filip Tehlard5fcc462016-10-17 16:20:18 +0200469 if (MR_MODE_SRC_DST == lcm->map_request_mode)
Florin Corasdca88042016-09-14 16:01:38 +0200470 {
Florin Corasba888e42017-01-24 11:38:18 -0800471 if (GID_ADDR_SRC_DST == gid_address_type (rmt_eid))
Filip Tehlard5fcc462016-10-17 16:20:18 +0200472 {
Florin Corasba888e42017-01-24 11:38:18 -0800473 gid_address_sd_to_flat (&a->rmt_eid, rmt_eid,
474 &gid_address_sd_dst (rmt_eid));
475 gid_address_sd_to_flat (&a->lcl_eid, rmt_eid,
476 &gid_address_sd_src (rmt_eid));
Filip Tehlard5fcc462016-10-17 16:20:18 +0200477 }
478 else
479 {
Florin Corasba888e42017-01-24 11:38:18 -0800480 gid_address_copy (&a->rmt_eid, rmt_eid);
481 gid_address_copy (&a->lcl_eid, lcl_eid);
Filip Tehlard5fcc462016-10-17 16:20:18 +0200482 }
Filip Tehlar69a9b762016-09-23 10:00:52 +0200483 is_src_dst = 1;
Florin Corasdca88042016-09-14 16:01:38 +0200484 }
485 else
Florin Corasba888e42017-01-24 11:38:18 -0800486 gid_address_copy (&a->rmt_eid, rmt_eid);
Florin Corasdca88042016-09-14 16:01:38 +0200487
Florin Corasa2157cf2016-08-16 21:09:14 +0200488 a->vni = gid_address_vni (&a->rmt_eid);
Filip Tehlared6b52b2017-03-22 09:02:33 +0100489 a->is_src_dst = is_src_dst;
Florin Coras1a1adc72016-07-22 01:45:30 +0200490
491 /* get vrf or bd_index associated to vni */
Florin Corasdca88042016-09-14 16:01:38 +0200492 type = gid_address_type (&a->rmt_eid);
Florin Coras1a1adc72016-07-22 01:45:30 +0200493 if (GID_ADDR_IP_PREFIX == type)
494 {
Florin Corasa2157cf2016-08-16 21:09:14 +0200495 dpid = hash_get (lcm->table_id_by_vni, a->vni);
Florin Coras1a1adc72016-07-22 01:45:30 +0200496 if (!dpid)
Florin Corasa2157cf2016-08-16 21:09:14 +0200497 {
498 clib_warning ("vni %d not associated to a vrf!", a->vni);
499 return;
500 }
Florin Coras1a1adc72016-07-22 01:45:30 +0200501 a->table_id = dpid[0];
502 }
503 else if (GID_ADDR_MAC == type)
504 {
Florin Corasa2157cf2016-08-16 21:09:14 +0200505 dpid = hash_get (lcm->bd_id_by_vni, a->vni);
Florin Coras1a1adc72016-07-22 01:45:30 +0200506 if (!dpid)
Florin Corasa2157cf2016-08-16 21:09:14 +0200507 {
508 clib_warning ("vni %d not associated to a bridge domain !", a->vni);
509 return;
510 }
Florin Coras1a1adc72016-07-22 01:45:30 +0200511 a->bd_id = dpid[0];
512 }
513
Florin Corasf727db92016-06-23 15:01:58 +0200514 /* find best locator pair that 1) verifies LISP policy 2) are connected */
Florin Corasba888e42017-01-24 11:38:18 -0800515 rv = get_locator_pairs (lcm, lcl_map, rmt_map, &a->locator_pairs);
516
517 /* Either rmt mapping is negative or we can't find underlay path.
518 * Try again with petr if configured */
519 if (rv == 0 && (lcm->flags & LISP_FLAG_USE_PETR))
Florin Corasf727db92016-06-23 15:01:58 +0200520 {
Florin Corasba888e42017-01-24 11:38:18 -0800521 rmt_map = lisp_get_petr_mapping (lcm);
522 rv = get_locator_pairs (lcm, lcl_map, rmt_map, &a->locator_pairs);
Florin Corasf727db92016-06-23 15:01:58 +0200523 }
524
Florin Corasba888e42017-01-24 11:38:18 -0800525 /* negative entry */
526 if (rv == 0)
527 {
528 a->is_negative = 1;
529 a->action = rmt_map->action;
530 }
Florin Corasf727db92016-06-23 15:01:58 +0200531
Filip Tehlar21511912017-04-07 10:41:42 +0200532 rv = vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
533 if (rv)
534 {
535 if (a->locator_pairs)
536 vec_free (a->locator_pairs);
537 return;
538 }
Florin Corasf727db92016-06-23 15:01:58 +0200539
Filip Tehlar21511912017-04-07 10:41:42 +0200540 /* add tunnel to fwd entry table */
Florin Corasf727db92016-06-23 15:01:58 +0200541 pool_get (lcm->fwd_entry_pool, fe);
Filip Tehlar21511912017-04-07 10:41:42 +0200542 vnet_lisp_gpe_add_fwd_counters (a, fe - lcm->fwd_entry_pool);
543
Florin Corasbb5c22f2016-08-02 02:31:03 +0200544 fe->locator_pairs = a->locator_pairs;
Filip Tehlar2fdaece2016-09-28 14:27:59 +0200545 gid_address_copy (&fe->reid, &a->rmt_eid);
Filip Tehlarb601f222017-01-02 10:22:56 +0100546
547 if (is_src_dst)
548 gid_address_copy (&fe->leid, &a->lcl_eid);
549 else
Florin Corasba888e42017-01-24 11:38:18 -0800550 gid_address_copy (&fe->leid, lcl_eid);
Filip Tehlarb601f222017-01-02 10:22:56 +0100551
Filip Tehlar69a9b762016-09-23 10:00:52 +0200552 fe->is_src_dst = is_src_dst;
Florin Corasf727db92016-06-23 15:01:58 +0200553 hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
Florin Corasa2157cf2016-08-16 21:09:14 +0200554 fe - lcm->fwd_entry_pool);
Florin Corasf727db92016-06-23 15:01:58 +0200555}
556
Filip Tehlarce1aae42017-01-04 10:42:25 +0100557typedef struct
558{
559 u32 si;
560 u32 di;
561} fwd_entry_mt_arg_t;
562
563static void *
564dp_add_fwd_entry_thread_fn (void *arg)
565{
566 fwd_entry_mt_arg_t *a = arg;
567 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
568 dp_add_fwd_entry (lcm, a->si, a->di);
569 return 0;
570}
571
572static int
573dp_add_fwd_entry_from_mt (u32 si, u32 di)
574{
575 fwd_entry_mt_arg_t a;
576
577 memset (&a, 0, sizeof (a));
578 a.si = si;
579 a.di = di;
580
581 vl_api_rpc_call_main_thread (dp_add_fwd_entry_thread_fn,
582 (u8 *) & a, sizeof (a));
583 return 0;
584}
585
Florin Corasf727db92016-06-23 15:01:58 +0200586/**
Filip Tehlar69a9b762016-09-23 10:00:52 +0200587 * Returns vector of adjacencies.
588 *
589 * The caller must free the vector returned by this function.
590 *
591 * @param vni virtual network identifier
592 * @return vector of adjacencies
593 */
594lisp_adjacency_t *
595vnet_lisp_adjacencies_get_by_vni (u32 vni)
596{
597 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
598 fwd_entry_t *fwd;
599 lisp_adjacency_t *adjs = 0, adj;
600
601 /* *INDENT-OFF* */
602 pool_foreach(fwd, lcm->fwd_entry_pool,
603 ({
604 if (gid_address_vni (&fwd->reid) != vni)
605 continue;
606
607 gid_address_copy (&adj.reid, &fwd->reid);
608 gid_address_copy (&adj.leid, &fwd->leid);
609 vec_add1 (adjs, adj);
610 }));
611 /* *INDENT-ON* */
612
613 return adjs;
614}
615
Filip Tehlar397fd7d2016-10-26 14:31:24 +0200616static lisp_msmr_t *
617get_map_server (ip_address_t * a)
618{
619 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
620 lisp_msmr_t *m;
621
622 vec_foreach (m, lcm->map_servers)
623 {
624 if (!ip_address_cmp (&m->address, a))
625 {
626 return m;
627 }
628 }
629 return 0;
630}
631
632static lisp_msmr_t *
633get_map_resolver (ip_address_t * a)
634{
635 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
636 lisp_msmr_t *m;
637
638 vec_foreach (m, lcm->map_resolvers)
639 {
640 if (!ip_address_cmp (&m->address, a))
641 {
642 return m;
643 }
644 }
645 return 0;
646}
647
648int
649vnet_lisp_add_del_map_server (ip_address_t * addr, u8 is_add)
650{
651 u32 i;
652 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
653 lisp_msmr_t _ms, *ms = &_ms;
654
655 if (vnet_lisp_enable_disable_status () == 0)
656 {
657 clib_warning ("LISP is disabled!");
658 return VNET_API_ERROR_LISP_DISABLED;
659 }
660
661 if (is_add)
662 {
663 if (get_map_server (addr))
664 {
665 clib_warning ("map-server %U already exists!", format_ip_address,
666 addr);
667 return -1;
668 }
669
670 memset (ms, 0, sizeof (*ms));
671 ip_address_copy (&ms->address, addr);
672 vec_add1 (lcm->map_servers, ms[0]);
Filip Tehlar7048ff12017-07-27 08:09:14 +0200673
674 if (vec_len (lcm->map_servers) == 1)
675 lcm->do_map_server_election = 1;
Filip Tehlar397fd7d2016-10-26 14:31:24 +0200676 }
677 else
678 {
679 for (i = 0; i < vec_len (lcm->map_servers); i++)
680 {
681 ms = vec_elt_at_index (lcm->map_servers, i);
682 if (!ip_address_cmp (&ms->address, addr))
683 {
Filip Tehlar7048ff12017-07-27 08:09:14 +0200684 if (!ip_address_cmp (&ms->address, &lcm->active_map_server))
685 lcm->do_map_server_election = 1;
686
Filip Tehlar397fd7d2016-10-26 14:31:24 +0200687 vec_del1 (lcm->map_servers, i);
688 break;
689 }
690 }
691 }
692
693 return 0;
694}
695
Filip Tehlar69a9b762016-09-23 10:00:52 +0200696/**
Florin Corasf727db92016-06-23 15:01:58 +0200697 * Add/remove mapping to/from map-cache. Overwriting not allowed.
698 */
699int
700vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a,
Florin Corasa2157cf2016-08-16 21:09:14 +0200701 u32 * map_index_result)
Florin Corase127a7e2016-02-18 22:20:01 +0100702{
Florin Corasa2157cf2016-08-16 21:09:14 +0200703 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
704 u32 mi, *map_indexp, map_index, i;
705 mapping_t *m, *old_map;
706 u32 **eid_indexes;
Florin Corase127a7e2016-02-18 22:20:01 +0100707
Filip Tehlaref2a5bf2017-05-30 07:14:46 +0200708 if (gid_address_type (&a->eid) == GID_ADDR_NSH)
709 {
710 if (gid_address_vni (&a->eid) != 0)
711 {
712 clib_warning ("Supported only default VNI for NSH!");
713 return VNET_API_ERROR_INVALID_ARGUMENT;
714 }
715 if (gid_address_nsh_spi (&a->eid) > MAX_VALUE_U24)
716 {
717 clib_warning ("SPI is greater than 24bit!");
718 return VNET_API_ERROR_INVALID_ARGUMENT;
719 }
720 }
721
Florin Corasf727db92016-06-23 15:01:58 +0200722 mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid);
Filip Tehlar53f09e32016-05-19 14:25:44 +0200723 old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
Florin Corase127a7e2016-02-18 22:20:01 +0100724 if (a->is_add)
725 {
726 /* TODO check if overwriting and take appropriate actions */
Florin Corasa2157cf2016-08-16 21:09:14 +0200727 if (mi != GID_LOOKUP_MISS && !gid_address_cmp (&old_map->eid, &a->eid))
728 {
729 clib_warning ("eid %U found in the eid-table", format_gid_address,
730 &a->eid);
731 return VNET_API_ERROR_VALUE_EXIST;
732 }
Florin Corase127a7e2016-02-18 22:20:01 +0100733
Florin Corasa2157cf2016-08-16 21:09:14 +0200734 pool_get (lcm->mapping_pool, m);
Florin Corasf727db92016-06-23 15:01:58 +0200735 gid_address_copy (&m->eid, &a->eid);
Florin Corase127a7e2016-02-18 22:20:01 +0100736 m->locator_set_index = a->locator_set_index;
737 m->ttl = a->ttl;
Filip Tehlar53f09e32016-05-19 14:25:44 +0200738 m->action = a->action;
Florin Corase127a7e2016-02-18 22:20:01 +0100739 m->local = a->local;
Filip Tehlar3cd9e732016-08-23 10:52:44 +0200740 m->is_static = a->is_static;
Filip Tehlar397fd7d2016-10-26 14:31:24 +0200741 m->key = vec_dup (a->key);
742 m->key_id = a->key_id;
Florin Corase127a7e2016-02-18 22:20:01 +0100743
744 map_index = m - lcm->mapping_pool;
Florin Corasf727db92016-06-23 15:01:58 +0200745 gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, map_index,
Florin Corasa2157cf2016-08-16 21:09:14 +0200746 1);
Florin Corase127a7e2016-02-18 22:20:01 +0100747
Florin Corasa2157cf2016-08-16 21:09:14 +0200748 if (pool_is_free_index (lcm->locator_set_pool, a->locator_set_index))
749 {
750 clib_warning ("Locator set with index %d doesn't exist",
751 a->locator_set_index);
752 return VNET_API_ERROR_INVALID_VALUE;
753 }
Florin Corase127a7e2016-02-18 22:20:01 +0100754
755 /* add eid to list of eids supported by locator-set */
756 vec_validate (lcm->locator_set_to_eids, a->locator_set_index);
Florin Corasa2157cf2016-08-16 21:09:14 +0200757 eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
758 a->locator_set_index);
759 vec_add1 (eid_indexes[0], map_index);
Florin Corase127a7e2016-02-18 22:20:01 +0100760
761 if (a->local)
Florin Corasa2157cf2016-08-16 21:09:14 +0200762 {
763 /* mark as local */
764 vec_add1 (lcm->local_mappings_indexes, map_index);
765 }
Florin Corase127a7e2016-02-18 22:20:01 +0100766 map_index_result[0] = map_index;
767 }
768 else
769 {
Florin Coras577c3552016-04-21 00:45:40 +0200770 if (mi == GID_LOOKUP_MISS)
Florin Corasa2157cf2016-08-16 21:09:14 +0200771 {
772 clib_warning ("eid %U not found in the eid-table",
773 format_gid_address, &a->eid);
774 return VNET_API_ERROR_INVALID_VALUE;
775 }
Florin Corase127a7e2016-02-18 22:20:01 +0100776
777 /* clear locator-set to eids binding */
Florin Corasa2157cf2016-08-16 21:09:14 +0200778 eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
779 a->locator_set_index);
780 for (i = 0; i < vec_len (eid_indexes[0]); i++)
781 {
782 map_indexp = vec_elt_at_index (eid_indexes[0], i);
783 if (map_indexp[0] == mi)
784 break;
785 }
786 vec_del1 (eid_indexes[0], i);
Florin Corase127a7e2016-02-18 22:20:01 +0100787
788 /* remove local mark if needed */
Florin Corasa2157cf2016-08-16 21:09:14 +0200789 m = pool_elt_at_index (lcm->mapping_pool, mi);
Florin Corase127a7e2016-02-18 22:20:01 +0100790 if (m->local)
Florin Corasa2157cf2016-08-16 21:09:14 +0200791 {
792 u32 k, *lm_indexp;
793 for (k = 0; k < vec_len (lcm->local_mappings_indexes); k++)
794 {
795 lm_indexp = vec_elt_at_index (lcm->local_mappings_indexes, k);
796 if (lm_indexp[0] == mi)
797 break;
798 }
799 vec_del1 (lcm->local_mappings_indexes, k);
800 }
Florin Corase127a7e2016-02-18 22:20:01 +0100801
802 /* remove mapping from dictionary */
Florin Corasf727db92016-06-23 15:01:58 +0200803 gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, 0, 0);
Filip Tehlar324112f2016-06-02 16:07:38 +0200804 gid_address_free (&m->eid);
Florin Corase127a7e2016-02-18 22:20:01 +0100805 pool_put_index (lcm->mapping_pool, mi);
806 }
807
808 return 0;
809}
810
Florin Corasf727db92016-06-23 15:01:58 +0200811/**
812 * Add/update/delete mapping to/in/from map-cache.
813 */
Florin Coras577c3552016-04-21 00:45:40 +0200814int
815vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
Florin Corasa2157cf2016-08-16 21:09:14 +0200816 u32 * map_index_result)
Florin Coras577c3552016-04-21 00:45:40 +0200817{
Florin Corasa2157cf2016-08-16 21:09:14 +0200818 uword *dp_table = 0;
Florin Corasf727db92016-06-23 15:01:58 +0200819 u32 vni;
Florin Coras1a1adc72016-07-22 01:45:30 +0200820 u8 type;
Florin Corasf727db92016-06-23 15:01:58 +0200821
Florin Corasa2157cf2016-08-16 21:09:14 +0200822 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Florin Coras577c3552016-04-21 00:45:40 +0200823
Andrej Kozemcak8ebb2a12016-06-07 12:25:20 +0200824 if (vnet_lisp_enable_disable_status () == 0)
825 {
826 clib_warning ("LISP is disabled!");
827 return VNET_API_ERROR_LISP_DISABLED;
828 }
829
Florin Corasa2157cf2016-08-16 21:09:14 +0200830 vni = gid_address_vni (&a->eid);
831 type = gid_address_type (&a->eid);
Florin Coras1a1adc72016-07-22 01:45:30 +0200832 if (GID_ADDR_IP_PREFIX == type)
Florin Corasa2157cf2016-08-16 21:09:14 +0200833 dp_table = hash_get (lcm->table_id_by_vni, vni);
Florin Coras1a1adc72016-07-22 01:45:30 +0200834 else if (GID_ADDR_MAC == type)
Florin Corasa2157cf2016-08-16 21:09:14 +0200835 dp_table = hash_get (lcm->bd_id_by_vni, vni);
Florin Coras577c3552016-04-21 00:45:40 +0200836
Filip Tehlaref2a5bf2017-05-30 07:14:46 +0200837 if (!dp_table && GID_ADDR_NSH != type)
Florin Coras577c3552016-04-21 00:45:40 +0200838 {
Florin Corasa2157cf2016-08-16 21:09:14 +0200839 clib_warning ("vni %d not associated to a %s!", vni,
840 GID_ADDR_IP_PREFIX == type ? "vrf" : "bd");
Florin Coras577c3552016-04-21 00:45:40 +0200841 return VNET_API_ERROR_INVALID_VALUE;
842 }
843
Florin Corasf727db92016-06-23 15:01:58 +0200844 /* store/remove mapping from map-cache */
845 return vnet_lisp_map_cache_add_del (a, map_index_result);
Florin Coras577c3552016-04-21 00:45:40 +0200846}
847
Filip Tehlard5a65db2017-05-17 17:21:10 +0200848static void
849add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg)
850{
851 u32 **ht = arg;
852 u32 bd = (u32) kvp->key[0];
853 hash_set (ht[0], bd, 0);
854}
855
856u32 *
857vnet_lisp_l2_arp_bds_get (void)
858{
859 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
860 u32 *bds = 0;
861
862 gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid,
863 add_l2_arp_bd, &bds);
864 return bds;
865}
866
867typedef struct
868{
869 void *vector;
870 u32 bd;
871} lisp_add_l2_arp_args_t;
872
873static void
874add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg)
875{
876 lisp_add_l2_arp_args_t *a = arg;
877 lisp_api_l2_arp_entry_t **vector = a->vector, e;
878
879 if ((u32) kvp->key[0] == a->bd)
880 {
881 mac_copy (e.mac, (void *) &kvp->value);
882 e.ip4 = (u32) kvp->key[1];
883 vec_add1 (vector[0], e);
884 }
885}
886
887lisp_api_l2_arp_entry_t *
888vnet_lisp_l2_arp_entries_get_by_bd (u32 bd)
889{
890 lisp_api_l2_arp_entry_t *entries = 0;
891 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
892 lisp_add_l2_arp_args_t a;
893
894 a.vector = &entries;
895 a.bd = bd;
896
897 gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid,
898 add_l2_arp_entry, &a);
899 return entries;
900}
901
902int
903vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add)
904{
905 if (vnet_lisp_enable_disable_status () == 0)
906 {
907 clib_warning ("LISP is disabled!");
908 return VNET_API_ERROR_LISP_DISABLED;
909 }
910
911 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
912 int rc = 0;
913
914 u64 res = gid_dictionary_lookup (&lcm->mapping_index_by_gid, key);
915 if (is_add)
916 {
917 if (res != GID_LOOKUP_MISS_L2)
918 {
919 clib_warning ("Entry %U exists in DB!", format_gid_address, key);
920 return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
921 }
922 u64 val = mac_to_u64 (mac);
923 gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, val,
924 1 /* is_add */ );
925 }
926 else
927 {
928 if (res == GID_LOOKUP_MISS_L2)
929 {
930 clib_warning ("ONE ARP entry %U not found - cannot delete!",
931 format_gid_address, key);
932 return -1;
933 }
934 gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, 0,
935 0 /* is_add */ );
936 }
937
938 return rc;
939}
940
Filip Tehlar324112f2016-06-02 16:07:38 +0200941int
Florin Coras1a1adc72016-07-22 01:45:30 +0200942vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add)
Filip Tehlar324112f2016-06-02 16:07:38 +0200943{
Florin Corasa2157cf2016-08-16 21:09:14 +0200944 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
945 uword *dp_idp, *vnip, **dp_table_by_vni, **vni_by_dp_table;
Filip Tehlar324112f2016-06-02 16:07:38 +0200946
947 if (vnet_lisp_enable_disable_status () == 0)
948 {
949 clib_warning ("LISP is disabled!");
Filip Tehlard5a65db2017-05-17 17:21:10 +0200950 return VNET_API_ERROR_LISP_DISABLED;
Filip Tehlar324112f2016-06-02 16:07:38 +0200951 }
952
Florin Coras1a1adc72016-07-22 01:45:30 +0200953 dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni;
954 vni_by_dp_table = is_l2 ? &lcm->vni_by_bd_id : &lcm->vni_by_table_id;
955
956 if (!is_l2 && (vni == 0 || dp_id == 0))
Filip Tehlar324112f2016-06-02 16:07:38 +0200957 {
958 clib_warning ("can't add/del default vni-vrf mapping!");
959 return -1;
960 }
961
Florin Coras1a1adc72016-07-22 01:45:30 +0200962 dp_idp = hash_get (dp_table_by_vni[0], vni);
963 vnip = hash_get (vni_by_dp_table[0], dp_id);
Filip Tehlar324112f2016-06-02 16:07:38 +0200964
965 if (is_add)
966 {
Florin Coras1a1adc72016-07-22 01:45:30 +0200967 if (dp_idp || vnip)
Florin Corasa2157cf2016-08-16 21:09:14 +0200968 {
969 clib_warning ("vni %d or vrf %d already used in vrf/vni "
970 "mapping!", vni, dp_id);
971 return -1;
972 }
Florin Coras1a1adc72016-07-22 01:45:30 +0200973 hash_set (dp_table_by_vni[0], vni, dp_id);
974 hash_set (vni_by_dp_table[0], dp_id, vni);
Florin Corasf727db92016-06-23 15:01:58 +0200975
976 /* create dp iface */
Florin Coras1a1adc72016-07-22 01:45:30 +0200977 dp_add_del_iface (lcm, vni, is_l2, 1);
Filip Tehlar324112f2016-06-02 16:07:38 +0200978 }
979 else
980 {
Florin Coras1a1adc72016-07-22 01:45:30 +0200981 if (!dp_idp || !vnip)
Florin Corasa2157cf2016-08-16 21:09:14 +0200982 {
983 clib_warning ("vni %d or vrf %d not used in any vrf/vni! "
984 "mapping!", vni, dp_id);
985 return -1;
986 }
Florin Corasf727db92016-06-23 15:01:58 +0200987 /* remove dp iface */
Florin Coras1a1adc72016-07-22 01:45:30 +0200988 dp_add_del_iface (lcm, vni, is_l2, 0);
Filip Tehlarfc568412017-04-05 10:06:03 +0200989
990 hash_unset (dp_table_by_vni[0], vni);
991 hash_unset (vni_by_dp_table[0], dp_id);
Filip Tehlar324112f2016-06-02 16:07:38 +0200992 }
993 return 0;
Florin Coras1a1adc72016-07-22 01:45:30 +0200994
Filip Tehlar324112f2016-06-02 16:07:38 +0200995}
996
Florin Corasf727db92016-06-23 15:01:58 +0200997/* return 0 if the two locator sets are identical 1 otherwise */
998static u8
Florin Corasa2157cf2016-08-16 21:09:14 +0200999compare_locators (lisp_cp_main_t * lcm, u32 * old_ls_indexes,
1000 locator_t * new_locators)
Filip Tehlar53f09e32016-05-19 14:25:44 +02001001{
Florin Corasf727db92016-06-23 15:01:58 +02001002 u32 i, old_li;
Florin Corasa2157cf2016-08-16 21:09:14 +02001003 locator_t *old_loc, *new_loc;
Filip Tehlar53f09e32016-05-19 14:25:44 +02001004
Florin Corasa2157cf2016-08-16 21:09:14 +02001005 if (vec_len (old_ls_indexes) != vec_len (new_locators))
Florin Corasf727db92016-06-23 15:01:58 +02001006 return 1;
Filip Tehlar53f09e32016-05-19 14:25:44 +02001007
Florin Corasa2157cf2016-08-16 21:09:14 +02001008 for (i = 0; i < vec_len (new_locators); i++)
Filip Tehlar53f09e32016-05-19 14:25:44 +02001009 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001010 old_li = vec_elt (old_ls_indexes, i);
1011 old_loc = pool_elt_at_index (lcm->locator_pool, old_li);
Florin Corasf727db92016-06-23 15:01:58 +02001012
Florin Corasa2157cf2016-08-16 21:09:14 +02001013 new_loc = vec_elt_at_index (new_locators, i);
Florin Corasf727db92016-06-23 15:01:58 +02001014
1015 if (locator_cmp (old_loc, new_loc))
Florin Corasa2157cf2016-08-16 21:09:14 +02001016 return 1;
Filip Tehlar53f09e32016-05-19 14:25:44 +02001017 }
Florin Corasf727db92016-06-23 15:01:58 +02001018 return 0;
Filip Tehlar53f09e32016-05-19 14:25:44 +02001019}
1020
Filip Tehlard5fcc462016-10-17 16:20:18 +02001021typedef struct
1022{
1023 u8 is_negative;
1024 void *lcm;
1025 gid_address_t *eids_to_be_deleted;
1026} remove_mapping_args_t;
1027
1028/**
1029 * Callback invoked when a sub-prefix is found
1030 */
1031static void
1032remove_mapping_if_needed (u32 mi, void *arg)
1033{
1034 u8 delete = 0;
1035 remove_mapping_args_t *a = arg;
1036 lisp_cp_main_t *lcm = a->lcm;
1037 mapping_t *m;
1038 locator_set_t *ls;
1039
1040 m = pool_elt_at_index (lcm->mapping_pool, mi);
1041 if (!m)
1042 return;
1043
1044 ls = pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
1045
1046 if (a->is_negative)
1047 {
1048 if (0 != vec_len (ls->locator_indices))
1049 delete = 1;
1050 }
1051 else
1052 {
1053 if (0 == vec_len (ls->locator_indices))
1054 delete = 1;
1055 }
1056
1057 if (delete)
1058 vec_add1 (a->eids_to_be_deleted, m->eid);
1059}
1060
1061/**
1062 * This function searches map cache and looks for IP prefixes that are subset
1063 * of the provided one. If such prefix is found depending on 'is_negative'
1064 * it does follows:
1065 *
1066 * 1) if is_negative is true and found prefix points to positive mapping,
1067 * then the mapping is removed
1068 * 2) if is_negative is false and found prefix points to negative mapping,
1069 * then the mapping is removed
1070 */
1071static void
1072remove_overlapping_sub_prefixes (lisp_cp_main_t * lcm, gid_address_t * eid,
1073 u8 is_negative)
1074{
1075 gid_address_t *e;
1076 remove_mapping_args_t a;
Florin Corasf3dc11a2017-01-24 03:13:43 -08001077
Filip Tehlard5fcc462016-10-17 16:20:18 +02001078 memset (&a, 0, sizeof (a));
1079
1080 /* do this only in src/dst mode ... */
1081 if (MR_MODE_SRC_DST != lcm->map_request_mode)
1082 return;
1083
1084 /* ... and only for IP prefix */
1085 if (GID_ADDR_SRC_DST != gid_address_type (eid)
1086 || (FID_ADDR_IP_PREF != gid_address_sd_dst_type (eid)))
1087 return;
1088
1089 a.is_negative = is_negative;
1090 a.lcm = lcm;
1091
1092 gid_dict_foreach_subprefix (&lcm->mapping_index_by_gid, eid,
1093 remove_mapping_if_needed, &a);
1094
1095 vec_foreach (e, a.eids_to_be_deleted)
Filip Tehlarfb9931f2016-12-09 13:52:38 +01001096 {
Florin Corasf3dc11a2017-01-24 03:13:43 -08001097 vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
1098
1099 memset (adj_args, 0, sizeof (adj_args[0]));
1100 gid_address_copy (&adj_args->reid, e);
1101 adj_args->is_add = 0;
1102 if (vnet_lisp_add_del_adjacency (adj_args))
1103 clib_warning ("failed to del adjacency!");
1104
Filip Tehlard5fcc462016-10-17 16:20:18 +02001105 vnet_lisp_add_del_mapping (e, 0, 0, 0, 0, 0 /* is add */ , 0, 0);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01001106 }
Filip Tehlard5fcc462016-10-17 16:20:18 +02001107
1108 vec_free (a.eids_to_be_deleted);
1109}
1110
Filip Tehlar9677a942016-11-28 10:23:31 +01001111static void
1112mapping_delete_timer (lisp_cp_main_t * lcm, u32 mi)
1113{
1114 timing_wheel_delete (&lcm->wheel, mi);
1115}
1116
Filip Tehlara6bce492017-02-03 10:17:49 +01001117static int
1118is_local_ip (lisp_cp_main_t * lcm, ip_address_t * addr)
1119{
1120 fib_node_index_t fei;
1121 fib_prefix_t prefix;
1122 fib_entry_flag_t flags;
1123
1124 ip_address_to_fib_prefix (addr, &prefix);
1125
1126 fei = fib_table_lookup (0, &prefix);
1127 flags = fib_entry_get_flags (fei);
1128 return (FIB_ENTRY_FLAG_LOCAL & flags);
1129}
1130
Filip Tehlar195bcee2016-05-13 17:37:35 +02001131/**
Florin Corasf727db92016-06-23 15:01:58 +02001132 * Adds/removes/updates mapping. Does not program forwarding.
Filip Tehlar195bcee2016-05-13 17:37:35 +02001133 *
Florin Coras71893ac2016-07-10 20:09:32 +02001134 * @param eid end-host identifier
Filip Tehlar195bcee2016-05-13 17:37:35 +02001135 * @param rlocs vector of remote locators
1136 * @param action action for negative map-reply
1137 * @param is_add add mapping if non-zero, delete otherwise
Florin Coras71893ac2016-07-10 20:09:32 +02001138 * @param res_map_index the map-index that was created/updated/removed. It is
1139 * set to ~0 if no action is taken.
Filip Tehlar3cd9e732016-08-23 10:52:44 +02001140 * @param is_static used for distinguishing between statically learned
1141 remote mappings and mappings obtained from MR
Filip Tehlar195bcee2016-05-13 17:37:35 +02001142 * @return return code
1143 */
1144int
Florin Coras71893ac2016-07-10 20:09:32 +02001145vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
Filip Tehlar3cd9e732016-08-23 10:52:44 +02001146 u8 authoritative, u32 ttl, u8 is_add, u8 is_static,
Florin Corasa2157cf2016-08-16 21:09:14 +02001147 u32 * res_map_index)
Filip Tehlar195bcee2016-05-13 17:37:35 +02001148{
Florin Corasa2157cf2016-08-16 21:09:14 +02001149 vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args;
1150 vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
1151 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Florin Corasf727db92016-06-23 15:01:58 +02001152 u32 mi, ls_index = 0, dst_map_index;
Florin Corasa2157cf2016-08-16 21:09:14 +02001153 mapping_t *old_map;
Filip Tehlara6bce492017-02-03 10:17:49 +01001154 locator_t *loc;
Filip Tehlar195bcee2016-05-13 17:37:35 +02001155
Florin Corasa2157cf2016-08-16 21:09:14 +02001156 if (vnet_lisp_enable_disable_status () == 0)
Andrej Kozemcak8ebb2a12016-06-07 12:25:20 +02001157 {
1158 clib_warning ("LISP is disabled!");
1159 return VNET_API_ERROR_LISP_DISABLED;
1160 }
1161
Florin Corasf727db92016-06-23 15:01:58 +02001162 if (res_map_index)
1163 res_map_index[0] = ~0;
Filip Tehlar58f886a2016-05-30 15:57:40 +02001164
Florin Corasf727db92016-06-23 15:01:58 +02001165 memset (m_args, 0, sizeof (m_args[0]));
1166 memset (ls_args, 0, sizeof (ls_args[0]));
Filip Tehlar195bcee2016-05-13 17:37:35 +02001167
Florin Corasf727db92016-06-23 15:01:58 +02001168 ls_args->locators = rlocs;
Filip Tehlar195bcee2016-05-13 17:37:35 +02001169
Florin Coras71893ac2016-07-10 20:09:32 +02001170 mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid);
Florin Corasa2157cf2016-08-16 21:09:14 +02001171 old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
Florin Corasf727db92016-06-23 15:01:58 +02001172
1173 if (is_add)
Filip Tehlar195bcee2016-05-13 17:37:35 +02001174 {
Filip Tehlar272c69e2017-02-15 16:40:35 +01001175 /* check if none of the locators match localy configured address */
1176 vec_foreach (loc, rlocs)
1177 {
1178 ip_prefix_t *p = &gid_address_ippref (&loc->address);
1179 if (is_local_ip (lcm, &ip_prefix_addr (p)))
1180 {
1181 clib_warning ("RLOC %U matches a local address!",
1182 format_gid_address, &loc->address);
1183 return VNET_API_ERROR_LISP_RLOC_LOCAL;
1184 }
1185 }
1186
Florin Corasf727db92016-06-23 15:01:58 +02001187 /* overwrite: if mapping already exists, decide if locators should be
1188 * updated and be done */
Florin Coras71893ac2016-07-10 20:09:32 +02001189 if (old_map && gid_address_cmp (&old_map->eid, eid) == 0)
Florin Corasa2157cf2016-08-16 21:09:14 +02001190 {
Filip Tehlar3cd9e732016-08-23 10:52:44 +02001191 if (!is_static && (old_map->is_static || old_map->local))
1192 {
1193 /* do not overwrite local or static remote mappings */
1194 clib_warning ("mapping %U rejected due to collision with local "
1195 "or static remote mapping!", format_gid_address,
Filip Tehlard5fcc462016-10-17 16:20:18 +02001196 eid);
Filip Tehlar3cd9e732016-08-23 10:52:44 +02001197 return 0;
1198 }
1199
Florin Corasa2157cf2016-08-16 21:09:14 +02001200 locator_set_t *old_ls;
Filip Tehlar195bcee2016-05-13 17:37:35 +02001201
Florin Corasa2157cf2016-08-16 21:09:14 +02001202 /* update mapping attributes */
1203 old_map->action = action;
1204 old_map->authoritative = authoritative;
1205 old_map->ttl = ttl;
Filip Tehlar195bcee2016-05-13 17:37:35 +02001206
Florin Corasa2157cf2016-08-16 21:09:14 +02001207 old_ls = pool_elt_at_index (lcm->locator_set_pool,
1208 old_map->locator_set_index);
1209 if (compare_locators (lcm, old_ls->locator_indices,
1210 ls_args->locators))
1211 {
1212 /* set locator-set index to overwrite */
1213 ls_args->is_add = 1;
1214 ls_args->index = old_map->locator_set_index;
1215 vnet_lisp_add_del_locator_set (ls_args, 0);
1216 if (res_map_index)
1217 res_map_index[0] = mi;
1218 }
1219 }
Florin Corasf727db92016-06-23 15:01:58 +02001220 /* new mapping */
1221 else
Florin Corasa2157cf2016-08-16 21:09:14 +02001222 {
Filip Tehlard5fcc462016-10-17 16:20:18 +02001223 remove_overlapping_sub_prefixes (lcm, eid, 0 == ls_args->locators);
1224
Florin Corasa2157cf2016-08-16 21:09:14 +02001225 ls_args->is_add = 1;
1226 ls_args->index = ~0;
Florin Corasf727db92016-06-23 15:01:58 +02001227
Florin Corasa2157cf2016-08-16 21:09:14 +02001228 vnet_lisp_add_del_locator_set (ls_args, &ls_index);
Florin Corasf727db92016-06-23 15:01:58 +02001229
Florin Corasa2157cf2016-08-16 21:09:14 +02001230 /* add mapping */
1231 gid_address_copy (&m_args->eid, eid);
1232 m_args->is_add = 1;
1233 m_args->action = action;
1234 m_args->locator_set_index = ls_index;
Filip Tehlar3cd9e732016-08-23 10:52:44 +02001235 m_args->is_static = is_static;
Filip Tehlar9677a942016-11-28 10:23:31 +01001236 m_args->ttl = ttl;
Florin Corasa2157cf2016-08-16 21:09:14 +02001237 vnet_lisp_map_cache_add_del (m_args, &dst_map_index);
Florin Corasf727db92016-06-23 15:01:58 +02001238
Florin Corasa2157cf2016-08-16 21:09:14 +02001239 if (res_map_index)
1240 res_map_index[0] = dst_map_index;
1241 }
Filip Tehlar195bcee2016-05-13 17:37:35 +02001242 }
Florin Corasf727db92016-06-23 15:01:58 +02001243 else
1244 {
Florin Coras71893ac2016-07-10 20:09:32 +02001245 if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0)
Florin Corasa2157cf2016-08-16 21:09:14 +02001246 {
1247 clib_warning ("cannot delete mapping for eid %U",
1248 format_gid_address, eid);
1249 return -1;
1250 }
Florin Corasf727db92016-06-23 15:01:58 +02001251
1252 m_args->is_add = 0;
Florin Coras71893ac2016-07-10 20:09:32 +02001253 gid_address_copy (&m_args->eid, eid);
Florin Corasf727db92016-06-23 15:01:58 +02001254 m_args->locator_set_index = old_map->locator_set_index;
1255
1256 /* delete mapping associated from map-cache */
1257 vnet_lisp_map_cache_add_del (m_args, 0);
1258
1259 ls_args->is_add = 0;
1260 ls_args->index = old_map->locator_set_index;
1261 /* delete locator set */
1262 vnet_lisp_add_del_locator_set (ls_args, 0);
Filip Tehlarb93222f2016-07-07 09:58:08 +02001263
Filip Tehlar9677a942016-11-28 10:23:31 +01001264 /* delete timer associated to the mapping if any */
1265 if (old_map->timer_set)
1266 mapping_delete_timer (lcm, mi);
1267
Filip Tehlarb93222f2016-07-07 09:58:08 +02001268 /* return old mapping index */
Andrej Kozemcak438109d2016-07-22 12:54:12 +02001269 if (res_map_index)
Florin Corasa2157cf2016-08-16 21:09:14 +02001270 res_map_index[0] = mi;
Florin Corasf727db92016-06-23 15:01:58 +02001271 }
1272
Filip Tehlar195bcee2016-05-13 17:37:35 +02001273 /* success */
Florin Corasf727db92016-06-23 15:01:58 +02001274 return 0;
Filip Tehlar195bcee2016-05-13 17:37:35 +02001275}
1276
Filip Tehlar58f886a2016-05-30 15:57:40 +02001277int
Florin Corasf727db92016-06-23 15:01:58 +02001278vnet_lisp_clear_all_remote_adjacencies (void)
Filip Tehlar58f886a2016-05-30 15:57:40 +02001279{
1280 int rv = 0;
Florin Corasa2157cf2016-08-16 21:09:14 +02001281 u32 mi, *map_indices = 0, *map_indexp;
1282 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1283 vnet_lisp_add_del_mapping_args_t _dm_args, *dm_args = &_dm_args;
1284 vnet_lisp_add_del_locator_set_args_t _ls, *ls = &_ls;
Filip Tehlar58f886a2016-05-30 15:57:40 +02001285
Florin Corasa2157cf2016-08-16 21:09:14 +02001286 /* *INDENT-OFF* */
Filip Tehlar58f886a2016-05-30 15:57:40 +02001287 pool_foreach_index (mi, lcm->mapping_pool,
Florin Corasa2157cf2016-08-16 21:09:14 +02001288 ({
1289 vec_add1 (map_indices, mi);
1290 }));
1291 /* *INDENT-ON* */
Filip Tehlar58f886a2016-05-30 15:57:40 +02001292
1293 vec_foreach (map_indexp, map_indices)
Florin Corasa2157cf2016-08-16 21:09:14 +02001294 {
1295 mapping_t *map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
1296 if (!map->local)
1297 {
1298 dp_del_fwd_entry (lcm, 0, map_indexp[0]);
Filip Tehlar58f886a2016-05-30 15:57:40 +02001299
Florin Corasa2157cf2016-08-16 21:09:14 +02001300 dm_args->is_add = 0;
1301 gid_address_copy (&dm_args->eid, &map->eid);
1302 dm_args->locator_set_index = map->locator_set_index;
Filip Tehlar58f886a2016-05-30 15:57:40 +02001303
Florin Corasa2157cf2016-08-16 21:09:14 +02001304 /* delete mapping associated to fwd entry */
1305 vnet_lisp_map_cache_add_del (dm_args, 0);
Filip Tehlar58f886a2016-05-30 15:57:40 +02001306
Florin Corasa2157cf2016-08-16 21:09:14 +02001307 ls->is_add = 0;
1308 ls->local = 0;
1309 ls->index = map->locator_set_index;
1310 /* delete locator set */
1311 rv = vnet_lisp_add_del_locator_set (ls, 0);
1312 if (rv != 0)
1313 goto cleanup;
1314 }
1315 }
Filip Tehlar58f886a2016-05-30 15:57:40 +02001316
1317cleanup:
1318 if (map_indices)
1319 vec_free (map_indices);
1320 return rv;
1321}
1322
Filip Tehlar195bcee2016-05-13 17:37:35 +02001323/**
Florin Coras71893ac2016-07-10 20:09:32 +02001324 * Adds adjacency or removes forwarding entry associated to remote mapping.
1325 * Note that adjacencies are not stored, they only result in forwarding entries
1326 * being created.
Florin Corasf727db92016-06-23 15:01:58 +02001327 */
Florin Corasf3dc11a2017-01-24 03:13:43 -08001328int
1329vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a)
Florin Corasf727db92016-06-23 15:01:58 +02001330{
Florin Corasf3dc11a2017-01-24 03:13:43 -08001331 lisp_cp_main_t *lcm = &lisp_control_main;
Florin Coras71893ac2016-07-10 20:09:32 +02001332 u32 local_mi, remote_mi = ~0;
Florin Corasf727db92016-06-23 15:01:58 +02001333
1334 if (vnet_lisp_enable_disable_status () == 0)
1335 {
1336 clib_warning ("LISP is disabled!");
1337 return VNET_API_ERROR_LISP_DISABLED;
1338 }
1339
Filip Tehlar69a9b762016-09-23 10:00:52 +02001340 remote_mi = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid,
Florin Corasf3dc11a2017-01-24 03:13:43 -08001341 &a->reid, &a->leid);
Florin Coras71893ac2016-07-10 20:09:32 +02001342 if (GID_LOOKUP_MISS == remote_mi)
1343 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001344 clib_warning ("Remote eid %U not found. Cannot add adjacency!",
Florin Corasf3dc11a2017-01-24 03:13:43 -08001345 format_gid_address, &a->reid);
Florin Corasf727db92016-06-23 15:01:58 +02001346
Florin Coras71893ac2016-07-10 20:09:32 +02001347 return -1;
1348 }
1349
Florin Corasf3dc11a2017-01-24 03:13:43 -08001350 if (a->is_add)
Florin Corasf727db92016-06-23 15:01:58 +02001351 {
Florin Corasf727db92016-06-23 15:01:58 +02001352 /* check if source eid has an associated mapping. If pitr mode is on,
1353 * just use the pitr's mapping */
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02001354 if (lcm->lisp_pitr)
1355 local_mi = lcm->pitr_map_index;
1356 else
1357 {
1358 if (gid_address_type (&a->reid) == GID_ADDR_NSH)
1359 {
1360 if (lcm->nsh_map_index == ~0)
1361 local_mi = GID_LOOKUP_MISS;
1362 else
1363 local_mi = lcm->nsh_map_index;
1364 }
1365 else
1366 {
1367 local_mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid,
1368 &a->leid);
1369 }
1370 }
Florin Corasf727db92016-06-23 15:01:58 +02001371
Florin Coras71893ac2016-07-10 20:09:32 +02001372 if (GID_LOOKUP_MISS == local_mi)
Florin Corasa2157cf2016-08-16 21:09:14 +02001373 {
1374 clib_warning ("Local eid %U not found. Cannot add adjacency!",
Florin Corasf3dc11a2017-01-24 03:13:43 -08001375 format_gid_address, &a->leid);
Florin Corasf727db92016-06-23 15:01:58 +02001376
Florin Corasa2157cf2016-08-16 21:09:14 +02001377 return -1;
1378 }
Florin Corasf727db92016-06-23 15:01:58 +02001379
Florin Coras71893ac2016-07-10 20:09:32 +02001380 /* update forwarding */
1381 dp_add_fwd_entry (lcm, local_mi, remote_mi);
Florin Corasf727db92016-06-23 15:01:58 +02001382 }
1383 else
Florin Coras71893ac2016-07-10 20:09:32 +02001384 dp_del_fwd_entry (lcm, 0, remote_mi);
Florin Corasf727db92016-06-23 15:01:58 +02001385
1386 return 0;
1387}
1388
1389int
Florin Corasdca88042016-09-14 16:01:38 +02001390vnet_lisp_set_map_request_mode (u8 mode)
1391{
1392 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1393
1394 if (vnet_lisp_enable_disable_status () == 0)
1395 {
1396 clib_warning ("LISP is disabled!");
1397 return VNET_API_ERROR_LISP_DISABLED;
1398 }
1399
1400 if (mode >= _MR_MODE_MAX)
1401 {
1402 clib_warning ("Invalid LISP map request mode %d!", mode);
1403 return VNET_API_ERROR_INVALID_ARGUMENT;
1404 }
1405
1406 lcm->map_request_mode = mode;
1407 return 0;
1408}
1409
Filip Tehlar53f09e32016-05-19 14:25:44 +02001410int
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02001411vnet_lisp_nsh_set_locator_set (u8 * locator_set_name, u8 is_add)
1412{
1413 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1414 lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
1415 u32 locator_set_index = ~0;
1416 mapping_t *m;
1417 uword *p;
1418
1419 if (vnet_lisp_enable_disable_status () == 0)
1420 {
1421 clib_warning ("LISP is disabled!");
1422 return VNET_API_ERROR_LISP_DISABLED;
1423 }
1424
1425 if (is_add)
1426 {
1427 if (lcm->nsh_map_index == (u32) ~ 0)
1428 {
1429 p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1430 if (!p)
1431 {
1432 clib_warning ("locator-set %v doesn't exist", locator_set_name);
1433 return -1;
1434 }
1435 locator_set_index = p[0];
1436
1437 pool_get (lcm->mapping_pool, m);
1438 memset (m, 0, sizeof *m);
1439 m->locator_set_index = locator_set_index;
1440 m->local = 1;
1441 m->nsh_set = 1;
1442 lcm->nsh_map_index = m - lcm->mapping_pool;
1443
1444 if (~0 == vnet_lisp_gpe_add_nsh_iface (lgm))
1445 return -1;
1446 }
1447 }
1448 else
1449 {
1450 if (lcm->nsh_map_index != (u32) ~ 0)
1451 {
1452 /* remove NSH mapping */
1453 pool_put_index (lcm->mapping_pool, lcm->nsh_map_index);
1454 lcm->nsh_map_index = ~0;
1455 vnet_lisp_gpe_del_nsh_iface (lgm);
1456 }
1457 }
1458 return 0;
1459}
1460
1461int
Filip Tehlar53f09e32016-05-19 14:25:44 +02001462vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
1463{
Florin Corasa2157cf2016-08-16 21:09:14 +02001464 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlar53f09e32016-05-19 14:25:44 +02001465 u32 locator_set_index = ~0;
Florin Corasa2157cf2016-08-16 21:09:14 +02001466 mapping_t *m;
1467 uword *p;
Filip Tehlar53f09e32016-05-19 14:25:44 +02001468
Andrej Kozemcak8ebb2a12016-06-07 12:25:20 +02001469 if (vnet_lisp_enable_disable_status () == 0)
1470 {
1471 clib_warning ("LISP is disabled!");
1472 return VNET_API_ERROR_LISP_DISABLED;
1473 }
1474
Filip Tehlar53f09e32016-05-19 14:25:44 +02001475 p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1476 if (!p)
1477 {
1478 clib_warning ("locator-set %v doesn't exist", locator_set_name);
1479 return -1;
1480 }
1481 locator_set_index = p[0];
1482
1483 if (is_add)
1484 {
1485 pool_get (lcm->mapping_pool, m);
1486 m->locator_set_index = locator_set_index;
1487 m->local = 1;
Filip Tehlar38206ee2017-02-20 17:31:57 +01001488 m->pitr_set = 1;
Filip Tehlar53f09e32016-05-19 14:25:44 +02001489 lcm->pitr_map_index = m - lcm->mapping_pool;
1490
1491 /* enable pitr mode */
1492 lcm->lisp_pitr = 1;
1493 }
1494 else
1495 {
1496 /* remove pitr mapping */
1497 pool_put_index (lcm->mapping_pool, lcm->pitr_map_index);
1498
1499 /* disable pitr mode */
1500 lcm->lisp_pitr = 0;
1501 }
1502 return 0;
1503}
1504
Filip Tehlar7048ff12017-07-27 08:09:14 +02001505int
1506vnet_lisp_map_register_fallback_threshold_set (u32 value)
1507{
1508 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1509 if (0 == value)
1510 {
1511 return VNET_API_ERROR_INVALID_ARGUMENT;
1512 }
1513
1514 lcm->max_expired_map_registers = value;
1515 return 0;
1516}
1517
1518u32
1519vnet_lisp_map_register_fallback_threshold_get (void)
1520{
1521 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1522 return lcm->max_expired_map_registers;
1523}
1524
Florin Corasba888e42017-01-24 11:38:18 -08001525/**
1526 * Configure Proxy-ETR
1527 *
1528 * @param ip PETR's IP address
1529 * @param is_add Flag that indicates if this is an addition or removal
1530 *
1531 * return 0 on success
1532 */
1533int
1534vnet_lisp_use_petr (ip_address_t * ip, u8 is_add)
1535{
1536 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1537 u32 ls_index = ~0;
1538 mapping_t *m;
1539 vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
1540 locator_t loc;
1541
1542 if (vnet_lisp_enable_disable_status () == 0)
1543 {
1544 clib_warning ("LISP is disabled!");
1545 return VNET_API_ERROR_LISP_DISABLED;
1546 }
1547
1548 memset (ls_args, 0, sizeof (*ls_args));
1549
1550 if (is_add)
1551 {
1552 /* Create dummy petr locator-set */
Florin Corasb69259a2017-03-09 14:39:54 -08001553 memset (&loc, 0, sizeof (loc));
Florin Corasba888e42017-01-24 11:38:18 -08001554 gid_address_from_ip (&loc.address, ip);
1555 loc.priority = 1;
1556 loc.state = loc.weight = 1;
Florin Coras2743cc42017-01-29 16:42:20 -08001557 loc.local = 0;
Florin Corasba888e42017-01-24 11:38:18 -08001558
1559 ls_args->is_add = 1;
1560 ls_args->index = ~0;
1561 vec_add1 (ls_args->locators, loc);
1562 vnet_lisp_add_del_locator_set (ls_args, &ls_index);
1563
1564 /* Add petr mapping */
1565 pool_get (lcm->mapping_pool, m);
1566 m->locator_set_index = ls_index;
1567 lcm->petr_map_index = m - lcm->mapping_pool;
1568
1569 /* Enable use-petr */
1570 lcm->flags |= LISP_FLAG_USE_PETR;
1571 }
1572 else
1573 {
1574 m = pool_elt_at_index (lcm->mapping_pool, lcm->petr_map_index);
1575
1576 /* Remove petr locator */
1577 ls_args->is_add = 0;
1578 ls_args->index = m->locator_set_index;
1579 vnet_lisp_add_del_locator_set (ls_args, 0);
1580
1581 /* Remove petr mapping */
1582 pool_put_index (lcm->mapping_pool, lcm->petr_map_index);
1583
1584 /* Disable use-petr */
1585 lcm->flags &= ~LISP_FLAG_USE_PETR;
1586 }
1587 return 0;
1588}
1589
Florin Corase127a7e2016-02-18 22:20:01 +01001590/* cleans locator to locator-set data and removes locators not part of
1591 * any locator-set */
1592static void
1593clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
1594{
Filip Tehlard1c5cc32016-05-30 10:39:20 +02001595 u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
Florin Corasa2157cf2016-08-16 21:09:14 +02001596 locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool, lsi);
1597 for (i = 0; i < vec_len (ls->locator_indices); i++)
Florin Corase127a7e2016-02-18 22:20:01 +01001598 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001599 loc_indexp = vec_elt_at_index (ls->locator_indices, i);
1600 ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
1601 loc_indexp[0]);
1602 for (j = 0; j < vec_len (ls_indexes[0]); j++)
1603 {
1604 ls_indexp = vec_elt_at_index (ls_indexes[0], j);
1605 if (ls_indexp[0] == lsi)
1606 break;
1607 }
Florin Corase127a7e2016-02-18 22:20:01 +01001608
Florin Corasa2157cf2016-08-16 21:09:14 +02001609 /* delete index for removed locator-set */
1610 vec_del1 (ls_indexes[0], j);
Florin Corase127a7e2016-02-18 22:20:01 +01001611
1612 /* delete locator if it's part of no locator-set */
1613 if (vec_len (ls_indexes[0]) == 0)
Florin Corasa2157cf2016-08-16 21:09:14 +02001614 {
1615 pool_put_index (lcm->locator_pool, loc_indexp[0]);
1616 vec_add1 (to_be_deleted, i);
1617 }
Filip Tehlard1c5cc32016-05-30 10:39:20 +02001618 }
1619
1620 if (to_be_deleted)
1621 {
1622 for (i = 0; i < vec_len (to_be_deleted); i++)
Florin Corasa2157cf2016-08-16 21:09:14 +02001623 {
1624 loc_indexp = vec_elt_at_index (to_be_deleted, i);
1625 vec_del1 (ls->locator_indices, loc_indexp[0]);
1626 }
Filip Tehlard1c5cc32016-05-30 10:39:20 +02001627 vec_free (to_be_deleted);
Florin Corase127a7e2016-02-18 22:20:01 +01001628 }
1629}
Filip Tehlard1c5cc32016-05-30 10:39:20 +02001630
Florin Corasf727db92016-06-23 15:01:58 +02001631static inline uword *
1632get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p)
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001633{
Florin Corasa2157cf2016-08-16 21:09:14 +02001634 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001635
Florin Corasa2157cf2016-08-16 21:09:14 +02001636 ASSERT (a != NULL);
1637 ASSERT (p != NULL);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001638
1639 /* find locator-set */
1640 if (a->local)
1641 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001642 p = hash_get_mem (lcm->locator_set_index_by_name, a->name);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001643 }
1644 else
1645 {
1646 *p = a->index;
1647 }
1648
1649 return p;
1650}
1651
Florin Corasf727db92016-06-23 15:01:58 +02001652static inline int
1653is_locator_in_locator_set (lisp_cp_main_t * lcm, locator_set_t * ls,
Florin Corasa2157cf2016-08-16 21:09:14 +02001654 locator_t * loc)
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001655{
Florin Corasa2157cf2016-08-16 21:09:14 +02001656 locator_t *itloc;
1657 u32 *locit;
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001658
Florin Corasa2157cf2016-08-16 21:09:14 +02001659 ASSERT (ls != NULL);
1660 ASSERT (loc != NULL);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001661
Florin Corasa2157cf2016-08-16 21:09:14 +02001662 vec_foreach (locit, ls->locator_indices)
1663 {
1664 itloc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1665 if ((ls->local && itloc->sw_if_index == loc->sw_if_index) ||
1666 (!ls->local && !gid_address_cmp (&itloc->address, &loc->address)))
1667 {
1668 clib_warning ("Duplicate locator");
1669 return VNET_API_ERROR_VALUE_EXIST;
1670 }
1671 }
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001672
1673 return 0;
1674}
1675
Filip Tehlar68d2e242017-04-21 12:05:58 +02001676static void
1677update_adjacencies_by_map_index (lisp_cp_main_t * lcm, u8 is_local,
1678 u32 mapping_index, u8 remove_only)
1679{
1680 fwd_entry_t *fwd;
1681 mapping_t *map;
1682 vnet_lisp_add_del_adjacency_args_t _a, *a = &_a;
1683
1684 map = pool_elt_at_index (lcm->mapping_pool, mapping_index);
1685
1686 /* *INDENT-OFF* */
1687 pool_foreach(fwd, lcm->fwd_entry_pool,
1688 ({
1689 if ((is_local && 0 == gid_address_cmp (&map->eid, &fwd->leid)) ||
1690 (!is_local && 0 == gid_address_cmp (&map->eid, &fwd->reid)))
1691 {
1692 a->is_add = 0;
1693 gid_address_copy (&a->leid, &fwd->leid);
1694 gid_address_copy (&a->reid, &fwd->reid);
1695
1696 vnet_lisp_add_del_adjacency (a);
1697
1698 if (!remove_only)
1699 {
1700 a->is_add = 1;
1701 vnet_lisp_add_del_adjacency (a);
1702 }
1703 }
1704 }));
1705 /* *INDENT-ON* */
1706}
1707
1708static void
1709update_fwd_entries_by_locator_set (lisp_cp_main_t * lcm, u8 is_local,
1710 u32 ls_index, u8 remove_only)
1711{
1712 u32 i, *map_indexp;
1713 u32 **eid_indexes;
Filip Tehlarfacee282017-04-27 14:29:27 +02001714
1715 if (vec_len (lcm->locator_set_to_eids) <= ls_index)
1716 return;
1717
Filip Tehlar68d2e242017-04-21 12:05:58 +02001718 eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids, ls_index);
1719
1720 for (i = 0; i < vec_len (eid_indexes[0]); i++)
1721 {
1722 map_indexp = vec_elt_at_index (eid_indexes[0], i);
1723 update_adjacencies_by_map_index (lcm, is_local, map_indexp[0],
1724 remove_only);
1725 }
1726}
1727
Florin Corasf727db92016-06-23 15:01:58 +02001728static inline void
Florin Corasa2157cf2016-08-16 21:09:14 +02001729remove_locator_from_locator_set (locator_set_t * ls, u32 * locit,
1730 u32 ls_index, u32 loc_id)
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001731{
Florin Corasa2157cf2016-08-16 21:09:14 +02001732 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1733 u32 **ls_indexes = NULL;
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001734
Florin Corasa2157cf2016-08-16 21:09:14 +02001735 ASSERT (ls != NULL);
1736 ASSERT (locit != NULL);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001737
Florin Corasa2157cf2016-08-16 21:09:14 +02001738 ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets, locit[0]);
1739 pool_put_index (lcm->locator_pool, locit[0]);
1740 vec_del1 (ls->locator_indices, loc_id);
1741 vec_del1 (ls_indexes[0], ls_index);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001742}
1743
1744int
1745vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
Florin Corasa2157cf2016-08-16 21:09:14 +02001746 locator_set_t * ls, u32 * ls_result)
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001747{
Florin Corasa2157cf2016-08-16 21:09:14 +02001748 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1749 locator_t *loc = NULL, *itloc = NULL;
1750 uword _p = (u32) ~ 0, *p = &_p;
1751 u32 loc_index = ~0, ls_index = ~0, *locit = NULL, **ls_indexes = NULL;
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001752 u32 loc_id = ~0;
1753 int ret = 0;
1754
Florin Corasa2157cf2016-08-16 21:09:14 +02001755 ASSERT (a != NULL);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001756
Andrej Kozemcak8ebb2a12016-06-07 12:25:20 +02001757 if (vnet_lisp_enable_disable_status () == 0)
1758 {
1759 clib_warning ("LISP is disabled!");
1760 return VNET_API_ERROR_LISP_DISABLED;
1761 }
1762
Florin Corasa2157cf2016-08-16 21:09:14 +02001763 p = get_locator_set_index (a, p);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001764 if (!p)
1765 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001766 clib_warning ("locator-set %v doesn't exist", a->name);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001767 return VNET_API_ERROR_INVALID_ARGUMENT;
1768 }
1769
1770 if (ls == 0)
1771 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001772 ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001773 if (!ls)
Florin Corasa2157cf2016-08-16 21:09:14 +02001774 {
1775 clib_warning ("locator-set %d to be overwritten doesn't exist!",
1776 p[0]);
1777 return VNET_API_ERROR_INVALID_ARGUMENT;
1778 }
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001779 }
1780
1781 if (a->is_add)
1782 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001783 if (ls_result)
1784 ls_result[0] = p[0];
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001785
Florin Corasa2157cf2016-08-16 21:09:14 +02001786 /* allocate locators */
1787 vec_foreach (itloc, a->locators)
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001788 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001789 ret = is_locator_in_locator_set (lcm, ls, itloc);
1790 if (0 != ret)
1791 {
1792 return ret;
1793 }
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001794
Florin Corasa2157cf2016-08-16 21:09:14 +02001795 pool_get (lcm->locator_pool, loc);
1796 loc[0] = itloc[0];
1797 loc_index = loc - lcm->locator_pool;
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001798
Florin Corasa2157cf2016-08-16 21:09:14 +02001799 vec_add1 (ls->locator_indices, loc_index);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001800
Florin Corasa2157cf2016-08-16 21:09:14 +02001801 vec_validate (lcm->locator_to_locator_sets, loc_index);
1802 ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
1803 loc_index);
Filip Tehlarc5bb0d62016-09-02 12:14:31 +02001804 vec_add1 (ls_indexes[0], p[0]);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001805 }
Florin Corasa2157cf2016-08-16 21:09:14 +02001806 }
1807 else
1808 {
1809 ls_index = p[0];
Filip Tehlar68d2e242017-04-21 12:05:58 +02001810 u8 removed;
Florin Corasa2157cf2016-08-16 21:09:14 +02001811
Filip Tehlar68d2e242017-04-21 12:05:58 +02001812 vec_foreach (itloc, a->locators)
Florin Corasa2157cf2016-08-16 21:09:14 +02001813 {
Filip Tehlar68d2e242017-04-21 12:05:58 +02001814 removed = 0;
1815 loc_id = 0;
1816 vec_foreach (locit, ls->locator_indices)
1817 {
1818 loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
Florin Corasa2157cf2016-08-16 21:09:14 +02001819
Filip Tehlar68d2e242017-04-21 12:05:58 +02001820 if (loc->local && loc->sw_if_index == itloc->sw_if_index)
1821 {
1822 removed = 1;
1823 remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
1824 }
1825 if (0 == loc->local &&
1826 !gid_address_cmp (&loc->address, &itloc->address))
1827 {
1828 removed = 1;
1829 remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
1830 }
Florin Corasa2157cf2016-08-16 21:09:14 +02001831
Filip Tehlar68d2e242017-04-21 12:05:58 +02001832 if (removed)
1833 {
1834 /* update fwd entries using this locator in DP */
1835 update_fwd_entries_by_locator_set (lcm, loc->local, ls_index,
1836 vec_len (ls->locator_indices)
1837 == 0);
1838 }
1839
1840 loc_id++;
1841 }
Florin Corasa2157cf2016-08-16 21:09:14 +02001842 }
1843 }
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001844
1845 return 0;
1846}
1847
Florin Corase127a7e2016-02-18 22:20:01 +01001848int
1849vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
Florin Corasa2157cf2016-08-16 21:09:14 +02001850 u32 * ls_result)
Florin Corase127a7e2016-02-18 22:20:01 +01001851{
Florin Corasa2157cf2016-08-16 21:09:14 +02001852 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1853 locator_set_t *ls;
1854 uword _p = (u32) ~ 0, *p = &_p;
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001855 u32 ls_index;
Florin Corasa2157cf2016-08-16 21:09:14 +02001856 u32 **eid_indexes;
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001857 int ret = 0;
Florin Corase127a7e2016-02-18 22:20:01 +01001858
Andrej Kozemcak8ebb2a12016-06-07 12:25:20 +02001859 if (vnet_lisp_enable_disable_status () == 0)
1860 {
1861 clib_warning ("LISP is disabled!");
1862 return VNET_API_ERROR_LISP_DISABLED;
1863 }
1864
Florin Corase127a7e2016-02-18 22:20:01 +01001865 if (a->is_add)
1866 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001867 p = get_locator_set_index (a, p);
Florin Corase127a7e2016-02-18 22:20:01 +01001868
1869 /* overwrite */
Florin Corasa2157cf2016-08-16 21:09:14 +02001870 if (p && p[0] != (u32) ~ 0)
1871 {
1872 ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
1873 if (!ls)
1874 {
1875 clib_warning ("locator-set %d to be overwritten doesn't exist!",
1876 p[0]);
1877 return -1;
1878 }
Florin Corase127a7e2016-02-18 22:20:01 +01001879
Florin Corasa2157cf2016-08-16 21:09:14 +02001880 /* clean locator to locator-set vectors and remove locators if
1881 * they're not part of another locator-set */
1882 clean_locator_to_locator_set (lcm, p[0]);
Florin Corase127a7e2016-02-18 22:20:01 +01001883
Florin Corasa2157cf2016-08-16 21:09:14 +02001884 /* remove locator indices from locator set */
1885 vec_free (ls->locator_indices);
Florin Corase127a7e2016-02-18 22:20:01 +01001886
Florin Corasa2157cf2016-08-16 21:09:14 +02001887 ls_index = p[0];
Florin Corase127a7e2016-02-18 22:20:01 +01001888
Florin Corasa2157cf2016-08-16 21:09:14 +02001889 if (ls_result)
1890 ls_result[0] = p[0];
1891 }
Florin Corase127a7e2016-02-18 22:20:01 +01001892 /* new locator-set */
1893 else
Florin Corasa2157cf2016-08-16 21:09:14 +02001894 {
1895 pool_get (lcm->locator_set_pool, ls);
1896 memset (ls, 0, sizeof (*ls));
1897 ls_index = ls - lcm->locator_set_pool;
Florin Corase127a7e2016-02-18 22:20:01 +01001898
Florin Corasa2157cf2016-08-16 21:09:14 +02001899 if (a->local)
1900 {
1901 ls->name = vec_dup (a->name);
Florin Corase127a7e2016-02-18 22:20:01 +01001902
Florin Corasa2157cf2016-08-16 21:09:14 +02001903 if (!lcm->locator_set_index_by_name)
1904 lcm->locator_set_index_by_name = hash_create_vec (
1905 /* size */
1906 0,
1907 sizeof
1908 (ls->name
1909 [0]),
1910 sizeof
1911 (uword));
1912 hash_set_mem (lcm->locator_set_index_by_name, ls->name,
1913 ls_index);
Florin Corase127a7e2016-02-18 22:20:01 +01001914
Florin Corasa2157cf2016-08-16 21:09:14 +02001915 /* mark as local locator-set */
1916 vec_add1 (lcm->local_locator_set_indexes, ls_index);
1917 }
1918 ls->local = a->local;
1919 if (ls_result)
1920 ls_result[0] = ls_index;
1921 }
Florin Corase127a7e2016-02-18 22:20:01 +01001922
Florin Corasa2157cf2016-08-16 21:09:14 +02001923 ret = vnet_lisp_add_del_locator (a, ls, NULL);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001924 if (0 != ret)
Florin Corasa2157cf2016-08-16 21:09:14 +02001925 {
1926 return ret;
1927 }
Florin Corase127a7e2016-02-18 22:20:01 +01001928 }
1929 else
1930 {
Florin Corasa2157cf2016-08-16 21:09:14 +02001931 p = get_locator_set_index (a, p);
Andrej Kozemcak6a2e4392016-05-26 12:20:08 +02001932 if (!p)
Florin Corasa2157cf2016-08-16 21:09:14 +02001933 {
1934 clib_warning ("locator-set %v doesn't exists", a->name);
1935 return -1;
1936 }
Florin Corase127a7e2016-02-18 22:20:01 +01001937
Florin Corasa2157cf2016-08-16 21:09:14 +02001938 ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
Florin Corase127a7e2016-02-18 22:20:01 +01001939 if (!ls)
Florin Corasa2157cf2016-08-16 21:09:14 +02001940 {
1941 clib_warning ("locator-set with index %d doesn't exists", p[0]);
1942 return -1;
1943 }
Florin Corase127a7e2016-02-18 22:20:01 +01001944
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02001945 if (lcm->mreq_itr_rlocs == p[0])
Florin Corasa2157cf2016-08-16 21:09:14 +02001946 {
1947 clib_warning ("Can't delete the locator-set used to constrain "
1948 "the itr-rlocs in map-requests!");
1949 return -1;
1950 }
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02001951
Florin Corasa2157cf2016-08-16 21:09:14 +02001952 if (vec_len (lcm->locator_set_to_eids) != 0)
1953 {
1954 eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids, p[0]);
1955 if (vec_len (eid_indexes[0]) != 0)
1956 {
1957 clib_warning
1958 ("Can't delete a locator that supports a mapping!");
1959 return -1;
1960 }
1961 }
Andrej Kozemcakb92feb62016-03-31 13:51:42 +02001962
1963 /* clean locator to locator-sets data */
1964 clean_locator_to_locator_set (lcm, p[0]);
1965
1966 if (ls->local)
Florin Corasa2157cf2016-08-16 21:09:14 +02001967 {
1968 u32 it, lsi;
Andrej Kozemcakb92feb62016-03-31 13:51:42 +02001969
Florin Corasa2157cf2016-08-16 21:09:14 +02001970 vec_foreach_index (it, lcm->local_locator_set_indexes)
1971 {
1972 lsi = vec_elt (lcm->local_locator_set_indexes, it);
1973 if (lsi == p[0])
1974 {
1975 vec_del1 (lcm->local_locator_set_indexes, it);
1976 break;
1977 }
1978 }
1979 hash_unset_mem (lcm->locator_set_index_by_name, ls->name);
1980 }
1981 vec_free (ls->name);
1982 vec_free (ls->locator_indices);
1983 pool_put (lcm->locator_set_pool, ls);
Andrej Kozemcakb92feb62016-03-31 13:51:42 +02001984 }
1985 return 0;
1986}
1987
Filip Tehlar397fd7d2016-10-26 14:31:24 +02001988int
1989vnet_lisp_rloc_probe_enable_disable (u8 is_enable)
1990{
1991 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1992
1993 lcm->rloc_probing = is_enable;
1994 return 0;
1995}
1996
1997int
1998vnet_lisp_map_register_enable_disable (u8 is_enable)
1999{
2000 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2001
2002 lcm->map_registering = is_enable;
2003 return 0;
2004}
2005
Filip Tehlar46d4e362016-05-09 09:39:26 +02002006clib_error_t *
Florin Corasf727db92016-06-23 15:01:58 +02002007vnet_lisp_enable_disable (u8 is_enable)
Filip Tehlar46d4e362016-05-09 09:39:26 +02002008{
Florin Coras1a1adc72016-07-22 01:45:30 +02002009 u32 vni, dp_table;
Florin Corasa2157cf2016-08-16 21:09:14 +02002010 clib_error_t *error = 0;
2011 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2012 vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a;
Filip Tehlar46d4e362016-05-09 09:39:26 +02002013
Florin Corasf727db92016-06-23 15:01:58 +02002014 a->is_en = is_enable;
Filip Tehlar46d4e362016-05-09 09:39:26 +02002015 error = vnet_lisp_gpe_enable_disable (a);
2016 if (error)
2017 {
2018 return clib_error_return (0, "failed to %s data-plane!",
Florin Corasa2157cf2016-08-16 21:09:14 +02002019 a->is_en ? "enable" : "disable");
Filip Tehlar46d4e362016-05-09 09:39:26 +02002020 }
2021
Florin Corasf727db92016-06-23 15:01:58 +02002022 if (is_enable)
Filip Tehlar46d4e362016-05-09 09:39:26 +02002023 {
Florin Coras1a1adc72016-07-22 01:45:30 +02002024 /* enable all l2 and l3 ifaces */
Florin Corasa2157cf2016-08-16 21:09:14 +02002025
2026 /* *INDENT-OFF* */
Florin Coras1a1adc72016-07-22 01:45:30 +02002027 hash_foreach(vni, dp_table, lcm->table_id_by_vni, ({
2028 dp_add_del_iface(lcm, vni, 0, 1);
2029 }));
Florin Coras1a1adc72016-07-22 01:45:30 +02002030 hash_foreach(vni, dp_table, lcm->bd_id_by_vni, ({
2031 dp_add_del_iface(lcm, vni, /* is_l2 */ 1, 1);
Florin Corasf727db92016-06-23 15:01:58 +02002032 }));
Florin Corasa2157cf2016-08-16 21:09:14 +02002033 /* *INDENT-ON* */
Filip Tehlar46d4e362016-05-09 09:39:26 +02002034 }
2035 else
2036 {
Florin Corasf727db92016-06-23 15:01:58 +02002037 /* clear interface table */
Florin Corasa2157cf2016-08-16 21:09:14 +02002038 hash_free (lcm->fwd_entry_by_mapping_index);
2039 pool_free (lcm->fwd_entry_pool);
Filip Tehlar46d4e362016-05-09 09:39:26 +02002040 }
2041
2042 /* update global flag */
Florin Corasf727db92016-06-23 15:01:58 +02002043 lcm->is_enabled = is_enable;
Filip Tehlar46d4e362016-05-09 09:39:26 +02002044
2045 return 0;
2046}
2047
Filip Tehlar46d4e362016-05-09 09:39:26 +02002048u8
2049vnet_lisp_enable_disable_status (void)
2050{
Florin Corasa2157cf2016-08-16 21:09:14 +02002051 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlar46d4e362016-05-09 09:39:26 +02002052 return lcm->is_enabled;
2053}
2054
Florin Corase127a7e2016-02-18 22:20:01 +01002055int
2056vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
2057{
Florin Corasa2157cf2016-08-16 21:09:14 +02002058 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Florin Corase127a7e2016-02-18 22:20:01 +01002059 u32 i;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002060 lisp_msmr_t _mr, *mr = &_mr;
Florin Corase127a7e2016-02-18 22:20:01 +01002061
Andrej Kozemcak8ebb2a12016-06-07 12:25:20 +02002062 if (vnet_lisp_enable_disable_status () == 0)
2063 {
2064 clib_warning ("LISP is disabled!");
2065 return VNET_API_ERROR_LISP_DISABLED;
2066 }
2067
Florin Corase127a7e2016-02-18 22:20:01 +01002068 if (a->is_add)
2069 {
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002070
2071 if (get_map_resolver (&a->address))
Florin Corasa2157cf2016-08-16 21:09:14 +02002072 {
2073 clib_warning ("map-resolver %U already exists!", format_ip_address,
2074 &a->address);
2075 return -1;
2076 }
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002077
2078 memset (mr, 0, sizeof (*mr));
Florin Corasa2157cf2016-08-16 21:09:14 +02002079 ip_address_copy (&mr->address, &a->address);
2080 vec_add1 (lcm->map_resolvers, *mr);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002081
2082 if (vec_len (lcm->map_resolvers) == 1)
Florin Corasa2157cf2016-08-16 21:09:14 +02002083 lcm->do_map_resolver_election = 1;
Florin Corase127a7e2016-02-18 22:20:01 +01002084 }
2085 else
2086 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002087 for (i = 0; i < vec_len (lcm->map_resolvers); i++)
2088 {
2089 mr = vec_elt_at_index (lcm->map_resolvers, i);
2090 if (!ip_address_cmp (&mr->address, &a->address))
2091 {
2092 if (!ip_address_cmp (&mr->address, &lcm->active_map_resolver))
2093 lcm->do_map_resolver_election = 1;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002094
Florin Corasa2157cf2016-08-16 21:09:14 +02002095 vec_del1 (lcm->map_resolvers, i);
2096 break;
2097 }
2098 }
Florin Corase127a7e2016-02-18 22:20:01 +01002099 }
2100 return 0;
2101}
2102
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002103int
Filip Tehlar1e553a02017-08-02 12:45:07 +02002104vnet_lisp_map_register_set_ttl (u32 ttl)
2105{
2106 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2107 lcm->map_register_ttl = ttl;
2108 return 0;
2109}
2110
2111u32
2112vnet_lisp_map_register_get_ttl (void)
2113{
2114 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2115 return lcm->map_register_ttl;
2116}
2117
2118int
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002119vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
2120{
Florin Corasa2157cf2016-08-16 21:09:14 +02002121 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2122 uword *p = 0;
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002123
Florin Corasf727db92016-06-23 15:01:58 +02002124 if (vnet_lisp_enable_disable_status () == 0)
2125 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002126 clib_warning ("LISP is disabled!");
Florin Corasf727db92016-06-23 15:01:58 +02002127 return VNET_API_ERROR_LISP_DISABLED;
2128 }
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002129
2130 if (a->is_add)
2131 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002132 p = hash_get_mem (lcm->locator_set_index_by_name, a->locator_set_name);
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002133 if (!p)
Florin Corasa2157cf2016-08-16 21:09:14 +02002134 {
2135 clib_warning ("locator-set %v doesn't exist", a->locator_set_name);
2136 return VNET_API_ERROR_INVALID_ARGUMENT;
2137 }
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002138
2139 lcm->mreq_itr_rlocs = p[0];
2140 }
2141 else
2142 {
2143 lcm->mreq_itr_rlocs = ~0;
2144 }
2145
2146 return 0;
2147}
2148
Florin Corase127a7e2016-02-18 22:20:01 +01002149/* Statistics (not really errors) */
2150#define foreach_lisp_cp_lookup_error \
2151_(DROP, "drop") \
Filip Tehlard5a65db2017-05-17 17:21:10 +02002152_(MAP_REQUESTS_SENT, "map-request sent") \
2153_(ARP_REPLY_TX, "ARP replies sent")
Florin Corase127a7e2016-02-18 22:20:01 +01002154
Florin Corasa2157cf2016-08-16 21:09:14 +02002155static char *lisp_cp_lookup_error_strings[] = {
Florin Corase127a7e2016-02-18 22:20:01 +01002156#define _(sym,string) string,
2157 foreach_lisp_cp_lookup_error
2158#undef _
2159};
2160
2161typedef enum
2162{
2163#define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
Florin Corasa2157cf2016-08-16 21:09:14 +02002164 foreach_lisp_cp_lookup_error
Florin Corase127a7e2016-02-18 22:20:01 +01002165#undef _
2166 LISP_CP_LOOKUP_N_ERROR,
2167} lisp_cp_lookup_error_t;
2168
2169typedef enum
2170{
2171 LISP_CP_LOOKUP_NEXT_DROP,
Filip Tehlard5a65db2017-05-17 17:21:10 +02002172 LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX,
Florin Corase127a7e2016-02-18 22:20:01 +01002173 LISP_CP_LOOKUP_N_NEXT,
2174} lisp_cp_lookup_next_t;
2175
2176typedef struct
2177{
2178 gid_address_t dst_eid;
Andrej Kozemcak94e34762016-05-25 12:43:21 +02002179 ip_address_t map_resolver_ip;
Florin Corase127a7e2016-02-18 22:20:01 +01002180} lisp_cp_lookup_trace_t;
2181
2182u8 *
2183format_lisp_cp_lookup_trace (u8 * s, va_list * args)
2184{
2185 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2186 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Florin Corasa2157cf2016-08-16 21:09:14 +02002187 lisp_cp_lookup_trace_t *t = va_arg (*args, lisp_cp_lookup_trace_t *);
Florin Corase127a7e2016-02-18 22:20:01 +01002188
2189 s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
Florin Corasa2157cf2016-08-16 21:09:14 +02002190 format_ip_address, &t->map_resolver_ip, format_gid_address,
2191 &t->dst_eid);
Florin Corase127a7e2016-02-18 22:20:01 +01002192 return s;
2193}
2194
Florin Coras1c494842016-06-16 21:08:56 +02002195int
2196get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
Florin Corasa2157cf2016-08-16 21:09:14 +02002197 ip_address_t * sloc)
Florin Corasc2c90082016-06-13 18:37:15 +02002198{
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002199 lisp_msmr_t *mrit;
Florin Corasa2157cf2016-08-16 21:09:14 +02002200 ip_address_t *a;
Florin Corase127a7e2016-02-18 22:20:01 +01002201
Florin Corasa2157cf2016-08-16 21:09:14 +02002202 if (vec_len (lcm->map_resolvers) == 0)
Florin Corase127a7e2016-02-18 22:20:01 +01002203 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002204 clib_warning ("No map-resolver configured");
Florin Coras1c494842016-06-16 21:08:56 +02002205 return 0;
Florin Corase127a7e2016-02-18 22:20:01 +01002206 }
2207
Florin Corasddfafb82016-05-13 18:09:56 +02002208 /* find the first mr ip we have a route to and the ip of the
2209 * iface that has a route to it */
Florin Corasa2157cf2016-08-16 21:09:14 +02002210 vec_foreach (mrit, lcm->map_resolvers)
2211 {
2212 a = &mrit->address;
2213 if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, a, sloc))
2214 {
2215 ip_address_copy (mr_ip, a);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002216
Florin Corasa2157cf2016-08-16 21:09:14 +02002217 /* also update globals */
2218 return 1;
2219 }
2220 }
Florin Corasddfafb82016-05-13 18:09:56 +02002221
Florin Corasa2157cf2016-08-16 21:09:14 +02002222 clib_warning ("Can't find map-resolver and local interface ip!");
Florin Coras1c494842016-06-16 21:08:56 +02002223 return 0;
Florin Corasddfafb82016-05-13 18:09:56 +02002224}
Filip Tehlar254b0362016-04-07 10:04:34 +02002225
Filip Tehlarbeceab92016-04-20 17:21:55 +02002226static gid_address_t *
Filip Tehlar254b0362016-04-07 10:04:34 +02002227build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
2228{
Florin Corasa2157cf2016-08-16 21:09:14 +02002229 void *addr;
Filip Tehlar254b0362016-04-07 10:04:34 +02002230 u32 i;
Florin Corasa2157cf2016-08-16 21:09:14 +02002231 locator_t *loc;
2232 u32 *loc_indexp;
2233 ip_interface_address_t *ia = 0;
2234 gid_address_t gid_data, *gid = &gid_data;
2235 gid_address_t *rlocs = 0;
2236 ip_prefix_t *ippref = &gid_address_ippref (gid);
2237 ip_address_t *rloc = &ip_prefix_addr (ippref);
Filip Tehlar254b0362016-04-07 10:04:34 +02002238
Filip Tehlar324112f2016-06-02 16:07:38 +02002239 memset (gid, 0, sizeof (gid[0]));
Filip Tehlarbeceab92016-04-20 17:21:55 +02002240 gid_address_type (gid) = GID_ADDR_IP_PREFIX;
Florin Corasa2157cf2016-08-16 21:09:14 +02002241 for (i = 0; i < vec_len (loc_set->locator_indices); i++)
Filip Tehlar254b0362016-04-07 10:04:34 +02002242 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002243 loc_indexp = vec_elt_at_index (loc_set->locator_indices, i);
Filip Tehlar254b0362016-04-07 10:04:34 +02002244 loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
2245
Filip Tehlar254b0362016-04-07 10:04:34 +02002246 /* Add ipv4 locators first TODO sort them */
Florin Corasa2157cf2016-08-16 21:09:14 +02002247
2248 /* *INDENT-OFF* */
Filip Tehlar254b0362016-04-07 10:04:34 +02002249 foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2250 loc->sw_if_index, 1 /* unnumbered */,
2251 ({
Florin Coras1c494842016-06-16 21:08:56 +02002252 addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
2253 ip_address_set (rloc, addr, IP4);
Florin Corasddfafb82016-05-13 18:09:56 +02002254 ip_prefix_len (ippref) = 32;
Andrej Kozemcak438109d2016-07-22 12:54:12 +02002255 ip_prefix_normalize (ippref);
Filip Tehlarbeceab92016-04-20 17:21:55 +02002256 vec_add1 (rlocs, gid[0]);
Filip Tehlar254b0362016-04-07 10:04:34 +02002257 }));
2258
Filip Tehlar254b0362016-04-07 10:04:34 +02002259 /* Add ipv6 locators */
2260 foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2261 loc->sw_if_index, 1 /* unnumbered */,
2262 ({
Florin Coras1c494842016-06-16 21:08:56 +02002263 addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
2264 ip_address_set (rloc, addr, IP6);
Florin Corasddfafb82016-05-13 18:09:56 +02002265 ip_prefix_len (ippref) = 128;
Andrej Kozemcak438109d2016-07-22 12:54:12 +02002266 ip_prefix_normalize (ippref);
Filip Tehlarbeceab92016-04-20 17:21:55 +02002267 vec_add1 (rlocs, gid[0]);
Filip Tehlar254b0362016-04-07 10:04:34 +02002268 }));
Florin Corasa2157cf2016-08-16 21:09:14 +02002269 /* *INDENT-ON* */
2270
Filip Tehlar254b0362016-04-07 10:04:34 +02002271 }
2272 return rlocs;
2273}
2274
Florin Corase127a7e2016-02-18 22:20:01 +01002275static vlib_buffer_t *
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002276build_map_request (lisp_cp_main_t * lcm, gid_address_t * deid,
2277 ip_address_t * sloc, ip_address_t * rloc,
2278 gid_address_t * itr_rlocs, u64 * nonce_res, u32 * bi_res)
2279{
2280 vlib_buffer_t *b;
2281 u32 bi;
2282 vlib_main_t *vm = lcm->vlib_main;
2283
2284 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2285 {
2286 clib_warning ("Can't allocate buffer for Map-Request!");
2287 return 0;
2288 }
2289
2290 b = vlib_get_buffer (vm, bi);
2291
2292 /* leave some space for the encap headers */
2293 vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2294
2295 /* put lisp msg */
2296 lisp_msg_put_mreq (lcm, b, NULL, deid, itr_rlocs, 0 /* smr invoked */ ,
2297 1 /* rloc probe */ , nonce_res);
2298
2299 /* push outer ip header */
2300 pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
Florin Corasfdbc3822017-07-27 00:34:12 -07002301 rloc, 1);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002302
2303 bi_res[0] = bi;
2304
2305 return b;
2306}
2307
2308static vlib_buffer_t *
Florin Corasa2157cf2016-08-16 21:09:14 +02002309build_encapsulated_map_request (lisp_cp_main_t * lcm,
2310 gid_address_t * seid, gid_address_t * deid,
2311 locator_set_t * loc_set, ip_address_t * mr_ip,
2312 ip_address_t * sloc, u8 is_smr_invoked,
2313 u64 * nonce_res, u32 * bi_res)
Florin Corase127a7e2016-02-18 22:20:01 +01002314{
Florin Corasa2157cf2016-08-16 21:09:14 +02002315 vlib_buffer_t *b;
Florin Corase127a7e2016-02-18 22:20:01 +01002316 u32 bi;
Florin Corasa2157cf2016-08-16 21:09:14 +02002317 gid_address_t *rlocs = 0;
2318 vlib_main_t *vm = lcm->vlib_main;
Florin Corase127a7e2016-02-18 22:20:01 +01002319
2320 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2321 {
2322 clib_warning ("Can't allocate buffer for Map-Request!");
2323 return 0;
2324 }
2325
2326 b = vlib_get_buffer (vm, bi);
Florin Corasfdbc3822017-07-27 00:34:12 -07002327 b->flags = 0;
Florin Corase127a7e2016-02-18 22:20:01 +01002328
2329 /* leave some space for the encap headers */
2330 vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2331
Filip Tehlar254b0362016-04-07 10:04:34 +02002332 /* get rlocs */
2333 rlocs = build_itr_rloc_list (lcm, loc_set);
2334
Filip Tehlard5fcc462016-10-17 16:20:18 +02002335 if (MR_MODE_SRC_DST == lcm->map_request_mode
2336 && GID_ADDR_SRC_DST != gid_address_type (deid))
Florin Corasdca88042016-09-14 16:01:38 +02002337 {
2338 gid_address_t sd;
2339 memset (&sd, 0, sizeof (sd));
2340 build_src_dst (&sd, seid, deid);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002341 lisp_msg_put_mreq (lcm, b, seid, &sd, rlocs, is_smr_invoked,
2342 0 /* rloc probe */ , nonce_res);
Florin Corasdca88042016-09-14 16:01:38 +02002343 }
2344 else
2345 {
2346 /* put lisp msg */
2347 lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked,
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002348 0 /* rloc probe */ , nonce_res);
Florin Corasdca88042016-09-14 16:01:38 +02002349 }
Florin Corase127a7e2016-02-18 22:20:01 +01002350
2351 /* push ecm: udp-ip-lisp */
2352 lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
2353
Florin Corase127a7e2016-02-18 22:20:01 +01002354 /* push outer ip header */
Florin Corasddfafb82016-05-13 18:09:56 +02002355 pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
Florin Corasfdbc3822017-07-27 00:34:12 -07002356 mr_ip, 1);
Florin Corase127a7e2016-02-18 22:20:01 +01002357
2358 bi_res[0] = bi;
Filip Tehlar254b0362016-04-07 10:04:34 +02002359
Florin Corasa2157cf2016-08-16 21:09:14 +02002360 vec_free (rlocs);
Florin Corase127a7e2016-02-18 22:20:01 +01002361 return b;
2362}
2363
2364static void
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002365reset_pending_mr_counters (pending_map_request_t * r)
Florin Corase127a7e2016-02-18 22:20:01 +01002366{
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002367 r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
2368 r->retries_num = 0;
2369}
2370
Filip Tehlar7048ff12017-07-27 08:09:14 +02002371#define foreach_msmr \
2372 _(server) \
2373 _(resolver)
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002374
Filip Tehlar7048ff12017-07-27 08:09:14 +02002375#define _(name) \
2376static int \
2377elect_map_ ## name (lisp_cp_main_t * lcm) \
2378{ \
2379 lisp_msmr_t *mr; \
2380 vec_foreach (mr, lcm->map_ ## name ## s) \
2381 { \
2382 if (!mr->is_down) \
2383 { \
2384 ip_address_copy (&lcm->active_map_ ##name, &mr->address); \
2385 lcm->do_map_ ## name ## _election = 0; \
2386 return 1; \
2387 } \
2388 } \
2389 return 0; \
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002390}
Filip Tehlar7048ff12017-07-27 08:09:14 +02002391foreach_msmr
2392#undef _
2393 static void
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002394free_map_register_records (mapping_t * maps)
2395{
2396 mapping_t *map;
2397 vec_foreach (map, maps) vec_free (map->locators);
2398
2399 vec_free (maps);
2400}
2401
2402static void
2403add_locators (lisp_cp_main_t * lcm, mapping_t * m, u32 locator_set_index,
2404 ip_address_t * probed_loc)
2405{
2406 u32 *li;
2407 locator_t *loc, new;
2408 ip_interface_address_t *ia = 0;
2409 void *addr;
2410 ip_address_t *new_ip = &gid_address_ip (&new.address);
2411
2412 m->locators = 0;
2413 locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool,
2414 locator_set_index);
2415 vec_foreach (li, ls->locator_indices)
2416 {
2417 loc = pool_elt_at_index (lcm->locator_pool, li[0]);
2418 new = loc[0];
2419 if (loc->local)
2420 {
2421 /* *INDENT-OFF* */
2422 foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2423 loc->sw_if_index, 1 /* unnumbered */,
2424 ({
2425 addr = ip_interface_address_get_address (&lcm->im4->lookup_main,
2426 ia);
2427 ip_address_set (new_ip, addr, IP4);
2428 }));
2429
2430 /* Add ipv6 locators */
2431 foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2432 loc->sw_if_index, 1 /* unnumbered */,
2433 ({
2434 addr = ip_interface_address_get_address (&lcm->im6->lookup_main,
2435 ia);
2436 ip_address_set (new_ip, addr, IP6);
2437 }));
2438 /* *INDENT-ON* */
2439
2440 if (probed_loc && ip_address_cmp (probed_loc, new_ip) == 0)
2441 new.probed = 1;
2442 }
2443 vec_add1 (m->locators, new);
2444 }
2445}
2446
2447static mapping_t *
2448build_map_register_record_list (lisp_cp_main_t * lcm)
2449{
2450 mapping_t *recs = 0, rec, *m;
2451
2452 /* *INDENT-OFF* */
2453 pool_foreach(m, lcm->mapping_pool,
2454 {
2455 /* for now build only local mappings */
2456 if (!m->local)
2457 continue;
2458
2459 rec = m[0];
2460 add_locators (lcm, &rec, m->locator_set_index, NULL);
2461 vec_add1 (recs, rec);
2462 });
2463 /* *INDENT-ON* */
2464
2465 return recs;
2466}
2467
2468static int
2469update_map_register_auth_data (map_register_hdr_t * map_reg_hdr,
2470 lisp_key_type_t key_id, u8 * key,
2471 u16 auth_data_len, u32 msg_len)
2472{
2473 MREG_KEY_ID (map_reg_hdr) = clib_host_to_net_u16 (key_id);
2474 MREG_AUTH_DATA_LEN (map_reg_hdr) = clib_host_to_net_u16 (auth_data_len);
2475
2476 unsigned char *result = HMAC (get_encrypt_fcn (key_id), key, vec_len (key),
2477 (unsigned char *) map_reg_hdr, msg_len, NULL,
2478 NULL);
2479 clib_memcpy (MREG_DATA (map_reg_hdr), result, auth_data_len);
2480
2481 return 0;
2482}
2483
2484static vlib_buffer_t *
2485build_map_register (lisp_cp_main_t * lcm, ip_address_t * sloc,
2486 ip_address_t * ms_ip, u64 * nonce_res, u8 want_map_notif,
2487 mapping_t * records, lisp_key_type_t key_id, u8 * key,
2488 u32 * bi_res)
2489{
2490 void *map_reg_hdr;
2491 vlib_buffer_t *b;
2492 u32 bi, auth_data_len = 0, msg_len = 0;
2493 vlib_main_t *vm = lcm->vlib_main;
2494
2495 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2496 {
2497 clib_warning ("Can't allocate buffer for Map-Register!");
2498 return 0;
2499 }
2500
2501 b = vlib_get_buffer (vm, bi);
2502
2503 /* leave some space for the encap headers */
2504 vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2505
2506 auth_data_len = auth_data_len_by_key_id (key_id);
2507 map_reg_hdr = lisp_msg_put_map_register (b, records, want_map_notif,
2508 auth_data_len, nonce_res,
2509 &msg_len);
2510
2511 update_map_register_auth_data (map_reg_hdr, key_id, key, auth_data_len,
2512 msg_len);
2513
2514 /* push outer ip header */
2515 pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
Florin Corasfdbc3822017-07-27 00:34:12 -07002516 ms_ip, 1);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002517
2518 bi_res[0] = bi;
2519 return b;
2520}
2521
Filip Tehlar7048ff12017-07-27 08:09:14 +02002522#define _(name) \
2523static int \
2524get_egress_map_ ##name## _ip (lisp_cp_main_t * lcm, ip_address_t * ip) \
2525{ \
2526 lisp_msmr_t *mr; \
2527 while (lcm->do_map_ ## name ## _election \
2528 | (0 == ip_fib_get_first_egress_ip_for_dst \
2529 (lcm, &lcm->active_map_ ##name, ip))) \
2530 { \
2531 if (0 == elect_map_ ## name (lcm)) \
2532 /* all map resolvers/servers are down */ \
2533 { \
2534 /* restart MR/MS checking by marking all of them up */ \
2535 vec_foreach (mr, lcm->map_ ## name ## s) mr->is_down = 0; \
2536 return -1; \
2537 } \
2538 } \
2539 return 0; \
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002540}
2541
Filip Tehlar7048ff12017-07-27 08:09:14 +02002542foreach_msmr
2543#undef _
Filip Tehlarcda70662017-01-16 10:30:03 +01002544/* CP output statistics */
2545#define foreach_lisp_cp_output_error \
2546_(MAP_REGISTERS_SENT, "map-registers sent") \
2547_(RLOC_PROBES_SENT, "rloc-probes sent")
Filip Tehlarcda70662017-01-16 10:30:03 +01002548static char *lisp_cp_output_error_strings[] = {
2549#define _(sym,string) string,
2550 foreach_lisp_cp_output_error
2551#undef _
2552};
2553
2554typedef enum
2555{
2556#define _(sym,str) LISP_CP_OUTPUT_ERROR_##sym,
2557 foreach_lisp_cp_output_error
2558#undef _
2559 LISP_CP_OUTPUT_N_ERROR,
2560} lisp_cp_output_error_t;
2561
2562static uword
2563lisp_cp_output (vlib_main_t * vm, vlib_node_runtime_t * node,
2564 vlib_frame_t * from_frame)
2565{
2566 return 0;
2567}
2568
2569/* dummy node used only for statistics */
2570/* *INDENT-OFF* */
2571VLIB_REGISTER_NODE (lisp_cp_output_node) = {
2572 .function = lisp_cp_output,
2573 .name = "lisp-cp-output",
2574 .vector_size = sizeof (u32),
2575 .format_trace = format_lisp_cp_input_trace,
2576 .type = VLIB_NODE_TYPE_INTERNAL,
2577
2578 .n_errors = LISP_CP_OUTPUT_N_ERROR,
2579 .error_strings = lisp_cp_output_error_strings,
2580
2581 .n_next_nodes = LISP_CP_INPUT_N_NEXT,
2582
2583 .next_nodes = {
2584 [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
2585 },
2586};
2587/* *INDENT-ON* */
2588
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002589static int
2590send_rloc_probe (lisp_cp_main_t * lcm, gid_address_t * deid,
2591 u32 local_locator_set_index, ip_address_t * sloc,
2592 ip_address_t * rloc)
2593{
2594 locator_set_t *ls;
2595 u32 bi;
2596 vlib_buffer_t *b;
2597 vlib_frame_t *f;
2598 u64 nonce = 0;
2599 u32 next_index, *to_next;
2600 gid_address_t *itr_rlocs;
2601
2602 ls = pool_elt_at_index (lcm->locator_set_pool, local_locator_set_index);
2603 itr_rlocs = build_itr_rloc_list (lcm, ls);
2604
2605 b = build_map_request (lcm, deid, sloc, rloc, itr_rlocs, &nonce, &bi);
2606 vec_free (itr_rlocs);
2607 if (!b)
2608 return -1;
2609
2610 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
2611
Filip Tehlar272c69e2017-02-15 16:40:35 +01002612 next_index = (ip_addr_version (rloc) == IP4) ?
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002613 ip4_lookup_node.index : ip6_lookup_node.index;
2614
2615 f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
2616
2617 /* Enqueue the packet */
2618 to_next = vlib_frame_vector_args (f);
2619 to_next[0] = bi;
2620 f->n_vectors = 1;
2621 vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
2622
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002623 return 0;
2624}
2625
2626static int
2627send_rloc_probes (lisp_cp_main_t * lcm)
2628{
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002629 u8 lprio = 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002630 mapping_t *lm;
2631 fwd_entry_t *e;
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002632 locator_pair_t *lp;
Filip Tehlarcda70662017-01-16 10:30:03 +01002633 u32 si, rloc_probes_sent = 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002634
2635 /* *INDENT-OFF* */
2636 pool_foreach (e, lcm->fwd_entry_pool,
2637 {
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002638 if (vec_len (e->locator_pairs) == 0)
2639 continue;
2640
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002641 si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &e->leid);
2642 if (~0 == si)
2643 {
2644 clib_warning ("internal error: cannot find local eid %U in "
2645 "map-cache!", format_gid_address, &e->leid);
2646 continue;
2647 }
2648 lm = pool_elt_at_index (lcm->mapping_pool, si);
2649
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002650 /* get the best (lowest) priority */
2651 lprio = e->locator_pairs[0].priority;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002652
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002653 /* send rloc-probe for pair(s) with the best remote locator priority */
2654 vec_foreach (lp, e->locator_pairs)
2655 {
2656 if (lp->priority != lprio)
2657 break;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002658
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002659 /* get first remote locator */
2660 send_rloc_probe (lcm, &e->reid, lm->locator_set_index, &lp->lcl_loc,
2661 &lp->rmt_loc);
Filip Tehlarcda70662017-01-16 10:30:03 +01002662 rloc_probes_sent++;
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002663 }
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002664 });
2665 /* *INDENT-ON* */
2666
Filip Tehlarcda70662017-01-16 10:30:03 +01002667 vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
2668 LISP_CP_OUTPUT_ERROR_RLOC_PROBES_SENT,
2669 rloc_probes_sent);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002670 return 0;
2671}
2672
2673static int
2674send_map_register (lisp_cp_main_t * lcm, u8 want_map_notif)
2675{
Filip Tehlar7048ff12017-07-27 08:09:14 +02002676 pending_map_register_t *pmr;
Filip Tehlarcda70662017-01-16 10:30:03 +01002677 u32 bi, map_registers_sent = 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002678 vlib_buffer_t *b;
2679 ip_address_t sloc;
2680 vlib_frame_t *f;
2681 u64 nonce = 0;
2682 u32 next_index, *to_next;
Filip Tehlarcf121c82017-05-03 10:12:44 +02002683 mapping_t *records, *r, *group, *k;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002684
Filip Tehlar7048ff12017-07-27 08:09:14 +02002685 if (get_egress_map_server_ip (lcm, &sloc) < 0)
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002686 return -1;
2687
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002688 records = build_map_register_record_list (lcm);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002689 if (!records)
2690 return -1;
2691
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002692 vec_foreach (r, records)
2693 {
2694 u8 *key = r->key;
2695 u8 key_id = r->key_id;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002696
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002697 if (!key)
2698 continue; /* no secret key -> map-register cannot be sent */
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002699
Filip Tehlarcf121c82017-05-03 10:12:44 +02002700 group = 0;
2701 vec_add1 (group, r[0]);
2702
2703 /* group mappings that share common key */
2704 for (k = r + 1; k < vec_end (records); k++)
2705 {
2706 if (k->key_id != r->key_id)
2707 continue;
2708
2709 if (vec_is_equal (k->key, r->key))
2710 {
2711 vec_add1 (group, k[0]);
2712 k->key = 0; /* don't process this mapping again */
2713 }
2714 }
2715
Filip Tehlar7048ff12017-07-27 08:09:14 +02002716 b = build_map_register (lcm, &sloc, &lcm->active_map_server, &nonce,
2717 want_map_notif, group, key_id, key, &bi);
Filip Tehlarcf121c82017-05-03 10:12:44 +02002718 vec_free (group);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002719 if (!b)
2720 continue;
2721
2722 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
2723
Filip Tehlar7048ff12017-07-27 08:09:14 +02002724 next_index = (ip_addr_version (&lcm->active_map_server) == IP4) ?
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002725 ip4_lookup_node.index : ip6_lookup_node.index;
2726
2727 f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
2728
2729 /* Enqueue the packet */
2730 to_next = vlib_frame_vector_args (f);
2731 to_next[0] = bi;
2732 f->n_vectors = 1;
2733 vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
Filip Tehlarcda70662017-01-16 10:30:03 +01002734 map_registers_sent++;
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002735
Filip Tehlar7048ff12017-07-27 08:09:14 +02002736 pool_get (lcm->pending_map_registers_pool, pmr);
2737 memset (pmr, 0, sizeof (*pmr));
2738 pmr->time_to_expire = PENDING_MREG_EXPIRATION_TIME;
2739 hash_set (lcm->map_register_messages_by_nonce, nonce,
2740 pmr - lcm->pending_map_registers_pool);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01002741 }
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002742 free_map_register_records (records);
2743
Filip Tehlarcda70662017-01-16 10:30:03 +01002744 vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
2745 LISP_CP_OUTPUT_ERROR_MAP_REGISTERS_SENT,
2746 map_registers_sent);
2747
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002748 return 0;
2749}
2750
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002751#define send_encapsulated_map_request(lcm, seid, deid, smr) \
2752 _send_encapsulated_map_request(lcm, seid, deid, smr, 0)
2753
2754#define resend_encapsulated_map_request(lcm, seid, deid, smr) \
2755 _send_encapsulated_map_request(lcm, seid, deid, smr, 1)
2756
2757static int
Florin Corasa2157cf2016-08-16 21:09:14 +02002758_send_encapsulated_map_request (lisp_cp_main_t * lcm,
2759 gid_address_t * seid, gid_address_t * deid,
2760 u8 is_smr_invoked, u8 is_resend)
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002761{
Florin Corasa2157cf2016-08-16 21:09:14 +02002762 u32 next_index, bi = 0, *to_next, map_index;
2763 vlib_buffer_t *b;
2764 vlib_frame_t *f;
Florin Corase127a7e2016-02-18 22:20:01 +01002765 u64 nonce = 0;
Florin Corasa2157cf2016-08-16 21:09:14 +02002766 locator_set_t *loc_set;
2767 mapping_t *map;
2768 pending_map_request_t *pmr, *duplicate_pmr = 0;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002769 ip_address_t sloc;
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002770 u32 ls_index;
Florin Corase127a7e2016-02-18 22:20:01 +01002771
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002772 /* if there is already a pending request remember it */
Florin Corasa2157cf2016-08-16 21:09:14 +02002773
2774 /* *INDENT-OFF* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002775 pool_foreach(pmr, lcm->pending_map_requests_pool,
2776 ({
2777 if (!gid_address_cmp (&pmr->src, seid)
2778 && !gid_address_cmp (&pmr->dst, deid))
2779 {
2780 duplicate_pmr = pmr;
2781 break;
2782 }
2783 }));
Florin Corasa2157cf2016-08-16 21:09:14 +02002784 /* *INDENT-ON* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002785
2786 if (!is_resend && duplicate_pmr)
2787 {
2788 /* don't send the request if there is a pending map request already */
2789 return 0;
2790 }
2791
Florin Corase127a7e2016-02-18 22:20:01 +01002792 /* get locator-set for seid */
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02002793 if (!lcm->lisp_pitr && gid_address_type (deid) != GID_ADDR_NSH)
Florin Corase127a7e2016-02-18 22:20:01 +01002794 {
Filip Tehlar53f09e32016-05-19 14:25:44 +02002795 map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
2796 if (map_index == ~0)
Florin Corasa2157cf2016-08-16 21:09:14 +02002797 {
2798 clib_warning ("No local mapping found in eid-table for %U!",
2799 format_gid_address, seid);
2800 return -1;
2801 }
Filip Tehlar53f09e32016-05-19 14:25:44 +02002802
2803 map = pool_elt_at_index (lcm->mapping_pool, map_index);
2804
2805 if (!map->local)
Florin Corasa2157cf2016-08-16 21:09:14 +02002806 {
2807 clib_warning
2808 ("Mapping found for src eid %U is not marked as local!",
2809 format_gid_address, seid);
2810 return -1;
2811 }
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002812 ls_index = map->locator_set_index;
Filip Tehlar53f09e32016-05-19 14:25:44 +02002813 }
2814 else
2815 {
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02002816 if (lcm->lisp_pitr)
2817 {
2818 map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
2819 ls_index = map->locator_set_index;
2820 }
2821 else
2822 {
2823 if (lcm->nsh_map_index == (u32) ~ 0)
2824 {
2825 clib_warning ("No locator-set defined for NSH!");
2826 return -1;
2827 }
2828 else
2829 {
2830 map = pool_elt_at_index (lcm->mapping_pool, lcm->nsh_map_index);
2831 ls_index = map->locator_set_index;
2832 }
2833 }
Florin Corase127a7e2016-02-18 22:20:01 +01002834 }
2835
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02002836 /* overwrite locator set if map-request itr-rlocs configured */
2837 if (~0 != lcm->mreq_itr_rlocs)
2838 {
2839 ls_index = lcm->mreq_itr_rlocs;
2840 }
2841
2842 loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
Florin Corase127a7e2016-02-18 22:20:01 +01002843
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002844 if (get_egress_map_resolver_ip (lcm, &sloc) < 0)
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002845 {
Filip Tehlar397fd7d2016-10-26 14:31:24 +02002846 if (duplicate_pmr)
2847 duplicate_pmr->to_be_removed = 1;
2848 return -1;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002849 }
Florin Corasddfafb82016-05-13 18:09:56 +02002850
Florin Corase127a7e2016-02-18 22:20:01 +01002851 /* build the encapsulated map request */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002852 b = build_encapsulated_map_request (lcm, seid, deid, loc_set,
Florin Corasa2157cf2016-08-16 21:09:14 +02002853 &lcm->active_map_resolver,
2854 &sloc, is_smr_invoked, &nonce, &bi);
Florin Corase127a7e2016-02-18 22:20:01 +01002855
2856 if (!b)
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002857 return -1;
Florin Corase127a7e2016-02-18 22:20:01 +01002858
Florin Corasf727db92016-06-23 15:01:58 +02002859 /* set fib index to default and lookup node */
Florin Corasa2157cf2016-08-16 21:09:14 +02002860 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
2861 next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
2862 ip4_lookup_node.index : ip6_lookup_node.index;
Florin Corase127a7e2016-02-18 22:20:01 +01002863
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002864 f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
Florin Corase127a7e2016-02-18 22:20:01 +01002865
2866 /* Enqueue the packet */
2867 to_next = vlib_frame_vector_args (f);
2868 to_next[0] = bi;
2869 f->n_vectors = 1;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002870 vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
Florin Corase127a7e2016-02-18 22:20:01 +01002871
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002872 if (duplicate_pmr)
2873 /* if there is a pending request already update it */
2874 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002875 if (clib_fifo_elts (duplicate_pmr->nonces) >= PENDING_MREQ_QUEUE_LEN)
2876 {
2877 /* remove the oldest nonce */
2878 u64 CLIB_UNUSED (tmp), *nonce_del;
2879 nonce_del = clib_fifo_head (duplicate_pmr->nonces);
2880 hash_unset (lcm->pending_map_requests_by_nonce, nonce_del[0]);
2881 clib_fifo_sub1 (duplicate_pmr->nonces, tmp);
2882 }
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002883
Florin Corasf4691cd2016-08-15 19:16:32 +02002884 clib_fifo_add1 (duplicate_pmr->nonces, nonce);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002885 hash_set (lcm->pending_map_requests_by_nonce, nonce,
Florin Corasa2157cf2016-08-16 21:09:14 +02002886 duplicate_pmr - lcm->pending_map_requests_pool);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002887 }
2888 else
2889 {
2890 /* add map-request to pending requests table */
Florin Corasa2157cf2016-08-16 21:09:14 +02002891 pool_get (lcm->pending_map_requests_pool, pmr);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002892 memset (pmr, 0, sizeof (*pmr));
2893 gid_address_copy (&pmr->src, seid);
2894 gid_address_copy (&pmr->dst, deid);
Florin Corasf4691cd2016-08-15 19:16:32 +02002895 clib_fifo_add1 (pmr->nonces, nonce);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002896 pmr->is_smr_invoked = is_smr_invoked;
2897 reset_pending_mr_counters (pmr);
2898 hash_set (lcm->pending_map_requests_by_nonce, nonce,
Florin Corasa2157cf2016-08-16 21:09:14 +02002899 pmr - lcm->pending_map_requests_pool);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002900 }
2901
2902 return 0;
Florin Corase127a7e2016-02-18 22:20:01 +01002903}
2904
2905static void
Florin Corasa2157cf2016-08-16 21:09:14 +02002906get_src_and_dst_ip (void *hdr, ip_address_t * src, ip_address_t * dst)
Florin Corase127a7e2016-02-18 22:20:01 +01002907{
Florin Corasa2157cf2016-08-16 21:09:14 +02002908 ip4_header_t *ip4 = hdr;
2909 ip6_header_t *ip6;
Florin Corase127a7e2016-02-18 22:20:01 +01002910
2911 if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
2912 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002913 ip_address_set (src, &ip4->src_address, IP4);
2914 ip_address_set (dst, &ip4->dst_address, IP4);
Florin Corase127a7e2016-02-18 22:20:01 +01002915 }
2916 else
2917 {
2918 ip6 = hdr;
Florin Corasa2157cf2016-08-16 21:09:14 +02002919 ip_address_set (src, &ip6->src_address, IP6);
2920 ip_address_set (dst, &ip6->dst_address, IP6);
Florin Corase127a7e2016-02-18 22:20:01 +01002921 }
2922}
2923
Filip Tehlar324112f2016-06-02 16:07:38 +02002924static u32
Florin Coras1a1adc72016-07-22 01:45:30 +02002925lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b,
Florin Corasa2157cf2016-08-16 21:09:14 +02002926 u8 version)
Filip Tehlar324112f2016-06-02 16:07:38 +02002927{
Florin Corasa2157cf2016-08-16 21:09:14 +02002928 uword *vnip;
Neale Ranns0bfe5d82016-08-25 15:29:12 +01002929 u32 vni = ~0, table_id = ~0;
Filip Tehlar324112f2016-06-02 16:07:38 +02002930
Florin Coras87e40692016-09-22 18:02:17 +02002931 table_id = fib_table_get_table_id_for_sw_if_index ((version ==
2932 IP4 ? FIB_PROTOCOL_IP4 :
2933 FIB_PROTOCOL_IP6),
2934 vnet_buffer
2935 (b)->sw_if_index
2936 [VLIB_RX]);
Filip Tehlar324112f2016-06-02 16:07:38 +02002937
2938 vnip = hash_get (lcm->vni_by_table_id, table_id);
2939 if (vnip)
2940 vni = vnip[0];
2941 else
2942 clib_warning ("vrf %d is not mapped to any vni!", table_id);
2943
2944 return vni;
2945}
2946
Florin Coras1a1adc72016-07-22 01:45:30 +02002947always_inline u32
Filip Tehlard5a65db2017-05-17 17:21:10 +02002948lisp_get_bd_from_buffer_eth (vlib_buffer_t * b)
Florin Coras1a1adc72016-07-22 01:45:30 +02002949{
Florin Coras1a1adc72016-07-22 01:45:30 +02002950 u32 sw_if_index0;
2951
Florin Corasa2157cf2016-08-16 21:09:14 +02002952 l2input_main_t *l2im = &l2input_main;
2953 l2_input_config_t *config;
2954 l2_bridge_domain_t *bd_config;
Florin Coras1a1adc72016-07-22 01:45:30 +02002955
Florin Corasa2157cf2016-08-16 21:09:14 +02002956 sw_if_index0 = vnet_buffer (b)->sw_if_index[VLIB_RX];
2957 config = vec_elt_at_index (l2im->configs, sw_if_index0);
Florin Coras1a1adc72016-07-22 01:45:30 +02002958 bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index);
2959
Filip Tehlard5a65db2017-05-17 17:21:10 +02002960 return bd_config->bd_id;
2961}
2962
2963always_inline u32
2964lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b)
2965{
2966 uword *vnip;
2967 u32 vni = ~0;
2968 u32 bd = lisp_get_bd_from_buffer_eth (b);
2969
2970 vnip = hash_get (lcm->vni_by_bd_id, bd);
Florin Coras1a1adc72016-07-22 01:45:30 +02002971 if (vnip)
2972 vni = vnip[0];
2973 else
Filip Tehlard5a65db2017-05-17 17:21:10 +02002974 clib_warning ("bridge domain %d is not mapped to any vni!", bd);
Florin Coras1a1adc72016-07-22 01:45:30 +02002975
2976 return vni;
2977}
2978
Filip Tehlar4868ff62017-03-09 16:48:39 +01002979void
Florin Corasa2157cf2016-08-16 21:09:14 +02002980get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
Filip Tehlar4868ff62017-03-09 16:48:39 +01002981 gid_address_t * src, gid_address_t * dst,
2982 u16 type)
Florin Coras1a1adc72016-07-22 01:45:30 +02002983{
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02002984 ethernet_header_t *eh;
Florin Coras1a1adc72016-07-22 01:45:30 +02002985 u32 vni = 0;
Florin Coras1a1adc72016-07-22 01:45:30 +02002986
Filip Tehlara5abdeb2016-07-18 17:35:40 +02002987 memset (src, 0, sizeof (*src));
2988 memset (dst, 0, sizeof (*dst));
Florin Coras1a1adc72016-07-22 01:45:30 +02002989
Filip Tehlard5a65db2017-05-17 17:21:10 +02002990 gid_address_type (dst) = GID_ADDR_NO_ADDRESS;
2991 gid_address_type (src) = GID_ADDR_NO_ADDRESS;
2992
Florin Coras1a1adc72016-07-22 01:45:30 +02002993 if (LISP_AFI_IP == type || LISP_AFI_IP6 == type)
2994 {
Florin Corasa2157cf2016-08-16 21:09:14 +02002995 ip4_header_t *ip;
Florin Coras1a1adc72016-07-22 01:45:30 +02002996 u8 version, preflen;
2997
Florin Corasa2157cf2016-08-16 21:09:14 +02002998 gid_address_type (src) = GID_ADDR_IP_PREFIX;
2999 gid_address_type (dst) = GID_ADDR_IP_PREFIX;
Florin Coras1a1adc72016-07-22 01:45:30 +02003000
3001 ip = vlib_buffer_get_current (b);
Florin Corasa2157cf2016-08-16 21:09:14 +02003002 get_src_and_dst_ip (ip, &gid_address_ip (src), &gid_address_ip (dst));
Florin Coras1a1adc72016-07-22 01:45:30 +02003003
Florin Corasa2157cf2016-08-16 21:09:14 +02003004 version = gid_address_ip_version (src);
Florin Coras1a1adc72016-07-22 01:45:30 +02003005 preflen = ip_address_max_len (version);
Florin Corasa2157cf2016-08-16 21:09:14 +02003006 gid_address_ippref_len (src) = preflen;
3007 gid_address_ippref_len (dst) = preflen;
Florin Coras1a1adc72016-07-22 01:45:30 +02003008
3009 vni = lisp_get_vni_from_buffer_ip (lcm, b, version);
3010 gid_address_vni (dst) = vni;
3011 gid_address_vni (src) = vni;
3012 }
3013 else if (LISP_AFI_MAC == type)
3014 {
Filip Tehlard5a65db2017-05-17 17:21:10 +02003015 ethernet_arp_header_t *ah;
Florin Coras1a1adc72016-07-22 01:45:30 +02003016
3017 eh = vlib_buffer_get_current (b);
3018
Filip Tehlard5a65db2017-05-17 17:21:10 +02003019 if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_ARP)
3020 {
3021 ah = (ethernet_arp_header_t *) (((u8 *) eh) + sizeof (*eh));
3022 if (clib_net_to_host_u16 (ah->opcode)
3023 != ETHERNET_ARP_OPCODE_request)
3024 return;
Florin Coras1a1adc72016-07-22 01:45:30 +02003025
Filip Tehlard5a65db2017-05-17 17:21:10 +02003026 gid_address_type (dst) = GID_ADDR_ARP;
3027 gid_address_arp_bd (dst) = lisp_get_bd_from_buffer_eth (b);
3028 clib_memcpy (&gid_address_arp_ip4 (dst),
3029 &ah->ip4_over_ethernet[1].ip4, 4);
3030 }
3031 else
3032 {
3033 gid_address_type (src) = GID_ADDR_MAC;
3034 gid_address_type (dst) = GID_ADDR_MAC;
3035 mac_copy (&gid_address_mac (src), eh->src_address);
3036 mac_copy (&gid_address_mac (dst), eh->dst_address);
Florin Coras1a1adc72016-07-22 01:45:30 +02003037
Filip Tehlard5a65db2017-05-17 17:21:10 +02003038 /* get vni */
3039 vni = lisp_get_vni_from_buffer_eth (lcm, b);
3040
3041 gid_address_vni (dst) = vni;
3042 gid_address_vni (src) = vni;
3043 }
Florin Coras1a1adc72016-07-22 01:45:30 +02003044 }
Florin Corasce1b4c72017-01-26 14:25:34 -08003045 else if (LISP_AFI_LCAF == type)
3046 {
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02003047 lisp_nsh_hdr_t *nh;
3048 eh = vlib_buffer_get_current (b);
3049
3050 if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_NSH)
3051 {
3052 nh = (lisp_nsh_hdr_t *) (((u8 *) eh) + sizeof (*eh));
3053 u32 spi = clib_net_to_host_u32 (nh->spi_si << 8);
3054 u8 si = (u8) clib_net_to_host_u32 (nh->spi_si);
3055 gid_address_nsh_spi (dst) = spi;
3056 gid_address_nsh_si (dst) = si;
3057
3058 gid_address_type (dst) = GID_ADDR_NSH;
3059 }
Florin Corasce1b4c72017-01-26 14:25:34 -08003060 }
Florin Coras1a1adc72016-07-22 01:45:30 +02003061}
3062
Florin Corase127a7e2016-02-18 22:20:01 +01003063static uword
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003064lisp_cp_lookup_inline (vlib_main_t * vm,
3065 vlib_node_runtime_t * node,
3066 vlib_frame_t * from_frame, int overlay)
Florin Corase127a7e2016-02-18 22:20:01 +01003067{
Filip Tehlard5a65db2017-05-17 17:21:10 +02003068 u32 *from, *to_next, di, si;
Florin Corasa2157cf2016-08-16 21:09:14 +02003069 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlard5a65db2017-05-17 17:21:10 +02003070 u32 pkts_mapped = 0, next_index;
3071 uword n_left_from, n_left_to_next;
3072 vnet_main_t *vnm = vnet_get_main ();
Florin Corase127a7e2016-02-18 22:20:01 +01003073
3074 from = vlib_frame_vector_args (from_frame);
3075 n_left_from = from_frame->n_vectors;
Filip Tehlard5a65db2017-05-17 17:21:10 +02003076 next_index = node->cached_next_index;
Florin Corase127a7e2016-02-18 22:20:01 +01003077
3078 while (n_left_from > 0)
3079 {
Filip Tehlard5a65db2017-05-17 17:21:10 +02003080 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
Florin Corase127a7e2016-02-18 22:20:01 +01003081
Filip Tehlard5a65db2017-05-17 17:21:10 +02003082 while (n_left_from > 0 && n_left_to_next > 0)
Florin Corasa2157cf2016-08-16 21:09:14 +02003083 {
Filip Tehlard5a65db2017-05-17 17:21:10 +02003084 u32 pi0, sw_if_index0, next0;
3085 u64 mac0;
Florin Corasa2157cf2016-08-16 21:09:14 +02003086 vlib_buffer_t *b0;
3087 gid_address_t src, dst;
Filip Tehlard5a65db2017-05-17 17:21:10 +02003088 ethernet_arp_header_t *arp0;
3089 ethernet_header_t *eth0;
3090 vnet_hw_interface_t *hw_if0;
Florin Corase127a7e2016-02-18 22:20:01 +01003091
Florin Corasa2157cf2016-08-16 21:09:14 +02003092 pi0 = from[0];
3093 from += 1;
3094 n_left_from -= 1;
Filip Tehlard5a65db2017-05-17 17:21:10 +02003095 to_next[0] = pi0;
3096 to_next += 1;
3097 n_left_to_next -= 1;
Florin Corase127a7e2016-02-18 22:20:01 +01003098
Florin Corasa2157cf2016-08-16 21:09:14 +02003099 b0 = vlib_get_buffer (vm, pi0);
Florin Corase127a7e2016-02-18 22:20:01 +01003100
Florin Corasa2157cf2016-08-16 21:09:14 +02003101 /* src/dst eid pair */
Filip Tehlar4868ff62017-03-09 16:48:39 +01003102 get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst, overlay);
Filip Tehlar324112f2016-06-02 16:07:38 +02003103
Filip Tehlard5a65db2017-05-17 17:21:10 +02003104 if (gid_address_type (&dst) == GID_ADDR_ARP)
3105 {
3106 mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
3107 if (GID_LOOKUP_MISS_L2 != mac0)
3108 {
3109 /* send ARP reply */
3110
3111 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
3112 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
3113
3114 hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
3115
3116 eth0 = vlib_buffer_get_current (b0);
3117 arp0 = (ethernet_arp_header_t *) (((u8 *) eth0)
3118 + sizeof (*eth0));
3119 arp0->opcode =
3120 clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
3121 arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
3122 clib_memcpy (arp0->ip4_over_ethernet[0].ethernet,
3123 (u8 *) & mac0, 6);
3124 clib_memcpy (&arp0->ip4_over_ethernet[0].ip4,
3125 &gid_address_arp_ip4 (&dst), 4);
3126
3127 /* Hardware must be ethernet-like. */
3128 ASSERT (vec_len (hw_if0->hw_address) == 6);
3129
3130 clib_memcpy (eth0->dst_address, eth0->src_address, 6);
3131 clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
3132
3133 b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX];
3134 next0 = LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX;
3135 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3136 to_next,
3137 n_left_to_next, pi0,
3138 next0);
Florin Corasbae851f2017-08-09 17:50:09 -07003139 continue;
Filip Tehlard5a65db2017-05-17 17:21:10 +02003140 }
Florin Corasbae851f2017-08-09 17:50:09 -07003141 goto done;
Filip Tehlard5a65db2017-05-17 17:21:10 +02003142 }
3143
Florin Corasa2157cf2016-08-16 21:09:14 +02003144 /* if we have remote mapping for destination already in map-chache
3145 add forwarding tunnel directly. If not send a map-request */
Florin Corasdca88042016-09-14 16:01:38 +02003146 di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst,
3147 &src);
Florin Corasa2157cf2016-08-16 21:09:14 +02003148 if (~0 != di)
3149 {
3150 mapping_t *m = vec_elt_at_index (lcm->mapping_pool, di);
3151 /* send a map-request also in case of negative mapping entry
3152 with corresponding action */
3153 if (m->action == LISP_SEND_MAP_REQUEST)
3154 {
3155 /* send map-request */
3156 queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3157 0 /* is_resend */ );
3158 pkts_mapped++;
3159 }
3160 else
3161 {
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02003162 if (GID_ADDR_NSH != gid_address_type (&dst))
3163 {
3164 si = gid_dictionary_lookup (&lcm->mapping_index_by_gid,
3165 &src);
3166 }
3167 else
3168 si = lcm->nsh_map_index;
3169
Florin Corasa2157cf2016-08-16 21:09:14 +02003170 if (~0 != si)
3171 {
Filip Tehlarce1aae42017-01-04 10:42:25 +01003172 dp_add_fwd_entry_from_mt (si, di);
Florin Corasa2157cf2016-08-16 21:09:14 +02003173 }
3174 }
3175 }
3176 else
3177 {
3178 /* send map-request */
3179 queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3180 0 /* is_resend */ );
3181 pkts_mapped++;
3182 }
Florin Corase127a7e2016-02-18 22:20:01 +01003183
Florin Corasbae851f2017-08-09 17:50:09 -07003184 done:
Filip Tehlard5a65db2017-05-17 17:21:10 +02003185 b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
Florin Corasa2157cf2016-08-16 21:09:14 +02003186 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3187 {
3188 lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
3189 sizeof (*tr));
Andrej Kozemcak94e34762016-05-25 12:43:21 +02003190
Florin Corasa2157cf2016-08-16 21:09:14 +02003191 memset (tr, 0, sizeof (*tr));
3192 gid_address_copy (&tr->dst_eid, &dst);
Florin Coras5a1c11b2016-09-06 16:29:34 +02003193 ip_address_copy (&tr->map_resolver_ip,
3194 &lcm->active_map_resolver);
Florin Corasa2157cf2016-08-16 21:09:14 +02003195 }
3196 gid_address_free (&dst);
3197 gid_address_free (&src);
Filip Tehlard5a65db2017-05-17 17:21:10 +02003198 next0 = LISP_CP_LOOKUP_NEXT_DROP;
3199 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3200 to_next,
3201 n_left_to_next, pi0, next0);
Florin Corasa2157cf2016-08-16 21:09:14 +02003202 }
Florin Corase127a7e2016-02-18 22:20:01 +01003203
Filip Tehlard5a65db2017-05-17 17:21:10 +02003204 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
Florin Corase127a7e2016-02-18 22:20:01 +01003205 }
3206 vlib_node_increment_counter (vm, node->node_index,
Florin Corasa2157cf2016-08-16 21:09:14 +02003207 LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
3208 pkts_mapped);
Florin Corase127a7e2016-02-18 22:20:01 +01003209 return from_frame->n_vectors;
3210}
3211
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003212static uword
3213lisp_cp_lookup_ip4 (vlib_main_t * vm,
3214 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3215{
3216 return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP));
3217}
3218
3219static uword
3220lisp_cp_lookup_ip6 (vlib_main_t * vm,
3221 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3222{
3223 return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP6));
3224}
3225
Neale Ranns5e575b12016-10-03 09:40:25 +01003226static uword
3227lisp_cp_lookup_l2 (vlib_main_t * vm,
3228 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3229{
3230 return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_MAC));
3231}
3232
Florin Corasce1b4c72017-01-26 14:25:34 -08003233static uword
3234lisp_cp_lookup_nsh (vlib_main_t * vm,
3235 vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3236{
3237 /* TODO decide if NSH should be propagated as LCAF or not */
3238 return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_LCAF));
3239}
3240
Florin Corasa2157cf2016-08-16 21:09:14 +02003241/* *INDENT-OFF* */
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003242VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = {
3243 .function = lisp_cp_lookup_ip4,
3244 .name = "lisp-cp-lookup-ip4",
3245 .vector_size = sizeof (u32),
3246 .format_trace = format_lisp_cp_lookup_trace,
3247 .type = VLIB_NODE_TYPE_INTERNAL,
3248
3249 .n_errors = LISP_CP_LOOKUP_N_ERROR,
3250 .error_strings = lisp_cp_lookup_error_strings,
3251
3252 .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3253
3254 .next_nodes = {
3255 [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
Filip Tehlard5a65db2017-05-17 17:21:10 +02003256 [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
Neale Ranns0bfe5d82016-08-25 15:29:12 +01003257 },
3258};
3259/* *INDENT-ON* */
3260
3261/* *INDENT-OFF* */
3262VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = {
3263 .function = lisp_cp_lookup_ip6,
3264 .name = "lisp-cp-lookup-ip6",
Florin Corase127a7e2016-02-18 22:20:01 +01003265 .vector_size = sizeof (u32),
3266 .format_trace = format_lisp_cp_lookup_trace,
3267 .type = VLIB_NODE_TYPE_INTERNAL,
3268
3269 .n_errors = LISP_CP_LOOKUP_N_ERROR,
3270 .error_strings = lisp_cp_lookup_error_strings,
3271
3272 .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3273
3274 .next_nodes = {
3275 [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
Filip Tehlard5a65db2017-05-17 17:21:10 +02003276 [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
Neale Ranns5e575b12016-10-03 09:40:25 +01003277 },
3278};
3279/* *INDENT-ON* */
3280
3281/* *INDENT-OFF* */
3282VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
3283 .function = lisp_cp_lookup_l2,
3284 .name = "lisp-cp-lookup-l2",
3285 .vector_size = sizeof (u32),
3286 .format_trace = format_lisp_cp_lookup_trace,
3287 .type = VLIB_NODE_TYPE_INTERNAL,
3288
3289 .n_errors = LISP_CP_LOOKUP_N_ERROR,
3290 .error_strings = lisp_cp_lookup_error_strings,
3291
3292 .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3293
3294 .next_nodes = {
3295 [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
Filip Tehlard5a65db2017-05-17 17:21:10 +02003296 [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
Florin Corase127a7e2016-02-18 22:20:01 +01003297 },
3298};
Florin Corasa2157cf2016-08-16 21:09:14 +02003299/* *INDENT-ON* */
Florin Corase127a7e2016-02-18 22:20:01 +01003300
Florin Corasce1b4c72017-01-26 14:25:34 -08003301/* *INDENT-OFF* */
3302VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = {
3303 .function = lisp_cp_lookup_nsh,
3304 .name = "lisp-cp-lookup-nsh",
3305 .vector_size = sizeof (u32),
3306 .format_trace = format_lisp_cp_lookup_trace,
3307 .type = VLIB_NODE_TYPE_INTERNAL,
3308
3309 .n_errors = LISP_CP_LOOKUP_N_ERROR,
3310 .error_strings = lisp_cp_lookup_error_strings,
3311
3312 .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3313
3314 .next_nodes = {
3315 [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
Filip Tehlard5a65db2017-05-17 17:21:10 +02003316 [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output",
Florin Corasce1b4c72017-01-26 14:25:34 -08003317 },
3318};
3319/* *INDENT-ON* */
3320
Florin Corase127a7e2016-02-18 22:20:01 +01003321/* lisp_cp_input statistics */
Filip Tehlarcda70662017-01-16 10:30:03 +01003322#define foreach_lisp_cp_input_error \
3323_(DROP, "drop") \
3324_(RLOC_PROBE_REQ_RECEIVED, "rloc-probe requests received") \
3325_(RLOC_PROBE_REP_RECEIVED, "rloc-probe replies received") \
3326_(MAP_NOTIFIES_RECEIVED, "map-notifies received") \
Florin Corase127a7e2016-02-18 22:20:01 +01003327_(MAP_REPLIES_RECEIVED, "map-replies received")
3328
Florin Corasa2157cf2016-08-16 21:09:14 +02003329static char *lisp_cp_input_error_strings[] = {
Florin Corase127a7e2016-02-18 22:20:01 +01003330#define _(sym,string) string,
3331 foreach_lisp_cp_input_error
3332#undef _
3333};
3334
3335typedef enum
3336{
3337#define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
Florin Corasa2157cf2016-08-16 21:09:14 +02003338 foreach_lisp_cp_input_error
Florin Corase127a7e2016-02-18 22:20:01 +01003339#undef _
3340 LISP_CP_INPUT_N_ERROR,
3341} lisp_cp_input_error_t;
3342
Florin Corase127a7e2016-02-18 22:20:01 +01003343typedef struct
3344{
3345 gid_address_t dst_eid;
3346 ip4_address_t map_resolver_ip;
3347} lisp_cp_input_trace_t;
3348
3349u8 *
3350format_lisp_cp_input_trace (u8 * s, va_list * args)
3351{
3352 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
3353 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Florin Corasa2157cf2016-08-16 21:09:14 +02003354 CLIB_UNUSED (lisp_cp_input_trace_t * t) =
3355 va_arg (*args, lisp_cp_input_trace_t *);
Florin Corase127a7e2016-02-18 22:20:01 +01003356
3357 s = format (s, "LISP-CP-INPUT: TODO");
3358 return s;
3359}
3360
Filip Tehlar9677a942016-11-28 10:23:31 +01003361static void
3362remove_expired_mapping (lisp_cp_main_t * lcm, u32 mi)
3363{
3364 mapping_t *m;
Florin Corasf3dc11a2017-01-24 03:13:43 -08003365 vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
3366 memset (adj_args, 0, sizeof (adj_args[0]));
Filip Tehlar9677a942016-11-28 10:23:31 +01003367
3368 m = pool_elt_at_index (lcm->mapping_pool, mi);
Florin Corasf3dc11a2017-01-24 03:13:43 -08003369
3370 gid_address_copy (&adj_args->reid, &m->eid);
3371 adj_args->is_add = 0;
3372 if (vnet_lisp_add_del_adjacency (adj_args))
3373 clib_warning ("failed to del adjacency!");
3374
Filip Tehlar9677a942016-11-28 10:23:31 +01003375 vnet_lisp_add_del_mapping (&m->eid, 0, 0, 0, ~0, 0 /* is_add */ ,
3376 0 /* is_static */ , 0);
3377 mapping_delete_timer (lcm, mi);
3378}
3379
3380static void
3381mapping_start_expiration_timer (lisp_cp_main_t * lcm, u32 mi,
3382 f64 expiration_time)
3383{
3384 mapping_t *m;
3385 u64 now = clib_cpu_time_now ();
3386 u64 cpu_cps = lcm->vlib_main->clib_time.clocks_per_second;
3387 u64 exp_clock_time = now + expiration_time * cpu_cps;
3388
3389 m = pool_elt_at_index (lcm->mapping_pool, mi);
3390
3391 m->timer_set = 1;
3392 timing_wheel_insert (&lcm->wheel, exp_clock_time, mi);
3393}
3394
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003395static void
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003396map_records_arg_free (map_records_arg_t * a)
Florin Corase127a7e2016-02-18 22:20:01 +01003397{
Florin Corasacd4c632017-06-15 14:33:48 -07003398 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003399 mapping_t *m;
3400 vec_foreach (m, a->mappings)
3401 {
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003402 vec_free (m->locators);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003403 gid_address_free (&m->eid);
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003404 }
Florin Corasacd4c632017-06-15 14:33:48 -07003405 pool_put (lcm->map_records_args_pool[vlib_get_thread_index ()], a);
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003406}
3407
3408void *
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003409process_map_reply (map_records_arg_t * a)
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003410{
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003411 mapping_t *m;
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003412 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3413 u32 dst_map_index = 0;
3414 pending_map_request_t *pmr;
3415 u64 *noncep;
3416 uword *pmr_index;
3417
3418 if (a->is_rloc_probe)
3419 goto done;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02003420
Florin Corase127a7e2016-02-18 22:20:01 +01003421 /* Check pending requests table and nonce */
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003422 pmr_index = hash_get (lcm->pending_map_requests_by_nonce, a->nonce);
Florin Corase127a7e2016-02-18 22:20:01 +01003423 if (!pmr_index)
3424 {
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003425 clib_warning ("No pending map-request entry with nonce %lu!", a->nonce);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02003426 goto done;
Florin Corase127a7e2016-02-18 22:20:01 +01003427 }
Florin Corasa2157cf2016-08-16 21:09:14 +02003428 pmr = pool_elt_at_index (lcm->pending_map_requests_pool, pmr_index[0]);
Florin Corase127a7e2016-02-18 22:20:01 +01003429
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003430 vec_foreach (m, a->mappings)
3431 {
3432 /* insert/update mappings cache */
3433 vnet_lisp_add_del_mapping (&m->eid, m->locators, m->action,
3434 m->authoritative, m->ttl,
3435 1, 0 /* is_static */ , &dst_map_index);
Florin Corase127a7e2016-02-18 22:20:01 +01003436
Florin Corasba888e42017-01-24 11:38:18 -08003437 if (dst_map_index == (u32) ~ 0)
3438 continue;
3439
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003440 /* try to program forwarding only if mapping saved or updated */
Florin Corasba888e42017-01-24 11:38:18 -08003441 vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
3442 memset (adj_args, 0, sizeof (adj_args[0]));
Florin Corasf3dc11a2017-01-24 03:13:43 -08003443
Florin Corasba888e42017-01-24 11:38:18 -08003444 gid_address_copy (&adj_args->leid, &pmr->src);
3445 gid_address_copy (&adj_args->reid, &m->eid);
3446 adj_args->is_add = 1;
3447 if (vnet_lisp_add_del_adjacency (adj_args))
3448 clib_warning ("failed to add adjacency!");
Florin Corasf3dc11a2017-01-24 03:13:43 -08003449
Florin Corasba888e42017-01-24 11:38:18 -08003450 if ((u32) ~ 0 != m->ttl)
3451 mapping_start_expiration_timer (lcm, dst_map_index, m->ttl * 60);
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003452 }
Florin Corase127a7e2016-02-18 22:20:01 +01003453
3454 /* remove pending map request entry */
Florin Corasa2157cf2016-08-16 21:09:14 +02003455
3456 /* *INDENT-OFF* */
Florin Corasf4691cd2016-08-15 19:16:32 +02003457 clib_fifo_foreach (noncep, pmr->nonces, ({
Filip Tehlara5abdeb2016-07-18 17:35:40 +02003458 hash_unset(lcm->pending_map_requests_by_nonce, noncep[0]);
Florin Corasf4691cd2016-08-15 19:16:32 +02003459 }));
Florin Corasa2157cf2016-08-16 21:09:14 +02003460 /* *INDENT-ON* */
3461
3462 clib_fifo_free (pmr->nonces);
3463 pool_put (lcm->pending_map_requests_pool, pmr);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02003464
3465done:
Florin Corasacd4c632017-06-15 14:33:48 -07003466 a->is_free = 1;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02003467 return 0;
Florin Corase127a7e2016-02-18 22:20:01 +01003468}
3469
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003470static int
3471is_auth_data_valid (map_notify_hdr_t * h, u32 msg_len,
3472 lisp_key_type_t key_id, u8 * key)
3473{
3474 u8 *auth_data = 0;
3475 u16 auth_data_len;
3476 int result;
3477
3478 auth_data_len = auth_data_len_by_key_id (key_id);
3479 if ((u16) ~ 0 == auth_data_len)
3480 {
3481 clib_warning ("invalid length for key_id %d!", key_id);
3482 return 0;
3483 }
3484
3485 /* save auth data */
3486 vec_validate (auth_data, auth_data_len - 1);
3487 clib_memcpy (auth_data, MNOTIFY_DATA (h), auth_data_len);
3488
3489 /* clear auth data */
3490 memset (MNOTIFY_DATA (h), 0, auth_data_len);
3491
3492 /* get hash of the message */
3493 unsigned char *code = HMAC (get_encrypt_fcn (key_id), key, vec_len (key),
3494 (unsigned char *) h, msg_len, NULL, NULL);
3495
3496 result = memcmp (code, auth_data, auth_data_len);
3497
3498 vec_free (auth_data);
3499
3500 return !result;
3501}
3502
3503static void
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003504process_map_notify (map_records_arg_t * a)
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003505{
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003506 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003507 uword *pmr_index;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003508
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003509 pmr_index = hash_get (lcm->map_register_messages_by_nonce, a->nonce);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003510 if (!pmr_index)
3511 {
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003512 clib_warning ("No pending map-register entry with nonce %lu!",
3513 a->nonce);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003514 return;
3515 }
3516
Florin Corasacd4c632017-06-15 14:33:48 -07003517 a->is_free = 1;
Filip Tehlar7048ff12017-07-27 08:09:14 +02003518 pool_put_index (lcm->pending_map_registers_pool, pmr_index[0]);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003519 hash_unset (lcm->map_register_messages_by_nonce, a->nonce);
Filip Tehlar7048ff12017-07-27 08:09:14 +02003520
3521 /* reset map-notify counter */
3522 lcm->expired_map_registers = 0;
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003523}
3524
3525static mapping_t *
3526get_mapping (lisp_cp_main_t * lcm, gid_address_t * e)
3527{
3528 u32 mi;
3529
3530 mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, e);
3531 if (~0 == mi)
3532 {
3533 clib_warning ("eid %U not found in map-cache!", unformat_gid_address,
3534 e);
3535 return 0;
3536 }
3537 return pool_elt_at_index (lcm->mapping_pool, mi);
3538}
3539
3540/**
3541 * When map-notify is received it is necessary that all EIDs in the record
3542 * list share common key. The key is then used to verify authentication
3543 * data in map-notify message.
3544 */
3545static int
3546map_record_integrity_check (lisp_cp_main_t * lcm, mapping_t * maps,
3547 u32 key_id, u8 ** key_out)
3548{
3549 u32 i, len = vec_len (maps);
3550 mapping_t *m;
3551
3552 /* get key of the first mapping */
3553 m = get_mapping (lcm, &maps[0].eid);
3554 if (!m || !m->key)
3555 return -1;
3556
3557 key_out[0] = m->key;
3558
3559 for (i = 1; i < len; i++)
3560 {
3561 m = get_mapping (lcm, &maps[i].eid);
3562 if (!m || !m->key)
3563 return -1;
3564
3565 if (key_id != m->key_id || vec_cmp (m->key, key_out[0]))
3566 {
3567 clib_warning ("keys does not match! %v, %v", key_out[0], m->key);
3568 return -1;
3569 }
3570 }
3571 return 0;
3572}
3573
3574static int
3575parse_map_records (vlib_buffer_t * b, map_records_arg_t * a, u8 count)
3576{
3577 locator_t *locators = 0;
3578 u32 i, len;
3579 gid_address_t deid;
3580 mapping_t m;
3581 locator_t *loc;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003582
Filip Tehlar68c74fc2017-05-04 14:52:42 +02003583 memset (&m, 0, sizeof (m));
3584
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003585 /* parse record eid */
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003586 for (i = 0; i < count; i++)
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003587 {
Florin Corase68de8c2017-06-05 15:38:50 -07003588 locators = 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003589 len = lisp_msg_parse_mapping_record (b, &deid, &locators, NULL);
3590 if (len == ~0)
3591 {
3592 clib_warning ("Failed to parse mapping record!");
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003593 vec_foreach (loc, locators) locator_free (loc);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003594 vec_free (locators);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003595 return -1;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003596 }
3597
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003598 m.locators = locators;
3599 gid_address_copy (&m.eid, &deid);
3600 vec_add1 (a->mappings, m);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003601 }
3602
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003603 return 0;
3604}
3605
3606static map_records_arg_t *
Florin Corasacd4c632017-06-15 14:33:48 -07003607map_record_args_get ()
3608{
3609 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3610 map_records_arg_t *rec;
3611
3612 /* Cleanup first */
3613 /* *INDENT-OFF* */
3614 pool_foreach (rec, lcm->map_records_args_pool[vlib_get_thread_index()], ({
3615 if (rec->is_free)
3616 map_records_arg_free (rec);
3617 }));
3618 /* *INDENT-ON* */
3619
3620 pool_get (lcm->map_records_args_pool[vlib_get_thread_index ()], rec);
3621 return rec;
3622}
3623
3624static map_records_arg_t *
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003625parse_map_notify (vlib_buffer_t * b)
3626{
3627 int rc = 0;
3628 map_notify_hdr_t *mnotif_hdr;
3629 lisp_key_type_t key_id;
3630 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3631 u8 *key = 0;
3632 gid_address_t deid;
3633 u16 auth_data_len = 0;
3634 u8 record_count;
Florin Corasacd4c632017-06-15 14:33:48 -07003635 map_records_arg_t *a;
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003636
Florin Corasacd4c632017-06-15 14:33:48 -07003637 a = map_record_args_get ();
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003638 memset (a, 0, sizeof (*a));
3639 mnotif_hdr = vlib_buffer_get_current (b);
3640 vlib_buffer_pull (b, sizeof (*mnotif_hdr));
3641 memset (&deid, 0, sizeof (deid));
3642
3643 a->nonce = MNOTIFY_NONCE (mnotif_hdr);
3644 key_id = clib_net_to_host_u16 (MNOTIFY_KEY_ID (mnotif_hdr));
3645 auth_data_len = auth_data_len_by_key_id (key_id);
3646
3647 /* advance buffer by authentication data */
3648 vlib_buffer_pull (b, auth_data_len);
3649
3650 record_count = MNOTIFY_REC_COUNT (mnotif_hdr);
3651 rc = parse_map_records (b, a, record_count);
3652 if (rc != 0)
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003653 {
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003654 map_records_arg_free (a);
3655 return 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003656 }
3657
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003658 rc = map_record_integrity_check (lcm, a->mappings, key_id, &key);
3659 if (rc != 0)
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003660 {
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003661 map_records_arg_free (a);
3662 return 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003663 }
3664
3665 /* verify authentication data */
3666 if (!is_auth_data_valid (mnotif_hdr, vlib_buffer_get_tail (b)
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003667 - (u8 *) mnotif_hdr, key_id, key))
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003668 {
Filip Tehlar7048ff12017-07-27 08:09:14 +02003669 clib_warning ("Map-notify auth data verification failed for nonce "
3670 "0x%lx!", a->nonce);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003671 map_records_arg_free (a);
3672 return 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003673 }
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003674 return a;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003675}
3676
3677static vlib_buffer_t *
3678build_map_reply (lisp_cp_main_t * lcm, ip_address_t * sloc,
3679 ip_address_t * dst, u64 nonce, u8 probe_bit,
3680 mapping_t * records, u16 dst_port, u32 * bi_res)
3681{
3682 vlib_buffer_t *b;
3683 u32 bi;
3684 vlib_main_t *vm = lcm->vlib_main;
3685
3686 if (vlib_buffer_alloc (vm, &bi, 1) != 1)
3687 {
3688 clib_warning ("Can't allocate buffer for Map-Register!");
3689 return 0;
3690 }
3691
3692 b = vlib_get_buffer (vm, bi);
3693
3694 /* leave some space for the encap headers */
3695 vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
3696
3697 lisp_msg_put_map_reply (b, records, nonce, probe_bit);
3698
3699 /* push outer ip header */
Florin Corasfdbc3822017-07-27 00:34:12 -07003700 pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, dst_port, sloc, dst, 1);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003701
3702 bi_res[0] = bi;
3703 return b;
3704}
3705
3706static int
3707send_map_reply (lisp_cp_main_t * lcm, u32 mi, ip_address_t * dst,
3708 u8 probe_bit, u64 nonce, u16 dst_port,
3709 ip_address_t * probed_loc)
3710{
3711 ip_address_t src;
3712 u32 bi;
3713 vlib_buffer_t *b;
3714 vlib_frame_t *f;
3715 u32 next_index, *to_next;
3716 mapping_t *records = 0, *m;
3717
3718 m = pool_elt_at_index (lcm->mapping_pool, mi);
3719 if (!m)
3720 return -1;
3721
3722 vec_add1 (records, m[0]);
3723 add_locators (lcm, &records[0], m->locator_set_index, probed_loc);
3724 memset (&src, 0, sizeof (src));
3725
3726 if (!ip_fib_get_first_egress_ip_for_dst (lcm, dst, &src))
3727 {
3728 clib_warning ("can't find inteface address for %U", format_ip_address,
3729 dst);
3730 return -1;
3731 }
3732
3733 b = build_map_reply (lcm, &src, dst, nonce, probe_bit, records, dst_port,
3734 &bi);
3735 if (!b)
3736 return -1;
3737 free_map_register_records (records);
3738
3739 vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
3740 next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
3741 ip4_lookup_node.index : ip6_lookup_node.index;
3742
3743 f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
3744
3745 /* Enqueue the packet */
3746 to_next = vlib_frame_vector_args (f);
3747 to_next[0] = bi;
3748 f->n_vectors = 1;
3749 vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
3750 return 0;
3751}
3752
Filip Tehlarb601f222017-01-02 10:22:56 +01003753static void
3754find_ip_header (vlib_buffer_t * b, u8 ** ip_hdr)
3755{
Damjan Marion072401e2017-07-13 18:53:27 +02003756 const i32 start = vnet_buffer (b)->l3_hdr_offset;
Filip Tehlarb601f222017-01-02 10:22:56 +01003757 if (start < 0 && start < -sizeof (b->pre_data))
3758 {
3759 *ip_hdr = 0;
3760 return;
3761 }
3762
3763 *ip_hdr = b->data + start;
3764 if ((u8 *) * ip_hdr > (u8 *) vlib_buffer_get_current (b))
3765 *ip_hdr = 0;
3766}
3767
Florin Corase127a7e2016-02-18 22:20:01 +01003768void
Filip Tehlarcda70662017-01-16 10:30:03 +01003769process_map_request (vlib_main_t * vm, vlib_node_runtime_t * node,
3770 lisp_cp_main_t * lcm, vlib_buffer_t * b)
Florin Corase127a7e2016-02-18 22:20:01 +01003771{
Filip Tehlarb601f222017-01-02 10:22:56 +01003772 u8 *ip_hdr = 0;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003773 ip_address_t *dst_loc = 0, probed_loc, src_loc;
3774 mapping_t m;
Florin Corasa2157cf2016-08-16 21:09:14 +02003775 map_request_hdr_t *mreq_hdr;
Florin Corase127a7e2016-02-18 22:20:01 +01003776 gid_address_t src, dst;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003777 u64 nonce;
Filip Tehlarcda70662017-01-16 10:30:03 +01003778 u32 i, len = 0, rloc_probe_recv = 0;
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003779 gid_address_t *itr_rlocs = 0;
Florin Corase127a7e2016-02-18 22:20:01 +01003780
3781 mreq_hdr = vlib_buffer_get_current (b);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003782 if (!MREQ_SMR (mreq_hdr) && !MREQ_RLOC_PROBE (mreq_hdr))
Florin Corasa2157cf2016-08-16 21:09:14 +02003783 {
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003784 clib_warning
3785 ("Only SMR Map-Requests and RLOC probe supported for now!");
Florin Corase127a7e2016-02-18 22:20:01 +01003786 return;
Florin Corasa2157cf2016-08-16 21:09:14 +02003787 }
Florin Corase127a7e2016-02-18 22:20:01 +01003788
Filip Tehlarb601f222017-01-02 10:22:56 +01003789 vlib_buffer_pull (b, sizeof (*mreq_hdr));
3790 nonce = MREQ_NONCE (mreq_hdr);
3791
Florin Corase127a7e2016-02-18 22:20:01 +01003792 /* parse src eid */
3793 len = lisp_msg_parse_addr (b, &src);
3794 if (len == ~0)
3795 return;
3796
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003797 len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs,
3798 MREQ_ITR_RLOC_COUNT (mreq_hdr) + 1);
Florin Corase127a7e2016-02-18 22:20:01 +01003799 if (len == ~0)
Filip Tehlarcda70662017-01-16 10:30:03 +01003800 goto done;
Florin Corase127a7e2016-02-18 22:20:01 +01003801
3802 /* parse eid records and send SMR-invoked map-requests */
Florin Corasa2157cf2016-08-16 21:09:14 +02003803 for (i = 0; i < MREQ_REC_COUNT (mreq_hdr); i++)
Florin Corase127a7e2016-02-18 22:20:01 +01003804 {
Florin Corasa2157cf2016-08-16 21:09:14 +02003805 memset (&dst, 0, sizeof (dst));
Florin Corase127a7e2016-02-18 22:20:01 +01003806 len = lisp_msg_parse_eid_rec (b, &dst);
3807 if (len == ~0)
Florin Corasa2157cf2016-08-16 21:09:14 +02003808 {
3809 clib_warning ("Can't parse map-request EID-record");
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003810 goto done;
Florin Corasa2157cf2016-08-16 21:09:14 +02003811 }
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003812
3813 if (MREQ_SMR (mreq_hdr))
3814 {
3815 /* send SMR-invoked map-requests */
3816 queue_map_request (&dst, &src, 1 /* invoked */ , 0 /* resend */ );
3817 }
3818 else if (MREQ_RLOC_PROBE (mreq_hdr))
3819 {
Filip Tehlarb601f222017-01-02 10:22:56 +01003820 find_ip_header (b, &ip_hdr);
3821 if (!ip_hdr)
3822 {
3823 clib_warning ("Cannot find the IP header!");
Filip Tehlarcda70662017-01-16 10:30:03 +01003824 goto done;
Filip Tehlarb601f222017-01-02 10:22:56 +01003825 }
Filip Tehlarcda70662017-01-16 10:30:03 +01003826 rloc_probe_recv++;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003827 memset (&m, 0, sizeof (m));
3828 u32 mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
3829
3830 // TODO: select best locator; for now use the first one
3831 dst_loc = &gid_address_ip (&itr_rlocs[0]);
3832
3833 /* get src/dst IP addresses */
3834 get_src_and_dst_ip (ip_hdr, &src_loc, &probed_loc);
3835
3836 // TODO get source port from buffer
3837 u16 src_port = LISP_CONTROL_PORT;
3838
3839 send_map_reply (lcm, mi, dst_loc, 1 /* probe-bit */ , nonce,
3840 src_port, &probed_loc);
3841 }
Florin Corase127a7e2016-02-18 22:20:01 +01003842 }
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003843
3844done:
Filip Tehlarcda70662017-01-16 10:30:03 +01003845 vlib_node_increment_counter (vm, node->node_index,
3846 LISP_CP_INPUT_ERROR_RLOC_PROBE_REQ_RECEIVED,
3847 rloc_probe_recv);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003848 vec_free (itr_rlocs);
Florin Corase127a7e2016-02-18 22:20:01 +01003849}
3850
Filip Tehlar816f4372017-04-26 16:09:06 +02003851map_records_arg_t *
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003852parse_map_reply (vlib_buffer_t * b)
3853{
3854 locator_t probed;
3855 gid_address_t deid;
3856 void *h;
3857 u32 i, len = 0;
3858 mapping_t m;
3859 map_reply_hdr_t *mrep_hdr;
Florin Corasacd4c632017-06-15 14:33:48 -07003860 map_records_arg_t *a;
3861
3862 a = map_record_args_get ();
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003863 memset (a, 0, sizeof (*a));
Florin Corasacd4c632017-06-15 14:33:48 -07003864
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003865 locator_t *locators;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02003866
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003867 mrep_hdr = vlib_buffer_get_current (b);
3868 a->nonce = MREP_NONCE (mrep_hdr);
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003869 a->is_rloc_probe = MREP_RLOC_PROBE (mrep_hdr);
Filip Tehlar816f4372017-04-26 16:09:06 +02003870 if (!vlib_buffer_has_space (b, sizeof (*mrep_hdr)))
3871 {
3872 clib_mem_free (a);
3873 return 0;
3874 }
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003875 vlib_buffer_pull (b, sizeof (*mrep_hdr));
3876
3877 for (i = 0; i < MREP_REC_COUNT (mrep_hdr); i++)
3878 {
3879 memset (&m, 0, sizeof (m));
3880 locators = 0;
3881 h = vlib_buffer_get_current (b);
3882
3883 m.ttl = clib_net_to_host_u32 (MAP_REC_TTL (h));
3884 m.action = MAP_REC_ACTION (h);
3885 m.authoritative = MAP_REC_AUTH (h);
3886
3887 len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
3888 if (len == ~0)
3889 {
3890 clib_warning ("Failed to parse mapping record!");
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003891 map_records_arg_free (a);
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003892 return 0;
3893 }
3894
3895 m.locators = locators;
3896 gid_address_copy (&m.eid, &deid);
3897 vec_add1 (a->mappings, m);
3898 }
3899 return a;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02003900}
3901
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003902static void
3903queue_map_reply_for_processing (map_records_arg_t * a)
3904{
Florin Coras655fcc42017-01-10 08:57:54 -08003905 vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (*a));
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003906}
3907
3908static void
3909queue_map_notify_for_processing (map_records_arg_t * a)
3910{
3911 vl_api_rpc_call_main_thread (process_map_notify, (u8 *) a, sizeof (a[0]));
3912}
3913
Florin Corase127a7e2016-02-18 22:20:01 +01003914static uword
3915lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
Florin Corasa2157cf2016-08-16 21:09:14 +02003916 vlib_frame_t * from_frame)
Florin Corase127a7e2016-02-18 22:20:01 +01003917{
Filip Tehlarcda70662017-01-16 10:30:03 +01003918 u32 n_left_from, *from, *to_next_drop, rloc_probe_rep_recv = 0,
3919 map_notifies_recv = 0;
Florin Corase127a7e2016-02-18 22:20:01 +01003920 lisp_msg_type_e type;
Florin Corasa2157cf2016-08-16 21:09:14 +02003921 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003922 map_records_arg_t *a;
Florin Corase127a7e2016-02-18 22:20:01 +01003923
3924 from = vlib_frame_vector_args (from_frame);
3925 n_left_from = from_frame->n_vectors;
3926
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003927
Florin Corase127a7e2016-02-18 22:20:01 +01003928 while (n_left_from > 0)
3929 {
3930 u32 n_left_to_next_drop;
3931
3932 vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
Florin Corasa2157cf2016-08-16 21:09:14 +02003933 to_next_drop, n_left_to_next_drop);
Florin Corase127a7e2016-02-18 22:20:01 +01003934 while (n_left_from > 0 && n_left_to_next_drop > 0)
Florin Corasa2157cf2016-08-16 21:09:14 +02003935 {
3936 u32 bi0;
3937 vlib_buffer_t *b0;
Florin Corase127a7e2016-02-18 22:20:01 +01003938
Florin Corasa2157cf2016-08-16 21:09:14 +02003939 bi0 = from[0];
3940 from += 1;
3941 n_left_from -= 1;
3942 to_next_drop[0] = bi0;
3943 to_next_drop += 1;
3944 n_left_to_next_drop -= 1;
Florin Corase127a7e2016-02-18 22:20:01 +01003945
Florin Corasa2157cf2016-08-16 21:09:14 +02003946 b0 = vlib_get_buffer (vm, bi0);
Florin Corase127a7e2016-02-18 22:20:01 +01003947
Florin Corasa2157cf2016-08-16 21:09:14 +02003948 type = lisp_msg_type (vlib_buffer_get_current (b0));
3949 switch (type)
3950 {
3951 case LISP_MAP_REPLY:
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01003952 a = parse_map_reply (b0);
3953 if (a)
Filip Tehlarcda70662017-01-16 10:30:03 +01003954 {
3955 if (a->is_rloc_probe)
3956 rloc_probe_rep_recv++;
3957 queue_map_reply_for_processing (a);
3958 }
Florin Corasa2157cf2016-08-16 21:09:14 +02003959 break;
3960 case LISP_MAP_REQUEST:
Filip Tehlarcda70662017-01-16 10:30:03 +01003961 process_map_request (vm, node, lcm, b0);
Florin Corasa2157cf2016-08-16 21:09:14 +02003962 break;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003963 case LISP_MAP_NOTIFY:
Filip Tehlarfb9931f2016-12-09 13:52:38 +01003964 a = parse_map_notify (b0);
3965 if (a)
Filip Tehlarcda70662017-01-16 10:30:03 +01003966 {
3967 map_notifies_recv++;
3968 queue_map_notify_for_processing (a);
3969 }
Filip Tehlar397fd7d2016-10-26 14:31:24 +02003970 break;
Florin Corasa2157cf2016-08-16 21:09:14 +02003971 default:
3972 clib_warning ("Unsupported LISP message type %d", type);
3973 break;
3974 }
Florin Corase127a7e2016-02-18 22:20:01 +01003975
Florin Corasa2157cf2016-08-16 21:09:14 +02003976 b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
Florin Corase127a7e2016-02-18 22:20:01 +01003977
Florin Corasa2157cf2016-08-16 21:09:14 +02003978 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3979 {
Florin Corase127a7e2016-02-18 22:20:01 +01003980
Florin Corasa2157cf2016-08-16 21:09:14 +02003981 }
3982 }
Florin Corase127a7e2016-02-18 22:20:01 +01003983
Florin Corasa2157cf2016-08-16 21:09:14 +02003984 vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
3985 n_left_to_next_drop);
Florin Corase127a7e2016-02-18 22:20:01 +01003986 }
Filip Tehlarcda70662017-01-16 10:30:03 +01003987 vlib_node_increment_counter (vm, node->node_index,
3988 LISP_CP_INPUT_ERROR_RLOC_PROBE_REP_RECEIVED,
3989 rloc_probe_rep_recv);
3990 vlib_node_increment_counter (vm, node->node_index,
3991 LISP_CP_INPUT_ERROR_MAP_NOTIFIES_RECEIVED,
3992 map_notifies_recv);
Florin Corase127a7e2016-02-18 22:20:01 +01003993 return from_frame->n_vectors;
3994}
3995
Florin Corasa2157cf2016-08-16 21:09:14 +02003996/* *INDENT-OFF* */
Florin Corase127a7e2016-02-18 22:20:01 +01003997VLIB_REGISTER_NODE (lisp_cp_input_node) = {
3998 .function = lisp_cp_input,
3999 .name = "lisp-cp-input",
4000 .vector_size = sizeof (u32),
4001 .format_trace = format_lisp_cp_input_trace,
4002 .type = VLIB_NODE_TYPE_INTERNAL,
4003
4004 .n_errors = LISP_CP_INPUT_N_ERROR,
4005 .error_strings = lisp_cp_input_error_strings,
4006
4007 .n_next_nodes = LISP_CP_INPUT_N_NEXT,
4008
4009 .next_nodes = {
4010 [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
4011 },
4012};
Florin Corasa2157cf2016-08-16 21:09:14 +02004013/* *INDENT-ON* */
Florin Corase127a7e2016-02-18 22:20:01 +01004014
4015clib_error_t *
Florin Corasa2157cf2016-08-16 21:09:14 +02004016lisp_cp_init (vlib_main_t * vm)
Florin Corase127a7e2016-02-18 22:20:01 +01004017{
Florin Corasa2157cf2016-08-16 21:09:14 +02004018 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4019 clib_error_t *error = 0;
Florin Corasacd4c632017-06-15 14:33:48 -07004020 vlib_thread_main_t *vtm = vlib_get_thread_main ();
4021 u32 num_threads;
Florin Corase127a7e2016-02-18 22:20:01 +01004022
4023 if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
4024 return error;
4025
4026 lcm->im4 = &ip4_main;
4027 lcm->im6 = &ip6_main;
4028 lcm->vlib_main = vm;
Florin Corasa2157cf2016-08-16 21:09:14 +02004029 lcm->vnet_main = vnet_get_main ();
Andrej Kozemcakb6e4d392016-06-14 13:55:57 +02004030 lcm->mreq_itr_rlocs = ~0;
Florin Corasf727db92016-06-23 15:01:58 +02004031 lcm->lisp_pitr = 0;
Florin Corasba888e42017-01-24 11:38:18 -08004032 lcm->flags = 0;
Florin Coras5a1c11b2016-09-06 16:29:34 +02004033 memset (&lcm->active_map_resolver, 0, sizeof (lcm->active_map_resolver));
Filip Tehlar7048ff12017-07-27 08:09:14 +02004034 memset (&lcm->active_map_server, 0, sizeof (lcm->active_map_server));
Florin Corase127a7e2016-02-18 22:20:01 +01004035
4036 gid_dictionary_init (&lcm->mapping_index_by_gid);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004037 lcm->do_map_resolver_election = 1;
Filip Tehlar7048ff12017-07-27 08:09:14 +02004038 lcm->do_map_server_election = 1;
Florin Corasdca88042016-09-14 16:01:38 +02004039 lcm->map_request_mode = MR_MODE_DST_ONLY;
Florin Corase127a7e2016-02-18 22:20:01 +01004040
Florin Corasacd4c632017-06-15 14:33:48 -07004041 num_threads = 1 /* main thread */ + vtm->n_threads;
4042 vec_validate (lcm->map_records_args_pool, num_threads - 1);
4043
Florin Coras577c3552016-04-21 00:45:40 +02004044 /* default vrf mapped to vni 0 */
Florin Corasa2157cf2016-08-16 21:09:14 +02004045 hash_set (lcm->table_id_by_vni, 0, 0);
4046 hash_set (lcm->vni_by_table_id, 0, 0);
Florin Coras577c3552016-04-21 00:45:40 +02004047
Florin Corase127a7e2016-02-18 22:20:01 +01004048 udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
Florin Corasa2157cf2016-08-16 21:09:14 +02004049 lisp_cp_input_node.index, 1 /* is_ip4 */ );
Florin Corase127a7e2016-02-18 22:20:01 +01004050 udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
Florin Corasa2157cf2016-08-16 21:09:14 +02004051 lisp_cp_input_node.index, 0 /* is_ip4 */ );
Florin Corase127a7e2016-02-18 22:20:01 +01004052
Filip Tehlar9677a942016-11-28 10:23:31 +01004053 u64 now = clib_cpu_time_now ();
4054 timing_wheel_init (&lcm->wheel, now, vm->clib_time.clocks_per_second);
Filip Tehlaref2a5bf2017-05-30 07:14:46 +02004055 lcm->nsh_map_index = ~0;
Filip Tehlar1e553a02017-08-02 12:45:07 +02004056 lcm->map_register_ttl = MAP_REGISTER_DEFAULT_TTL;
Filip Tehlar7048ff12017-07-27 08:09:14 +02004057 lcm->max_expired_map_registers = MAX_EXPIRED_MAP_REGISTERS_DEFAULT;
4058 lcm->expired_map_registers = 0;
Florin Corase127a7e2016-02-18 22:20:01 +01004059 return 0;
4060}
4061
Filip Tehlar4868ff62017-03-09 16:48:39 +01004062static int
4063lisp_stats_api_fill (lisp_cp_main_t * lcm, lisp_gpe_main_t * lgm,
4064 lisp_api_stats_t * stat, lisp_stats_key_t * key,
4065 u32 stats_index)
4066{
Filip Tehlar21511912017-04-07 10:41:42 +02004067 vlib_counter_t v;
4068 vlib_combined_counter_main_t *cm = &lgm->counters;
Filip Tehlar4868ff62017-03-09 16:48:39 +01004069 lisp_gpe_fwd_entry_key_t fwd_key;
4070 const lisp_gpe_tunnel_t *lgt;
4071 fwd_entry_t *fe;
4072
4073 memset (stat, 0, sizeof (*stat));
4074 memset (&fwd_key, 0, sizeof (fwd_key));
4075
4076 fe = pool_elt_at_index (lcm->fwd_entry_pool, key->fwd_entry_index);
4077 ASSERT (fe != 0);
4078
4079 gid_to_dp_address (&fe->reid, &stat->deid);
4080 gid_to_dp_address (&fe->leid, &stat->seid);
4081 stat->vni = gid_address_vni (&fe->reid);
4082
4083 lgt = lisp_gpe_tunnel_get (key->tunnel_index);
4084 stat->loc_rloc = lgt->key->lcl;
4085 stat->rmt_rloc = lgt->key->rmt;
4086
Filip Tehlar21511912017-04-07 10:41:42 +02004087 vlib_get_combined_counter (cm, stats_index, &v);
4088 stat->counters = v;
Filip Tehlar4868ff62017-03-09 16:48:39 +01004089 return 1;
4090}
4091
4092lisp_api_stats_t *
4093vnet_lisp_get_stats (void)
4094{
4095 lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
4096 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4097 lisp_api_stats_t *stats = 0, stat;
4098 lisp_stats_key_t *key;
4099 u32 index;
4100
4101 /* *INDENT-OFF* */
4102 hash_foreach_mem (key, index, lgm->lisp_stats_index_by_key,
4103 {
4104 if (lisp_stats_api_fill (lcm, lgm, &stat, key, index))
4105 vec_add1 (stats, stat);
4106 });
4107 /* *INDENT-ON* */
4108
4109 return stats;
4110}
4111
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004112static void *
Florin Corasa2157cf2016-08-16 21:09:14 +02004113send_map_request_thread_fn (void *arg)
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004114{
Florin Corasa2157cf2016-08-16 21:09:14 +02004115 map_request_args_t *a = arg;
4116 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004117
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004118 if (a->is_resend)
4119 resend_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
4120 else
Filip Tehlarcdab4bd2016-12-06 10:31:57 +01004121 send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004122
4123 return 0;
4124}
4125
4126static int
4127queue_map_request (gid_address_t * seid, gid_address_t * deid,
Florin Corasa2157cf2016-08-16 21:09:14 +02004128 u8 smr_invoked, u8 is_resend)
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004129{
4130 map_request_args_t a;
4131
4132 a.is_resend = is_resend;
4133 gid_address_copy (&a.seid, seid);
4134 gid_address_copy (&a.deid, deid);
4135 a.smr_invoked = smr_invoked;
4136
4137 vl_api_rpc_call_main_thread (send_map_request_thread_fn,
Florin Corasa2157cf2016-08-16 21:09:14 +02004138 (u8 *) & a, sizeof (a));
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004139 return 0;
4140}
4141
4142/**
4143 * Take an action with a pending map request depending on expiration time
4144 * and re-try counters.
4145 */
4146static void
4147update_pending_request (pending_map_request_t * r, f64 dt)
4148{
Florin Corasa2157cf2016-08-16 21:09:14 +02004149 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlar397fd7d2016-10-26 14:31:24 +02004150 lisp_msmr_t *mr;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004151
4152 if (r->time_to_expire - dt < 0)
4153 /* it's time to decide what to do with this pending request */
4154 {
4155 if (r->retries_num >= NUMBER_OF_RETRIES)
Florin Corasa2157cf2016-08-16 21:09:14 +02004156 /* too many retries -> assume current map resolver is not available */
4157 {
4158 mr = get_map_resolver (&lcm->active_map_resolver);
4159 if (!mr)
4160 {
4161 clib_warning ("Map resolver %U not found - probably deleted "
4162 "by the user recently.", format_ip_address,
4163 &lcm->active_map_resolver);
4164 }
4165 else
4166 {
4167 clib_warning ("map resolver %U is unreachable, ignoring",
4168 format_ip_address, &lcm->active_map_resolver);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004169
Florin Corasa2157cf2016-08-16 21:09:14 +02004170 /* mark current map resolver unavailable so it won't be
4171 * selected next time */
4172 mr->is_down = 1;
4173 mr->last_update = vlib_time_now (lcm->vlib_main);
4174 }
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004175
Florin Corasa2157cf2016-08-16 21:09:14 +02004176 reset_pending_mr_counters (r);
4177 elect_map_resolver (lcm);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004178
Florin Corasa2157cf2016-08-16 21:09:14 +02004179 /* try to find a next eligible map resolver and re-send */
4180 queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
4181 1 /* resend */ );
4182 }
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004183 else
Florin Corasa2157cf2016-08-16 21:09:14 +02004184 {
4185 /* try again */
4186 queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
4187 1 /* resend */ );
4188 r->retries_num++;
4189 r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
4190 }
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004191 }
4192 else
4193 r->time_to_expire -= dt;
4194}
4195
4196static void
4197remove_dead_pending_map_requests (lisp_cp_main_t * lcm)
4198{
Florin Corasa2157cf2016-08-16 21:09:14 +02004199 u64 *nonce;
4200 pending_map_request_t *pmr;
4201 u32 *to_be_removed = 0, *pmr_index;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004202
Florin Corasa2157cf2016-08-16 21:09:14 +02004203 /* *INDENT-OFF* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004204 pool_foreach (pmr, lcm->pending_map_requests_pool,
Florin Corasa2157cf2016-08-16 21:09:14 +02004205 ({
4206 if (pmr->to_be_removed)
4207 {
4208 clib_fifo_foreach (nonce, pmr->nonces, ({
4209 hash_unset (lcm->pending_map_requests_by_nonce, nonce[0]);
4210 }));
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004211
Florin Corasa2157cf2016-08-16 21:09:14 +02004212 vec_add1 (to_be_removed, pmr - lcm->pending_map_requests_pool);
4213 }
4214 }));
4215 /* *INDENT-ON* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004216
4217 vec_foreach (pmr_index, to_be_removed)
Filip Tehlar7048ff12017-07-27 08:09:14 +02004218 pool_put_index (lcm->pending_map_requests_pool, pmr_index[0]);
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004219
4220 vec_free (to_be_removed);
4221}
4222
Filip Tehlar397fd7d2016-10-26 14:31:24 +02004223static void
4224update_rloc_probing (lisp_cp_main_t * lcm, f64 dt)
4225{
4226 static f64 time_left = RLOC_PROBING_INTERVAL;
4227
4228 if (!lcm->is_enabled || !lcm->rloc_probing)
4229 return;
4230
4231 time_left -= dt;
4232 if (time_left <= 0)
4233 {
4234 time_left = RLOC_PROBING_INTERVAL;
4235 send_rloc_probes (lcm);
4236 }
4237}
4238
Filip Tehlar7048ff12017-07-27 08:09:14 +02004239static int
4240update_pending_map_register (pending_map_register_t * r, f64 dt, u8 * del_all)
4241{
4242 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4243 lisp_msmr_t *ms;
4244 del_all[0] = 0;
4245
4246 r->time_to_expire -= dt;
4247
4248 if (r->time_to_expire < 0)
4249 {
4250 lcm->expired_map_registers++;
4251
4252 if (lcm->expired_map_registers >= lcm->max_expired_map_registers)
4253 {
4254 ms = get_map_server (&lcm->active_map_server);
4255 if (!ms)
4256 {
4257 clib_warning ("Map server %U not found - probably deleted "
4258 "by the user recently.", format_ip_address,
4259 &lcm->active_map_server);
4260 }
4261 else
4262 {
4263 clib_warning ("map server %U is unreachable, ignoring",
4264 format_ip_address, &lcm->active_map_server);
4265
4266 /* mark current map server unavailable so it won't be
4267 * elected next time */
4268 ms->is_down = 1;
4269 ms->last_update = vlib_time_now (lcm->vlib_main);
4270 }
4271
4272 elect_map_server (lcm);
4273
4274 /* indication for deleting all pending map registers */
4275 del_all[0] = 1;
4276 lcm->expired_map_registers = 0;
4277 return 0;
4278 }
4279 else
4280 {
4281 /* delete pending map register */
4282 return 0;
4283 }
4284 }
4285 return 1;
4286}
4287
Filip Tehlar397fd7d2016-10-26 14:31:24 +02004288static void
4289update_map_register (lisp_cp_main_t * lcm, f64 dt)
4290{
Filip Tehlar7048ff12017-07-27 08:09:14 +02004291 u32 *to_be_removed = 0, *pmr_index;
Filip Tehlar397fd7d2016-10-26 14:31:24 +02004292 static f64 time_left = QUICK_MAP_REGISTER_INTERVAL;
4293 static u64 mreg_sent_counter = 0;
4294
Filip Tehlar7048ff12017-07-27 08:09:14 +02004295 pending_map_register_t *pmr;
4296 u8 del_all = 0;
4297
Filip Tehlar397fd7d2016-10-26 14:31:24 +02004298 if (!lcm->is_enabled || !lcm->map_registering)
4299 return;
4300
Filip Tehlar7048ff12017-07-27 08:09:14 +02004301 /* *INDENT-OFF* */
4302 pool_foreach (pmr, lcm->pending_map_registers_pool,
4303 ({
4304 if (!update_pending_map_register (pmr, dt, &del_all))
4305 {
4306 if (del_all)
4307 break;
4308 vec_add1 (to_be_removed, pmr - lcm->pending_map_registers_pool);
4309 }
4310 }));
4311 /* *INDENT-ON* */
4312
4313 if (del_all)
4314 {
4315 /* delete all pending map register messages so they won't
4316 * trigger another map server election.. */
4317 pool_free (lcm->pending_map_registers_pool);
4318 hash_free (lcm->map_register_messages_by_nonce);
4319
4320 /* ..and trigger registration against next map server (if any) */
4321 time_left = 0;
4322 }
4323 else
4324 {
4325 vec_foreach (pmr_index, to_be_removed)
4326 pool_put_index (lcm->pending_map_registers_pool, pmr_index[0]);
4327 }
4328
4329 vec_free (to_be_removed);
4330
Filip Tehlar397fd7d2016-10-26 14:31:24 +02004331 time_left -= dt;
4332 if (time_left <= 0)
4333 {
4334 if (mreg_sent_counter >= QUICK_MAP_REGISTER_MSG_COUNT)
4335 time_left = MAP_REGISTER_INTERVAL;
4336 else
4337 {
4338 mreg_sent_counter++;
4339 time_left = QUICK_MAP_REGISTER_INTERVAL;
4340 }
4341 send_map_register (lcm, 1 /* want map notify */ );
4342 }
4343}
4344
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004345static uword
4346send_map_resolver_service (vlib_main_t * vm,
Florin Corasa2157cf2016-08-16 21:09:14 +02004347 vlib_node_runtime_t * rt, vlib_frame_t * f)
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004348{
Filip Tehlar9677a942016-11-28 10:23:31 +01004349 u32 *expired = 0;
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004350 f64 period = 2.0;
Florin Corasa2157cf2016-08-16 21:09:14 +02004351 pending_map_request_t *pmr;
4352 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004353
4354 while (1)
4355 {
4356 vlib_process_wait_for_event_or_clock (vm, period);
4357
4358 /* currently no signals are expected - just wait for clock */
4359 (void) vlib_process_get_events (vm, 0);
4360
Florin Corasa2157cf2016-08-16 21:09:14 +02004361 /* *INDENT-OFF* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004362 pool_foreach (pmr, lcm->pending_map_requests_pool,
Florin Corasa2157cf2016-08-16 21:09:14 +02004363 ({
4364 if (!pmr->to_be_removed)
4365 update_pending_request (pmr, period);
4366 }));
4367 /* *INDENT-ON* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004368
4369 remove_dead_pending_map_requests (lcm);
Filip Tehlar397fd7d2016-10-26 14:31:24 +02004370
4371 update_map_register (lcm, period);
4372 update_rloc_probing (lcm, period);
Filip Tehlar9677a942016-11-28 10:23:31 +01004373
4374 u64 now = clib_cpu_time_now ();
4375
4376 expired = timing_wheel_advance (&lcm->wheel, now, expired, 0);
4377 if (vec_len (expired) > 0)
4378 {
4379 u32 *mi = 0;
4380 vec_foreach (mi, expired)
4381 {
4382 remove_expired_mapping (lcm, mi[0]);
4383 }
4384 _vec_len (expired) = 0;
4385 }
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004386 }
4387
4388 /* unreachable */
4389 return 0;
4390}
4391
Filip Tehlar7eaf0e52017-03-08 08:46:51 +01004392vnet_api_error_t
4393vnet_lisp_stats_enable_disable (u8 enable)
4394{
4395 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4396
4397 if (vnet_lisp_enable_disable_status () == 0)
4398 return VNET_API_ERROR_LISP_DISABLED;
4399
Filip Tehlar4868ff62017-03-09 16:48:39 +01004400 if (enable)
4401 lcm->flags |= LISP_FLAG_STATS_ENABLED;
4402 else
4403 lcm->flags &= ~LISP_FLAG_STATS_ENABLED;
4404
Filip Tehlar7eaf0e52017-03-08 08:46:51 +01004405 return 0;
4406}
4407
4408u8
4409vnet_lisp_stats_enable_disable_state (void)
4410{
4411 lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4412
4413 if (vnet_lisp_enable_disable_status () == 0)
4414 return VNET_API_ERROR_LISP_DISABLED;
4415
Filip Tehlar4868ff62017-03-09 16:48:39 +01004416 return lcm->flags & LISP_FLAG_STATS_ENABLED;
Filip Tehlar7eaf0e52017-03-08 08:46:51 +01004417}
4418
Florin Corasa2157cf2016-08-16 21:09:14 +02004419/* *INDENT-OFF* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004420VLIB_REGISTER_NODE (lisp_retry_service_node,static) = {
4421 .function = send_map_resolver_service,
4422 .type = VLIB_NODE_TYPE_PROCESS,
4423 .name = "lisp-retry-service",
4424 .process_log2_n_stack_bytes = 16,
4425};
Florin Corasa2157cf2016-08-16 21:09:14 +02004426/* *INDENT-ON* */
Filip Tehlara5abdeb2016-07-18 17:35:40 +02004427
Florin Corasa2157cf2016-08-16 21:09:14 +02004428VLIB_INIT_FUNCTION (lisp_cp_init);
4429
4430/*
4431 * fd.io coding-style-patch-verification: ON
4432 *
4433 * Local Variables:
4434 * eval: (c-set-style "gnu")
4435 * End:
4436 */