Line data Source code
1 : /*
2 : * Copyright (c) 2016 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <vlibmemory/api.h>
17 : #include <lisp/lisp-cp/control.h>
18 : #include <lisp/lisp-cp/packets.h>
19 : #include <lisp/lisp-cp/lisp_msg_serdes.h>
20 : #include <lisp/lisp-gpe/lisp_gpe_fwd_entry.h>
21 : #include <lisp/lisp-gpe/lisp_gpe_tenant.h>
22 : #include <lisp/lisp-gpe/lisp_gpe_tunnel.h>
23 : #include <vnet/fib/fib_entry.h>
24 : #include <vnet/fib/fib_table.h>
25 : #include <vnet/ethernet/arp_packet.h>
26 : #include <vnet/ethernet/packet.h>
27 :
28 : #include <openssl/evp.h>
29 : #include <vnet/crypto/crypto.h>
30 :
31 : #define MAX_VALUE_U24 0xffffff
32 :
33 : /* mapping timer control constants (in seconds) */
34 : #define TIME_UNTIL_REFETCH_OR_DELETE 20
35 : #define MAPPING_TIMEOUT (((m->ttl) * 60) - TIME_UNTIL_REFETCH_OR_DELETE)
36 :
37 : u8 *format_lisp_cp_input_trace (u8 * s, va_list * args);
38 : static void *send_map_request_thread_fn (void *arg);
39 :
40 : typedef enum
41 : {
42 : LISP_CP_INPUT_NEXT_DROP,
43 : LISP_CP_INPUT_N_NEXT,
44 : } lisp_cp_input_next_t;
45 :
46 : typedef struct
47 : {
48 : u8 is_resend;
49 : gid_address_t seid;
50 : gid_address_t deid;
51 : u8 smr_invoked;
52 : } map_request_args_t;
53 :
54 : u8
55 0 : vnet_lisp_get_map_request_mode (void)
56 : {
57 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
58 0 : return lcm->map_request_mode;
59 : }
60 :
61 : static u16
62 0 : auth_data_len_by_key_id (lisp_key_type_t key_id)
63 : {
64 0 : switch (key_id)
65 : {
66 0 : case HMAC_SHA_1_96:
67 0 : return SHA1_AUTH_DATA_LEN;
68 0 : case HMAC_SHA_256_128:
69 0 : return SHA256_AUTH_DATA_LEN;
70 0 : default:
71 0 : clib_warning ("unsupported key type: %d!", key_id);
72 0 : return (u16) ~ 0;
73 : }
74 : return (u16) ~ 0;
75 : }
76 :
77 : static int
78 : queue_map_request (gid_address_t * seid, gid_address_t * deid,
79 : u8 smr_invoked, u8 is_resend);
80 :
81 : ip_interface_address_t *
82 1 : ip_interface_get_first_interface_address (ip_lookup_main_t * lm,
83 : u32 sw_if_index, u8 loop)
84 : {
85 1 : vnet_main_t *vnm = vnet_get_main ();
86 1 : vnet_sw_interface_t *swif = vnet_get_sw_interface (vnm, sw_if_index);
87 1 : if (loop && swif->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
88 0 : sw_if_index = swif->unnumbered_sw_if_index;
89 1 : u32 ia =
90 1 : (vec_len ((lm)->if_address_pool_index_by_sw_if_index) > (sw_if_index)) ?
91 1 : vec_elt ((lm)->if_address_pool_index_by_sw_if_index, (sw_if_index)) :
92 : (u32) ~ 0;
93 1 : return pool_elt_at_index ((lm)->if_address_pool, ia);
94 : }
95 :
96 : void *
97 1 : ip_interface_get_first_address (ip_lookup_main_t * lm, u32 sw_if_index,
98 : u8 version)
99 : {
100 : ip_interface_address_t *ia;
101 :
102 1 : ia = ip_interface_get_first_interface_address (lm, sw_if_index, 1);
103 1 : if (!ia)
104 0 : return 0;
105 1 : return ip_interface_address_get_address (lm, ia);
106 : }
107 :
108 : int
109 1 : ip_interface_get_first_ip_address (lisp_cp_main_t *lcm, u32 sw_if_index,
110 : ip_address_family_t version,
111 : ip_address_t *result)
112 : {
113 : ip_lookup_main_t *lm;
114 : void *addr;
115 :
116 1 : lm = (version == AF_IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
117 1 : addr = ip_interface_get_first_address (lm, sw_if_index, version);
118 1 : if (!addr)
119 0 : return 0;
120 :
121 1 : ip_address_set (result, addr, version);
122 1 : return 1;
123 : }
124 :
125 : /**
126 : * Find the sw_if_index of the interface that would be used to egress towards
127 : * dst.
128 : */
129 : u32
130 1 : ip_fib_get_egress_iface_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst)
131 : {
132 : fib_node_index_t fei;
133 : fib_prefix_t prefix;
134 :
135 1 : ip_address_to_fib_prefix (dst, &prefix);
136 :
137 1 : fei = fib_table_lookup (0, &prefix);
138 :
139 1 : return (fib_entry_get_resolving_interface (fei));
140 : }
141 :
142 : /**
143 : * Find first IP of the interface that would be used to egress towards dst.
144 : * Returns 1 if the address is found 0 otherwise.
145 : */
146 : int
147 0 : ip_fib_get_first_egress_ip_for_dst (lisp_cp_main_t * lcm, ip_address_t * dst,
148 : ip_address_t * result)
149 : {
150 : u32 si;
151 : ip_lookup_main_t *lm;
152 0 : void *addr = 0;
153 : ip_address_family_t ipver;
154 :
155 0 : ASSERT (result != 0);
156 :
157 0 : ipver = ip_addr_version (dst);
158 :
159 0 : lm = (ipver == AF_IP4) ? &lcm->im4->lookup_main : &lcm->im6->lookup_main;
160 0 : si = ip_fib_get_egress_iface_for_dst (lcm, dst);
161 :
162 0 : if ((u32) ~ 0 == si)
163 0 : return 0;
164 :
165 : /* find the first ip address */
166 0 : addr = ip_interface_get_first_address (lm, si, ipver);
167 0 : if (0 == addr)
168 0 : return 0;
169 :
170 0 : ip_address_set (result, addr, ipver);
171 0 : return 1;
172 : }
173 :
174 : static int
175 1 : dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_l2, u8 is_add,
176 : u8 with_default_route)
177 : {
178 : uword *dp_table;
179 :
180 1 : if (!is_l2)
181 : {
182 1 : dp_table = hash_get (lcm->table_id_by_vni, vni);
183 :
184 1 : if (!dp_table)
185 : {
186 0 : clib_warning ("vni %d not associated to a vrf!", vni);
187 0 : return VNET_API_ERROR_INVALID_VALUE;
188 : }
189 : }
190 : else
191 : {
192 0 : dp_table = hash_get (lcm->bd_id_by_vni, vni);
193 0 : if (!dp_table)
194 : {
195 0 : clib_warning ("vni %d not associated to a bridge domain!", vni);
196 0 : return VNET_API_ERROR_INVALID_VALUE;
197 : }
198 : }
199 :
200 : /* enable/disable data-plane interface */
201 1 : if (is_add)
202 : {
203 1 : if (is_l2)
204 0 : lisp_gpe_tenant_l2_iface_add_or_lock (vni, dp_table[0]);
205 : else
206 1 : lisp_gpe_tenant_l3_iface_add_or_lock (vni, dp_table[0],
207 : with_default_route);
208 : }
209 : else
210 : {
211 0 : if (is_l2)
212 0 : lisp_gpe_tenant_l2_iface_unlock (vni);
213 : else
214 0 : lisp_gpe_tenant_l3_iface_unlock (vni);
215 : }
216 :
217 1 : return 0;
218 : }
219 :
220 : static void
221 1 : dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 dst_map_index)
222 : {
223 1 : vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
224 1 : fwd_entry_t *fe = 0;
225 1 : uword *feip = 0;
226 1 : clib_memset (a, 0, sizeof (*a));
227 :
228 1 : feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
229 1 : if (!feip)
230 0 : return;
231 :
232 1 : fe = pool_elt_at_index (lcm->fwd_entry_pool, feip[0]);
233 :
234 : /* delete dp fwd entry */
235 : u32 sw_if_index;
236 1 : a->is_add = 0;
237 1 : a->locator_pairs = fe->locator_pairs;
238 1 : a->vni = gid_address_vni (&fe->reid);
239 1 : gid_address_copy (&a->rmt_eid, &fe->reid);
240 1 : if (fe->is_src_dst)
241 0 : gid_address_copy (&a->lcl_eid, &fe->leid);
242 :
243 1 : vnet_lisp_gpe_del_fwd_counters (a, feip[0]);
244 1 : vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
245 :
246 : /* delete entry in fwd table */
247 1 : hash_unset (lcm->fwd_entry_by_mapping_index, dst_map_index);
248 1 : vec_free (fe->locator_pairs);
249 1 : pool_put (lcm->fwd_entry_pool, fe);
250 : }
251 :
252 : /**
253 : * Finds first remote locator with best (lowest) priority that has a local
254 : * peer locator with an underlying route to it.
255 : *
256 : */
257 : static u32
258 1 : get_locator_pairs (lisp_cp_main_t * lcm, mapping_t * lcl_map,
259 : mapping_t * rmt_map, locator_pair_t ** locator_pairs)
260 : {
261 1 : u32 i, limitp = 0, li, found = 0, esi;
262 : locator_set_t *rmt_ls, *lcl_ls;
263 1 : ip_address_t _lcl_addr, *lcl_addr = &_lcl_addr;
264 1 : locator_t *lp, *rmt = 0;
265 1 : uword *checked = 0;
266 : locator_pair_t pair;
267 :
268 1 : rmt_ls =
269 1 : pool_elt_at_index (lcm->locator_set_pool, rmt_map->locator_set_index);
270 1 : lcl_ls =
271 1 : pool_elt_at_index (lcm->locator_set_pool, lcl_map->locator_set_index);
272 :
273 1 : if (!rmt_ls || vec_len (rmt_ls->locator_indices) == 0)
274 0 : return 0;
275 :
276 : while (1)
277 : {
278 2 : rmt = 0;
279 :
280 : /* find unvisited remote locator with best priority */
281 3 : for (i = 0; i < vec_len (rmt_ls->locator_indices); i++)
282 : {
283 2 : if (0 != hash_get (checked, i))
284 1 : continue;
285 :
286 1 : li = vec_elt (rmt_ls->locator_indices, i);
287 1 : lp = pool_elt_at_index (lcm->locator_pool, li);
288 :
289 : /* we don't support non-IP locators for now */
290 1 : if (gid_address_type (&lp->address) != GID_ADDR_IP_PREFIX)
291 0 : continue;
292 :
293 1 : if ((found && lp->priority == limitp)
294 1 : || (!found && lp->priority >= limitp))
295 : {
296 1 : rmt = lp;
297 :
298 : /* don't search for locators with lower priority and don't
299 : * check this locator again*/
300 1 : limitp = lp->priority;
301 1 : hash_set (checked, i, 1);
302 1 : break;
303 : }
304 : }
305 : /* check if a local locator with a route to remote locator exists */
306 2 : if (rmt != 0)
307 : {
308 : /* find egress sw_if_index for rmt locator */
309 : esi =
310 1 : ip_fib_get_egress_iface_for_dst (lcm,
311 : &gid_address_ip (&rmt->address));
312 1 : if ((u32) ~ 0 == esi)
313 0 : continue;
314 :
315 2 : for (i = 0; i < vec_len (lcl_ls->locator_indices); i++)
316 : {
317 1 : li = vec_elt (lcl_ls->locator_indices, i);
318 1 : locator_t *sl = pool_elt_at_index (lcm->locator_pool, li);
319 :
320 : /* found local locator with the needed sw_if_index */
321 1 : if (sl->sw_if_index == esi)
322 : {
323 : /* and it has an address */
324 1 : if (0 == ip_interface_get_first_ip_address (lcm,
325 : sl->sw_if_index,
326 1 : gid_address_ip_version
327 : (&rmt->address),
328 : lcl_addr))
329 0 : continue;
330 :
331 1 : clib_memset (&pair, 0, sizeof (pair));
332 1 : ip_address_copy (&pair.rmt_loc,
333 1 : &gid_address_ip (&rmt->address));
334 1 : ip_address_copy (&pair.lcl_loc, lcl_addr);
335 1 : pair.weight = rmt->weight;
336 1 : pair.priority = rmt->priority;
337 1 : vec_add1 (locator_pairs[0], pair);
338 1 : found = 1;
339 : }
340 : }
341 : }
342 : else
343 1 : break;
344 : }
345 :
346 1 : hash_free (checked);
347 1 : return found;
348 : }
349 :
350 : static void
351 0 : gid_address_sd_to_flat (gid_address_t * dst, gid_address_t * src,
352 : fid_address_t * fid)
353 : {
354 0 : ASSERT (GID_ADDR_SRC_DST == gid_address_type (src));
355 :
356 0 : dst[0] = src[0];
357 :
358 0 : switch (fid_addr_type (fid))
359 : {
360 0 : case FID_ADDR_IP_PREF:
361 0 : gid_address_type (dst) = GID_ADDR_IP_PREFIX;
362 0 : gid_address_ippref (dst) = fid_addr_ippref (fid);
363 0 : break;
364 0 : case FID_ADDR_MAC:
365 0 : gid_address_type (dst) = GID_ADDR_MAC;
366 0 : mac_copy (gid_address_mac (dst), fid_addr_mac (fid));
367 0 : break;
368 0 : default:
369 0 : clib_warning ("Unsupported fid type %d!", fid_addr_type (fid));
370 0 : break;
371 : }
372 0 : }
373 :
374 : u8
375 0 : vnet_lisp_map_register_state_get (void)
376 : {
377 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
378 0 : return lcm->map_registering;
379 : }
380 :
381 : u8
382 0 : vnet_lisp_rloc_probe_state_get (void)
383 : {
384 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
385 0 : return lcm->rloc_probing;
386 : }
387 :
388 : static void
389 1 : dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
390 : {
391 1 : vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
392 : gid_address_t *rmt_eid, *lcl_eid;
393 : mapping_t *lcl_map, *rmt_map;
394 : u32 sw_if_index, **rmts, rmts_idx;
395 1 : uword *feip = 0, *dpid, *rmts_stored_idxp = 0;
396 : fwd_entry_t *fe;
397 1 : u8 type, is_src_dst = 0;
398 : int rv;
399 :
400 1 : clib_memset (a, 0, sizeof (*a));
401 :
402 : /* remove entry if it already exists */
403 1 : feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index);
404 1 : if (feip)
405 0 : dp_del_fwd_entry (lcm, dst_map_index);
406 :
407 : /*
408 : * Determine local mapping and eid
409 : */
410 1 : if (lcm->flags & LISP_FLAG_PITR_MODE)
411 : {
412 0 : if (lcm->pitr_map_index != ~0)
413 0 : lcl_map = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
414 : else
415 : {
416 0 : clib_warning ("no PITR mapping configured!");
417 0 : return;
418 : }
419 : }
420 : else
421 1 : lcl_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
422 1 : lcl_eid = &lcl_map->eid;
423 :
424 : /*
425 : * Determine remote mapping and eid
426 : */
427 1 : rmt_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
428 1 : rmt_eid = &rmt_map->eid;
429 :
430 : /*
431 : * Build and insert data plane forwarding entry
432 : */
433 1 : a->is_add = 1;
434 :
435 1 : if (MR_MODE_SRC_DST == lcm->map_request_mode)
436 : {
437 0 : if (GID_ADDR_SRC_DST == gid_address_type (rmt_eid))
438 : {
439 0 : gid_address_sd_to_flat (&a->rmt_eid, rmt_eid,
440 : &gid_address_sd_dst (rmt_eid));
441 0 : gid_address_sd_to_flat (&a->lcl_eid, rmt_eid,
442 : &gid_address_sd_src (rmt_eid));
443 : }
444 : else
445 : {
446 0 : gid_address_copy (&a->rmt_eid, rmt_eid);
447 0 : gid_address_copy (&a->lcl_eid, lcl_eid);
448 : }
449 0 : is_src_dst = 1;
450 : }
451 : else
452 1 : gid_address_copy (&a->rmt_eid, rmt_eid);
453 :
454 1 : a->vni = gid_address_vni (&a->rmt_eid);
455 1 : a->is_src_dst = is_src_dst;
456 :
457 : /* get vrf or bd_index associated to vni */
458 1 : type = gid_address_type (&a->rmt_eid);
459 1 : if (GID_ADDR_IP_PREFIX == type)
460 : {
461 1 : dpid = hash_get (lcm->table_id_by_vni, a->vni);
462 1 : if (!dpid)
463 : {
464 0 : clib_warning ("vni %d not associated to a vrf!", a->vni);
465 0 : return;
466 : }
467 1 : a->table_id = dpid[0];
468 : }
469 0 : else if (GID_ADDR_MAC == type)
470 : {
471 0 : dpid = hash_get (lcm->bd_id_by_vni, a->vni);
472 0 : if (!dpid)
473 : {
474 0 : clib_warning ("vni %d not associated to a bridge domain !", a->vni);
475 0 : return;
476 : }
477 0 : a->bd_id = dpid[0];
478 : }
479 :
480 : /* find best locator pair that 1) verifies LISP policy 2) are connected */
481 1 : rv = get_locator_pairs (lcm, lcl_map, rmt_map, &a->locator_pairs);
482 :
483 : /* Either rmt mapping is negative or we can't find underlay path.
484 : * Try again with petr if configured */
485 1 : if (rv == 0 && (lcm->flags & LISP_FLAG_USE_PETR))
486 : {
487 0 : rmt_map = lisp_get_petr_mapping (lcm);
488 0 : rv = get_locator_pairs (lcm, lcl_map, rmt_map, &a->locator_pairs);
489 : }
490 :
491 : /* negative entry */
492 1 : if (rv == 0)
493 : {
494 0 : a->is_negative = 1;
495 0 : a->action = rmt_map->action;
496 : }
497 :
498 1 : rv = vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
499 1 : if (rv)
500 : {
501 0 : if (a->locator_pairs)
502 0 : vec_free (a->locator_pairs);
503 0 : return;
504 : }
505 :
506 : /* add tunnel to fwd entry table */
507 1 : pool_get (lcm->fwd_entry_pool, fe);
508 1 : vnet_lisp_gpe_add_fwd_counters (a, fe - lcm->fwd_entry_pool);
509 :
510 1 : fe->locator_pairs = a->locator_pairs;
511 1 : gid_address_copy (&fe->reid, &a->rmt_eid);
512 :
513 1 : if (is_src_dst)
514 0 : gid_address_copy (&fe->leid, &a->lcl_eid);
515 : else
516 1 : gid_address_copy (&fe->leid, lcl_eid);
517 :
518 1 : fe->is_src_dst = is_src_dst;
519 1 : hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
520 : fe - lcm->fwd_entry_pool);
521 :
522 : /* Add rmt mapping to the vector of adjacent mappings to lcl mapping */
523 : rmts_stored_idxp =
524 1 : hash_get (lcm->lcl_to_rmt_adjs_by_lcl_idx, src_map_index);
525 1 : if (!rmts_stored_idxp)
526 : {
527 1 : pool_get (lcm->lcl_to_rmt_adjacencies, rmts);
528 1 : clib_memset (rmts, 0, sizeof (*rmts));
529 1 : rmts_idx = rmts - lcm->lcl_to_rmt_adjacencies;
530 1 : hash_set (lcm->lcl_to_rmt_adjs_by_lcl_idx, src_map_index, rmts_idx);
531 : }
532 : else
533 : {
534 0 : rmts_idx = (u32) (*rmts_stored_idxp);
535 0 : rmts = pool_elt_at_index (lcm->lcl_to_rmt_adjacencies, rmts_idx);
536 : }
537 1 : vec_add1 (rmts[0], dst_map_index);
538 : }
539 :
540 : typedef struct
541 : {
542 : u32 si;
543 : u32 di;
544 : } fwd_entry_mt_arg_t;
545 :
546 : static void *
547 0 : dp_add_fwd_entry_thread_fn (void *arg)
548 : {
549 0 : fwd_entry_mt_arg_t *a = arg;
550 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
551 0 : dp_add_fwd_entry (lcm, a->si, a->di);
552 0 : return 0;
553 : }
554 :
555 : static int
556 0 : dp_add_fwd_entry_from_mt (u32 si, u32 di)
557 : {
558 : fwd_entry_mt_arg_t a;
559 :
560 0 : clib_memset (&a, 0, sizeof (a));
561 0 : a.si = si;
562 0 : a.di = di;
563 :
564 0 : vl_api_rpc_call_main_thread (dp_add_fwd_entry_thread_fn,
565 : (u8 *) & a, sizeof (a));
566 0 : return 0;
567 : }
568 :
569 : /**
570 : * Returns vector of adjacencies.
571 : *
572 : * The caller must free the vector returned by this function.
573 : *
574 : * @param vni virtual network identifier
575 : * @return vector of adjacencies
576 : */
577 : lisp_adjacency_t *
578 1 : vnet_lisp_adjacencies_get_by_vni (u32 vni)
579 : {
580 1 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
581 : fwd_entry_t *fwd;
582 1 : lisp_adjacency_t *adjs = 0, adj;
583 :
584 : /* *INDENT-OFF* */
585 2 : pool_foreach (fwd, lcm->fwd_entry_pool)
586 : {
587 1 : if (gid_address_vni (&fwd->reid) != vni)
588 0 : continue;
589 :
590 1 : gid_address_copy (&adj.reid, &fwd->reid);
591 1 : gid_address_copy (&adj.leid, &fwd->leid);
592 1 : vec_add1 (adjs, adj);
593 : }
594 : /* *INDENT-ON* */
595 :
596 1 : return adjs;
597 : }
598 :
599 : static lisp_msmr_t *
600 0 : get_map_server (ip_address_t * a)
601 : {
602 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
603 : lisp_msmr_t *m;
604 :
605 0 : vec_foreach (m, lcm->map_servers)
606 : {
607 0 : if (!ip_address_cmp (&m->address, a))
608 : {
609 0 : return m;
610 : }
611 : }
612 0 : return 0;
613 : }
614 :
615 : static lisp_msmr_t *
616 0 : get_map_resolver (ip_address_t * a)
617 : {
618 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
619 : lisp_msmr_t *m;
620 :
621 0 : vec_foreach (m, lcm->map_resolvers)
622 : {
623 0 : if (!ip_address_cmp (&m->address, a))
624 : {
625 0 : return m;
626 : }
627 : }
628 0 : return 0;
629 : }
630 :
631 : int
632 0 : vnet_lisp_add_del_map_server (ip_address_t * addr, u8 is_add)
633 : {
634 : u32 i;
635 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
636 0 : lisp_msmr_t _ms, *ms = &_ms;
637 :
638 0 : if (vnet_lisp_enable_disable_status () == 0)
639 : {
640 0 : clib_warning ("LISP is disabled!");
641 0 : return VNET_API_ERROR_LISP_DISABLED;
642 : }
643 :
644 0 : if (is_add)
645 : {
646 0 : if (get_map_server (addr))
647 : {
648 0 : clib_warning ("map-server %U already exists!", format_ip_address,
649 : addr);
650 0 : return -1;
651 : }
652 :
653 0 : clib_memset (ms, 0, sizeof (*ms));
654 0 : ip_address_copy (&ms->address, addr);
655 0 : vec_add1 (lcm->map_servers, ms[0]);
656 :
657 0 : if (vec_len (lcm->map_servers) == 1)
658 0 : lcm->do_map_server_election = 1;
659 : }
660 : else
661 : {
662 0 : for (i = 0; i < vec_len (lcm->map_servers); i++)
663 : {
664 0 : ms = vec_elt_at_index (lcm->map_servers, i);
665 0 : if (!ip_address_cmp (&ms->address, addr))
666 : {
667 0 : if (!ip_address_cmp (&ms->address, &lcm->active_map_server))
668 0 : lcm->do_map_server_election = 1;
669 :
670 0 : vec_del1 (lcm->map_servers, i);
671 0 : break;
672 : }
673 : }
674 : }
675 :
676 0 : return 0;
677 : }
678 :
679 : /**
680 : * Add/remove mapping to/from map-cache. Overwriting not allowed.
681 : */
682 : int
683 4 : vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a,
684 : u32 * map_index_result)
685 : {
686 4 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
687 : u32 mi, *map_indexp, map_index, i;
688 4 : u32 **rmts = 0, *remote_idxp, rmts_itr, remote_idx;
689 : uword *rmts_idxp;
690 : mapping_t *m, *old_map;
691 : u32 **eid_indexes;
692 :
693 4 : if (gid_address_type (&a->eid) == GID_ADDR_NSH)
694 : {
695 0 : if (gid_address_vni (&a->eid) != 0)
696 : {
697 0 : clib_warning ("Supported only default VNI for NSH!");
698 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
699 : }
700 0 : if (gid_address_nsh_spi (&a->eid) > MAX_VALUE_U24)
701 : {
702 0 : clib_warning ("SPI is greater than 24bit!");
703 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
704 : }
705 : }
706 :
707 4 : mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid);
708 4 : old_map = mi != ~0 ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
709 4 : if (a->is_add)
710 : {
711 : /* TODO check if overwriting and take appropriate actions */
712 2 : if (mi != GID_LOOKUP_MISS && !gid_address_cmp (&old_map->eid, &a->eid))
713 : {
714 0 : clib_warning ("eid %U found in the eid-table", format_gid_address,
715 : &a->eid);
716 0 : return VNET_API_ERROR_VALUE_EXIST;
717 : }
718 :
719 2 : pool_get (lcm->mapping_pool, m);
720 2 : gid_address_copy (&m->eid, &a->eid);
721 2 : m->locator_set_index = a->locator_set_index;
722 2 : m->ttl = a->ttl;
723 2 : m->action = a->action;
724 2 : m->local = a->local;
725 2 : m->is_static = a->is_static;
726 2 : m->key = vec_dup (a->key);
727 2 : m->key_id = a->key_id;
728 2 : m->authoritative = a->authoritative;
729 :
730 2 : map_index = m - lcm->mapping_pool;
731 2 : gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, map_index,
732 : 1);
733 :
734 2 : if (pool_is_free_index (lcm->locator_set_pool, a->locator_set_index))
735 : {
736 0 : clib_warning ("Locator set with index %d doesn't exist",
737 : a->locator_set_index);
738 0 : return VNET_API_ERROR_INVALID_VALUE;
739 : }
740 :
741 : /* add eid to list of eids supported by locator-set */
742 2 : vec_validate (lcm->locator_set_to_eids, a->locator_set_index);
743 2 : eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
744 : a->locator_set_index);
745 2 : vec_add1 (eid_indexes[0], map_index);
746 :
747 2 : if (a->local)
748 : {
749 : /* mark as local */
750 1 : vec_add1 (lcm->local_mappings_indexes, map_index);
751 : }
752 2 : map_index_result[0] = map_index;
753 : }
754 : else
755 : {
756 2 : if (mi == GID_LOOKUP_MISS)
757 : {
758 0 : clib_warning ("eid %U not found in the eid-table",
759 : format_gid_address, &a->eid);
760 0 : return VNET_API_ERROR_INVALID_VALUE;
761 : }
762 :
763 : /* clear locator-set to eids binding */
764 2 : eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids,
765 : a->locator_set_index);
766 2 : for (i = 0; i < vec_len (eid_indexes[0]); i++)
767 : {
768 2 : map_indexp = vec_elt_at_index (eid_indexes[0], i);
769 2 : if (map_indexp[0] == mi)
770 2 : break;
771 : }
772 2 : vec_del1 (eid_indexes[0], i);
773 :
774 : /* remove local mark if needed */
775 2 : m = pool_elt_at_index (lcm->mapping_pool, mi);
776 2 : if (m->local)
777 : {
778 : /* Remove adjacencies associated with the local mapping */
779 1 : rmts_idxp = hash_get (lcm->lcl_to_rmt_adjs_by_lcl_idx, mi);
780 1 : if (rmts_idxp)
781 : {
782 1 : rmts =
783 1 : pool_elt_at_index (lcm->lcl_to_rmt_adjacencies, rmts_idxp[0]);
784 1 : vec_foreach (remote_idxp, rmts[0])
785 : {
786 0 : dp_del_fwd_entry (lcm, remote_idxp[0]);
787 : }
788 1 : vec_free (rmts[0]);
789 1 : pool_put (lcm->lcl_to_rmt_adjacencies, rmts);
790 1 : hash_unset (lcm->lcl_to_rmt_adjs_by_lcl_idx, mi);
791 : }
792 :
793 : u32 k, *lm_indexp;
794 1 : for (k = 0; k < vec_len (lcm->local_mappings_indexes); k++)
795 : {
796 1 : lm_indexp = vec_elt_at_index (lcm->local_mappings_indexes, k);
797 1 : if (lm_indexp[0] == mi)
798 1 : break;
799 : }
800 1 : vec_del1 (lcm->local_mappings_indexes, k);
801 : }
802 : else
803 : {
804 : /* Remove remote (if present) from the vectors of lcl-to-rmts
805 : * TODO: Address this in a more efficient way.
806 : */
807 : /* *INDENT-OFF* */
808 2 : pool_foreach (rmts, lcm->lcl_to_rmt_adjacencies)
809 : {
810 1 : vec_foreach_index (rmts_itr, rmts[0])
811 : {
812 1 : remote_idx = vec_elt (rmts[0], rmts_itr);
813 1 : if (mi == remote_idx)
814 : {
815 1 : vec_del1 (rmts[0], rmts_itr);
816 1 : break;
817 : }
818 : }
819 : }
820 : /* *INDENT-ON* */
821 : }
822 :
823 : /* remove mapping from dictionary */
824 2 : gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, 0, 0);
825 2 : gid_address_free (&m->eid);
826 2 : pool_put_index (lcm->mapping_pool, mi);
827 : }
828 :
829 4 : return 0;
830 : }
831 :
832 : /**
833 : * Add/update/delete mapping to/in/from map-cache.
834 : */
835 : int
836 2 : vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
837 : u32 * map_index_result)
838 : {
839 2 : uword *dp_table = 0;
840 : u32 vni;
841 : u8 type;
842 :
843 2 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
844 :
845 2 : if (vnet_lisp_enable_disable_status () == 0)
846 : {
847 0 : clib_warning ("LISP is disabled!");
848 0 : return VNET_API_ERROR_LISP_DISABLED;
849 : }
850 :
851 2 : vni = gid_address_vni (&a->eid);
852 2 : type = gid_address_type (&a->eid);
853 2 : if (GID_ADDR_IP_PREFIX == type)
854 2 : dp_table = hash_get (lcm->table_id_by_vni, vni);
855 0 : else if (GID_ADDR_MAC == type)
856 0 : dp_table = hash_get (lcm->bd_id_by_vni, vni);
857 :
858 2 : if (!dp_table && GID_ADDR_NSH != type)
859 : {
860 0 : clib_warning ("vni %d not associated to a %s!", vni,
861 : GID_ADDR_IP_PREFIX == type ? "vrf" : "bd");
862 0 : return VNET_API_ERROR_INVALID_VALUE;
863 : }
864 :
865 : /* store/remove mapping from map-cache */
866 2 : return vnet_lisp_map_cache_add_del (a, map_index_result);
867 : }
868 :
869 : static int
870 0 : add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg)
871 : {
872 0 : u32 **ht = arg;
873 0 : u32 version = (u32) kvp->key[0];
874 0 : if (AF_IP6 == version)
875 0 : return (BIHASH_WALK_CONTINUE);
876 :
877 0 : u32 bd = (u32) (kvp->key[0] >> 32);
878 0 : hash_set (ht[0], bd, 0);
879 0 : return (BIHASH_WALK_CONTINUE);
880 : }
881 :
882 : u32 *
883 0 : vnet_lisp_l2_arp_bds_get (void)
884 : {
885 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
886 0 : u32 *bds = 0;
887 :
888 0 : gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
889 : add_l2_arp_bd, &bds);
890 0 : return bds;
891 : }
892 :
893 : static int
894 0 : add_ndp_bd (BVT (clib_bihash_kv) * kvp, void *arg)
895 : {
896 0 : u32 **ht = arg;
897 0 : u32 version = (u32) kvp->key[0];
898 0 : if (AF_IP4 == version)
899 0 : return (BIHASH_WALK_CONTINUE);
900 :
901 0 : u32 bd = (u32) (kvp->key[0] >> 32);
902 0 : hash_set (ht[0], bd, 0);
903 0 : return (BIHASH_WALK_CONTINUE);
904 : }
905 :
906 : u32 *
907 0 : vnet_lisp_ndp_bds_get (void)
908 : {
909 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
910 0 : u32 *bds = 0;
911 :
912 0 : gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
913 : add_ndp_bd, &bds);
914 0 : return bds;
915 : }
916 :
917 : typedef struct
918 : {
919 : void *vector;
920 : u32 bd;
921 : } lisp_add_l2_arp_ndp_args_t;
922 :
923 : static int
924 0 : add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg)
925 : {
926 0 : lisp_add_l2_arp_ndp_args_t *a = arg;
927 0 : lisp_api_l2_arp_entry_t **vector = a->vector, e;
928 :
929 0 : u32 version = (u32) kvp->key[0];
930 0 : if (AF_IP6 == version)
931 0 : return (BIHASH_WALK_CONTINUE);
932 :
933 0 : u32 bd = (u32) (kvp->key[0] >> 32);
934 :
935 0 : if (bd == a->bd)
936 : {
937 0 : mac_copy (e.mac, (void *) &kvp->value);
938 0 : e.ip4 = (u32) kvp->key[1];
939 0 : vec_add1 (vector[0], e);
940 : }
941 0 : return (BIHASH_WALK_CONTINUE);
942 : }
943 :
944 : lisp_api_l2_arp_entry_t *
945 0 : vnet_lisp_l2_arp_entries_get_by_bd (u32 bd)
946 : {
947 0 : lisp_api_l2_arp_entry_t *entries = 0;
948 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
949 : lisp_add_l2_arp_ndp_args_t a;
950 :
951 0 : a.vector = &entries;
952 0 : a.bd = bd;
953 :
954 0 : gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
955 : add_l2_arp_entry, &a);
956 0 : return entries;
957 : }
958 :
959 : static int
960 0 : add_ndp_entry (BVT (clib_bihash_kv) * kvp, void *arg)
961 : {
962 0 : lisp_add_l2_arp_ndp_args_t *a = arg;
963 0 : lisp_api_ndp_entry_t **vector = a->vector, e;
964 :
965 0 : u32 version = (u32) kvp->key[0];
966 0 : if (AF_IP4 == version)
967 0 : return (BIHASH_WALK_CONTINUE);
968 :
969 0 : u32 bd = (u32) (kvp->key[0] >> 32);
970 :
971 0 : if (bd == a->bd)
972 : {
973 0 : mac_copy (e.mac, (void *) &kvp->value);
974 0 : clib_memcpy (e.ip6, &kvp->key[1], 16);
975 0 : vec_add1 (vector[0], e);
976 : }
977 0 : return (BIHASH_WALK_CONTINUE);
978 : }
979 :
980 : lisp_api_ndp_entry_t *
981 0 : vnet_lisp_ndp_entries_get_by_bd (u32 bd)
982 : {
983 0 : lisp_api_ndp_entry_t *entries = 0;
984 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
985 : lisp_add_l2_arp_ndp_args_t a;
986 :
987 0 : a.vector = &entries;
988 0 : a.bd = bd;
989 :
990 0 : gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid,
991 : add_ndp_entry, &a);
992 0 : return entries;
993 : }
994 :
995 : int
996 0 : vnet_lisp_add_del_l2_arp_ndp_entry (gid_address_t * key, u8 * mac, u8 is_add)
997 : {
998 0 : if (vnet_lisp_enable_disable_status () == 0)
999 : {
1000 0 : clib_warning ("LISP is disabled!");
1001 0 : return VNET_API_ERROR_LISP_DISABLED;
1002 : }
1003 :
1004 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1005 0 : int rc = 0;
1006 :
1007 0 : u64 res = gid_dictionary_lookup (&lcm->mapping_index_by_gid, key);
1008 0 : if (is_add)
1009 : {
1010 0 : if (res != GID_LOOKUP_MISS_L2)
1011 : {
1012 0 : clib_warning ("Entry %U exists in DB!", format_gid_address, key);
1013 0 : return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
1014 : }
1015 0 : u64 val = mac_to_u64 (mac);
1016 0 : gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, val,
1017 : 1 /* is_add */ );
1018 : }
1019 : else
1020 : {
1021 0 : if (res == GID_LOOKUP_MISS_L2)
1022 : {
1023 0 : clib_warning ("ONE entry %U not found - cannot delete!",
1024 : format_gid_address, key);
1025 0 : return -1;
1026 : }
1027 0 : gid_dictionary_add_del (&lcm->mapping_index_by_gid, key, 0,
1028 : 0 /* is_add */ );
1029 : }
1030 :
1031 0 : return rc;
1032 : }
1033 :
1034 : int
1035 0 : vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add)
1036 : {
1037 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1038 : uword *dp_idp, *vnip, **dp_table_by_vni, **vni_by_dp_table;
1039 :
1040 0 : if (vnet_lisp_enable_disable_status () == 0)
1041 : {
1042 0 : clib_warning ("LISP is disabled!");
1043 0 : return VNET_API_ERROR_LISP_DISABLED;
1044 : }
1045 :
1046 0 : dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni;
1047 0 : vni_by_dp_table = is_l2 ? &lcm->vni_by_bd_id : &lcm->vni_by_table_id;
1048 :
1049 0 : if (!is_l2 && (vni == 0 || dp_id == 0))
1050 : {
1051 0 : clib_warning ("can't add/del default vni-vrf mapping!");
1052 0 : return -1;
1053 : }
1054 :
1055 0 : dp_idp = hash_get (dp_table_by_vni[0], vni);
1056 0 : vnip = hash_get (vni_by_dp_table[0], dp_id);
1057 :
1058 0 : if (is_add)
1059 : {
1060 0 : if (dp_idp || vnip)
1061 : {
1062 0 : clib_warning ("vni %d or vrf %d already used in vrf/vni "
1063 : "mapping!", vni, dp_id);
1064 0 : return -1;
1065 : }
1066 0 : hash_set (dp_table_by_vni[0], vni, dp_id);
1067 0 : hash_set (vni_by_dp_table[0], dp_id, vni);
1068 :
1069 : /* create dp iface */
1070 0 : dp_add_del_iface (lcm, vni, is_l2, 1 /* is_add */ ,
1071 : 1 /* with_default_route */ );
1072 : }
1073 : else
1074 : {
1075 0 : if (!dp_idp || !vnip)
1076 : {
1077 0 : clib_warning ("vni %d or vrf %d not used in any vrf/vni! "
1078 : "mapping!", vni, dp_id);
1079 0 : return -1;
1080 : }
1081 : /* remove dp iface */
1082 0 : dp_add_del_iface (lcm, vni, is_l2, 0 /* is_add */ , 0 /* unused */ );
1083 :
1084 0 : hash_unset (dp_table_by_vni[0], vni);
1085 0 : hash_unset (vni_by_dp_table[0], dp_id);
1086 : }
1087 0 : return 0;
1088 :
1089 : }
1090 :
1091 : /* return 0 if the two locator sets are identical 1 otherwise */
1092 : static u8
1093 0 : compare_locators (lisp_cp_main_t * lcm, u32 * old_ls_indexes,
1094 : locator_t * new_locators)
1095 : {
1096 : u32 i, old_li;
1097 : locator_t *old_loc, *new_loc;
1098 :
1099 0 : if (vec_len (old_ls_indexes) != vec_len (new_locators))
1100 0 : return 1;
1101 :
1102 0 : for (i = 0; i < vec_len (new_locators); i++)
1103 : {
1104 0 : old_li = vec_elt (old_ls_indexes, i);
1105 0 : old_loc = pool_elt_at_index (lcm->locator_pool, old_li);
1106 :
1107 0 : new_loc = vec_elt_at_index (new_locators, i);
1108 :
1109 0 : if (locator_cmp (old_loc, new_loc))
1110 0 : return 1;
1111 : }
1112 0 : return 0;
1113 : }
1114 :
1115 : typedef struct
1116 : {
1117 : u8 is_negative;
1118 : void *lcm;
1119 : gid_address_t *eids_to_be_deleted;
1120 : } remove_mapping_args_t;
1121 :
1122 : /**
1123 : * Callback invoked when a sub-prefix is found
1124 : */
1125 : static void
1126 0 : remove_mapping_if_needed (u32 mi, void *arg)
1127 : {
1128 0 : u8 delete = 0;
1129 0 : remove_mapping_args_t *a = arg;
1130 0 : lisp_cp_main_t *lcm = a->lcm;
1131 : mapping_t *m;
1132 : locator_set_t *ls;
1133 :
1134 0 : m = pool_elt_at_index (lcm->mapping_pool, mi);
1135 0 : ls = pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
1136 :
1137 0 : if (a->is_negative)
1138 : {
1139 0 : if (0 != vec_len (ls->locator_indices))
1140 0 : delete = 1;
1141 : }
1142 : else
1143 : {
1144 0 : if (0 == vec_len (ls->locator_indices))
1145 0 : delete = 1;
1146 : }
1147 :
1148 0 : if (delete)
1149 0 : vec_add1 (a->eids_to_be_deleted, m->eid);
1150 0 : }
1151 :
1152 : /**
1153 : * This function searches map cache and looks for IP prefixes that are subset
1154 : * of the provided one. If such prefix is found depending on 'is_negative'
1155 : * it does follows:
1156 : *
1157 : * 1) if is_negative is true and found prefix points to positive mapping,
1158 : * then the mapping is removed
1159 : * 2) if is_negative is false and found prefix points to negative mapping,
1160 : * then the mapping is removed
1161 : */
1162 : static void
1163 1 : remove_overlapping_sub_prefixes (lisp_cp_main_t * lcm, gid_address_t * eid,
1164 : u8 is_negative)
1165 : {
1166 : gid_address_t *e;
1167 : remove_mapping_args_t a;
1168 :
1169 1 : clib_memset (&a, 0, sizeof (a));
1170 :
1171 : /* do this only in src/dst mode ... */
1172 1 : if (MR_MODE_SRC_DST != lcm->map_request_mode)
1173 1 : return;
1174 :
1175 : /* ... and only for IP prefix */
1176 0 : if (GID_ADDR_SRC_DST != gid_address_type (eid)
1177 0 : || (FID_ADDR_IP_PREF != gid_address_sd_dst_type (eid)))
1178 0 : return;
1179 :
1180 0 : a.is_negative = is_negative;
1181 0 : a.lcm = lcm;
1182 :
1183 0 : gid_dict_foreach_subprefix (&lcm->mapping_index_by_gid, eid,
1184 : remove_mapping_if_needed, &a);
1185 :
1186 0 : vec_foreach (e, a.eids_to_be_deleted)
1187 : {
1188 0 : vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
1189 :
1190 0 : clib_memset (adj_args, 0, sizeof (adj_args[0]));
1191 0 : gid_address_copy (&adj_args->reid, e);
1192 0 : adj_args->is_add = 0;
1193 0 : if (vnet_lisp_add_del_adjacency (adj_args))
1194 0 : clib_warning ("failed to del adjacency!");
1195 :
1196 0 : vnet_lisp_del_mapping (e, NULL);
1197 : }
1198 :
1199 0 : vec_free (a.eids_to_be_deleted);
1200 : }
1201 :
1202 : static int
1203 1 : is_local_ip (lisp_cp_main_t * lcm, ip_address_t * addr)
1204 : {
1205 : fib_node_index_t fei;
1206 : fib_prefix_t prefix;
1207 : fib_entry_flag_t flags;
1208 :
1209 1 : ip_address_to_fib_prefix (addr, &prefix);
1210 :
1211 1 : fei = fib_table_lookup (0, &prefix);
1212 1 : flags = fib_entry_get_flags (fei);
1213 1 : return (FIB_ENTRY_FLAG_LOCAL & flags);
1214 : }
1215 :
1216 : /**
1217 : * Adds/updates mapping. Does not program forwarding.
1218 : *
1219 : * @param a parameters of the new mapping
1220 : * @param rlocs vector of remote locators
1221 : * @param res_map_index index of the newly created mapping
1222 : * @param locators_changed indicator if locators were updated in the mapping
1223 : * @return return code
1224 : */
1225 : int
1226 1 : vnet_lisp_add_mapping (vnet_lisp_add_del_mapping_args_t * a,
1227 : locator_t * rlocs,
1228 : u32 * res_map_index, u8 * is_updated)
1229 : {
1230 1 : vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
1231 1 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1232 1 : u32 mi, ls_index = 0, dst_map_index;
1233 : mapping_t *old_map;
1234 : locator_t *loc;
1235 :
1236 1 : if (vnet_lisp_enable_disable_status () == 0)
1237 : {
1238 0 : clib_warning ("LISP is disabled!");
1239 0 : return VNET_API_ERROR_LISP_DISABLED;
1240 : }
1241 :
1242 1 : if (res_map_index)
1243 0 : res_map_index[0] = ~0;
1244 1 : if (is_updated)
1245 0 : is_updated[0] = 0;
1246 :
1247 1 : clib_memset (ls_args, 0, sizeof (ls_args[0]));
1248 :
1249 1 : ls_args->locators = rlocs;
1250 1 : mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid);
1251 1 : old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
1252 :
1253 : /* check if none of the locators match locally configured address */
1254 2 : vec_foreach (loc, rlocs)
1255 : {
1256 1 : ip_prefix_t *p = &gid_address_ippref (&loc->address);
1257 1 : if (is_local_ip (lcm, &ip_prefix_addr (p)))
1258 : {
1259 0 : clib_warning ("RLOC %U matches a local address!",
1260 : format_gid_address, &loc->address);
1261 0 : return VNET_API_ERROR_LISP_RLOC_LOCAL;
1262 : }
1263 : }
1264 :
1265 : /* overwrite: if mapping already exists, decide if locators should be
1266 : * updated and be done */
1267 1 : if (old_map && gid_address_cmp (&old_map->eid, &a->eid) == 0)
1268 0 : {
1269 0 : if (!a->is_static && (old_map->is_static || old_map->local))
1270 : {
1271 : /* do not overwrite local or static remote mappings */
1272 0 : clib_warning ("mapping %U rejected due to collision with local "
1273 : "or static remote mapping!", format_gid_address,
1274 : &a->eid);
1275 0 : return 0;
1276 : }
1277 :
1278 : locator_set_t *old_ls;
1279 :
1280 : /* update mapping attributes */
1281 0 : old_map->action = a->action;
1282 0 : if (old_map->action != a->action && NULL != is_updated)
1283 0 : is_updated[0] = 1;
1284 :
1285 0 : old_map->authoritative = a->authoritative;
1286 0 : old_map->ttl = a->ttl;
1287 :
1288 0 : old_ls = pool_elt_at_index (lcm->locator_set_pool,
1289 : old_map->locator_set_index);
1290 0 : if (compare_locators (lcm, old_ls->locator_indices, ls_args->locators))
1291 : {
1292 : /* set locator-set index to overwrite */
1293 0 : ls_args->is_add = 1;
1294 0 : ls_args->index = old_map->locator_set_index;
1295 0 : vnet_lisp_add_del_locator_set (ls_args, 0);
1296 0 : if (is_updated)
1297 0 : is_updated[0] = 1;
1298 : }
1299 0 : if (res_map_index)
1300 0 : res_map_index[0] = mi;
1301 : }
1302 : /* new mapping */
1303 : else
1304 : {
1305 1 : if (is_updated)
1306 0 : is_updated[0] = 1;
1307 1 : remove_overlapping_sub_prefixes (lcm, &a->eid, 0 == ls_args->locators);
1308 :
1309 1 : ls_args->is_add = 1;
1310 1 : ls_args->index = ~0;
1311 :
1312 1 : vnet_lisp_add_del_locator_set (ls_args, &ls_index);
1313 :
1314 : /* add mapping */
1315 1 : a->is_add = 1;
1316 1 : a->locator_set_index = ls_index;
1317 1 : vnet_lisp_map_cache_add_del (a, &dst_map_index);
1318 :
1319 1 : if (res_map_index)
1320 0 : res_map_index[0] = dst_map_index;
1321 : }
1322 :
1323 : /* success */
1324 1 : return 0;
1325 : }
1326 :
1327 : /**
1328 : * Removes a mapping. Does not program forwarding.
1329 : *
1330 : * @param eid end-host identifier
1331 : * @param res_map_index index of the removed mapping
1332 : * @return return code
1333 : */
1334 : int
1335 1 : vnet_lisp_del_mapping (gid_address_t * eid, u32 * res_map_index)
1336 : {
1337 1 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1338 1 : vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args;
1339 1 : vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
1340 : mapping_t *old_map;
1341 : u32 mi;
1342 :
1343 1 : clib_memset (ls_args, 0, sizeof (ls_args[0]));
1344 1 : clib_memset (m_args, 0, sizeof (m_args[0]));
1345 1 : if (res_map_index)
1346 0 : res_map_index[0] = ~0;
1347 :
1348 1 : mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid);
1349 1 : old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0;
1350 :
1351 1 : if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0)
1352 : {
1353 0 : clib_warning ("cannot delete mapping for eid %U",
1354 : format_gid_address, eid);
1355 0 : return -1;
1356 : }
1357 :
1358 1 : m_args->is_add = 0;
1359 1 : gid_address_copy (&m_args->eid, eid);
1360 1 : m_args->locator_set_index = old_map->locator_set_index;
1361 :
1362 1 : ls_args->is_add = 0;
1363 1 : ls_args->index = old_map->locator_set_index;
1364 :
1365 : /* delete timer associated to the mapping if any */
1366 1 : if (old_map->timer_set)
1367 0 : TW (tw_timer_stop) (&lcm->wheel, old_map->timer_handle);
1368 :
1369 : /* delete locator set */
1370 1 : vnet_lisp_add_del_locator_set (ls_args, 0);
1371 :
1372 : /* delete mapping associated from map-cache */
1373 1 : vnet_lisp_map_cache_add_del (m_args, 0);
1374 :
1375 : /* return old mapping index */
1376 1 : if (res_map_index)
1377 0 : res_map_index[0] = mi;
1378 :
1379 : /* success */
1380 1 : return 0;
1381 : }
1382 :
1383 : int
1384 0 : vnet_lisp_clear_all_remote_adjacencies (void)
1385 : {
1386 0 : int rv = 0;
1387 0 : u32 mi, *map_indices = 0, *map_indexp;
1388 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1389 0 : vnet_lisp_add_del_mapping_args_t _dm_args, *dm_args = &_dm_args;
1390 0 : vnet_lisp_add_del_locator_set_args_t _ls, *ls = &_ls;
1391 :
1392 : /* *INDENT-OFF* */
1393 0 : pool_foreach_index (mi, lcm->mapping_pool)
1394 : {
1395 0 : vec_add1 (map_indices, mi);
1396 : }
1397 : /* *INDENT-ON* */
1398 :
1399 0 : vec_foreach (map_indexp, map_indices)
1400 : {
1401 0 : mapping_t *map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]);
1402 0 : if (!map->local)
1403 : {
1404 0 : dp_del_fwd_entry (lcm, map_indexp[0]);
1405 :
1406 0 : dm_args->is_add = 0;
1407 0 : gid_address_copy (&dm_args->eid, &map->eid);
1408 0 : dm_args->locator_set_index = map->locator_set_index;
1409 :
1410 : /* delete mapping associated to fwd entry */
1411 0 : vnet_lisp_map_cache_add_del (dm_args, 0);
1412 :
1413 0 : ls->is_add = 0;
1414 0 : ls->local = 0;
1415 0 : ls->index = map->locator_set_index;
1416 : /* delete locator set */
1417 0 : rv = vnet_lisp_add_del_locator_set (ls, 0);
1418 0 : if (rv != 0)
1419 0 : goto cleanup;
1420 : }
1421 : }
1422 :
1423 0 : cleanup:
1424 0 : if (map_indices)
1425 0 : vec_free (map_indices);
1426 0 : return rv;
1427 : }
1428 :
1429 : /**
1430 : * Adds adjacency or removes forwarding entry associated to remote mapping.
1431 : * Note that adjacencies are not stored, they only result in forwarding entries
1432 : * being created.
1433 : */
1434 : int
1435 2 : vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a)
1436 : {
1437 2 : lisp_cp_main_t *lcm = &lisp_control_main;
1438 2 : u32 local_mi, remote_mi = ~0;
1439 :
1440 2 : if (vnet_lisp_enable_disable_status () == 0)
1441 : {
1442 0 : clib_warning ("LISP is disabled!");
1443 0 : return VNET_API_ERROR_LISP_DISABLED;
1444 : }
1445 :
1446 2 : remote_mi = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid,
1447 : &a->reid, &a->leid);
1448 2 : if (GID_LOOKUP_MISS == remote_mi)
1449 : {
1450 0 : clib_warning ("Remote eid %U not found. Cannot add adjacency!",
1451 : format_gid_address, &a->reid);
1452 :
1453 0 : return -1;
1454 : }
1455 :
1456 2 : if (a->is_add)
1457 : {
1458 : /* check if source eid has an associated mapping. If pitr mode is on,
1459 : * just use the pitr's mapping */
1460 1 : if (lcm->flags & LISP_FLAG_PITR_MODE)
1461 : {
1462 0 : if (lcm->pitr_map_index != ~0)
1463 : {
1464 0 : local_mi = lcm->pitr_map_index;
1465 : }
1466 : else
1467 : {
1468 : /* PITR mode is on, but no mapping is configured */
1469 0 : return -1;
1470 : }
1471 : }
1472 : else
1473 : {
1474 1 : if (gid_address_type (&a->reid) == GID_ADDR_NSH)
1475 : {
1476 0 : if (lcm->nsh_map_index == ~0)
1477 0 : local_mi = GID_LOOKUP_MISS;
1478 : else
1479 0 : local_mi = lcm->nsh_map_index;
1480 : }
1481 : else
1482 : {
1483 1 : local_mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid,
1484 : &a->leid);
1485 : }
1486 : }
1487 :
1488 1 : if (GID_LOOKUP_MISS == local_mi)
1489 : {
1490 0 : clib_warning ("Local eid %U not found. Cannot add adjacency!",
1491 : format_gid_address, &a->leid);
1492 :
1493 0 : return -1;
1494 : }
1495 :
1496 : /* update forwarding */
1497 1 : dp_add_fwd_entry (lcm, local_mi, remote_mi);
1498 : }
1499 : else
1500 1 : dp_del_fwd_entry (lcm, remote_mi);
1501 :
1502 2 : return 0;
1503 : }
1504 :
1505 : int
1506 0 : vnet_lisp_set_map_request_mode (u8 mode)
1507 : {
1508 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1509 :
1510 0 : if (vnet_lisp_enable_disable_status () == 0)
1511 : {
1512 0 : clib_warning ("LISP is disabled!");
1513 0 : return VNET_API_ERROR_LISP_DISABLED;
1514 : }
1515 :
1516 0 : if (mode >= _MR_MODE_MAX)
1517 : {
1518 0 : clib_warning ("Invalid LISP map request mode %d!", mode);
1519 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
1520 : }
1521 :
1522 0 : lcm->map_request_mode = mode;
1523 0 : return 0;
1524 : }
1525 :
1526 : int
1527 0 : vnet_lisp_nsh_set_locator_set (u8 * locator_set_name, u8 is_add)
1528 : {
1529 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1530 0 : lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
1531 0 : u32 locator_set_index = ~0;
1532 : mapping_t *m;
1533 : uword *p;
1534 :
1535 0 : if (vnet_lisp_enable_disable_status () == 0)
1536 : {
1537 0 : clib_warning ("LISP is disabled!");
1538 0 : return VNET_API_ERROR_LISP_DISABLED;
1539 : }
1540 :
1541 0 : if (is_add)
1542 : {
1543 0 : if (lcm->nsh_map_index == (u32) ~ 0)
1544 : {
1545 0 : p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1546 0 : if (!p)
1547 : {
1548 0 : clib_warning ("locator-set %v doesn't exist", locator_set_name);
1549 0 : return -1;
1550 : }
1551 0 : locator_set_index = p[0];
1552 :
1553 0 : pool_get (lcm->mapping_pool, m);
1554 0 : clib_memset (m, 0, sizeof *m);
1555 0 : m->locator_set_index = locator_set_index;
1556 0 : m->local = 1;
1557 0 : m->nsh_set = 1;
1558 0 : lcm->nsh_map_index = m - lcm->mapping_pool;
1559 :
1560 0 : if (~0 == vnet_lisp_gpe_add_nsh_iface (lgm))
1561 0 : return -1;
1562 : }
1563 : }
1564 : else
1565 : {
1566 0 : if (lcm->nsh_map_index != (u32) ~ 0)
1567 : {
1568 : /* remove NSH mapping */
1569 0 : pool_put_index (lcm->mapping_pool, lcm->nsh_map_index);
1570 0 : lcm->nsh_map_index = ~0;
1571 0 : vnet_lisp_gpe_del_nsh_iface (lgm);
1572 : }
1573 : }
1574 0 : return 0;
1575 : }
1576 :
1577 : int
1578 0 : vnet_lisp_pitr_set_locator_set (u8 * locator_set_name, u8 is_add)
1579 : {
1580 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1581 0 : u32 locator_set_index = ~0;
1582 : mapping_t *m;
1583 : uword *p;
1584 :
1585 0 : if (vnet_lisp_enable_disable_status () == 0)
1586 : {
1587 0 : clib_warning ("LISP is disabled!");
1588 0 : return VNET_API_ERROR_LISP_DISABLED;
1589 : }
1590 :
1591 0 : p = hash_get_mem (lcm->locator_set_index_by_name, locator_set_name);
1592 0 : if (!p)
1593 : {
1594 0 : clib_warning ("locator-set %v doesn't exist", locator_set_name);
1595 0 : return -1;
1596 : }
1597 0 : locator_set_index = p[0];
1598 :
1599 0 : if (is_add)
1600 : {
1601 0 : pool_get (lcm->mapping_pool, m);
1602 0 : m->locator_set_index = locator_set_index;
1603 0 : m->local = 1;
1604 0 : m->pitr_set = 1;
1605 0 : lcm->pitr_map_index = m - lcm->mapping_pool;
1606 : }
1607 : else
1608 : {
1609 : /* remove pitr mapping */
1610 0 : pool_put_index (lcm->mapping_pool, lcm->pitr_map_index);
1611 0 : lcm->pitr_map_index = ~0;
1612 : }
1613 0 : return 0;
1614 : }
1615 :
1616 : int
1617 0 : vnet_lisp_map_register_fallback_threshold_set (u32 value)
1618 : {
1619 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1620 0 : if (0 == value)
1621 : {
1622 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
1623 : }
1624 :
1625 0 : lcm->max_expired_map_registers = value;
1626 0 : return 0;
1627 : }
1628 :
1629 : u32
1630 0 : vnet_lisp_map_register_fallback_threshold_get (void)
1631 : {
1632 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1633 0 : return lcm->max_expired_map_registers;
1634 : }
1635 :
1636 : /**
1637 : * Configure Proxy-ETR
1638 : *
1639 : * @param ip PETR's IP address
1640 : * @param is_add Flag that indicates if this is an addition or removal
1641 : *
1642 : * return 0 on success
1643 : */
1644 : int
1645 0 : vnet_lisp_use_petr (ip_address_t * ip, u8 is_add)
1646 : {
1647 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1648 0 : u32 ls_index = ~0;
1649 : mapping_t *m;
1650 0 : vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args;
1651 : locator_t loc;
1652 :
1653 0 : if (vnet_lisp_enable_disable_status () == 0)
1654 : {
1655 0 : clib_warning ("LISP is disabled!");
1656 0 : return VNET_API_ERROR_LISP_DISABLED;
1657 : }
1658 :
1659 0 : clib_memset (ls_args, 0, sizeof (*ls_args));
1660 :
1661 0 : if (is_add)
1662 : {
1663 : /* Create placeholder petr locator-set */
1664 0 : clib_memset (&loc, 0, sizeof (loc));
1665 0 : gid_address_from_ip (&loc.address, ip);
1666 0 : loc.priority = 1;
1667 0 : loc.state = loc.weight = 1;
1668 0 : loc.local = 0;
1669 :
1670 0 : ls_args->is_add = 1;
1671 0 : ls_args->index = ~0;
1672 0 : vec_add1 (ls_args->locators, loc);
1673 0 : vnet_lisp_add_del_locator_set (ls_args, &ls_index);
1674 :
1675 : /* Add petr mapping */
1676 0 : pool_get (lcm->mapping_pool, m);
1677 0 : m->locator_set_index = ls_index;
1678 0 : lcm->petr_map_index = m - lcm->mapping_pool;
1679 :
1680 : /* Enable use-petr */
1681 0 : lcm->flags |= LISP_FLAG_USE_PETR;
1682 : }
1683 : else
1684 : {
1685 0 : m = pool_elt_at_index (lcm->mapping_pool, lcm->petr_map_index);
1686 :
1687 : /* Remove petr locator */
1688 0 : ls_args->is_add = 0;
1689 0 : ls_args->index = m->locator_set_index;
1690 0 : vnet_lisp_add_del_locator_set (ls_args, 0);
1691 :
1692 : /* Remove petr mapping */
1693 0 : pool_put_index (lcm->mapping_pool, lcm->petr_map_index);
1694 :
1695 : /* Disable use-petr */
1696 0 : lcm->flags &= ~LISP_FLAG_USE_PETR;
1697 0 : lcm->petr_map_index = ~0;
1698 : }
1699 0 : return 0;
1700 : }
1701 :
1702 : /* cleans locator to locator-set data and removes locators not part of
1703 : * any locator-set */
1704 : static void
1705 1 : clean_locator_to_locator_set (lisp_cp_main_t * lcm, u32 lsi)
1706 : {
1707 1 : u32 i, j, *loc_indexp, *ls_indexp, **ls_indexes, *to_be_deleted = 0;
1708 1 : locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool, lsi);
1709 1 : for (i = 0; i < vec_len (ls->locator_indices); i++)
1710 : {
1711 0 : loc_indexp = vec_elt_at_index (ls->locator_indices, i);
1712 0 : ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
1713 : loc_indexp[0]);
1714 0 : for (j = 0; j < vec_len (ls_indexes[0]); j++)
1715 : {
1716 0 : ls_indexp = vec_elt_at_index (ls_indexes[0], j);
1717 0 : if (ls_indexp[0] == lsi)
1718 0 : break;
1719 : }
1720 :
1721 : /* delete index for removed locator-set */
1722 0 : vec_del1 (ls_indexes[0], j);
1723 :
1724 : /* delete locator if it's part of no locator-set */
1725 0 : if (vec_len (ls_indexes[0]) == 0)
1726 : {
1727 0 : pool_put_index (lcm->locator_pool, loc_indexp[0]);
1728 0 : vec_add1 (to_be_deleted, i);
1729 : }
1730 : }
1731 :
1732 1 : if (to_be_deleted)
1733 : {
1734 0 : for (i = 0; i < vec_len (to_be_deleted); i++)
1735 : {
1736 0 : loc_indexp = vec_elt_at_index (to_be_deleted, i);
1737 0 : vec_del1 (ls->locator_indices, loc_indexp[0]);
1738 : }
1739 0 : vec_free (to_be_deleted);
1740 : }
1741 1 : }
1742 :
1743 : static inline uword *
1744 8 : get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p)
1745 : {
1746 8 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1747 :
1748 8 : ASSERT (a != NULL);
1749 8 : ASSERT (p != NULL);
1750 :
1751 : /* find locator-set */
1752 8 : if (a->local)
1753 : {
1754 5 : ASSERT (a->name);
1755 10 : p = hash_get_mem (lcm->locator_set_index_by_name, a->name);
1756 : }
1757 : else
1758 : {
1759 3 : *p = a->index;
1760 : }
1761 :
1762 8 : return p;
1763 : }
1764 :
1765 : static inline int
1766 2 : is_locator_in_locator_set (lisp_cp_main_t * lcm, locator_set_t * ls,
1767 : locator_t * loc)
1768 : {
1769 : locator_t *itloc;
1770 : u32 *locit;
1771 :
1772 2 : ASSERT (ls != NULL);
1773 2 : ASSERT (loc != NULL);
1774 :
1775 2 : vec_foreach (locit, ls->locator_indices)
1776 : {
1777 0 : itloc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1778 0 : if ((ls->local && itloc->sw_if_index == loc->sw_if_index) ||
1779 0 : (!ls->local && !gid_address_cmp (&itloc->address, &loc->address)))
1780 : {
1781 0 : clib_warning ("Duplicate locator");
1782 0 : return VNET_API_ERROR_VALUE_EXIST;
1783 : }
1784 : }
1785 :
1786 2 : return 0;
1787 : }
1788 :
1789 : static void
1790 0 : update_adjacencies_by_map_index (lisp_cp_main_t * lcm,
1791 : u32 mapping_index, u8 remove_only)
1792 : {
1793 : fwd_entry_t *fwd;
1794 : mapping_t *map;
1795 0 : uword *fei = 0, *rmts_idxp = 0;
1796 0 : u32 **rmts = 0, *remote_idxp = 0, *rmts_copy = 0;
1797 0 : vnet_lisp_add_del_adjacency_args_t _a, *a = &_a;
1798 0 : clib_memset (a, 0, sizeof (*a));
1799 :
1800 0 : map = pool_elt_at_index (lcm->mapping_pool, mapping_index);
1801 :
1802 0 : if (map->local)
1803 : {
1804 0 : rmts_idxp = hash_get (lcm->lcl_to_rmt_adjs_by_lcl_idx, mapping_index);
1805 0 : if (rmts_idxp)
1806 : {
1807 0 : rmts =
1808 0 : pool_elt_at_index (lcm->lcl_to_rmt_adjacencies, rmts_idxp[0]);
1809 0 : rmts_copy = vec_dup (rmts[0]);
1810 :
1811 0 : vec_foreach (remote_idxp, rmts_copy)
1812 : {
1813 0 : fei = hash_get (lcm->fwd_entry_by_mapping_index, remote_idxp[0]);
1814 0 : if (!fei)
1815 0 : continue;
1816 :
1817 0 : fwd = pool_elt_at_index (lcm->fwd_entry_pool, fei[0]);
1818 0 : a->is_add = 0;
1819 0 : gid_address_copy (&a->leid, &fwd->leid);
1820 0 : gid_address_copy (&a->reid, &fwd->reid);
1821 0 : vnet_lisp_add_del_adjacency (a);
1822 :
1823 0 : if (!remove_only)
1824 : {
1825 0 : a->is_add = 1;
1826 0 : vnet_lisp_add_del_adjacency (a);
1827 : }
1828 : }
1829 0 : vec_free (rmts_copy);
1830 : }
1831 : }
1832 : else
1833 : {
1834 0 : fei = hash_get (lcm->fwd_entry_by_mapping_index, mapping_index);
1835 0 : if (!fei)
1836 0 : return;
1837 :
1838 0 : fwd = pool_elt_at_index (lcm->fwd_entry_pool, fei[0]);
1839 0 : a->is_add = 0;
1840 0 : gid_address_copy (&a->leid, &fwd->leid);
1841 0 : gid_address_copy (&a->reid, &fwd->reid);
1842 0 : vnet_lisp_add_del_adjacency (a);
1843 :
1844 0 : if (!remove_only)
1845 : {
1846 0 : a->is_add = 1;
1847 0 : vnet_lisp_add_del_adjacency (a);
1848 : }
1849 : }
1850 : }
1851 :
1852 : static void
1853 1 : update_fwd_entries_by_locator_set (lisp_cp_main_t * lcm,
1854 : u32 ls_index, u8 remove_only)
1855 : {
1856 : u32 i, *map_indexp;
1857 : u32 **eid_indexes;
1858 :
1859 1 : if (vec_len (lcm->locator_set_to_eids) <= ls_index)
1860 0 : return;
1861 :
1862 1 : eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids, ls_index);
1863 :
1864 1 : for (i = 0; i < vec_len (eid_indexes[0]); i++)
1865 : {
1866 0 : map_indexp = vec_elt_at_index (eid_indexes[0], i);
1867 0 : update_adjacencies_by_map_index (lcm, map_indexp[0], remove_only);
1868 : }
1869 : }
1870 :
1871 : static inline void
1872 1 : remove_locator_from_locator_set (locator_set_t * ls, u32 * locit,
1873 : u32 ls_index, u32 loc_id)
1874 : {
1875 1 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1876 1 : u32 **ls_indexes = NULL;
1877 :
1878 1 : ASSERT (ls != NULL);
1879 1 : ASSERT (locit != NULL);
1880 :
1881 1 : ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets, locit[0]);
1882 1 : pool_put_index (lcm->locator_pool, locit[0]);
1883 1 : vec_del1 (ls->locator_indices, loc_id);
1884 1 : vec_del1 (ls_indexes[0], ls_index);
1885 1 : }
1886 :
1887 : int
1888 4 : vnet_lisp_add_del_locator (vnet_lisp_add_del_locator_set_args_t * a,
1889 : locator_set_t * ls, u32 * ls_result)
1890 : {
1891 4 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1892 4 : locator_t *loc = NULL, *itloc = NULL;
1893 4 : uword _p = (u32) ~ 0, *p = &_p;
1894 4 : u32 loc_index = ~0, ls_index = ~0, *locit = NULL, **ls_indexes = NULL;
1895 4 : u32 loc_id = ~0;
1896 4 : int ret = 0;
1897 :
1898 4 : ASSERT (a != NULL);
1899 :
1900 4 : if (vnet_lisp_enable_disable_status () == 0)
1901 : {
1902 0 : clib_warning ("LISP is disabled!");
1903 0 : return VNET_API_ERROR_LISP_DISABLED;
1904 : }
1905 :
1906 4 : p = get_locator_set_index (a, p);
1907 4 : if (!p)
1908 : {
1909 0 : clib_warning ("locator-set %v doesn't exist", a->name);
1910 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
1911 : }
1912 :
1913 4 : if (ls == 0)
1914 : {
1915 2 : ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
1916 2 : if (!ls)
1917 : {
1918 0 : clib_warning ("locator-set %d to be overwritten doesn't exist!",
1919 : p[0]);
1920 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
1921 : }
1922 : }
1923 :
1924 4 : if (a->is_add)
1925 : {
1926 3 : if (ls_result)
1927 1 : ls_result[0] = p[0];
1928 :
1929 : /* allocate locators */
1930 5 : vec_foreach (itloc, a->locators)
1931 : {
1932 2 : ret = is_locator_in_locator_set (lcm, ls, itloc);
1933 2 : if (0 != ret)
1934 : {
1935 0 : return ret;
1936 : }
1937 :
1938 2 : pool_get (lcm->locator_pool, loc);
1939 2 : loc[0] = itloc[0];
1940 2 : loc_index = loc - lcm->locator_pool;
1941 :
1942 2 : vec_add1 (ls->locator_indices, loc_index);
1943 :
1944 2 : vec_validate (lcm->locator_to_locator_sets, loc_index);
1945 2 : ls_indexes = vec_elt_at_index (lcm->locator_to_locator_sets,
1946 : loc_index);
1947 2 : vec_add1 (ls_indexes[0], p[0]);
1948 : }
1949 : }
1950 : else
1951 : {
1952 1 : ls_index = p[0];
1953 : u8 removed;
1954 :
1955 2 : vec_foreach (itloc, a->locators)
1956 : {
1957 1 : removed = 0;
1958 1 : loc_id = 0;
1959 2 : vec_foreach (locit, ls->locator_indices)
1960 : {
1961 1 : loc = pool_elt_at_index (lcm->locator_pool, locit[0]);
1962 :
1963 1 : if (loc->local && loc->sw_if_index == itloc->sw_if_index)
1964 : {
1965 1 : removed = 1;
1966 1 : remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
1967 : }
1968 0 : else if (0 == loc->local &&
1969 0 : !gid_address_cmp (&loc->address, &itloc->address))
1970 : {
1971 0 : removed = 1;
1972 0 : remove_locator_from_locator_set (ls, locit, ls_index, loc_id);
1973 : }
1974 :
1975 1 : if (removed)
1976 : {
1977 : /* update fwd entries using this locator in DP */
1978 1 : update_fwd_entries_by_locator_set (lcm, ls_index,
1979 1 : vec_len (ls->locator_indices)
1980 2 : == 0);
1981 : }
1982 :
1983 1 : loc_id++;
1984 : }
1985 : }
1986 : }
1987 :
1988 4 : return 0;
1989 : }
1990 :
1991 : int
1992 4 : vnet_lisp_add_del_locator_set (vnet_lisp_add_del_locator_set_args_t * a,
1993 : u32 * ls_result)
1994 : {
1995 4 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
1996 : locator_set_t *ls;
1997 4 : uword _p = (u32) ~ 0, *p = &_p;
1998 : u32 ls_index;
1999 : u32 **eid_indexes;
2000 4 : int ret = 0;
2001 :
2002 4 : if (vnet_lisp_enable_disable_status () == 0)
2003 : {
2004 0 : clib_warning ("LISP is disabled!");
2005 0 : return VNET_API_ERROR_LISP_DISABLED;
2006 : }
2007 :
2008 4 : if (a->is_add)
2009 : {
2010 2 : p = get_locator_set_index (a, p);
2011 :
2012 : /* overwrite */
2013 2 : if (p && p[0] != (u32) ~ 0)
2014 : {
2015 0 : ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
2016 0 : if (!ls)
2017 : {
2018 0 : clib_warning ("locator-set %d to be overwritten doesn't exist!",
2019 : p[0]);
2020 0 : return -1;
2021 : }
2022 :
2023 : /* clean locator to locator-set vectors and remove locators if
2024 : * they're not part of another locator-set */
2025 0 : clean_locator_to_locator_set (lcm, p[0]);
2026 :
2027 : /* remove locator indices from locator set */
2028 0 : vec_free (ls->locator_indices);
2029 :
2030 0 : ls_index = p[0];
2031 :
2032 0 : if (ls_result)
2033 0 : ls_result[0] = p[0];
2034 : }
2035 : /* new locator-set */
2036 : else
2037 : {
2038 2 : pool_get (lcm->locator_set_pool, ls);
2039 2 : clib_memset (ls, 0, sizeof (*ls));
2040 2 : ls_index = ls - lcm->locator_set_pool;
2041 :
2042 2 : if (a->local)
2043 : {
2044 1 : ls->name = vec_dup (a->name);
2045 :
2046 1 : if (!lcm->locator_set_index_by_name)
2047 1 : lcm->locator_set_index_by_name =
2048 1 : hash_create_vec ( /* size */ 0, sizeof (ls->name[0]),
2049 : sizeof (uword));
2050 2 : hash_set_mem (lcm->locator_set_index_by_name, ls->name,
2051 : ls_index);
2052 :
2053 : /* mark as local locator-set */
2054 1 : vec_add1 (lcm->local_locator_set_indexes, ls_index);
2055 : }
2056 2 : ls->local = a->local;
2057 2 : if (ls_result)
2058 2 : ls_result[0] = ls_index;
2059 : }
2060 :
2061 2 : ret = vnet_lisp_add_del_locator (a, ls, NULL);
2062 2 : if (0 != ret)
2063 : {
2064 0 : return ret;
2065 : }
2066 : }
2067 : else
2068 : {
2069 2 : p = get_locator_set_index (a, p);
2070 2 : if (!p)
2071 : {
2072 0 : clib_warning ("locator-set %v doesn't exists", a->name);
2073 0 : return -1;
2074 : }
2075 :
2076 2 : ls = pool_elt_at_index (lcm->locator_set_pool, p[0]);
2077 2 : if (!ls)
2078 : {
2079 0 : clib_warning ("locator-set with index %d doesn't exists", p[0]);
2080 0 : return -1;
2081 : }
2082 :
2083 2 : if (lcm->mreq_itr_rlocs == p[0])
2084 : {
2085 0 : clib_warning ("Can't delete the locator-set used to constrain "
2086 : "the itr-rlocs in map-requests!");
2087 0 : return -1;
2088 : }
2089 :
2090 2 : if (vec_len (lcm->locator_set_to_eids) != 0)
2091 : {
2092 2 : eid_indexes = vec_elt_at_index (lcm->locator_set_to_eids, p[0]);
2093 2 : if (vec_len (eid_indexes[0]) != 0)
2094 : {
2095 1 : clib_warning
2096 : ("Can't delete a locator that supports a mapping!");
2097 1 : return -1;
2098 : }
2099 : }
2100 :
2101 : /* clean locator to locator-sets data */
2102 1 : clean_locator_to_locator_set (lcm, p[0]);
2103 :
2104 1 : if (ls->local)
2105 : {
2106 : u32 it, lsi;
2107 :
2108 1 : vec_foreach_index (it, lcm->local_locator_set_indexes)
2109 : {
2110 1 : lsi = vec_elt (lcm->local_locator_set_indexes, it);
2111 1 : if (lsi == p[0])
2112 : {
2113 1 : vec_del1 (lcm->local_locator_set_indexes, it);
2114 1 : break;
2115 : }
2116 : }
2117 2 : hash_unset_mem (lcm->locator_set_index_by_name, ls->name);
2118 : }
2119 1 : vec_free (ls->name);
2120 1 : vec_free (ls->locator_indices);
2121 1 : pool_put (lcm->locator_set_pool, ls);
2122 : }
2123 3 : return 0;
2124 : }
2125 :
2126 : int
2127 0 : vnet_lisp_rloc_probe_enable_disable (u8 is_enable)
2128 : {
2129 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2130 :
2131 0 : lcm->rloc_probing = is_enable;
2132 0 : return 0;
2133 : }
2134 :
2135 : int
2136 0 : vnet_lisp_map_register_enable_disable (u8 is_enable)
2137 : {
2138 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2139 :
2140 0 : lcm->map_registering = is_enable;
2141 0 : return 0;
2142 : }
2143 :
2144 : static void
2145 1 : lisp_cp_register_dst_port (vlib_main_t * vm)
2146 : {
2147 1 : udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp,
2148 : lisp_cp_input_node.index, 1 /* is_ip4 */ );
2149 1 : udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
2150 : lisp_cp_input_node.index, 0 /* is_ip4 */ );
2151 1 : }
2152 :
2153 : static void
2154 0 : lisp_cp_unregister_dst_port (vlib_main_t * vm)
2155 : {
2156 0 : udp_unregister_dst_port (vm, UDP_DST_PORT_lisp_cp, 0 /* is_ip4 */ );
2157 0 : udp_unregister_dst_port (vm, UDP_DST_PORT_lisp_cp6, 1 /* is_ip4 */ );
2158 0 : }
2159 :
2160 : /**
2161 : * lisp_cp_enable_l2_l3_ifaces
2162 : *
2163 : * Enable all l2 and l3 ifaces
2164 : */
2165 : static void
2166 1 : lisp_cp_enable_l2_l3_ifaces (lisp_cp_main_t * lcm, u8 with_default_route)
2167 : {
2168 : u32 vni, dp_table;
2169 :
2170 : /* *INDENT-OFF* */
2171 66 : hash_foreach(vni, dp_table, lcm->table_id_by_vni, ({
2172 : dp_add_del_iface(lcm, vni, /* is_l2 */ 0, /* is_add */1,
2173 : with_default_route);
2174 : }));
2175 1 : hash_foreach(vni, dp_table, lcm->bd_id_by_vni, ({
2176 : dp_add_del_iface(lcm, vni, /* is_l2 */ 1, 1,
2177 : with_default_route);
2178 : }));
2179 : /* *INDENT-ON* */
2180 1 : }
2181 :
2182 : static void
2183 0 : lisp_cp_disable_l2_l3_ifaces (lisp_cp_main_t * lcm)
2184 : {
2185 : u32 **rmts;
2186 :
2187 : /* clear interface table */
2188 0 : hash_free (lcm->fwd_entry_by_mapping_index);
2189 0 : pool_free (lcm->fwd_entry_pool);
2190 : /* Clear state tracking rmt-lcl fwd entries */
2191 : /* *INDENT-OFF* */
2192 0 : pool_foreach (rmts, lcm->lcl_to_rmt_adjacencies)
2193 : {
2194 0 : vec_free(rmts[0]);
2195 : }
2196 : /* *INDENT-ON* */
2197 0 : hash_free (lcm->lcl_to_rmt_adjs_by_lcl_idx);
2198 0 : pool_free (lcm->lcl_to_rmt_adjacencies);
2199 0 : }
2200 :
2201 : clib_error_t *
2202 1 : vnet_lisp_enable_disable (u8 is_enable)
2203 : {
2204 1 : clib_error_t *error = 0;
2205 1 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2206 1 : vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a;
2207 :
2208 1 : a->is_en = is_enable;
2209 1 : error = vnet_lisp_gpe_enable_disable (a);
2210 1 : if (error)
2211 : {
2212 0 : return clib_error_return (0, "failed to %s data-plane!",
2213 : a->is_en ? "enable" : "disable");
2214 : }
2215 :
2216 : /* decide what to do based on mode */
2217 :
2218 1 : if (lcm->flags & LISP_FLAG_XTR_MODE)
2219 : {
2220 1 : if (is_enable)
2221 : {
2222 1 : lisp_cp_register_dst_port (lcm->vlib_main);
2223 1 : lisp_cp_enable_l2_l3_ifaces (lcm, 1 /* with_default_route */ );
2224 : }
2225 : else
2226 : {
2227 0 : lisp_cp_unregister_dst_port (lcm->vlib_main);
2228 0 : lisp_cp_disable_l2_l3_ifaces (lcm);
2229 : }
2230 : }
2231 :
2232 1 : if (lcm->flags & LISP_FLAG_PETR_MODE)
2233 : {
2234 : /* if in xTR mode, the LISP ports were already (un)registered above */
2235 0 : if (!(lcm->flags & LISP_FLAG_XTR_MODE))
2236 : {
2237 0 : if (is_enable)
2238 0 : lisp_cp_register_dst_port (lcm->vlib_main);
2239 : else
2240 0 : lisp_cp_unregister_dst_port (lcm->vlib_main);
2241 : }
2242 : }
2243 :
2244 1 : if (lcm->flags & LISP_FLAG_PITR_MODE)
2245 : {
2246 0 : if (is_enable)
2247 : {
2248 : /* install interfaces, but no default routes */
2249 0 : lisp_cp_enable_l2_l3_ifaces (lcm, 0 /* with_default_route */ );
2250 : }
2251 : else
2252 : {
2253 0 : lisp_cp_disable_l2_l3_ifaces (lcm);
2254 : }
2255 : }
2256 :
2257 1 : if (is_enable)
2258 1 : vnet_lisp_create_retry_process (lcm);
2259 :
2260 : /* update global flag */
2261 1 : lcm->is_enabled = is_enable;
2262 :
2263 1 : return 0;
2264 : }
2265 :
2266 : u8
2267 13 : vnet_lisp_enable_disable_status (void)
2268 : {
2269 13 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2270 13 : return lcm->is_enabled;
2271 : }
2272 :
2273 : int
2274 0 : vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
2275 : {
2276 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2277 : u32 i;
2278 0 : lisp_msmr_t _mr, *mr = &_mr;
2279 :
2280 0 : if (vnet_lisp_enable_disable_status () == 0)
2281 : {
2282 0 : clib_warning ("LISP is disabled!");
2283 0 : return VNET_API_ERROR_LISP_DISABLED;
2284 : }
2285 :
2286 0 : if (a->is_add)
2287 : {
2288 :
2289 0 : if (get_map_resolver (&a->address))
2290 : {
2291 0 : clib_warning ("map-resolver %U already exists!", format_ip_address,
2292 : &a->address);
2293 0 : return -1;
2294 : }
2295 :
2296 0 : clib_memset (mr, 0, sizeof (*mr));
2297 0 : ip_address_copy (&mr->address, &a->address);
2298 0 : vec_add1 (lcm->map_resolvers, *mr);
2299 :
2300 0 : if (vec_len (lcm->map_resolvers) == 1)
2301 0 : lcm->do_map_resolver_election = 1;
2302 : }
2303 : else
2304 : {
2305 0 : for (i = 0; i < vec_len (lcm->map_resolvers); i++)
2306 : {
2307 0 : mr = vec_elt_at_index (lcm->map_resolvers, i);
2308 0 : if (!ip_address_cmp (&mr->address, &a->address))
2309 : {
2310 0 : if (!ip_address_cmp (&mr->address, &lcm->active_map_resolver))
2311 0 : lcm->do_map_resolver_election = 1;
2312 :
2313 0 : vec_del1 (lcm->map_resolvers, i);
2314 0 : break;
2315 : }
2316 : }
2317 : }
2318 0 : return 0;
2319 : }
2320 :
2321 : int
2322 0 : vnet_lisp_map_register_set_ttl (u32 ttl)
2323 : {
2324 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2325 0 : lcm->map_register_ttl = ttl;
2326 0 : return 0;
2327 : }
2328 :
2329 : u32
2330 0 : vnet_lisp_map_register_get_ttl (void)
2331 : {
2332 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2333 0 : return lcm->map_register_ttl;
2334 : }
2335 :
2336 : int
2337 0 : vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a)
2338 : {
2339 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2340 0 : uword *p = 0;
2341 :
2342 0 : if (vnet_lisp_enable_disable_status () == 0)
2343 : {
2344 0 : clib_warning ("LISP is disabled!");
2345 0 : return VNET_API_ERROR_LISP_DISABLED;
2346 : }
2347 :
2348 0 : if (a->is_add)
2349 : {
2350 0 : p = hash_get_mem (lcm->locator_set_index_by_name, a->locator_set_name);
2351 0 : if (!p)
2352 : {
2353 0 : clib_warning ("locator-set %v doesn't exist", a->locator_set_name);
2354 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
2355 : }
2356 :
2357 0 : lcm->mreq_itr_rlocs = p[0];
2358 : }
2359 : else
2360 : {
2361 0 : lcm->mreq_itr_rlocs = ~0;
2362 : }
2363 :
2364 0 : return 0;
2365 : }
2366 :
2367 : /* Statistics (not really errors) */
2368 : #define foreach_lisp_cp_lookup_error \
2369 : _(DROP, "drop") \
2370 : _(MAP_REQUESTS_SENT, "map-request sent") \
2371 : _(ARP_REPLY_TX, "ARP replies sent") \
2372 : _(NDP_NEIGHBOR_ADVERTISEMENT_TX, \
2373 : "neighbor advertisement sent")
2374 :
2375 : static char *lisp_cp_lookup_error_strings[] = {
2376 : #define _(sym,string) string,
2377 : foreach_lisp_cp_lookup_error
2378 : #undef _
2379 : };
2380 :
2381 : typedef enum
2382 : {
2383 : #define _(sym,str) LISP_CP_LOOKUP_ERROR_##sym,
2384 : foreach_lisp_cp_lookup_error
2385 : #undef _
2386 : LISP_CP_LOOKUP_N_ERROR,
2387 : } lisp_cp_lookup_error_t;
2388 :
2389 : typedef enum
2390 : {
2391 : LISP_CP_LOOKUP_NEXT_DROP,
2392 : LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX,
2393 : LISP_CP_LOOKUP_N_NEXT,
2394 : } lisp_cp_lookup_next_t;
2395 :
2396 : typedef struct
2397 : {
2398 : gid_address_t dst_eid;
2399 : ip_address_t map_resolver_ip;
2400 : } lisp_cp_lookup_trace_t;
2401 :
2402 : u8 *
2403 0 : format_lisp_cp_lookup_trace (u8 * s, va_list * args)
2404 : {
2405 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
2406 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
2407 0 : lisp_cp_lookup_trace_t *t = va_arg (*args, lisp_cp_lookup_trace_t *);
2408 :
2409 0 : s = format (s, "LISP-CP-LOOKUP: map-resolver: %U destination eid %U",
2410 : format_ip_address, &t->map_resolver_ip, format_gid_address,
2411 : &t->dst_eid);
2412 0 : return s;
2413 : }
2414 :
2415 : int
2416 0 : get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
2417 : ip_address_t * sloc)
2418 : {
2419 : lisp_msmr_t *mrit;
2420 : ip_address_t *a;
2421 :
2422 0 : if (vec_len (lcm->map_resolvers) == 0)
2423 : {
2424 0 : clib_warning ("No map-resolver configured");
2425 0 : return 0;
2426 : }
2427 :
2428 : /* find the first mr ip we have a route to and the ip of the
2429 : * iface that has a route to it */
2430 0 : vec_foreach (mrit, lcm->map_resolvers)
2431 : {
2432 0 : a = &mrit->address;
2433 0 : if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, a, sloc))
2434 : {
2435 0 : ip_address_copy (mr_ip, a);
2436 :
2437 : /* also update globals */
2438 0 : return 1;
2439 : }
2440 : }
2441 :
2442 0 : clib_warning ("Can't find map-resolver and local interface ip!");
2443 0 : return 0;
2444 : }
2445 :
2446 : static gid_address_t *
2447 0 : build_itr_rloc_list (lisp_cp_main_t * lcm, locator_set_t * loc_set)
2448 : {
2449 : void *addr;
2450 : u32 i;
2451 : locator_t *loc;
2452 : u32 *loc_indexp;
2453 0 : ip_interface_address_t *ia = 0;
2454 0 : gid_address_t gid_data, *gid = &gid_data;
2455 0 : gid_address_t *rlocs = 0;
2456 0 : ip_prefix_t *ippref = &gid_address_ippref (gid);
2457 0 : ip_address_t *rloc = &ip_prefix_addr (ippref);
2458 :
2459 0 : clib_memset (gid, 0, sizeof (gid[0]));
2460 0 : gid_address_type (gid) = GID_ADDR_IP_PREFIX;
2461 0 : for (i = 0; i < vec_len (loc_set->locator_indices); i++)
2462 : {
2463 0 : loc_indexp = vec_elt_at_index (loc_set->locator_indices, i);
2464 0 : loc = pool_elt_at_index (lcm->locator_pool, loc_indexp[0]);
2465 :
2466 : /* Add ipv4 locators first TODO sort them */
2467 :
2468 : /* *INDENT-OFF* */
2469 0 : foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2470 : loc->sw_if_index, 1 /* unnumbered */,
2471 : ({
2472 : addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
2473 : ip_address_set (rloc, addr, AF_IP4);
2474 : ip_prefix_len (ippref) = 32;
2475 : ip_prefix_normalize (ippref);
2476 : vec_add1 (rlocs, gid[0]);
2477 : }));
2478 :
2479 : /* Add ipv6 locators */
2480 0 : foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2481 : loc->sw_if_index, 1 /* unnumbered */,
2482 : ({
2483 : addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
2484 : ip_address_set (rloc, addr, AF_IP6);
2485 : ip_prefix_len (ippref) = 128;
2486 : ip_prefix_normalize (ippref);
2487 : vec_add1 (rlocs, gid[0]);
2488 : }));
2489 : /* *INDENT-ON* */
2490 :
2491 : }
2492 0 : return rlocs;
2493 : }
2494 :
2495 : static vlib_buffer_t *
2496 0 : build_map_request (lisp_cp_main_t * lcm, gid_address_t * deid,
2497 : ip_address_t * sloc, ip_address_t * rloc,
2498 : gid_address_t * itr_rlocs, u64 * nonce_res, u32 * bi_res)
2499 : {
2500 : vlib_buffer_t *b;
2501 : u32 bi;
2502 0 : vlib_main_t *vm = lcm->vlib_main;
2503 :
2504 0 : if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2505 : {
2506 0 : clib_warning ("Can't allocate buffer for Map-Request!");
2507 0 : return 0;
2508 : }
2509 :
2510 0 : b = vlib_get_buffer (vm, bi);
2511 :
2512 : /* leave some space for the encap headers */
2513 0 : vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2514 :
2515 : /* put lisp msg */
2516 0 : lisp_msg_put_mreq (lcm, b, NULL, deid, itr_rlocs, 0 /* smr invoked */ ,
2517 : 1 /* rloc probe */ , nonce_res);
2518 :
2519 : /* push outer ip header */
2520 0 : pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
2521 : rloc, 1);
2522 :
2523 0 : bi_res[0] = bi;
2524 :
2525 0 : return b;
2526 : }
2527 :
2528 : static vlib_buffer_t *
2529 0 : build_encapsulated_map_request (lisp_cp_main_t * lcm,
2530 : gid_address_t * seid, gid_address_t * deid,
2531 : locator_set_t * loc_set, ip_address_t * mr_ip,
2532 : ip_address_t * sloc, u8 is_smr_invoked,
2533 : u64 * nonce_res, u32 * bi_res)
2534 : {
2535 : vlib_buffer_t *b;
2536 : u32 bi;
2537 0 : gid_address_t *rlocs = 0;
2538 0 : vlib_main_t *vm = lcm->vlib_main;
2539 :
2540 0 : if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2541 : {
2542 0 : clib_warning ("Can't allocate buffer for Map-Request!");
2543 0 : return 0;
2544 : }
2545 :
2546 0 : b = vlib_get_buffer (vm, bi);
2547 0 : b->flags = 0;
2548 :
2549 : /* leave some space for the encap headers */
2550 0 : vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2551 :
2552 : /* get rlocs */
2553 0 : rlocs = build_itr_rloc_list (lcm, loc_set);
2554 :
2555 0 : if (MR_MODE_SRC_DST == lcm->map_request_mode
2556 0 : && GID_ADDR_SRC_DST != gid_address_type (deid))
2557 0 : {
2558 : gid_address_t sd;
2559 0 : clib_memset (&sd, 0, sizeof (sd));
2560 0 : build_src_dst (&sd, seid, deid);
2561 0 : lisp_msg_put_mreq (lcm, b, seid, &sd, rlocs, is_smr_invoked,
2562 : 0 /* rloc probe */ , nonce_res);
2563 : }
2564 : else
2565 : {
2566 : /* put lisp msg */
2567 0 : lisp_msg_put_mreq (lcm, b, seid, deid, rlocs, is_smr_invoked,
2568 : 0 /* rloc probe */ , nonce_res);
2569 : }
2570 :
2571 : /* push ecm: udp-ip-lisp */
2572 0 : lisp_msg_push_ecm (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, seid, deid);
2573 :
2574 : /* push outer ip header */
2575 0 : pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
2576 : mr_ip, 1);
2577 :
2578 0 : bi_res[0] = bi;
2579 :
2580 0 : vec_free (rlocs);
2581 0 : return b;
2582 : }
2583 :
2584 : static void
2585 0 : reset_pending_mr_counters (pending_map_request_t * r)
2586 : {
2587 0 : r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
2588 0 : r->retries_num = 0;
2589 0 : }
2590 :
2591 : #define foreach_msmr \
2592 : _(server) \
2593 : _(resolver)
2594 :
2595 : #define _(name) \
2596 : static int \
2597 : elect_map_ ## name (lisp_cp_main_t * lcm) \
2598 : { \
2599 : lisp_msmr_t *mr; \
2600 : vec_foreach (mr, lcm->map_ ## name ## s) \
2601 : { \
2602 : if (!mr->is_down) \
2603 : { \
2604 : ip_address_copy (&lcm->active_map_ ##name, &mr->address); \
2605 : lcm->do_map_ ## name ## _election = 0; \
2606 : return 1; \
2607 : } \
2608 : } \
2609 : return 0; \
2610 : }
2611 0 : foreach_msmr
2612 : #undef _
2613 : static void
2614 0 : free_map_register_records (mapping_t * maps)
2615 : {
2616 : mapping_t *map;
2617 0 : vec_foreach (map, maps) vec_free (map->locators);
2618 :
2619 0 : vec_free (maps);
2620 0 : }
2621 :
2622 : static void
2623 0 : add_locators (lisp_cp_main_t * lcm, mapping_t * m, u32 locator_set_index,
2624 : ip_address_t * probed_loc)
2625 : {
2626 : u32 *li;
2627 : locator_t *loc, new;
2628 0 : ip_interface_address_t *ia = 0;
2629 : void *addr;
2630 0 : ip_address_t *new_ip = &gid_address_ip (&new.address);
2631 :
2632 0 : m->locators = 0;
2633 0 : locator_set_t *ls = pool_elt_at_index (lcm->locator_set_pool,
2634 : locator_set_index);
2635 0 : vec_foreach (li, ls->locator_indices)
2636 : {
2637 0 : loc = pool_elt_at_index (lcm->locator_pool, li[0]);
2638 0 : new = loc[0];
2639 0 : if (loc->local)
2640 : {
2641 : /* *INDENT-OFF* */
2642 0 : foreach_ip_interface_address (&lcm->im4->lookup_main, ia,
2643 : loc->sw_if_index, 1 /* unnumbered */,
2644 : ({
2645 : addr = ip_interface_address_get_address (&lcm->im4->lookup_main,
2646 : ia);
2647 : ip_address_set (new_ip, addr, AF_IP4);
2648 : }));
2649 :
2650 : /* Add ipv6 locators */
2651 0 : foreach_ip_interface_address (&lcm->im6->lookup_main, ia,
2652 : loc->sw_if_index, 1 /* unnumbered */,
2653 : ({
2654 : addr = ip_interface_address_get_address (&lcm->im6->lookup_main,
2655 : ia);
2656 : ip_address_set (new_ip, addr, AF_IP6);
2657 : }));
2658 : /* *INDENT-ON* */
2659 :
2660 0 : if (probed_loc && ip_address_cmp (probed_loc, new_ip) == 0)
2661 0 : new.probed = 1;
2662 : }
2663 0 : vec_add1 (m->locators, new);
2664 : }
2665 0 : }
2666 :
2667 : static mapping_t *
2668 0 : build_map_register_record_list (lisp_cp_main_t * lcm)
2669 : {
2670 0 : mapping_t *recs = 0, rec, *m;
2671 :
2672 : /* *INDENT-OFF* */
2673 0 : pool_foreach (m, lcm->mapping_pool)
2674 : {
2675 : /* for now build only local mappings */
2676 0 : if (!m->local)
2677 0 : continue;
2678 :
2679 0 : rec = m[0];
2680 0 : add_locators (lcm, &rec, m->locator_set_index, NULL);
2681 0 : vec_add1 (recs, rec);
2682 : }
2683 : /* *INDENT-ON* */
2684 :
2685 0 : return recs;
2686 : }
2687 :
2688 : static vnet_crypto_alg_t
2689 0 : lisp_key_type_to_crypto_alg (lisp_key_type_t key_id)
2690 : {
2691 0 : switch (key_id)
2692 : {
2693 0 : case HMAC_SHA_1_96:
2694 0 : return VNET_CRYPTO_ALG_HMAC_SHA1;
2695 0 : case HMAC_SHA_256_128:
2696 0 : return VNET_CRYPTO_ALG_HMAC_SHA256;
2697 0 : default:
2698 0 : clib_warning ("unsupported encryption key type: %d!", key_id);
2699 0 : break;
2700 : }
2701 0 : return VNET_CRYPTO_ALG_NONE;
2702 : }
2703 :
2704 : static vnet_crypto_op_id_t
2705 0 : lisp_key_type_to_crypto_op (lisp_key_type_t key_id)
2706 : {
2707 0 : switch (key_id)
2708 : {
2709 0 : case HMAC_SHA_1_96:
2710 0 : return VNET_CRYPTO_OP_SHA1_HMAC;
2711 0 : case HMAC_SHA_256_128:
2712 0 : return VNET_CRYPTO_OP_SHA256_HMAC;
2713 0 : default:
2714 0 : clib_warning ("unsupported encryption key type: %d!", key_id);
2715 0 : break;
2716 : }
2717 0 : return VNET_CRYPTO_OP_NONE;
2718 : }
2719 :
2720 : static int
2721 0 : update_map_register_auth_data (map_register_hdr_t * map_reg_hdr,
2722 : lisp_key_type_t key_id, u8 * key,
2723 : u16 auth_data_len, u32 msg_len)
2724 : {
2725 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
2726 0 : MREG_KEY_ID (map_reg_hdr) = clib_host_to_net_u16 (key_id);
2727 0 : MREG_AUTH_DATA_LEN (map_reg_hdr) = clib_host_to_net_u16 (auth_data_len);
2728 0 : vnet_crypto_op_t _op, *op = &_op;
2729 : vnet_crypto_key_index_t ki;
2730 :
2731 0 : vnet_crypto_op_init (op, lisp_key_type_to_crypto_op (key_id));
2732 0 : op->len = msg_len;
2733 0 : op->digest = MREG_DATA (map_reg_hdr);
2734 0 : op->src = (u8 *) map_reg_hdr;
2735 0 : op->digest_len = 0;
2736 0 : op->iv = 0;
2737 :
2738 0 : ki = vnet_crypto_key_add (lcm->vlib_main,
2739 : lisp_key_type_to_crypto_alg (key_id), key,
2740 0 : vec_len (key));
2741 :
2742 0 : op->key_index = ki;
2743 :
2744 0 : vnet_crypto_process_ops (lcm->vlib_main, op, 1);
2745 0 : vnet_crypto_key_del (lcm->vlib_main, ki);
2746 :
2747 0 : return 0;
2748 : }
2749 :
2750 : static vlib_buffer_t *
2751 0 : build_map_register (lisp_cp_main_t * lcm, ip_address_t * sloc,
2752 : ip_address_t * ms_ip, u64 * nonce_res, u8 want_map_notif,
2753 : mapping_t * records, lisp_key_type_t key_id, u8 * key,
2754 : u32 * bi_res)
2755 : {
2756 : void *map_reg_hdr;
2757 : vlib_buffer_t *b;
2758 0 : u32 bi, auth_data_len = 0, msg_len = 0;
2759 0 : vlib_main_t *vm = lcm->vlib_main;
2760 :
2761 0 : if (vlib_buffer_alloc (vm, &bi, 1) != 1)
2762 : {
2763 0 : clib_warning ("Can't allocate buffer for Map-Register!");
2764 0 : return 0;
2765 : }
2766 :
2767 0 : b = vlib_get_buffer (vm, bi);
2768 :
2769 : /* leave some space for the encap headers */
2770 0 : vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
2771 :
2772 0 : auth_data_len = auth_data_len_by_key_id (key_id);
2773 0 : map_reg_hdr = lisp_msg_put_map_register (b, records, want_map_notif,
2774 : auth_data_len, nonce_res,
2775 : &msg_len);
2776 :
2777 0 : update_map_register_auth_data (map_reg_hdr, key_id, key, auth_data_len,
2778 : msg_len);
2779 :
2780 : /* push outer ip header */
2781 0 : pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, LISP_CONTROL_PORT, sloc,
2782 : ms_ip, 1);
2783 :
2784 0 : bi_res[0] = bi;
2785 0 : return b;
2786 : }
2787 :
2788 : #define _(name) \
2789 : static int \
2790 : get_egress_map_ ##name## _ip (lisp_cp_main_t * lcm, ip_address_t * ip) \
2791 : { \
2792 : lisp_msmr_t *mr; \
2793 : while (lcm->do_map_ ## name ## _election \
2794 : | (0 == ip_fib_get_first_egress_ip_for_dst \
2795 : (lcm, &lcm->active_map_ ##name, ip))) \
2796 : { \
2797 : if (0 == elect_map_ ## name (lcm)) \
2798 : /* all map resolvers/servers are down */ \
2799 : { \
2800 : /* restart MR/MS checking by marking all of them up */ \
2801 : vec_foreach (mr, lcm->map_ ## name ## s) mr->is_down = 0; \
2802 : return -1; \
2803 : } \
2804 : } \
2805 : return 0; \
2806 : }
2807 :
2808 0 : foreach_msmr
2809 : #undef _
2810 : /* CP output statistics */
2811 : #define foreach_lisp_cp_output_error \
2812 : _(MAP_REGISTERS_SENT, "map-registers sent") \
2813 : _(MAP_REQUESTS_SENT, "map-requests sent") \
2814 : _(RLOC_PROBES_SENT, "rloc-probes sent")
2815 : static char *lisp_cp_output_error_strings[] = {
2816 : #define _(sym,string) string,
2817 : foreach_lisp_cp_output_error
2818 : #undef _
2819 : };
2820 :
2821 : typedef enum
2822 : {
2823 : #define _(sym,str) LISP_CP_OUTPUT_ERROR_##sym,
2824 : foreach_lisp_cp_output_error
2825 : #undef _
2826 : LISP_CP_OUTPUT_N_ERROR,
2827 : } lisp_cp_output_error_t;
2828 :
2829 : static uword
2830 0 : lisp_cp_output (vlib_main_t * vm, vlib_node_runtime_t * node,
2831 : vlib_frame_t * from_frame)
2832 : {
2833 0 : return 0;
2834 : }
2835 :
2836 : /* placeholder node used only for statistics */
2837 : /* *INDENT-OFF* */
2838 86264 : VLIB_REGISTER_NODE (lisp_cp_output_node) = {
2839 : .function = lisp_cp_output,
2840 : .name = "lisp-cp-output",
2841 : .vector_size = sizeof (u32),
2842 : .format_trace = format_lisp_cp_input_trace,
2843 : .type = VLIB_NODE_TYPE_INTERNAL,
2844 :
2845 : .n_errors = LISP_CP_OUTPUT_N_ERROR,
2846 : .error_strings = lisp_cp_output_error_strings,
2847 :
2848 : .n_next_nodes = LISP_CP_INPUT_N_NEXT,
2849 :
2850 : .next_nodes = {
2851 : [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
2852 : },
2853 : };
2854 : /* *INDENT-ON* */
2855 :
2856 : static int
2857 0 : send_rloc_probe (lisp_cp_main_t * lcm, gid_address_t * deid,
2858 : u32 local_locator_set_index, ip_address_t * sloc,
2859 : ip_address_t * rloc)
2860 : {
2861 : locator_set_t *ls;
2862 : u32 bi;
2863 : vlib_buffer_t *b;
2864 : vlib_frame_t *f;
2865 0 : u64 nonce = 0;
2866 : u32 next_index, *to_next;
2867 : gid_address_t *itr_rlocs;
2868 :
2869 0 : ls = pool_elt_at_index (lcm->locator_set_pool, local_locator_set_index);
2870 0 : itr_rlocs = build_itr_rloc_list (lcm, ls);
2871 :
2872 0 : b = build_map_request (lcm, deid, sloc, rloc, itr_rlocs, &nonce, &bi);
2873 0 : vec_free (itr_rlocs);
2874 0 : if (!b)
2875 0 : return -1;
2876 :
2877 0 : vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
2878 :
2879 0 : next_index = (ip_addr_version (rloc) == AF_IP4) ?
2880 0 : ip4_lookup_node.index : ip6_lookup_node.index;
2881 :
2882 0 : f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
2883 :
2884 : /* Enqueue the packet */
2885 0 : to_next = vlib_frame_vector_args (f);
2886 0 : to_next[0] = bi;
2887 0 : f->n_vectors = 1;
2888 0 : vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
2889 :
2890 0 : return 0;
2891 : }
2892 :
2893 : static int
2894 0 : send_rloc_probes (lisp_cp_main_t * lcm)
2895 : {
2896 0 : u8 lprio = 0;
2897 : mapping_t *lm;
2898 : fwd_entry_t *e;
2899 : locator_pair_t *lp;
2900 0 : u32 si, rloc_probes_sent = 0;
2901 :
2902 : /* *INDENT-OFF* */
2903 0 : pool_foreach (e, lcm->fwd_entry_pool)
2904 : {
2905 0 : if (vec_len (e->locator_pairs) == 0)
2906 0 : continue;
2907 :
2908 0 : si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &e->leid);
2909 0 : if (~0 == si)
2910 : {
2911 0 : clib_warning ("internal error: cannot find local eid %U in "
2912 : "map-cache!", format_gid_address, &e->leid);
2913 0 : continue;
2914 : }
2915 0 : lm = pool_elt_at_index (lcm->mapping_pool, si);
2916 :
2917 : /* get the best (lowest) priority */
2918 0 : lprio = e->locator_pairs[0].priority;
2919 :
2920 : /* send rloc-probe for pair(s) with the best remote locator priority */
2921 0 : vec_foreach (lp, e->locator_pairs)
2922 : {
2923 0 : if (lp->priority != lprio)
2924 0 : break;
2925 :
2926 : /* get first remote locator */
2927 0 : send_rloc_probe (lcm, &e->reid, lm->locator_set_index, &lp->lcl_loc,
2928 : &lp->rmt_loc);
2929 0 : rloc_probes_sent++;
2930 : }
2931 : }
2932 : /* *INDENT-ON* */
2933 :
2934 0 : vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
2935 : LISP_CP_OUTPUT_ERROR_RLOC_PROBES_SENT,
2936 : rloc_probes_sent);
2937 0 : return 0;
2938 : }
2939 :
2940 : static int
2941 0 : send_map_register (lisp_cp_main_t * lcm, u8 want_map_notif)
2942 : {
2943 : pending_map_register_t *pmr;
2944 0 : u32 bi, map_registers_sent = 0;
2945 : vlib_buffer_t *b;
2946 : ip_address_t sloc;
2947 : vlib_frame_t *f;
2948 0 : u64 nonce = 0;
2949 : u32 next_index, *to_next;
2950 : mapping_t *records, *r, *group, *k;
2951 :
2952 0 : if (get_egress_map_server_ip (lcm, &sloc) < 0)
2953 0 : return -1;
2954 :
2955 0 : records = build_map_register_record_list (lcm);
2956 0 : if (!records)
2957 0 : return -1;
2958 :
2959 0 : vec_foreach (r, records)
2960 : {
2961 0 : u8 *key = r->key;
2962 0 : u8 key_id = r->key_id;
2963 :
2964 0 : if (!key)
2965 0 : continue; /* no secret key -> map-register cannot be sent */
2966 :
2967 0 : group = 0;
2968 0 : vec_add1 (group, r[0]);
2969 :
2970 : /* group mappings that share common key */
2971 0 : for (k = r + 1; k < vec_end (records); k++)
2972 : {
2973 0 : if (k->key_id != r->key_id)
2974 0 : continue;
2975 :
2976 0 : if (vec_is_equal (k->key, r->key))
2977 : {
2978 0 : vec_add1 (group, k[0]);
2979 0 : k->key = 0; /* don't process this mapping again */
2980 : }
2981 : }
2982 :
2983 0 : b = build_map_register (lcm, &sloc, &lcm->active_map_server, &nonce,
2984 : want_map_notif, group, key_id, key, &bi);
2985 0 : vec_free (group);
2986 0 : if (!b)
2987 0 : continue;
2988 :
2989 0 : vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
2990 :
2991 0 : next_index = (ip_addr_version (&lcm->active_map_server) == AF_IP4) ?
2992 0 : ip4_lookup_node.index : ip6_lookup_node.index;
2993 :
2994 0 : f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
2995 :
2996 : /* Enqueue the packet */
2997 0 : to_next = vlib_frame_vector_args (f);
2998 0 : to_next[0] = bi;
2999 0 : f->n_vectors = 1;
3000 0 : vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
3001 0 : map_registers_sent++;
3002 :
3003 0 : pool_get (lcm->pending_map_registers_pool, pmr);
3004 0 : clib_memset (pmr, 0, sizeof (*pmr));
3005 0 : pmr->time_to_expire = PENDING_MREG_EXPIRATION_TIME;
3006 0 : hash_set (lcm->map_register_messages_by_nonce, nonce,
3007 : pmr - lcm->pending_map_registers_pool);
3008 : }
3009 0 : free_map_register_records (records);
3010 :
3011 0 : vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
3012 : LISP_CP_OUTPUT_ERROR_MAP_REGISTERS_SENT,
3013 : map_registers_sent);
3014 :
3015 0 : return 0;
3016 : }
3017 :
3018 : #define send_encapsulated_map_request(lcm, seid, deid, smr) \
3019 : _send_encapsulated_map_request(lcm, seid, deid, smr, 0)
3020 :
3021 : #define resend_encapsulated_map_request(lcm, seid, deid, smr) \
3022 : _send_encapsulated_map_request(lcm, seid, deid, smr, 1)
3023 :
3024 : static int
3025 0 : _send_encapsulated_map_request (lisp_cp_main_t * lcm,
3026 : gid_address_t * seid, gid_address_t * deid,
3027 : u8 is_smr_invoked, u8 is_resend)
3028 : {
3029 0 : u32 next_index, bi = 0, *to_next, map_index;
3030 : vlib_buffer_t *b;
3031 : vlib_frame_t *f;
3032 0 : u64 nonce = 0;
3033 : locator_set_t *loc_set;
3034 : mapping_t *map;
3035 0 : pending_map_request_t *pmr, *duplicate_pmr = 0;
3036 : ip_address_t sloc;
3037 : u32 ls_index;
3038 :
3039 : /* if there is already a pending request remember it */
3040 :
3041 : /* *INDENT-OFF* */
3042 0 : pool_foreach (pmr, lcm->pending_map_requests_pool)
3043 : {
3044 0 : if (!gid_address_cmp (&pmr->src, seid)
3045 0 : && !gid_address_cmp (&pmr->dst, deid))
3046 : {
3047 0 : duplicate_pmr = pmr;
3048 0 : break;
3049 : }
3050 : }
3051 : /* *INDENT-ON* */
3052 :
3053 0 : if (!is_resend && duplicate_pmr)
3054 : {
3055 : /* don't send the request if there is a pending map request already */
3056 0 : return 0;
3057 : }
3058 :
3059 0 : u8 pitr_mode = lcm->flags & LISP_FLAG_PITR_MODE;
3060 :
3061 : /* get locator-set for seid */
3062 0 : if (!pitr_mode && gid_address_type (deid) != GID_ADDR_NSH)
3063 : {
3064 0 : map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid);
3065 0 : if (map_index == ~0)
3066 : {
3067 0 : clib_warning ("No local mapping found in eid-table for %U!",
3068 : format_gid_address, seid);
3069 0 : return -1;
3070 : }
3071 :
3072 0 : map = pool_elt_at_index (lcm->mapping_pool, map_index);
3073 :
3074 0 : if (!map->local)
3075 : {
3076 0 : clib_warning
3077 : ("Mapping found for src eid %U is not marked as local!",
3078 : format_gid_address, seid);
3079 0 : return -1;
3080 : }
3081 0 : ls_index = map->locator_set_index;
3082 : }
3083 : else
3084 : {
3085 0 : if (pitr_mode)
3086 : {
3087 0 : if (lcm->pitr_map_index != ~0)
3088 : {
3089 0 : map =
3090 0 : pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
3091 0 : ls_index = map->locator_set_index;
3092 : }
3093 : else
3094 : {
3095 0 : return -1;
3096 : }
3097 : }
3098 : else
3099 : {
3100 0 : if (lcm->nsh_map_index == (u32) ~ 0)
3101 : {
3102 0 : clib_warning ("No locator-set defined for NSH!");
3103 0 : return -1;
3104 : }
3105 : else
3106 : {
3107 0 : map = pool_elt_at_index (lcm->mapping_pool, lcm->nsh_map_index);
3108 0 : ls_index = map->locator_set_index;
3109 : }
3110 : }
3111 : }
3112 :
3113 : /* overwrite locator set if map-request itr-rlocs configured */
3114 0 : if (~0 != lcm->mreq_itr_rlocs)
3115 : {
3116 0 : ls_index = lcm->mreq_itr_rlocs;
3117 : }
3118 :
3119 0 : loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
3120 :
3121 0 : if (get_egress_map_resolver_ip (lcm, &sloc) < 0)
3122 : {
3123 0 : if (duplicate_pmr)
3124 0 : duplicate_pmr->to_be_removed = 1;
3125 0 : return -1;
3126 : }
3127 :
3128 : /* build the encapsulated map request */
3129 0 : b = build_encapsulated_map_request (lcm, seid, deid, loc_set,
3130 : &lcm->active_map_resolver,
3131 : &sloc, is_smr_invoked, &nonce, &bi);
3132 :
3133 0 : if (!b)
3134 0 : return -1;
3135 :
3136 : /* set fib index to default and lookup node */
3137 0 : vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
3138 0 : next_index = (ip_addr_version (&lcm->active_map_resolver) == AF_IP4) ?
3139 0 : ip4_lookup_node.index : ip6_lookup_node.index;
3140 :
3141 0 : f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
3142 :
3143 : /* Enqueue the packet */
3144 0 : to_next = vlib_frame_vector_args (f);
3145 0 : to_next[0] = bi;
3146 0 : f->n_vectors = 1;
3147 0 : vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
3148 :
3149 0 : vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index,
3150 : LISP_CP_OUTPUT_ERROR_MAP_REQUESTS_SENT, 1);
3151 :
3152 0 : if (duplicate_pmr)
3153 : /* if there is a pending request already update it */
3154 : {
3155 0 : if (clib_fifo_elts (duplicate_pmr->nonces) >= PENDING_MREQ_QUEUE_LEN)
3156 : {
3157 : /* remove the oldest nonce */
3158 : u64 CLIB_UNUSED (tmp), *nonce_del;
3159 0 : nonce_del = clib_fifo_head (duplicate_pmr->nonces);
3160 0 : hash_unset (lcm->pending_map_requests_by_nonce, nonce_del[0]);
3161 0 : clib_fifo_sub1 (duplicate_pmr->nonces, tmp);
3162 : }
3163 :
3164 0 : clib_fifo_add1 (duplicate_pmr->nonces, nonce);
3165 0 : hash_set (lcm->pending_map_requests_by_nonce, nonce,
3166 : duplicate_pmr - lcm->pending_map_requests_pool);
3167 : }
3168 : else
3169 : {
3170 : /* add map-request to pending requests table */
3171 0 : pool_get (lcm->pending_map_requests_pool, pmr);
3172 0 : clib_memset (pmr, 0, sizeof (*pmr));
3173 0 : gid_address_copy (&pmr->src, seid);
3174 0 : gid_address_copy (&pmr->dst, deid);
3175 0 : clib_fifo_add1 (pmr->nonces, nonce);
3176 0 : pmr->is_smr_invoked = is_smr_invoked;
3177 0 : reset_pending_mr_counters (pmr);
3178 0 : hash_set (lcm->pending_map_requests_by_nonce, nonce,
3179 : pmr - lcm->pending_map_requests_pool);
3180 : }
3181 :
3182 0 : return 0;
3183 : }
3184 :
3185 : static void
3186 0 : get_src_and_dst_ip (void *hdr, ip_address_t * src, ip_address_t * dst)
3187 : {
3188 0 : ip4_header_t *ip4 = hdr;
3189 : ip6_header_t *ip6;
3190 :
3191 0 : if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
3192 : {
3193 0 : ip_address_set (src, &ip4->src_address, AF_IP4);
3194 0 : ip_address_set (dst, &ip4->dst_address, AF_IP4);
3195 : }
3196 : else
3197 : {
3198 0 : ip6 = hdr;
3199 0 : ip_address_set (src, &ip6->src_address, AF_IP6);
3200 0 : ip_address_set (dst, &ip6->dst_address, AF_IP6);
3201 : }
3202 0 : }
3203 :
3204 : static u32
3205 0 : lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b,
3206 : u8 version)
3207 : {
3208 : uword *vnip;
3209 0 : u32 vni = ~0, table_id = ~0;
3210 :
3211 0 : table_id = fib_table_get_table_id_for_sw_if_index ((version ==
3212 : AF_IP4 ?
3213 : FIB_PROTOCOL_IP4 :
3214 : FIB_PROTOCOL_IP6),
3215 0 : vnet_buffer
3216 : (b)->sw_if_index
3217 : [VLIB_RX]);
3218 :
3219 0 : vnip = hash_get (lcm->vni_by_table_id, table_id);
3220 0 : if (vnip)
3221 0 : vni = vnip[0];
3222 : else
3223 0 : clib_warning ("vrf %d is not mapped to any vni!", table_id);
3224 :
3225 0 : return vni;
3226 : }
3227 :
3228 : always_inline u32
3229 0 : lisp_get_bd_from_buffer_eth (vlib_buffer_t * b)
3230 : {
3231 : u32 sw_if_index0;
3232 :
3233 0 : l2input_main_t *l2im = &l2input_main;
3234 : l2_input_config_t *config;
3235 : l2_bridge_domain_t *bd_config;
3236 :
3237 0 : sw_if_index0 = vnet_buffer (b)->sw_if_index[VLIB_RX];
3238 0 : config = vec_elt_at_index (l2im->configs, sw_if_index0);
3239 0 : bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index);
3240 :
3241 0 : return bd_config->bd_id;
3242 : }
3243 :
3244 : always_inline u32
3245 0 : lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b)
3246 : {
3247 : uword *vnip;
3248 0 : u32 vni = ~0;
3249 0 : u32 bd = lisp_get_bd_from_buffer_eth (b);
3250 :
3251 0 : vnip = hash_get (lcm->vni_by_bd_id, bd);
3252 0 : if (vnip)
3253 0 : vni = vnip[0];
3254 : else
3255 0 : clib_warning ("bridge domain %d is not mapped to any vni!", bd);
3256 :
3257 0 : return vni;
3258 : }
3259 :
3260 : void
3261 0 : get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
3262 : gid_address_t * src, gid_address_t * dst,
3263 : u16 type)
3264 : {
3265 : ethernet_header_t *eh;
3266 0 : u32 vni = 0;
3267 : icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
3268 :
3269 0 : clib_memset (src, 0, sizeof (*src));
3270 0 : clib_memset (dst, 0, sizeof (*dst));
3271 :
3272 0 : gid_address_type (dst) = GID_ADDR_NO_ADDRESS;
3273 0 : gid_address_type (src) = GID_ADDR_NO_ADDRESS;
3274 :
3275 0 : if (LISP_AFI_IP == type || LISP_AFI_IP6 == type)
3276 0 : {
3277 : ip4_header_t *ip;
3278 : u8 version, preflen;
3279 :
3280 0 : gid_address_type (src) = GID_ADDR_IP_PREFIX;
3281 0 : gid_address_type (dst) = GID_ADDR_IP_PREFIX;
3282 :
3283 0 : ip = vlib_buffer_get_current (b);
3284 0 : get_src_and_dst_ip (ip, &gid_address_ip (src), &gid_address_ip (dst));
3285 :
3286 0 : version = gid_address_ip_version (src);
3287 0 : preflen = ip_address_max_len (version);
3288 0 : gid_address_ippref_len (src) = preflen;
3289 0 : gid_address_ippref_len (dst) = preflen;
3290 :
3291 0 : vni = lisp_get_vni_from_buffer_ip (lcm, b, version);
3292 0 : gid_address_vni (dst) = vni;
3293 0 : gid_address_vni (src) = vni;
3294 : }
3295 0 : else if (LISP_AFI_MAC == type)
3296 : {
3297 : ethernet_arp_header_t *ah;
3298 :
3299 0 : eh = vlib_buffer_get_current (b);
3300 :
3301 0 : if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_ARP)
3302 : {
3303 0 : ah = (ethernet_arp_header_t *) (((u8 *) eh) + sizeof (*eh));
3304 0 : gid_address_type (dst) = GID_ADDR_ARP;
3305 :
3306 0 : if (clib_net_to_host_u16 (ah->opcode)
3307 : != ETHERNET_ARP_OPCODE_request)
3308 : {
3309 0 : clib_memset (&gid_address_arp_ndp_ip (dst), 0,
3310 : sizeof (ip_address_t));
3311 0 : ip_addr_version (&gid_address_arp_ndp_ip (dst)) = AF_IP4;
3312 0 : gid_address_arp_ndp_bd (dst) = ~0;
3313 0 : return;
3314 : }
3315 :
3316 0 : gid_address_arp_bd (dst) = lisp_get_bd_from_buffer_eth (b);
3317 0 : clib_memcpy (&gid_address_arp_ip4 (dst),
3318 : &ah->ip4_over_ethernet[1].ip4, 4);
3319 : }
3320 : else
3321 : {
3322 0 : if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_IP6)
3323 : {
3324 : ip6_header_t *ip;
3325 0 : ip = (ip6_header_t *) (eh + 1);
3326 :
3327 0 : if (IP_PROTOCOL_ICMP6 == ip->protocol)
3328 : {
3329 : icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
3330 0 : ndh = ip6_next_header (ip);
3331 0 : if (ndh->icmp.type == ICMP6_neighbor_solicitation)
3332 : {
3333 0 : gid_address_type (dst) = GID_ADDR_NDP;
3334 :
3335 : /* check that source link layer address option is present */
3336 0 : opt = (void *) (ndh + 1);
3337 0 : if ((opt->header.type !=
3338 : ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address)
3339 0 : || (opt->header.n_data_u64s != 1))
3340 : {
3341 0 : clib_memset (&gid_address_arp_ndp_ip (dst), 0,
3342 : sizeof (ip_address_t));
3343 0 : ip_addr_version (&gid_address_arp_ndp_ip (dst)) =
3344 : AF_IP6;
3345 0 : gid_address_arp_ndp_bd (dst) = ~0;
3346 0 : gid_address_type (src) = GID_ADDR_NO_ADDRESS;
3347 0 : return;
3348 : }
3349 :
3350 0 : gid_address_ndp_bd (dst) =
3351 0 : lisp_get_bd_from_buffer_eth (b);
3352 0 : ip_address_set (&gid_address_arp_ndp_ip (dst),
3353 0 : &ndh->target_address, AF_IP6);
3354 0 : return;
3355 : }
3356 : }
3357 : }
3358 :
3359 0 : gid_address_type (src) = GID_ADDR_MAC;
3360 0 : gid_address_type (dst) = GID_ADDR_MAC;
3361 0 : mac_copy (&gid_address_mac (src), eh->src_address);
3362 0 : mac_copy (&gid_address_mac (dst), eh->dst_address);
3363 :
3364 : /* get vni */
3365 0 : vni = lisp_get_vni_from_buffer_eth (lcm, b);
3366 :
3367 0 : gid_address_vni (dst) = vni;
3368 0 : gid_address_vni (src) = vni;
3369 : }
3370 : }
3371 0 : else if (LISP_AFI_LCAF == type)
3372 : {
3373 : lisp_nsh_hdr_t *nh;
3374 0 : eh = vlib_buffer_get_current (b);
3375 :
3376 0 : if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_NSH)
3377 : {
3378 0 : nh = (lisp_nsh_hdr_t *) (((u8 *) eh) + sizeof (*eh));
3379 0 : u32 spi = clib_net_to_host_u32 (nh->spi_si << 8);
3380 0 : u8 si = (u8) clib_net_to_host_u32 (nh->spi_si);
3381 0 : gid_address_nsh_spi (dst) = spi;
3382 0 : gid_address_nsh_si (dst) = si;
3383 :
3384 0 : gid_address_type (dst) = GID_ADDR_NSH;
3385 0 : gid_address_type (src) = GID_ADDR_NSH;
3386 : }
3387 : }
3388 : }
3389 :
3390 : static uword
3391 0 : lisp_cp_lookup_inline (vlib_main_t * vm,
3392 : vlib_node_runtime_t * node,
3393 : vlib_frame_t * from_frame, int overlay)
3394 : {
3395 : icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt;
3396 : u32 *from, *to_next, di, si;
3397 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3398 : u32 next_index;
3399 : uword n_left_from, n_left_to_next;
3400 0 : vnet_main_t *vnm = vnet_get_main ();
3401 :
3402 0 : from = vlib_frame_vector_args (from_frame);
3403 0 : n_left_from = from_frame->n_vectors;
3404 0 : next_index = node->cached_next_index;
3405 :
3406 0 : while (n_left_from > 0)
3407 : {
3408 0 : vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
3409 :
3410 0 : while (n_left_from > 0 && n_left_to_next > 0)
3411 : {
3412 : u32 pi0, sw_if_index0, next0;
3413 : u64 mac0;
3414 : vlib_buffer_t *b0;
3415 : gid_address_t src, dst;
3416 : ethernet_arp_header_t *arp0;
3417 : ethernet_header_t *eth0;
3418 : vnet_hw_interface_t *hw_if0;
3419 : ethernet_header_t *eh0;
3420 : icmp6_neighbor_solicitation_or_advertisement_header_t *ndh;
3421 : ip6_header_t *ip0;
3422 :
3423 0 : pi0 = from[0];
3424 0 : from += 1;
3425 0 : n_left_from -= 1;
3426 0 : to_next[0] = pi0;
3427 0 : to_next += 1;
3428 0 : n_left_to_next -= 1;
3429 :
3430 0 : b0 = vlib_get_buffer (vm, pi0);
3431 :
3432 : /* src/dst eid pair */
3433 0 : get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst, overlay);
3434 :
3435 0 : if (gid_address_type (&dst) == GID_ADDR_ARP)
3436 : {
3437 0 : mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
3438 0 : if (GID_LOOKUP_MISS_L2 == mac0)
3439 0 : goto drop;
3440 :
3441 : /* send ARP reply */
3442 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
3443 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
3444 :
3445 0 : hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
3446 :
3447 0 : eth0 = vlib_buffer_get_current (b0);
3448 0 : arp0 = (ethernet_arp_header_t *) (((u8 *) eth0)
3449 : + sizeof (*eth0));
3450 0 : arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply);
3451 0 : arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0];
3452 0 : mac_address_from_u64 (&arp0->ip4_over_ethernet[0].mac, mac0);
3453 0 : clib_memcpy (&arp0->ip4_over_ethernet[0].ip4,
3454 : &gid_address_arp_ip4 (&dst), 4);
3455 :
3456 : /* Hardware must be ethernet-like. */
3457 0 : ASSERT (vec_len (hw_if0->hw_address) == 6);
3458 :
3459 0 : clib_memcpy (eth0->dst_address, eth0->src_address, 6);
3460 0 : clib_memcpy (eth0->src_address, hw_if0->hw_address, 6);
3461 :
3462 0 : b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX];
3463 0 : next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX;
3464 0 : goto enqueue;
3465 : }
3466 0 : else if (gid_address_type (&dst) == GID_ADDR_NDP)
3467 : {
3468 0 : mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
3469 0 : if (GID_LOOKUP_MISS_L2 == mac0)
3470 0 : goto drop;
3471 :
3472 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
3473 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
3474 :
3475 0 : eh0 = vlib_buffer_get_current (b0);
3476 0 : ip0 = (ip6_header_t *) (eh0 + 1);
3477 0 : ndh = ip6_next_header (ip0);
3478 : int bogus_length;
3479 0 : ip0->dst_address = ip0->src_address;
3480 0 : ip0->src_address = ndh->target_address;
3481 0 : ip0->hop_limit = 255;
3482 0 : opt = (void *) (ndh + 1);
3483 0 : opt->header.type =
3484 : ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address;
3485 0 : clib_memcpy (opt->ethernet_address, (u8 *) & mac0, 6);
3486 0 : ndh->icmp.type = ICMP6_neighbor_advertisement;
3487 0 : ndh->advertisement_flags = clib_host_to_net_u32
3488 : (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED |
3489 : ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE);
3490 0 : ndh->icmp.checksum = 0;
3491 0 : ndh->icmp.checksum =
3492 0 : ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0,
3493 : &bogus_length);
3494 0 : clib_memcpy (eh0->dst_address, eh0->src_address, 6);
3495 0 : clib_memcpy (eh0->src_address, (u8 *) & mac0, 6);
3496 0 : b0->error =
3497 0 : node->errors
3498 : [LISP_CP_LOOKUP_ERROR_NDP_NEIGHBOR_ADVERTISEMENT_TX];
3499 0 : next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX;
3500 0 : goto enqueue;
3501 : }
3502 :
3503 : /* if we have remote mapping for destination already in map-cache
3504 : add forwarding tunnel directly. If not send a map-request */
3505 0 : di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst,
3506 : &src);
3507 0 : if (~0 != di)
3508 : {
3509 0 : mapping_t *m = vec_elt_at_index (lcm->mapping_pool, di);
3510 : /* send a map-request also in case of negative mapping entry
3511 : with corresponding action */
3512 0 : if (m->action == LISP_SEND_MAP_REQUEST)
3513 : {
3514 : /* send map-request */
3515 0 : queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3516 : 0 /* is_resend */ );
3517 : }
3518 : else
3519 : {
3520 0 : if (GID_ADDR_NSH != gid_address_type (&dst))
3521 : {
3522 0 : si = gid_dictionary_lookup (&lcm->mapping_index_by_gid,
3523 : &src);
3524 : }
3525 : else
3526 0 : si = lcm->nsh_map_index;
3527 :
3528 0 : if (~0 != si)
3529 : {
3530 0 : dp_add_fwd_entry_from_mt (si, di);
3531 : }
3532 : }
3533 : }
3534 : else
3535 : {
3536 : /* send map-request */
3537 0 : queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
3538 : 0 /* is_resend */ );
3539 : }
3540 :
3541 0 : drop:
3542 0 : b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
3543 0 : next0 = LISP_CP_LOOKUP_NEXT_DROP;
3544 0 : enqueue:
3545 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
3546 : {
3547 0 : lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
3548 : sizeof (*tr));
3549 :
3550 0 : clib_memset (tr, 0, sizeof (*tr));
3551 0 : if ((gid_address_type (&dst) == GID_ADDR_NDP) ||
3552 0 : (gid_address_type (&dst) == GID_ADDR_ARP))
3553 0 : clib_memcpy (&tr->dst_eid, &dst, sizeof (gid_address_t));
3554 : else
3555 0 : gid_address_copy (&tr->dst_eid, &dst);
3556 0 : ip_address_copy (&tr->map_resolver_ip,
3557 0 : &lcm->active_map_resolver);
3558 : }
3559 0 : gid_address_free (&dst);
3560 0 : gid_address_free (&src);
3561 0 : vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
3562 : to_next,
3563 : n_left_to_next, pi0, next0);
3564 : }
3565 :
3566 0 : vlib_put_next_frame (vm, node, next_index, n_left_to_next);
3567 : }
3568 0 : return from_frame->n_vectors;
3569 : }
3570 :
3571 : static uword
3572 0 : lisp_cp_lookup_ip4 (vlib_main_t * vm,
3573 : vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3574 : {
3575 0 : return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP));
3576 : }
3577 :
3578 : static uword
3579 0 : lisp_cp_lookup_ip6 (vlib_main_t * vm,
3580 : vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3581 : {
3582 0 : return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP6));
3583 : }
3584 :
3585 : static uword
3586 0 : lisp_cp_lookup_l2 (vlib_main_t * vm,
3587 : vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3588 : {
3589 0 : return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_MAC));
3590 : }
3591 :
3592 : static uword
3593 0 : lisp_cp_lookup_nsh (vlib_main_t * vm,
3594 : vlib_node_runtime_t * node, vlib_frame_t * from_frame)
3595 : {
3596 : /* TODO decide if NSH should be propagated as LCAF or not */
3597 0 : return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_LCAF));
3598 : }
3599 :
3600 : /* *INDENT-OFF* */
3601 86264 : VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = {
3602 : .function = lisp_cp_lookup_ip4,
3603 : .name = "lisp-cp-lookup-ip4",
3604 : .vector_size = sizeof (u32),
3605 : .format_trace = format_lisp_cp_lookup_trace,
3606 : .type = VLIB_NODE_TYPE_INTERNAL,
3607 :
3608 : .n_errors = LISP_CP_LOOKUP_N_ERROR,
3609 : .error_strings = lisp_cp_lookup_error_strings,
3610 :
3611 : .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3612 :
3613 : .next_nodes = {
3614 : [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
3615 : [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
3616 : },
3617 : };
3618 : /* *INDENT-ON* */
3619 :
3620 : /* *INDENT-OFF* */
3621 86264 : VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = {
3622 : .function = lisp_cp_lookup_ip6,
3623 : .name = "lisp-cp-lookup-ip6",
3624 : .vector_size = sizeof (u32),
3625 : .format_trace = format_lisp_cp_lookup_trace,
3626 : .type = VLIB_NODE_TYPE_INTERNAL,
3627 :
3628 : .n_errors = LISP_CP_LOOKUP_N_ERROR,
3629 : .error_strings = lisp_cp_lookup_error_strings,
3630 :
3631 : .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3632 :
3633 : .next_nodes = {
3634 : [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
3635 : [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
3636 : },
3637 : };
3638 : /* *INDENT-ON* */
3639 :
3640 : /* *INDENT-OFF* */
3641 86264 : VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
3642 : .function = lisp_cp_lookup_l2,
3643 : .name = "lisp-cp-lookup-l2",
3644 : .vector_size = sizeof (u32),
3645 : .format_trace = format_lisp_cp_lookup_trace,
3646 : .type = VLIB_NODE_TYPE_INTERNAL,
3647 :
3648 : .n_errors = LISP_CP_LOOKUP_N_ERROR,
3649 : .error_strings = lisp_cp_lookup_error_strings,
3650 :
3651 : .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3652 :
3653 : .next_nodes = {
3654 : [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
3655 : [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
3656 : },
3657 : };
3658 : /* *INDENT-ON* */
3659 :
3660 : /* *INDENT-OFF* */
3661 86264 : VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = {
3662 : .function = lisp_cp_lookup_nsh,
3663 : .name = "lisp-cp-lookup-nsh",
3664 : .vector_size = sizeof (u32),
3665 : .format_trace = format_lisp_cp_lookup_trace,
3666 : .type = VLIB_NODE_TYPE_INTERNAL,
3667 :
3668 : .n_errors = LISP_CP_LOOKUP_N_ERROR,
3669 : .error_strings = lisp_cp_lookup_error_strings,
3670 :
3671 : .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
3672 :
3673 : .next_nodes = {
3674 : [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
3675 : [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output",
3676 : },
3677 : };
3678 : /* *INDENT-ON* */
3679 :
3680 : /* lisp_cp_input statistics */
3681 : #define foreach_lisp_cp_input_error \
3682 : _(DROP, "drop") \
3683 : _(RLOC_PROBE_REQ_RECEIVED, "rloc-probe requests received") \
3684 : _(RLOC_PROBE_REP_RECEIVED, "rloc-probe replies received") \
3685 : _(MAP_NOTIFIES_RECEIVED, "map-notifies received") \
3686 : _(MAP_REPLIES_RECEIVED, "map-replies received")
3687 :
3688 : static char *lisp_cp_input_error_strings[] = {
3689 : #define _(sym,string) string,
3690 : foreach_lisp_cp_input_error
3691 : #undef _
3692 : };
3693 :
3694 : typedef enum
3695 : {
3696 : #define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
3697 : foreach_lisp_cp_input_error
3698 : #undef _
3699 : LISP_CP_INPUT_N_ERROR,
3700 : } lisp_cp_input_error_t;
3701 :
3702 : typedef struct
3703 : {
3704 : gid_address_t dst_eid;
3705 : ip4_address_t map_resolver_ip;
3706 : } lisp_cp_input_trace_t;
3707 :
3708 : u8 *
3709 0 : format_lisp_cp_input_trace (u8 * s, va_list * args)
3710 : {
3711 0 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
3712 0 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
3713 0 : CLIB_UNUSED (lisp_cp_input_trace_t * t) =
3714 : va_arg (*args, lisp_cp_input_trace_t *);
3715 :
3716 0 : s = format (s, "LISP-CP-INPUT: TODO");
3717 0 : return s;
3718 : }
3719 :
3720 : static void
3721 0 : remove_expired_mapping (lisp_cp_main_t * lcm, u32 mi)
3722 : {
3723 : mapping_t *m;
3724 0 : vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
3725 0 : clib_memset (adj_args, 0, sizeof (adj_args[0]));
3726 :
3727 0 : m = pool_elt_at_index (lcm->mapping_pool, mi);
3728 :
3729 0 : gid_address_copy (&adj_args->reid, &m->eid);
3730 0 : adj_args->is_add = 0;
3731 0 : if (vnet_lisp_add_del_adjacency (adj_args))
3732 0 : clib_warning ("failed to del adjacency!");
3733 :
3734 0 : TW (tw_timer_stop) (&lcm->wheel, m->timer_handle);
3735 0 : vnet_lisp_del_mapping (&m->eid, NULL);
3736 0 : }
3737 :
3738 : static void
3739 0 : mapping_start_expiration_timer (lisp_cp_main_t * lcm, u32 mi,
3740 : f64 expiration_time)
3741 : {
3742 : mapping_t *m;
3743 0 : u64 now = clib_cpu_time_now ();
3744 0 : u64 cpu_cps = lcm->vlib_main->clib_time.clocks_per_second;
3745 0 : u64 exp_clock_time = now + expiration_time * cpu_cps;
3746 :
3747 0 : m = pool_elt_at_index (lcm->mapping_pool, mi);
3748 :
3749 0 : m->timer_set = 1;
3750 0 : m->timer_handle = TW (tw_timer_start) (&lcm->wheel, mi, 0, exp_clock_time);
3751 0 : }
3752 :
3753 : static void
3754 0 : process_expired_mapping (lisp_cp_main_t * lcm, u32 mi)
3755 : {
3756 : int rv;
3757 0 : vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
3758 0 : mapping_t *m = pool_elt_at_index (lcm->mapping_pool, mi);
3759 : uword *fei;
3760 : fwd_entry_t *fe;
3761 : vlib_counter_t c;
3762 0 : u8 have_stats = 0;
3763 :
3764 0 : if (m->delete_after_expiration)
3765 : {
3766 0 : remove_expired_mapping (lcm, mi);
3767 0 : return;
3768 : }
3769 :
3770 0 : fei = hash_get (lcm->fwd_entry_by_mapping_index, mi);
3771 0 : if (!fei)
3772 0 : return;
3773 :
3774 0 : fe = pool_elt_at_index (lcm->fwd_entry_pool, fei[0]);
3775 :
3776 0 : clib_memset (a, 0, sizeof (*a));
3777 0 : a->rmt_eid = fe->reid;
3778 0 : if (fe->is_src_dst)
3779 0 : a->lcl_eid = fe->leid;
3780 0 : a->vni = gid_address_vni (&fe->reid);
3781 :
3782 0 : rv = vnet_lisp_gpe_get_fwd_stats (a, &c);
3783 0 : if (0 == rv)
3784 0 : have_stats = 1;
3785 :
3786 0 : if (m->almost_expired)
3787 : {
3788 0 : m->almost_expired = 0; /* reset flag */
3789 0 : if (have_stats)
3790 : {
3791 0 : if (m->packets != c.packets)
3792 : {
3793 : /* mapping is in use, re-fetch */
3794 : map_request_args_t mr_args;
3795 0 : clib_memset (&mr_args, 0, sizeof (mr_args));
3796 0 : mr_args.seid = fe->leid;
3797 0 : mr_args.deid = fe->reid;
3798 :
3799 0 : send_map_request_thread_fn (&mr_args);
3800 : }
3801 : else
3802 0 : remove_expired_mapping (lcm, mi);
3803 : }
3804 : else
3805 0 : remove_expired_mapping (lcm, mi);
3806 : }
3807 : else
3808 : {
3809 0 : m->almost_expired = 1;
3810 0 : mapping_start_expiration_timer (lcm, mi, TIME_UNTIL_REFETCH_OR_DELETE);
3811 :
3812 0 : if (have_stats)
3813 : /* save counter */
3814 0 : m->packets = c.packets;
3815 : else
3816 0 : m->delete_after_expiration = 1;
3817 : }
3818 : }
3819 :
3820 : static void
3821 0 : map_records_arg_free (map_records_arg_t * a)
3822 : {
3823 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3824 : mapping_t *m;
3825 0 : vec_foreach (m, a->mappings)
3826 : {
3827 0 : vec_free (m->locators);
3828 0 : gid_address_free (&m->eid);
3829 : }
3830 0 : pool_put (lcm->map_records_args_pool[vlib_get_thread_index ()], a);
3831 0 : }
3832 :
3833 : void *
3834 0 : process_map_reply (map_records_arg_t * a)
3835 : {
3836 : mapping_t *m;
3837 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3838 0 : u32 dst_map_index = 0;
3839 : pending_map_request_t *pmr;
3840 : u64 *noncep;
3841 : uword *pmr_index;
3842 0 : u8 is_changed = 0;
3843 :
3844 0 : if (a->is_rloc_probe)
3845 0 : goto done;
3846 :
3847 : /* Check pending requests table and nonce */
3848 0 : pmr_index = hash_get (lcm->pending_map_requests_by_nonce, a->nonce);
3849 0 : if (!pmr_index)
3850 : {
3851 0 : clib_warning ("No pending map-request entry with nonce %lu!", a->nonce);
3852 0 : goto done;
3853 : }
3854 0 : pmr = pool_elt_at_index (lcm->pending_map_requests_pool, pmr_index[0]);
3855 :
3856 0 : vec_foreach (m, a->mappings)
3857 : {
3858 0 : vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args;
3859 0 : clib_memset (m_args, 0, sizeof (m_args[0]));
3860 0 : gid_address_copy (&m_args->eid, &m->eid);
3861 0 : m_args->action = m->action;
3862 0 : m_args->authoritative = m->authoritative;
3863 0 : m_args->ttl = m->ttl;
3864 0 : m_args->is_static = 0;
3865 :
3866 : /* insert/update mappings cache */
3867 0 : vnet_lisp_add_mapping (m_args, m->locators, &dst_map_index, &is_changed);
3868 :
3869 0 : if (dst_map_index == (u32) ~ 0)
3870 0 : continue;
3871 :
3872 0 : if (is_changed)
3873 : {
3874 : /* try to program forwarding only if mapping saved or updated */
3875 0 : vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args;
3876 0 : clib_memset (adj_args, 0, sizeof (adj_args[0]));
3877 :
3878 0 : gid_address_copy (&adj_args->leid, &pmr->src);
3879 0 : gid_address_copy (&adj_args->reid, &m->eid);
3880 0 : adj_args->is_add = 1;
3881 :
3882 0 : if (vnet_lisp_add_del_adjacency (adj_args))
3883 0 : clib_warning ("failed to add adjacency!");
3884 : }
3885 :
3886 0 : if ((u32) ~ 0 != m->ttl)
3887 0 : mapping_start_expiration_timer (lcm, dst_map_index,
3888 0 : (m->ttl == 0) ? 0 : MAPPING_TIMEOUT);
3889 : }
3890 :
3891 : /* remove pending map request entry */
3892 :
3893 : /* *INDENT-OFF* */
3894 0 : clib_fifo_foreach (noncep, pmr->nonces, ({
3895 : hash_unset(lcm->pending_map_requests_by_nonce, noncep[0]);
3896 : }));
3897 : /* *INDENT-ON* */
3898 :
3899 0 : clib_fifo_free (pmr->nonces);
3900 0 : pool_put (lcm->pending_map_requests_pool, pmr);
3901 :
3902 0 : done:
3903 0 : a->is_free = 1;
3904 0 : return 0;
3905 : }
3906 :
3907 : static int
3908 0 : is_auth_data_valid (map_notify_hdr_t * h, u32 msg_len,
3909 : lisp_key_type_t key_id, u8 * key)
3910 : {
3911 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3912 0 : u8 *auth_data = 0;
3913 : u16 auth_data_len;
3914 : int result;
3915 0 : vnet_crypto_op_t _op, *op = &_op;
3916 : vnet_crypto_key_index_t ki;
3917 0 : u8 out[EVP_MAX_MD_SIZE] = { 0, };
3918 :
3919 0 : auth_data_len = auth_data_len_by_key_id (key_id);
3920 0 : if ((u16) ~ 0 == auth_data_len)
3921 : {
3922 0 : clib_warning ("invalid length for key_id %d!", key_id);
3923 0 : return 0;
3924 : }
3925 :
3926 : /* save auth data */
3927 0 : vec_validate (auth_data, auth_data_len - 1);
3928 0 : clib_memcpy (auth_data, MNOTIFY_DATA (h), auth_data_len);
3929 :
3930 : /* clear auth data */
3931 0 : clib_memset (MNOTIFY_DATA (h), 0, auth_data_len);
3932 :
3933 0 : vnet_crypto_op_init (op, lisp_key_type_to_crypto_op (key_id));
3934 0 : op->len = msg_len;
3935 0 : op->digest = out;
3936 0 : op->src = (u8 *) h;
3937 0 : op->digest_len = 0;
3938 0 : op->iv = 0;
3939 :
3940 0 : ki = vnet_crypto_key_add (lcm->vlib_main,
3941 : lisp_key_type_to_crypto_alg (key_id), key,
3942 0 : vec_len (key));
3943 :
3944 0 : op->key_index = ki;
3945 :
3946 0 : vnet_crypto_process_ops (lcm->vlib_main, op, 1);
3947 0 : vnet_crypto_key_del (lcm->vlib_main, ki);
3948 :
3949 0 : result = memcmp (out, auth_data, auth_data_len);
3950 :
3951 0 : vec_free (auth_data);
3952 :
3953 0 : return !result;
3954 : }
3955 :
3956 : static void
3957 0 : process_map_notify (map_records_arg_t * a)
3958 : {
3959 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
3960 : uword *pmr_index;
3961 :
3962 0 : pmr_index = hash_get (lcm->map_register_messages_by_nonce, a->nonce);
3963 0 : if (!pmr_index)
3964 : {
3965 0 : clib_warning ("No pending map-register entry with nonce %lu!",
3966 : a->nonce);
3967 0 : return;
3968 : }
3969 :
3970 0 : a->is_free = 1;
3971 0 : pool_put_index (lcm->pending_map_registers_pool, pmr_index[0]);
3972 0 : hash_unset (lcm->map_register_messages_by_nonce, a->nonce);
3973 :
3974 : /* reset map-notify counter */
3975 0 : lcm->expired_map_registers = 0;
3976 : }
3977 :
3978 : static mapping_t *
3979 0 : get_mapping (lisp_cp_main_t * lcm, gid_address_t * e)
3980 : {
3981 : u32 mi;
3982 :
3983 0 : mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, e);
3984 0 : if (~0 == mi)
3985 : {
3986 0 : clib_warning ("eid %U not found in map-cache!", unformat_gid_address,
3987 : e);
3988 0 : return 0;
3989 : }
3990 0 : return pool_elt_at_index (lcm->mapping_pool, mi);
3991 : }
3992 :
3993 : /**
3994 : * When map-notify is received it is necessary that all EIDs in the record
3995 : * list share common key. The key is then used to verify authentication
3996 : * data in map-notify message.
3997 : */
3998 : static int
3999 0 : map_record_integrity_check (lisp_cp_main_t * lcm, mapping_t * maps,
4000 : u32 key_id, u8 ** key_out)
4001 : {
4002 0 : u32 i, len = vec_len (maps);
4003 : mapping_t *m;
4004 :
4005 : /* get key of the first mapping */
4006 0 : m = get_mapping (lcm, &maps[0].eid);
4007 0 : if (!m || !m->key)
4008 0 : return -1;
4009 :
4010 0 : key_out[0] = m->key;
4011 :
4012 0 : for (i = 1; i < len; i++)
4013 : {
4014 0 : m = get_mapping (lcm, &maps[i].eid);
4015 0 : if (!m || !m->key)
4016 0 : return -1;
4017 :
4018 0 : if (key_id != m->key_id || vec_cmp (m->key, key_out[0]))
4019 : {
4020 0 : clib_warning ("keys does not match! %v, %v", key_out[0], m->key);
4021 0 : return -1;
4022 : }
4023 : }
4024 0 : return 0;
4025 : }
4026 :
4027 : static int
4028 0 : parse_map_records (vlib_buffer_t * b, map_records_arg_t * a, u8 count)
4029 : {
4030 0 : locator_t *locators = 0;
4031 : u32 i, len;
4032 : gid_address_t deid;
4033 : mapping_t m;
4034 : locator_t *loc;
4035 :
4036 0 : clib_memset (&m, 0, sizeof (m));
4037 :
4038 : /* parse record eid */
4039 0 : for (i = 0; i < count; i++)
4040 : {
4041 0 : locators = 0;
4042 0 : len = lisp_msg_parse_mapping_record (b, &deid, &locators, NULL);
4043 0 : if (len == ~0)
4044 : {
4045 0 : clib_warning ("Failed to parse mapping record!");
4046 0 : vec_foreach (loc, locators) locator_free (loc);
4047 0 : vec_free (locators);
4048 0 : return -1;
4049 : }
4050 :
4051 0 : m.locators = locators;
4052 0 : gid_address_copy (&m.eid, &deid);
4053 0 : vec_add1 (a->mappings, m);
4054 : }
4055 :
4056 0 : return 0;
4057 : }
4058 :
4059 : static map_records_arg_t *
4060 0 : map_record_args_get ()
4061 : {
4062 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4063 : map_records_arg_t *rec;
4064 :
4065 : /* Cleanup first */
4066 : /* *INDENT-OFF* */
4067 0 : pool_foreach (rec, lcm->map_records_args_pool[vlib_get_thread_index()]) {
4068 0 : if (rec->is_free)
4069 0 : map_records_arg_free (rec);
4070 : }
4071 : /* *INDENT-ON* */
4072 :
4073 0 : pool_get (lcm->map_records_args_pool[vlib_get_thread_index ()], rec);
4074 0 : return rec;
4075 : }
4076 :
4077 : static map_records_arg_t *
4078 0 : parse_map_notify (vlib_buffer_t * b)
4079 : {
4080 0 : int rc = 0;
4081 : map_notify_hdr_t *mnotif_hdr;
4082 : lisp_key_type_t key_id;
4083 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4084 0 : u8 *key = 0;
4085 : gid_address_t deid;
4086 0 : u16 auth_data_len = 0;
4087 : u8 record_count;
4088 : map_records_arg_t *a;
4089 :
4090 0 : a = map_record_args_get ();
4091 0 : clib_memset (a, 0, sizeof (*a));
4092 0 : mnotif_hdr = vlib_buffer_get_current (b);
4093 0 : vlib_buffer_pull (b, sizeof (*mnotif_hdr));
4094 0 : clib_memset (&deid, 0, sizeof (deid));
4095 :
4096 0 : a->nonce = MNOTIFY_NONCE (mnotif_hdr);
4097 0 : key_id = clib_net_to_host_u16 (MNOTIFY_KEY_ID (mnotif_hdr));
4098 0 : auth_data_len = auth_data_len_by_key_id (key_id);
4099 :
4100 : /* advance buffer by authentication data */
4101 0 : vlib_buffer_pull (b, auth_data_len);
4102 :
4103 0 : record_count = MNOTIFY_REC_COUNT (mnotif_hdr);
4104 0 : rc = parse_map_records (b, a, record_count);
4105 0 : if (rc != 0)
4106 : {
4107 0 : map_records_arg_free (a);
4108 0 : return 0;
4109 : }
4110 :
4111 0 : rc = map_record_integrity_check (lcm, a->mappings, key_id, &key);
4112 0 : if (rc != 0)
4113 : {
4114 0 : map_records_arg_free (a);
4115 0 : return 0;
4116 : }
4117 :
4118 : /* verify authentication data */
4119 0 : if (!is_auth_data_valid (mnotif_hdr, vlib_buffer_get_tail (b)
4120 0 : - (u8 *) mnotif_hdr, key_id, key))
4121 : {
4122 0 : clib_warning ("Map-notify auth data verification failed for nonce "
4123 : "0x%lx!", a->nonce);
4124 0 : map_records_arg_free (a);
4125 0 : return 0;
4126 : }
4127 0 : return a;
4128 : }
4129 :
4130 : static vlib_buffer_t *
4131 0 : build_map_reply (lisp_cp_main_t * lcm, ip_address_t * sloc,
4132 : ip_address_t * dst, u64 nonce, u8 probe_bit,
4133 : mapping_t * records, u16 dst_port, u32 * bi_res)
4134 : {
4135 : vlib_buffer_t *b;
4136 : u32 bi;
4137 0 : vlib_main_t *vm = lcm->vlib_main;
4138 :
4139 0 : if (vlib_buffer_alloc (vm, &bi, 1) != 1)
4140 : {
4141 0 : clib_warning ("Can't allocate buffer for Map-Register!");
4142 0 : return 0;
4143 : }
4144 :
4145 0 : b = vlib_get_buffer (vm, bi);
4146 :
4147 : /* leave some space for the encap headers */
4148 0 : vlib_buffer_make_headroom (b, MAX_LISP_MSG_ENCAP_LEN);
4149 :
4150 0 : lisp_msg_put_map_reply (b, records, nonce, probe_bit);
4151 :
4152 : /* push outer ip header */
4153 0 : pkt_push_udp_and_ip (vm, b, LISP_CONTROL_PORT, dst_port, sloc, dst, 1);
4154 :
4155 0 : bi_res[0] = bi;
4156 0 : return b;
4157 : }
4158 :
4159 : static int
4160 0 : send_map_reply (lisp_cp_main_t * lcm, u32 mi, ip_address_t * dst,
4161 : u8 probe_bit, u64 nonce, u16 dst_port,
4162 : ip_address_t * probed_loc)
4163 : {
4164 : ip_address_t src;
4165 : u32 bi;
4166 : vlib_buffer_t *b;
4167 : vlib_frame_t *f;
4168 : u32 next_index, *to_next;
4169 0 : mapping_t *records = 0, *m;
4170 :
4171 0 : m = pool_elt_at_index (lcm->mapping_pool, mi);
4172 0 : vec_add1 (records, m[0]);
4173 0 : add_locators (lcm, &records[0], m->locator_set_index, probed_loc);
4174 0 : clib_memset (&src, 0, sizeof (src));
4175 :
4176 0 : if (!ip_fib_get_first_egress_ip_for_dst (lcm, dst, &src))
4177 : {
4178 0 : clib_warning ("can't find interface address for %U", format_ip_address,
4179 : dst);
4180 0 : return -1;
4181 : }
4182 :
4183 0 : b = build_map_reply (lcm, &src, dst, nonce, probe_bit, records, dst_port,
4184 : &bi);
4185 0 : if (!b)
4186 0 : return -1;
4187 0 : free_map_register_records (records);
4188 :
4189 0 : vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
4190 0 : next_index = (ip_addr_version (&lcm->active_map_resolver) == AF_IP4) ?
4191 0 : ip4_lookup_node.index : ip6_lookup_node.index;
4192 :
4193 0 : f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
4194 :
4195 : /* Enqueue the packet */
4196 0 : to_next = vlib_frame_vector_args (f);
4197 0 : to_next[0] = bi;
4198 0 : f->n_vectors = 1;
4199 0 : vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
4200 0 : return 0;
4201 : }
4202 :
4203 : static void
4204 0 : find_ip_header (vlib_buffer_t * b, u8 ** ip_hdr)
4205 : {
4206 0 : const i32 start = vnet_buffer (b)->l3_hdr_offset;
4207 0 : if (start < 0 && start < -sizeof (b->pre_data))
4208 : {
4209 0 : *ip_hdr = 0;
4210 0 : return;
4211 : }
4212 :
4213 0 : *ip_hdr = b->data + start;
4214 0 : if ((u8 *) * ip_hdr > (u8 *) vlib_buffer_get_current (b))
4215 0 : *ip_hdr = 0;
4216 : }
4217 :
4218 : void
4219 0 : process_map_request (vlib_main_t * vm, vlib_node_runtime_t * node,
4220 : lisp_cp_main_t * lcm, vlib_buffer_t * b)
4221 : {
4222 0 : u8 *ip_hdr = 0;
4223 0 : ip_address_t *dst_loc = 0, probed_loc, src_loc;
4224 : mapping_t m;
4225 : map_request_hdr_t *mreq_hdr;
4226 : gid_address_t src, dst;
4227 : u64 nonce;
4228 0 : u32 i, len = 0, rloc_probe_recv = 0;
4229 0 : gid_address_t *itr_rlocs = 0;
4230 :
4231 0 : mreq_hdr = vlib_buffer_get_current (b);
4232 0 : if (!MREQ_SMR (mreq_hdr) && !MREQ_RLOC_PROBE (mreq_hdr))
4233 : {
4234 0 : clib_warning
4235 : ("Only SMR Map-Requests and RLOC probe supported for now!");
4236 0 : return;
4237 : }
4238 :
4239 0 : vlib_buffer_pull (b, sizeof (*mreq_hdr));
4240 0 : nonce = MREQ_NONCE (mreq_hdr);
4241 :
4242 : /* parse src eid */
4243 0 : len = lisp_msg_parse_addr (b, &src);
4244 0 : if (len == ~0)
4245 0 : return;
4246 :
4247 0 : len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs,
4248 0 : MREQ_ITR_RLOC_COUNT (mreq_hdr) + 1);
4249 0 : if (len == ~0)
4250 0 : goto done;
4251 :
4252 : /* parse eid records and send SMR-invoked map-requests */
4253 0 : for (i = 0; i < MREQ_REC_COUNT (mreq_hdr); i++)
4254 : {
4255 0 : clib_memset (&dst, 0, sizeof (dst));
4256 0 : len = lisp_msg_parse_eid_rec (b, &dst);
4257 0 : if (len == ~0)
4258 : {
4259 0 : clib_warning ("Can't parse map-request EID-record");
4260 0 : goto done;
4261 : }
4262 :
4263 0 : if (MREQ_SMR (mreq_hdr))
4264 : {
4265 : /* send SMR-invoked map-requests */
4266 0 : queue_map_request (&dst, &src, 1 /* invoked */ , 0 /* resend */ );
4267 : }
4268 0 : else if (MREQ_RLOC_PROBE (mreq_hdr))
4269 : {
4270 0 : find_ip_header (b, &ip_hdr);
4271 0 : if (!ip_hdr)
4272 : {
4273 0 : clib_warning ("Cannot find the IP header!");
4274 0 : goto done;
4275 : }
4276 0 : rloc_probe_recv++;
4277 0 : clib_memset (&m, 0, sizeof (m));
4278 0 : u32 mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst);
4279 0 : if (GID_LOOKUP_MISS == mi)
4280 : {
4281 0 : clib_warning ("Cannot find mapping index by gid!");
4282 0 : continue;
4283 : }
4284 :
4285 : // TODO: select best locator; for now use the first one
4286 0 : dst_loc = &gid_address_ip (&itr_rlocs[0]);
4287 :
4288 : /* get src/dst IP addresses */
4289 0 : get_src_and_dst_ip (ip_hdr, &src_loc, &probed_loc);
4290 :
4291 : // TODO get source port from buffer
4292 0 : u16 src_port = LISP_CONTROL_PORT;
4293 :
4294 0 : send_map_reply (lcm, mi, dst_loc, 1 /* probe-bit */ , nonce,
4295 : src_port, &probed_loc);
4296 : }
4297 : }
4298 :
4299 0 : done:
4300 0 : vlib_node_increment_counter (vm, node->node_index,
4301 : LISP_CP_INPUT_ERROR_RLOC_PROBE_REQ_RECEIVED,
4302 : rloc_probe_recv);
4303 0 : vec_free (itr_rlocs);
4304 : }
4305 :
4306 : map_records_arg_t *
4307 0 : parse_map_reply (vlib_buffer_t * b)
4308 : {
4309 : locator_t probed;
4310 : gid_address_t deid;
4311 : void *h;
4312 0 : u32 i, len = 0;
4313 : mapping_t m;
4314 : map_reply_hdr_t *mrep_hdr;
4315 : map_records_arg_t *a;
4316 :
4317 0 : a = map_record_args_get ();
4318 0 : clib_memset (a, 0, sizeof (*a));
4319 :
4320 : locator_t *locators;
4321 :
4322 0 : mrep_hdr = vlib_buffer_get_current (b);
4323 0 : a->nonce = MREP_NONCE (mrep_hdr);
4324 0 : a->is_rloc_probe = MREP_RLOC_PROBE (mrep_hdr);
4325 0 : if (!vlib_buffer_has_space (b, sizeof (*mrep_hdr)))
4326 : {
4327 0 : map_records_arg_free (a);
4328 0 : return 0;
4329 : }
4330 0 : vlib_buffer_pull (b, sizeof (*mrep_hdr));
4331 :
4332 0 : for (i = 0; i < MREP_REC_COUNT (mrep_hdr); i++)
4333 : {
4334 0 : clib_memset (&m, 0, sizeof (m));
4335 0 : locators = 0;
4336 0 : h = vlib_buffer_get_current (b);
4337 :
4338 0 : m.ttl = clib_net_to_host_u32 (MAP_REC_TTL (h));
4339 0 : m.action = MAP_REC_ACTION (h);
4340 0 : m.authoritative = MAP_REC_AUTH (h);
4341 :
4342 0 : len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
4343 0 : if (len == ~0)
4344 : {
4345 0 : clib_warning ("Failed to parse mapping record!");
4346 0 : map_records_arg_free (a);
4347 0 : return 0;
4348 : }
4349 :
4350 0 : m.locators = locators;
4351 0 : gid_address_copy (&m.eid, &deid);
4352 0 : vec_add1 (a->mappings, m);
4353 : }
4354 0 : return a;
4355 : }
4356 :
4357 : static void
4358 0 : queue_map_reply_for_processing (map_records_arg_t * a)
4359 : {
4360 0 : vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (*a));
4361 0 : }
4362 :
4363 : static void
4364 0 : queue_map_notify_for_processing (map_records_arg_t * a)
4365 : {
4366 0 : vl_api_rpc_call_main_thread (process_map_notify, (u8 *) a, sizeof (a[0]));
4367 0 : }
4368 :
4369 : static uword
4370 0 : lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
4371 : vlib_frame_t * from_frame)
4372 : {
4373 0 : u32 n_left_from, *from, *to_next_drop, rloc_probe_rep_recv = 0,
4374 0 : map_notifies_recv = 0;
4375 : lisp_msg_type_e type;
4376 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4377 : map_records_arg_t *a;
4378 :
4379 0 : from = vlib_frame_vector_args (from_frame);
4380 0 : n_left_from = from_frame->n_vectors;
4381 :
4382 :
4383 0 : while (n_left_from > 0)
4384 : {
4385 : u32 n_left_to_next_drop;
4386 :
4387 0 : vlib_get_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
4388 : to_next_drop, n_left_to_next_drop);
4389 0 : while (n_left_from > 0 && n_left_to_next_drop > 0)
4390 : {
4391 : u32 bi0;
4392 : vlib_buffer_t *b0;
4393 :
4394 0 : bi0 = from[0];
4395 0 : from += 1;
4396 0 : n_left_from -= 1;
4397 0 : to_next_drop[0] = bi0;
4398 0 : to_next_drop += 1;
4399 0 : n_left_to_next_drop -= 1;
4400 :
4401 0 : b0 = vlib_get_buffer (vm, bi0);
4402 :
4403 0 : type = lisp_msg_type (vlib_buffer_get_current (b0));
4404 0 : switch (type)
4405 : {
4406 0 : case LISP_MAP_REPLY:
4407 0 : a = parse_map_reply (b0);
4408 0 : if (a)
4409 : {
4410 0 : if (a->is_rloc_probe)
4411 0 : rloc_probe_rep_recv++;
4412 0 : queue_map_reply_for_processing (a);
4413 : }
4414 0 : break;
4415 0 : case LISP_MAP_REQUEST:
4416 0 : process_map_request (vm, node, lcm, b0);
4417 0 : break;
4418 0 : case LISP_MAP_NOTIFY:
4419 0 : a = parse_map_notify (b0);
4420 0 : if (a)
4421 : {
4422 0 : map_notifies_recv++;
4423 0 : queue_map_notify_for_processing (a);
4424 : }
4425 0 : break;
4426 0 : default:
4427 0 : clib_warning ("Unsupported LISP message type %d", type);
4428 0 : break;
4429 : }
4430 :
4431 0 : b0->error = node->errors[LISP_CP_INPUT_ERROR_DROP];
4432 :
4433 0 : if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
4434 : {
4435 :
4436 : }
4437 : }
4438 :
4439 0 : vlib_put_next_frame (vm, node, LISP_CP_INPUT_NEXT_DROP,
4440 : n_left_to_next_drop);
4441 : }
4442 0 : vlib_node_increment_counter (vm, node->node_index,
4443 : LISP_CP_INPUT_ERROR_RLOC_PROBE_REP_RECEIVED,
4444 : rloc_probe_rep_recv);
4445 0 : vlib_node_increment_counter (vm, node->node_index,
4446 : LISP_CP_INPUT_ERROR_MAP_NOTIFIES_RECEIVED,
4447 : map_notifies_recv);
4448 0 : return from_frame->n_vectors;
4449 : }
4450 :
4451 : /* *INDENT-OFF* */
4452 86264 : VLIB_REGISTER_NODE (lisp_cp_input_node) = {
4453 : .function = lisp_cp_input,
4454 : .name = "lisp-cp-input",
4455 : .vector_size = sizeof (u32),
4456 : .format_trace = format_lisp_cp_input_trace,
4457 : .type = VLIB_NODE_TYPE_INTERNAL,
4458 :
4459 : .n_errors = LISP_CP_INPUT_N_ERROR,
4460 : .error_strings = lisp_cp_input_error_strings,
4461 :
4462 : .n_next_nodes = LISP_CP_INPUT_N_NEXT,
4463 :
4464 : .next_nodes = {
4465 : [LISP_CP_INPUT_NEXT_DROP] = "error-drop",
4466 : },
4467 : };
4468 : /* *INDENT-ON* */
4469 :
4470 : clib_error_t *
4471 559 : lisp_cp_init (vlib_main_t * vm)
4472 : {
4473 559 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4474 559 : clib_error_t *error = 0;
4475 559 : vlib_thread_main_t *vtm = vlib_get_thread_main ();
4476 : u32 num_threads;
4477 :
4478 559 : if ((error = vlib_call_init_function (vm, lisp_gpe_init)))
4479 0 : return error;
4480 :
4481 559 : lcm->im4 = &ip4_main;
4482 559 : lcm->im6 = &ip6_main;
4483 559 : lcm->vlib_main = vm;
4484 559 : lcm->vnet_main = vnet_get_main ();
4485 559 : lcm->mreq_itr_rlocs = ~0;
4486 559 : lcm->flags = 0;
4487 559 : lcm->pitr_map_index = ~0;
4488 559 : lcm->petr_map_index = ~0;
4489 559 : clib_memset (&lcm->active_map_resolver, 0,
4490 : sizeof (lcm->active_map_resolver));
4491 559 : clib_memset (&lcm->active_map_server, 0, sizeof (lcm->active_map_server));
4492 :
4493 559 : gid_dictionary_init (&lcm->mapping_index_by_gid);
4494 559 : lcm->do_map_resolver_election = 1;
4495 559 : lcm->do_map_server_election = 1;
4496 559 : lcm->map_request_mode = MR_MODE_DST_ONLY;
4497 :
4498 559 : num_threads = 1 /* main thread */ + vtm->n_threads;
4499 559 : vec_validate (lcm->map_records_args_pool, num_threads - 1);
4500 :
4501 : /* default vrf mapped to vni 0 */
4502 559 : hash_set (lcm->table_id_by_vni, 0, 0);
4503 559 : hash_set (lcm->vni_by_table_id, 0, 0);
4504 :
4505 559 : TW (tw_timer_wheel_init) (&lcm->wheel, 0 /* no callback */ ,
4506 : 1e-3 /* timer period 1ms */ ,
4507 : ~0 /* max expirations per call */ );
4508 559 : lcm->nsh_map_index = ~0;
4509 559 : lcm->map_register_ttl = MAP_REGISTER_DEFAULT_TTL;
4510 559 : lcm->max_expired_map_registers = MAX_EXPIRED_MAP_REGISTERS_DEFAULT;
4511 559 : lcm->expired_map_registers = 0;
4512 559 : lcm->transport_protocol = LISP_TRANSPORT_PROTOCOL_UDP;
4513 559 : lcm->flags |= LISP_FLAG_XTR_MODE;
4514 559 : return 0;
4515 : }
4516 :
4517 : static int
4518 0 : lisp_stats_api_fill (lisp_cp_main_t * lcm, lisp_gpe_main_t * lgm,
4519 : lisp_api_stats_t * stat, lisp_stats_key_t * key,
4520 : u32 stats_index)
4521 : {
4522 : vlib_counter_t v;
4523 0 : vlib_combined_counter_main_t *cm = &lgm->counters;
4524 : lisp_gpe_fwd_entry_key_t fwd_key;
4525 : const lisp_gpe_tunnel_t *lgt;
4526 : fwd_entry_t *fe;
4527 :
4528 0 : clib_memset (stat, 0, sizeof (*stat));
4529 0 : clib_memset (&fwd_key, 0, sizeof (fwd_key));
4530 :
4531 0 : fe = pool_elt_at_index (lcm->fwd_entry_pool, key->fwd_entry_index);
4532 0 : ASSERT (fe != 0);
4533 :
4534 0 : gid_to_dp_address (&fe->reid, &stat->deid);
4535 0 : gid_to_dp_address (&fe->leid, &stat->seid);
4536 0 : stat->vni = gid_address_vni (&fe->reid);
4537 :
4538 0 : lgt = lisp_gpe_tunnel_get (key->tunnel_index);
4539 0 : stat->loc_rloc = lgt->key->lcl;
4540 0 : stat->rmt_rloc = lgt->key->rmt;
4541 :
4542 0 : vlib_get_combined_counter (cm, stats_index, &v);
4543 0 : stat->counters = v;
4544 0 : return 1;
4545 : }
4546 :
4547 : lisp_api_stats_t *
4548 0 : vnet_lisp_get_stats (void)
4549 : {
4550 0 : lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
4551 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4552 0 : lisp_api_stats_t *stats = 0, stat;
4553 : lisp_stats_key_t *key;
4554 : u32 index;
4555 :
4556 : /* *INDENT-OFF* */
4557 0 : hash_foreach_mem (key, index, lgm->lisp_stats_index_by_key,
4558 : {
4559 : if (lisp_stats_api_fill (lcm, lgm, &stat, key, index))
4560 : vec_add1 (stats, stat);
4561 : });
4562 : /* *INDENT-ON* */
4563 :
4564 0 : return stats;
4565 : }
4566 :
4567 : static void *
4568 0 : send_map_request_thread_fn (void *arg)
4569 : {
4570 0 : map_request_args_t *a = arg;
4571 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4572 :
4573 0 : if (a->is_resend)
4574 0 : resend_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
4575 : else
4576 0 : send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
4577 :
4578 0 : return 0;
4579 : }
4580 :
4581 : static int
4582 0 : queue_map_request (gid_address_t * seid, gid_address_t * deid,
4583 : u8 smr_invoked, u8 is_resend)
4584 : {
4585 : map_request_args_t a;
4586 :
4587 0 : a.is_resend = is_resend;
4588 0 : gid_address_copy (&a.seid, seid);
4589 0 : gid_address_copy (&a.deid, deid);
4590 0 : a.smr_invoked = smr_invoked;
4591 :
4592 0 : vl_api_rpc_call_main_thread (send_map_request_thread_fn,
4593 : (u8 *) & a, sizeof (a));
4594 0 : return 0;
4595 : }
4596 :
4597 : /**
4598 : * Take an action with a pending map request depending on expiration time
4599 : * and re-try counters.
4600 : */
4601 : static void
4602 0 : update_pending_request (pending_map_request_t * r, f64 dt)
4603 : {
4604 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4605 : lisp_msmr_t *mr;
4606 :
4607 0 : if (r->time_to_expire - dt < 0)
4608 : /* it's time to decide what to do with this pending request */
4609 : {
4610 0 : if (r->retries_num >= NUMBER_OF_RETRIES)
4611 : /* too many retries -> assume current map resolver is not available */
4612 : {
4613 0 : mr = get_map_resolver (&lcm->active_map_resolver);
4614 0 : if (!mr)
4615 : {
4616 0 : clib_warning ("Map resolver %U not found - probably deleted "
4617 : "by the user recently.", format_ip_address,
4618 : &lcm->active_map_resolver);
4619 : }
4620 : else
4621 : {
4622 0 : clib_warning ("map resolver %U is unreachable, ignoring",
4623 : format_ip_address, &lcm->active_map_resolver);
4624 :
4625 : /* mark current map resolver unavailable so it won't be
4626 : * selected next time */
4627 0 : mr->is_down = 1;
4628 0 : mr->last_update = vlib_time_now (lcm->vlib_main);
4629 : }
4630 :
4631 0 : reset_pending_mr_counters (r);
4632 0 : elect_map_resolver (lcm);
4633 :
4634 : /* try to find a next eligible map resolver and re-send */
4635 0 : queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
4636 : 1 /* resend */ );
4637 : }
4638 : else
4639 : {
4640 : /* try again */
4641 0 : queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
4642 : 1 /* resend */ );
4643 0 : r->retries_num++;
4644 0 : r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
4645 : }
4646 : }
4647 : else
4648 0 : r->time_to_expire -= dt;
4649 0 : }
4650 :
4651 : static void
4652 0 : remove_dead_pending_map_requests (lisp_cp_main_t * lcm)
4653 : {
4654 : u64 *nonce;
4655 : pending_map_request_t *pmr;
4656 0 : u32 *to_be_removed = 0, *pmr_index;
4657 :
4658 : /* *INDENT-OFF* */
4659 0 : pool_foreach (pmr, lcm->pending_map_requests_pool)
4660 : {
4661 0 : if (pmr->to_be_removed)
4662 : {
4663 0 : clib_fifo_foreach (nonce, pmr->nonces, ({
4664 : hash_unset (lcm->pending_map_requests_by_nonce, nonce[0]);
4665 : }));
4666 :
4667 0 : vec_add1 (to_be_removed, pmr - lcm->pending_map_requests_pool);
4668 : }
4669 : }
4670 : /* *INDENT-ON* */
4671 :
4672 0 : vec_foreach (pmr_index, to_be_removed)
4673 0 : pool_put_index (lcm->pending_map_requests_pool, pmr_index[0]);
4674 :
4675 0 : vec_free (to_be_removed);
4676 0 : }
4677 :
4678 : static void
4679 0 : update_rloc_probing (lisp_cp_main_t * lcm, f64 dt)
4680 : {
4681 : static f64 time_left = RLOC_PROBING_INTERVAL;
4682 :
4683 0 : if (!lcm->is_enabled || !lcm->rloc_probing)
4684 0 : return;
4685 :
4686 0 : time_left -= dt;
4687 0 : if (time_left <= 0)
4688 : {
4689 0 : time_left = RLOC_PROBING_INTERVAL;
4690 0 : send_rloc_probes (lcm);
4691 : }
4692 : }
4693 :
4694 : static int
4695 0 : update_pending_map_register (pending_map_register_t * r, f64 dt, u8 * del_all)
4696 : {
4697 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4698 : lisp_msmr_t *ms;
4699 0 : del_all[0] = 0;
4700 :
4701 0 : r->time_to_expire -= dt;
4702 :
4703 0 : if (r->time_to_expire < 0)
4704 : {
4705 0 : lcm->expired_map_registers++;
4706 :
4707 0 : if (lcm->expired_map_registers >= lcm->max_expired_map_registers)
4708 : {
4709 0 : ms = get_map_server (&lcm->active_map_server);
4710 0 : if (!ms)
4711 : {
4712 0 : clib_warning ("Map server %U not found - probably deleted "
4713 : "by the user recently.", format_ip_address,
4714 : &lcm->active_map_server);
4715 : }
4716 : else
4717 : {
4718 0 : clib_warning ("map server %U is unreachable, ignoring",
4719 : format_ip_address, &lcm->active_map_server);
4720 :
4721 : /* mark current map server unavailable so it won't be
4722 : * elected next time */
4723 0 : ms->is_down = 1;
4724 0 : ms->last_update = vlib_time_now (lcm->vlib_main);
4725 : }
4726 :
4727 0 : elect_map_server (lcm);
4728 :
4729 : /* indication for deleting all pending map registers */
4730 0 : del_all[0] = 1;
4731 0 : lcm->expired_map_registers = 0;
4732 0 : return 0;
4733 : }
4734 : else
4735 : {
4736 : /* delete pending map register */
4737 0 : return 0;
4738 : }
4739 : }
4740 0 : return 1;
4741 : }
4742 :
4743 : static void
4744 0 : update_map_register (lisp_cp_main_t * lcm, f64 dt)
4745 : {
4746 0 : u32 *to_be_removed = 0, *pmr_index;
4747 : static f64 time_left = QUICK_MAP_REGISTER_INTERVAL;
4748 : static u64 mreg_sent_counter = 0;
4749 :
4750 : pending_map_register_t *pmr;
4751 0 : u8 del_all = 0;
4752 :
4753 0 : if (!lcm->is_enabled || !lcm->map_registering)
4754 0 : return;
4755 :
4756 : /* *INDENT-OFF* */
4757 0 : pool_foreach (pmr, lcm->pending_map_registers_pool)
4758 : {
4759 0 : if (!update_pending_map_register (pmr, dt, &del_all))
4760 : {
4761 0 : if (del_all)
4762 0 : break;
4763 0 : vec_add1 (to_be_removed, pmr - lcm->pending_map_registers_pool);
4764 : }
4765 : }
4766 : /* *INDENT-ON* */
4767 :
4768 0 : if (del_all)
4769 : {
4770 : /* delete all pending map register messages so they won't
4771 : * trigger another map server election.. */
4772 0 : pool_free (lcm->pending_map_registers_pool);
4773 0 : hash_free (lcm->map_register_messages_by_nonce);
4774 :
4775 : /* ..and trigger registration against next map server (if any) */
4776 0 : time_left = 0;
4777 : }
4778 : else
4779 : {
4780 0 : vec_foreach (pmr_index, to_be_removed)
4781 0 : pool_put_index (lcm->pending_map_registers_pool, pmr_index[0]);
4782 : }
4783 :
4784 0 : vec_free (to_be_removed);
4785 :
4786 0 : time_left -= dt;
4787 0 : if (time_left <= 0)
4788 : {
4789 0 : if (mreg_sent_counter >= QUICK_MAP_REGISTER_MSG_COUNT)
4790 0 : time_left = MAP_REGISTER_INTERVAL;
4791 : else
4792 : {
4793 0 : mreg_sent_counter++;
4794 0 : time_left = QUICK_MAP_REGISTER_INTERVAL;
4795 : }
4796 0 : send_map_register (lcm, 1 /* want map notify */ );
4797 : }
4798 : }
4799 :
4800 : static uword
4801 1 : send_map_resolver_service (vlib_main_t * vm,
4802 : vlib_node_runtime_t * rt, vlib_frame_t * f)
4803 : {
4804 1 : u32 *expired = 0;
4805 1 : f64 period = 2.0;
4806 : pending_map_request_t *pmr;
4807 1 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4808 :
4809 : while (1)
4810 : {
4811 1 : vlib_process_wait_for_event_or_clock (vm, period);
4812 :
4813 : /* currently no signals are expected - just wait for clock */
4814 0 : (void) vlib_process_get_events (vm, 0);
4815 :
4816 : /* *INDENT-OFF* */
4817 0 : pool_foreach (pmr, lcm->pending_map_requests_pool)
4818 : {
4819 0 : if (!pmr->to_be_removed)
4820 0 : update_pending_request (pmr, period);
4821 : }
4822 : /* *INDENT-ON* */
4823 :
4824 0 : remove_dead_pending_map_requests (lcm);
4825 :
4826 0 : update_map_register (lcm, period);
4827 0 : update_rloc_probing (lcm, period);
4828 :
4829 0 : expired = TW (tw_timer_expire_timers_vec) (&lcm->wheel,
4830 : vlib_time_now (vm), expired);
4831 0 : if (vec_len (expired) > 0)
4832 : {
4833 0 : u32 *mi = 0;
4834 0 : vec_foreach (mi, expired)
4835 : {
4836 0 : process_expired_mapping (lcm, mi[0]);
4837 : }
4838 0 : vec_set_len (expired, 0);
4839 : }
4840 : }
4841 :
4842 : /* unreachable */
4843 : return 0;
4844 : }
4845 :
4846 : vnet_api_error_t
4847 0 : vnet_lisp_stats_enable_disable (u8 enable)
4848 : {
4849 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4850 :
4851 0 : if (vnet_lisp_enable_disable_status () == 0)
4852 0 : return VNET_API_ERROR_LISP_DISABLED;
4853 :
4854 0 : if (enable)
4855 0 : lcm->flags |= LISP_FLAG_STATS_ENABLED;
4856 : else
4857 0 : lcm->flags &= ~LISP_FLAG_STATS_ENABLED;
4858 :
4859 0 : return 0;
4860 : }
4861 :
4862 : u8
4863 0 : vnet_lisp_stats_enable_disable_state (void)
4864 : {
4865 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4866 :
4867 0 : if (vnet_lisp_enable_disable_status () == 0)
4868 0 : return VNET_API_ERROR_LISP_DISABLED;
4869 :
4870 0 : return lcm->flags & LISP_FLAG_STATS_ENABLED;
4871 : }
4872 :
4873 : void
4874 1 : vnet_lisp_create_retry_process (lisp_cp_main_t * lcm)
4875 : {
4876 1 : if (lcm->retry_service_index)
4877 0 : return;
4878 :
4879 1 : lcm->retry_service_index = vlib_process_create (vlib_get_main (),
4880 : "lisp-retry-service",
4881 : send_map_resolver_service,
4882 : 16 /* stack_bytes */ );
4883 : }
4884 :
4885 : u32
4886 0 : vnet_lisp_set_transport_protocol (u8 protocol)
4887 : {
4888 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4889 :
4890 0 : if (protocol < LISP_TRANSPORT_PROTOCOL_UDP ||
4891 : protocol > LISP_TRANSPORT_PROTOCOL_API)
4892 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
4893 :
4894 0 : lcm->transport_protocol = protocol;
4895 0 : return 0;
4896 : }
4897 :
4898 : lisp_transport_protocol_t
4899 0 : vnet_lisp_get_transport_protocol (void)
4900 : {
4901 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4902 0 : return lcm->transport_protocol;
4903 : }
4904 :
4905 : int
4906 0 : vnet_lisp_enable_disable_xtr_mode (u8 is_enabled)
4907 : {
4908 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4909 0 : u8 pitr_mode = lcm->flags & LISP_FLAG_PITR_MODE;
4910 0 : u8 xtr_mode = lcm->flags & LISP_FLAG_XTR_MODE;
4911 0 : u8 petr_mode = lcm->flags & LISP_FLAG_PETR_MODE;
4912 :
4913 0 : if (pitr_mode && is_enabled)
4914 0 : return VNET_API_ERROR_INVALID_ARGUMENT;
4915 :
4916 0 : if (is_enabled && xtr_mode)
4917 0 : return 0;
4918 0 : if (!is_enabled && !xtr_mode)
4919 0 : return 0;
4920 :
4921 0 : if (is_enabled)
4922 : {
4923 0 : if (!petr_mode)
4924 : {
4925 0 : lisp_cp_register_dst_port (lcm->vlib_main);
4926 : }
4927 0 : lisp_cp_enable_l2_l3_ifaces (lcm, 1 /* with_default_route */ );
4928 0 : lcm->flags |= LISP_FLAG_XTR_MODE;
4929 : }
4930 : else
4931 : {
4932 0 : if (!petr_mode)
4933 : {
4934 0 : lisp_cp_unregister_dst_port (lcm->vlib_main);
4935 : }
4936 0 : lisp_cp_disable_l2_l3_ifaces (lcm);
4937 0 : lcm->flags &= ~LISP_FLAG_XTR_MODE;
4938 : }
4939 0 : return 0;
4940 : }
4941 :
4942 : int
4943 0 : vnet_lisp_enable_disable_pitr_mode (u8 is_enabled)
4944 : {
4945 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4946 0 : u8 xtr_mode = lcm->flags & LISP_FLAG_XTR_MODE;
4947 0 : u8 pitr_mode = lcm->flags & LISP_FLAG_PITR_MODE;
4948 :
4949 0 : if (xtr_mode && is_enabled)
4950 0 : return VNET_API_ERROR_INVALID_VALUE;
4951 :
4952 0 : if (is_enabled && pitr_mode)
4953 0 : return 0;
4954 0 : if (!is_enabled && !pitr_mode)
4955 0 : return 0;
4956 :
4957 0 : if (is_enabled)
4958 : {
4959 : /* create iface, no default route */
4960 0 : lisp_cp_enable_l2_l3_ifaces (lcm, 0 /* with_default_route */ );
4961 0 : lcm->flags |= LISP_FLAG_PITR_MODE;
4962 : }
4963 : else
4964 : {
4965 0 : lisp_cp_disable_l2_l3_ifaces (lcm);
4966 0 : lcm->flags &= ~LISP_FLAG_PITR_MODE;
4967 : }
4968 0 : return 0;
4969 : }
4970 :
4971 : int
4972 0 : vnet_lisp_enable_disable_petr_mode (u8 is_enabled)
4973 : {
4974 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
4975 0 : u8 xtr_mode = lcm->flags & LISP_FLAG_XTR_MODE;
4976 0 : u8 petr_mode = lcm->flags & LISP_FLAG_PETR_MODE;
4977 :
4978 0 : if (is_enabled && petr_mode)
4979 0 : return 0;
4980 0 : if (!is_enabled && !petr_mode)
4981 0 : return 0;
4982 :
4983 0 : if (is_enabled)
4984 : {
4985 0 : if (!xtr_mode)
4986 : {
4987 0 : lisp_cp_register_dst_port (lcm->vlib_main);
4988 : }
4989 0 : lcm->flags |= LISP_FLAG_PETR_MODE;
4990 : }
4991 : else
4992 : {
4993 0 : if (!xtr_mode)
4994 : {
4995 0 : lisp_cp_unregister_dst_port (lcm->vlib_main);
4996 : }
4997 0 : lcm->flags &= ~LISP_FLAG_PETR_MODE;
4998 : }
4999 0 : return 0;
5000 : }
5001 :
5002 : u8
5003 0 : vnet_lisp_get_xtr_mode (void)
5004 : {
5005 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
5006 0 : return (lcm->flags & LISP_FLAG_XTR_MODE);
5007 : }
5008 :
5009 : u8
5010 0 : vnet_lisp_get_pitr_mode (void)
5011 : {
5012 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
5013 0 : return (lcm->flags & LISP_FLAG_PITR_MODE);
5014 : }
5015 :
5016 : u8
5017 0 : vnet_lisp_get_petr_mode (void)
5018 : {
5019 0 : lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
5020 0 : return (lcm->flags & LISP_FLAG_PETR_MODE);
5021 : }
5022 :
5023 1119 : VLIB_INIT_FUNCTION (lisp_cp_init);
5024 :
5025 : /*
5026 : * fd.io coding-style-patch-verification: ON
5027 : *
5028 : * Local Variables:
5029 : * eval: (c-set-style "gnu")
5030 : * End:
5031 : */
|