1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright 2009-2016, LabN Consulting, L.L.C.
9 #include "lib/prefix.h"
10 #include "lib/agg_table.h"
12 #include "lib/memory.h"
13 #include "lib/routemap.h"
15 #include "lib/linklist.h"
16 #include "lib/command.h"
17 #include "lib/stream.h"
19 #include "bgpd/bgpd.h"
20 #include "bgpd/bgp_ecommunity.h"
21 #include "bgpd/bgp_attr.h"
23 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
24 #include "bgpd/rfapi/rfapi.h"
25 #include "bgpd/rfapi/rfapi_backend.h"
27 #include "bgpd/bgp_route.h"
28 #include "bgpd/bgp_mplsvpn.h"
29 #include "bgpd/bgp_aspath.h"
30 #include "bgpd/bgp_advertise.h"
32 #include "bgpd/rfapi/rfapi_import.h"
33 #include "bgpd/rfapi/rfapi_private.h"
34 #include "bgpd/rfapi/rfapi_monitor.h"
35 #include "bgpd/rfapi/rfapi_vty.h"
36 #include "bgpd/rfapi/vnc_export_bgp.h"
37 #include "bgpd/rfapi/vnc_export_bgp_p.h"
38 #include "bgpd/rfapi/vnc_zebra.h"
39 #include "bgpd/rfapi/vnc_import_bgp.h"
40 #include "bgpd/rfapi/rfapi_rib.h"
42 #include "bgpd/rfapi/rfapi_ap.h"
43 #include "bgpd/rfapi/vnc_debug.h"
46 * Per-NVE Advertised prefixes
48 * We maintain a list of prefixes advertised by each NVE.
49 * There are two indices: by prefix and by lifetime.
53 * key: ptr to struct prefix (when storing, point to prefix that
54 * is part of rfapi_adb).
56 * value: ptr to struct rfapi_adb
58 * BY-LIFETIME skiplist
60 * key: ptr to struct rfapi_adb
61 * value: ptr to struct rfapi_adb
66 * Skiplist sort function that sorts first according to lifetime
67 * and then according to adb pointer value. The adb pointer
68 * is used to spread out the sort for adbs with the same lifetime
69 * and thereby make the skip list operations more efficient.
71 static int sl_adb_lifetime_cmp(const void *adb1
, const void *adb2
)
73 const struct rfapi_adb
*a1
= adb1
;
74 const struct rfapi_adb
*a2
= adb2
;
76 if (a1
->lifetime
< a2
->lifetime
)
78 if (a1
->lifetime
> a2
->lifetime
)
89 void rfapiApInit(struct rfapi_advertised_prefixes
*ap
)
91 ap
->ipN_by_prefix
= skiplist_new(0, rfapi_rib_key_cmp
, NULL
);
92 ap
->ip0_by_ether
= skiplist_new(0, rfapi_rib_key_cmp
, NULL
);
93 ap
->by_lifetime
= skiplist_new(0, sl_adb_lifetime_cmp
, NULL
);
96 void rfapiApRelease(struct rfapi_advertised_prefixes
*ap
)
98 struct rfapi_adb
*adb
;
100 /* Free ADBs and lifetime items */
101 while (0 == skiplist_first(ap
->by_lifetime
, NULL
, (void **)&adb
)) {
103 skiplist_delete_first(ap
->by_lifetime
);
106 while (0 == skiplist_delete_first(ap
->ipN_by_prefix
))
108 while (0 == skiplist_delete_first(ap
->ip0_by_ether
))
112 skiplist_free(ap
->ipN_by_prefix
);
113 skiplist_free(ap
->ip0_by_ether
);
114 skiplist_free(ap
->by_lifetime
);
116 ap
->ipN_by_prefix
= NULL
;
117 ap
->ip0_by_ether
= NULL
;
118 ap
->by_lifetime
= NULL
;
121 int rfapiApCount(struct rfapi_descriptor
*rfd
)
123 if (!rfd
->advertised
.by_lifetime
)
126 return skiplist_count(rfd
->advertised
.by_lifetime
);
129 int rfapiApCountAll(struct bgp
*bgp
)
132 struct listnode
*node
;
133 struct rfapi_descriptor
*rfd
;
138 for (ALL_LIST_ELEMENTS_RO(&h
->descriptors
, node
, rfd
)) {
139 total
+= rfapiApCount(rfd
);
146 void rfapiApReadvertiseAll(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
)
148 struct rfapi_adb
*adb
;
152 for (rc
= skiplist_next(rfd
->advertised
.by_lifetime
, NULL
,
153 (void **)&adb
, &cursor
);
154 rc
== 0; rc
= skiplist_next(rfd
->advertised
.by_lifetime
, NULL
,
155 (void **)&adb
, &cursor
)) {
157 struct prefix_rd prd
;
158 uint32_t local_pref
= rfp_cost_to_localpref(adb
->cost
);
161 prd
.family
= AF_UNSPEC
;
165 * TBD this is not quite right. When pfx_ip is 0/32 or 0/128,
166 * we need to substitute the VN address as the prefix
168 add_vnc_route(rfd
, bgp
, SAFI_MPLS_VPN
, &adb
->u
.s
.prefix_ip
,
169 &prd
, /* RD to use (0 for ENCAP) */
170 &rfd
->vn_addr
, /* nexthop */
171 &local_pref
, &adb
->lifetime
, NULL
,
172 NULL
, /* struct rfapi_un_option */
173 NULL
, /* struct rfapi_vn_option */
174 rfd
->rt_export_list
, NULL
, /* med */
175 NULL
, ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, 0);
179 void rfapiApWithdrawAll(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
)
181 struct rfapi_adb
*adb
;
187 for (rc
= skiplist_next(rfd
->advertised
.by_lifetime
, NULL
,
188 (void **)&adb
, &cursor
);
189 rc
== 0; rc
= skiplist_next(rfd
->advertised
.by_lifetime
, NULL
,
190 (void **)&adb
, &cursor
)) {
192 struct prefix pfx_vn_buf
;
193 struct prefix
*pfx_ip
;
195 if (!(RFAPI_0_PREFIX(&adb
->u
.s
.prefix_ip
)
196 && RFAPI_HOST_PREFIX(&adb
->u
.s
.prefix_ip
))) {
198 pfx_ip
= &adb
->u
.s
.prefix_ip
;
205 * 0/32 or 0/128 => mac advertisement
207 if (rfapiRaddr2Qprefix(&rfd
->vn_addr
, &pfx_vn_buf
)) {
209 * Bad: it means we can't delete the route
211 vnc_zlog_debug_verbose(
212 "%s: BAD: handle has bad vn_addr: skipping",
218 del_vnc_route(rfd
, rfd
->peer
, bgp
, SAFI_MPLS_VPN
,
219 pfx_ip
? pfx_ip
: &pfx_vn_buf
,
220 &adb
->u
.s
.prd
, /* RD to use (0 for ENCAP) */
221 ZEBRA_ROUTE_BGP
, BGP_ROUTE_RFP
, NULL
, 0);
226 * returns nonzero if tunnel readvertisement is needed, 0 otherwise
228 static int rfapiApAdjustLifetimeStats(
229 struct rfapi_descriptor
*rfd
,
230 uint32_t *old_lifetime
, /* set if removing/replacing */
231 uint32_t *new_lifetime
) /* set if replacing/adding */
237 vnc_zlog_debug_verbose("%s: rfd=%p, pOldLife=%p, pNewLife=%p", __func__
,
238 rfd
, old_lifetime
, new_lifetime
);
240 vnc_zlog_debug_verbose("%s: OldLife=%d", __func__
,
243 vnc_zlog_debug_verbose("%s: NewLife=%d", __func__
,
248 * Adding new lifetime
252 * replacing existing lifetime
256 /* old and new are same */
257 if (*old_lifetime
== *new_lifetime
)
260 if (*old_lifetime
== rfd
->min_prefix_lifetime
) {
263 if (*old_lifetime
== rfd
->max_prefix_lifetime
) {
267 /* no need to search if new value is at or equals
269 if (*new_lifetime
<= rfd
->min_prefix_lifetime
) {
270 rfd
->min_prefix_lifetime
= *new_lifetime
;
273 if (*new_lifetime
>= rfd
->max_prefix_lifetime
) {
274 rfd
->max_prefix_lifetime
= *new_lifetime
;
281 * Just adding new lifetime
283 if (*new_lifetime
< rfd
->min_prefix_lifetime
) {
284 rfd
->min_prefix_lifetime
= *new_lifetime
;
286 if (*new_lifetime
> rfd
->max_prefix_lifetime
) {
288 rfd
->max_prefix_lifetime
= *new_lifetime
;
297 * See if the max prefix lifetime for this NVE has decreased.
298 * The easy optimization: track min & max; walk the table only
299 * if they are different.
300 * The general optimization: index the advertised_prefixes
303 * Note: for a given nve_descriptor, only one of the
304 * advertised_prefixes[] tables will be used: viz., the
305 * address family that matches the VN address.
308 if (rfd
->max_prefix_lifetime
== rfd
->min_prefix_lifetime
) {
311 * Common case: all lifetimes are the same. Only
312 * thing we need to do here is check if there are
313 * no exported routes left. In that case, reinitialize
314 * the max and min values.
316 if (!rfapiApCount(rfd
)) {
317 rfd
->max_prefix_lifetime
= 0;
318 rfd
->min_prefix_lifetime
= UINT32_MAX
;
324 if (*old_lifetime
== rfd
->min_prefix_lifetime
) {
327 if (*old_lifetime
== rfd
->max_prefix_lifetime
) {
334 if (find_min
|| find_max
) {
335 uint32_t min
= UINT32_MAX
;
338 struct rfapi_adb
*adb_min
;
339 struct rfapi_adb
*adb_max
;
341 if (!skiplist_first(rfd
->advertised
.by_lifetime
,
342 (void **)&adb_min
, NULL
)
343 && !skiplist_last(rfd
->advertised
.by_lifetime
,
344 (void **)&adb_max
, NULL
)) {
347 * This should always work
349 min
= adb_min
->lifetime
;
350 max
= adb_max
->lifetime
;
355 struct rfapi_rib_key rk
;
356 struct rfapi_adb
*adb
;
359 vnc_zlog_debug_verbose(
360 "%s: walking to find new min/max", __func__
);
363 for (rc
= skiplist_next(rfd
->advertised
.ipN_by_prefix
,
364 (void **)&rk
, (void **)&adb
,
367 rc
= skiplist_next(rfd
->advertised
.ipN_by_prefix
,
368 (void **)&rk
, (void **)&adb
,
371 uint32_t lt
= adb
->lifetime
;
379 for (rc
= skiplist_next(rfd
->advertised
.ip0_by_ether
,
380 (void **)&rk
, (void **)&adb
,
383 rc
= skiplist_next(rfd
->advertised
.ip0_by_ether
,
384 (void **)&rk
, (void **)&adb
,
387 uint32_t lt
= adb
->lifetime
;
397 * trigger tunnel route update
398 * but only if we found a VPN route and it had
399 * a lifetime greater than 0
401 if (max
&& rfd
->max_prefix_lifetime
!= max
)
403 rfd
->max_prefix_lifetime
= max
;
404 rfd
->min_prefix_lifetime
= min
;
407 vnc_zlog_debug_verbose("%s: returning advertise=%d, min=%d, max=%d",
408 __func__
, advertise
, rfd
->min_prefix_lifetime
,
409 rfd
->max_prefix_lifetime
);
411 return (advertise
!= 0);
417 * 0 No need to advertise tunnel route
418 * non-0 advertise tunnel route
420 int rfapiApAdd(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
421 struct prefix
*pfx_ip
, struct prefix
*pfx_eth
,
422 struct prefix_rd
*prd
, uint32_t lifetime
, uint8_t cost
,
423 struct rfapi_l2address_option
*l2o
) /* other options TBD */
426 struct rfapi_adb
*adb
;
427 uint32_t old_lifetime
= 0;
429 struct rfapi_rib_key rk
;
431 rfapi_rib_key_init(pfx_ip
, prd
, pfx_eth
, &rk
);
432 if (RFAPI_0_PREFIX(pfx_ip
) && RFAPI_HOST_PREFIX(pfx_ip
)) {
435 rc
= skiplist_search(rfd
->advertised
.ip0_by_ether
, &rk
,
440 /* find prefix in advertised prefixes list */
441 rc
= skiplist_search(rfd
->advertised
.ipN_by_prefix
, &rk
,
448 adb
= XCALLOC(MTYPE_RFAPI_ADB
, sizeof(struct rfapi_adb
));
449 adb
->lifetime
= lifetime
;
454 skiplist_insert(rfd
->advertised
.ip0_by_ether
,
457 skiplist_insert(rfd
->advertised
.ipN_by_prefix
,
461 skiplist_insert(rfd
->advertised
.by_lifetime
, adb
, adb
);
463 old_lifetime
= adb
->lifetime
;
464 if (old_lifetime
!= lifetime
) {
465 assert(!skiplist_delete(rfd
->advertised
.by_lifetime
,
467 adb
->lifetime
= lifetime
;
468 assert(!skiplist_insert(rfd
->advertised
.by_lifetime
,
476 memset(&adb
->l2o
, 0, sizeof(struct rfapi_l2address_option
));
478 if (rfapiApAdjustLifetimeStats(rfd
, (rc
? NULL
: &old_lifetime
),
486 * After this function returns successfully, caller should call
487 * rfapiAdjustLifetimeStats() and possibly rfapiTunnelRouteAnnounce()
489 int rfapiApDelete(struct bgp
*bgp
, struct rfapi_descriptor
*rfd
,
490 struct prefix
*pfx_ip
, struct prefix
*pfx_eth
,
491 struct prefix_rd
*prd
, int *advertise_tunnel
) /* out */
494 struct rfapi_adb
*adb
;
495 uint32_t old_lifetime
;
497 struct rfapi_rib_key rk
;
499 if (advertise_tunnel
)
500 *advertise_tunnel
= 0;
502 rfapi_rib_key_init(pfx_ip
, prd
, pfx_eth
, &rk
);
503 /* find prefix in advertised prefixes list */
504 if (RFAPI_0_PREFIX(pfx_ip
) && RFAPI_HOST_PREFIX(pfx_ip
)) {
508 rc
= skiplist_search(rfd
->advertised
.ip0_by_ether
, &rk
,
513 /* find prefix in advertised prefixes list */
514 rc
= skiplist_search(rfd
->advertised
.ipN_by_prefix
, &rk
,
522 old_lifetime
= adb
->lifetime
;
525 rc
= skiplist_delete(rfd
->advertised
.ip0_by_ether
, &rk
, NULL
);
527 rc
= skiplist_delete(rfd
->advertised
.ipN_by_prefix
, &rk
, NULL
);
531 rc
= skiplist_delete(rfd
->advertised
.by_lifetime
, adb
, NULL
);
536 if (rfapiApAdjustLifetimeStats(rfd
, &old_lifetime
, NULL
)) {
537 if (advertise_tunnel
)
538 *advertise_tunnel
= 1;