]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/rfapi/rfapi_ap.c
Merge pull request #12845 from sri-mohan1/sri-mohan-ldp
[mirror_frr.git] / bgpd / rfapi / rfapi_ap.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 *
4 * Copyright 2009-2016, LabN Consulting, L.L.C.
5 *
6 */
7
8 #include "lib/zebra.h"
9 #include "lib/prefix.h"
10 #include "lib/agg_table.h"
11 #include "lib/vty.h"
12 #include "lib/memory.h"
13 #include "lib/routemap.h"
14 #include "lib/log.h"
15 #include "lib/linklist.h"
16 #include "lib/command.h"
17 #include "lib/stream.h"
18
19 #include "bgpd/bgpd.h"
20 #include "bgpd/bgp_ecommunity.h"
21 #include "bgpd/bgp_attr.h"
22
23 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
24 #include "bgpd/rfapi/rfapi.h"
25 #include "bgpd/rfapi/rfapi_backend.h"
26
27 #include "bgpd/bgp_route.h"
28 #include "bgpd/bgp_mplsvpn.h"
29 #include "bgpd/bgp_aspath.h"
30 #include "bgpd/bgp_advertise.h"
31
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"
41
42 #include "bgpd/rfapi/rfapi_ap.h"
43 #include "bgpd/rfapi/vnc_debug.h"
44
45 /*
46 * Per-NVE Advertised prefixes
47 *
48 * We maintain a list of prefixes advertised by each NVE.
49 * There are two indices: by prefix and by lifetime.
50 *
51 * BY-PREFIX skiplist
52 *
53 * key: ptr to struct prefix (when storing, point to prefix that
54 * is part of rfapi_adb).
55 *
56 * value: ptr to struct rfapi_adb
57 *
58 * BY-LIFETIME skiplist
59 *
60 * key: ptr to struct rfapi_adb
61 * value: ptr to struct rfapi_adb
62 *
63 */
64
65 /*
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.
70 */
71 static int sl_adb_lifetime_cmp(const void *adb1, const void *adb2)
72 {
73 const struct rfapi_adb *a1 = adb1;
74 const struct rfapi_adb *a2 = adb2;
75
76 if (a1->lifetime < a2->lifetime)
77 return -1;
78 if (a1->lifetime > a2->lifetime)
79 return 1;
80
81 if (a1 < a2)
82 return -1;
83 if (a1 > a2)
84 return 1;
85
86 return 0;
87 }
88
89 void rfapiApInit(struct rfapi_advertised_prefixes *ap)
90 {
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);
94 }
95
96 void rfapiApRelease(struct rfapi_advertised_prefixes *ap)
97 {
98 struct rfapi_adb *adb;
99
100 /* Free ADBs and lifetime items */
101 while (0 == skiplist_first(ap->by_lifetime, NULL, (void **)&adb)) {
102 rfapiAdbFree(adb);
103 skiplist_delete_first(ap->by_lifetime);
104 }
105
106 while (0 == skiplist_delete_first(ap->ipN_by_prefix))
107 ;
108 while (0 == skiplist_delete_first(ap->ip0_by_ether))
109 ;
110
111 /* Free lists */
112 skiplist_free(ap->ipN_by_prefix);
113 skiplist_free(ap->ip0_by_ether);
114 skiplist_free(ap->by_lifetime);
115
116 ap->ipN_by_prefix = NULL;
117 ap->ip0_by_ether = NULL;
118 ap->by_lifetime = NULL;
119 }
120
121 int rfapiApCount(struct rfapi_descriptor *rfd)
122 {
123 if (!rfd->advertised.by_lifetime)
124 return 0;
125
126 return skiplist_count(rfd->advertised.by_lifetime);
127 }
128
129 int rfapiApCountAll(struct bgp *bgp)
130 {
131 struct rfapi *h;
132 struct listnode *node;
133 struct rfapi_descriptor *rfd;
134 int total = 0;
135
136 h = bgp->rfapi;
137 if (h) {
138 for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) {
139 total += rfapiApCount(rfd);
140 }
141 }
142 return total;
143 }
144
145
146 void rfapiApReadvertiseAll(struct bgp *bgp, struct rfapi_descriptor *rfd)
147 {
148 struct rfapi_adb *adb;
149 void *cursor = NULL;
150 int rc;
151
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)) {
156
157 struct prefix_rd prd;
158 uint32_t local_pref = rfp_cost_to_localpref(adb->cost);
159
160 prd = rfd->rd;
161 prd.family = AF_UNSPEC;
162 prd.prefixlen = 64;
163
164 /*
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
167 */
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);
176 }
177 }
178
179 void rfapiApWithdrawAll(struct bgp *bgp, struct rfapi_descriptor *rfd)
180 {
181 struct rfapi_adb *adb;
182 void *cursor;
183 int rc;
184
185
186 cursor = NULL;
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)) {
191
192 struct prefix pfx_vn_buf;
193 struct prefix *pfx_ip;
194
195 if (!(RFAPI_0_PREFIX(&adb->u.s.prefix_ip)
196 && RFAPI_HOST_PREFIX(&adb->u.s.prefix_ip))) {
197
198 pfx_ip = &adb->u.s.prefix_ip;
199
200 } else {
201
202 pfx_ip = NULL;
203
204 /*
205 * 0/32 or 0/128 => mac advertisement
206 */
207 if (rfapiRaddr2Qprefix(&rfd->vn_addr, &pfx_vn_buf)) {
208 /*
209 * Bad: it means we can't delete the route
210 */
211 vnc_zlog_debug_verbose(
212 "%s: BAD: handle has bad vn_addr: skipping",
213 __func__);
214 continue;
215 }
216 }
217
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);
222 }
223 }
224
225 /*
226 * returns nonzero if tunnel readvertisement is needed, 0 otherwise
227 */
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 */
232 {
233 int advertise = 0;
234 int find_max = 0;
235 int find_min = 0;
236
237 vnc_zlog_debug_verbose("%s: rfd=%p, pOldLife=%p, pNewLife=%p", __func__,
238 rfd, old_lifetime, new_lifetime);
239 if (old_lifetime)
240 vnc_zlog_debug_verbose("%s: OldLife=%d", __func__,
241 *old_lifetime);
242 if (new_lifetime)
243 vnc_zlog_debug_verbose("%s: NewLife=%d", __func__,
244 *new_lifetime);
245
246 if (new_lifetime) {
247 /*
248 * Adding new lifetime
249 */
250 if (old_lifetime) {
251 /*
252 * replacing existing lifetime
253 */
254
255
256 /* old and new are same */
257 if (*old_lifetime == *new_lifetime)
258 return 0;
259
260 if (*old_lifetime == rfd->min_prefix_lifetime) {
261 find_min = 1;
262 }
263 if (*old_lifetime == rfd->max_prefix_lifetime) {
264 find_max = 1;
265 }
266
267 /* no need to search if new value is at or equals
268 * min|max */
269 if (*new_lifetime <= rfd->min_prefix_lifetime) {
270 rfd->min_prefix_lifetime = *new_lifetime;
271 find_min = 0;
272 }
273 if (*new_lifetime >= rfd->max_prefix_lifetime) {
274 rfd->max_prefix_lifetime = *new_lifetime;
275 advertise = 1;
276 find_max = 0;
277 }
278
279 } else {
280 /*
281 * Just adding new lifetime
282 */
283 if (*new_lifetime < rfd->min_prefix_lifetime) {
284 rfd->min_prefix_lifetime = *new_lifetime;
285 }
286 if (*new_lifetime > rfd->max_prefix_lifetime) {
287 advertise = 1;
288 rfd->max_prefix_lifetime = *new_lifetime;
289 }
290 }
291 } else {
292 /*
293 * Deleting
294 */
295
296 /*
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
301 * table by lifetime.
302 *
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.
306 *
307 */
308 if (rfd->max_prefix_lifetime == rfd->min_prefix_lifetime) {
309
310 /*
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.
315 */
316 if (!rfapiApCount(rfd)) {
317 rfd->max_prefix_lifetime = 0;
318 rfd->min_prefix_lifetime = UINT32_MAX;
319 }
320
321
322 } else {
323 if (old_lifetime) {
324 if (*old_lifetime == rfd->min_prefix_lifetime) {
325 find_min = 1;
326 }
327 if (*old_lifetime == rfd->max_prefix_lifetime) {
328 find_max = 1;
329 }
330 }
331 }
332 }
333
334 if (find_min || find_max) {
335 uint32_t min = UINT32_MAX;
336 uint32_t max = 0;
337
338 struct rfapi_adb *adb_min;
339 struct rfapi_adb *adb_max;
340
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)) {
345
346 /*
347 * This should always work
348 */
349 min = adb_min->lifetime;
350 max = adb_max->lifetime;
351
352 } else {
353
354 void *cursor;
355 struct rfapi_rib_key rk;
356 struct rfapi_adb *adb;
357 int rc;
358
359 vnc_zlog_debug_verbose(
360 "%s: walking to find new min/max", __func__);
361
362 cursor = NULL;
363 for (rc = skiplist_next(rfd->advertised.ipN_by_prefix,
364 (void **)&rk, (void **)&adb,
365 &cursor);
366 !rc;
367 rc = skiplist_next(rfd->advertised.ipN_by_prefix,
368 (void **)&rk, (void **)&adb,
369 &cursor)) {
370
371 uint32_t lt = adb->lifetime;
372
373 if (lt > max)
374 max = lt;
375 if (lt < min)
376 min = lt;
377 }
378 cursor = NULL;
379 for (rc = skiplist_next(rfd->advertised.ip0_by_ether,
380 (void **)&rk, (void **)&adb,
381 &cursor);
382 !rc;
383 rc = skiplist_next(rfd->advertised.ip0_by_ether,
384 (void **)&rk, (void **)&adb,
385 &cursor)) {
386
387 uint32_t lt = adb->lifetime;
388
389 if (lt > max)
390 max = lt;
391 if (lt < min)
392 min = lt;
393 }
394 }
395
396 /*
397 * trigger tunnel route update
398 * but only if we found a VPN route and it had
399 * a lifetime greater than 0
400 */
401 if (max && rfd->max_prefix_lifetime != max)
402 advertise = 1;
403 rfd->max_prefix_lifetime = max;
404 rfd->min_prefix_lifetime = min;
405 }
406
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);
410
411 return (advertise != 0);
412 }
413
414 /*
415 * Return Value
416 *
417 * 0 No need to advertise tunnel route
418 * non-0 advertise tunnel route
419 */
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 */
424 {
425 int rc;
426 struct rfapi_adb *adb;
427 uint32_t old_lifetime = 0;
428 int use_ip0 = 0;
429 struct rfapi_rib_key rk;
430
431 rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
432 if (RFAPI_0_PREFIX(pfx_ip) && RFAPI_HOST_PREFIX(pfx_ip)) {
433 use_ip0 = 1;
434 assert(pfx_eth);
435 rc = skiplist_search(rfd->advertised.ip0_by_ether, &rk,
436 (void **)&adb);
437
438 } else {
439
440 /* find prefix in advertised prefixes list */
441 rc = skiplist_search(rfd->advertised.ipN_by_prefix, &rk,
442 (void **)&adb);
443 }
444
445
446 if (rc) {
447 /* Not found */
448 adb = XCALLOC(MTYPE_RFAPI_ADB, sizeof(struct rfapi_adb));
449 adb->lifetime = lifetime;
450 adb->u.key = rk;
451
452 if (use_ip0) {
453 assert(pfx_eth);
454 skiplist_insert(rfd->advertised.ip0_by_ether,
455 &adb->u.key, adb);
456 } else {
457 skiplist_insert(rfd->advertised.ipN_by_prefix,
458 &adb->u.key, adb);
459 }
460
461 skiplist_insert(rfd->advertised.by_lifetime, adb, adb);
462 } else {
463 old_lifetime = adb->lifetime;
464 if (old_lifetime != lifetime) {
465 assert(!skiplist_delete(rfd->advertised.by_lifetime,
466 adb, NULL));
467 adb->lifetime = lifetime;
468 assert(!skiplist_insert(rfd->advertised.by_lifetime,
469 adb, adb));
470 }
471 }
472 adb->cost = cost;
473 if (l2o)
474 adb->l2o = *l2o;
475 else
476 memset(&adb->l2o, 0, sizeof(struct rfapi_l2address_option));
477
478 if (rfapiApAdjustLifetimeStats(rfd, (rc ? NULL : &old_lifetime),
479 &lifetime))
480 return 1;
481
482 return 0;
483 }
484
485 /*
486 * After this function returns successfully, caller should call
487 * rfapiAdjustLifetimeStats() and possibly rfapiTunnelRouteAnnounce()
488 */
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 */
492 {
493 int rc;
494 struct rfapi_adb *adb;
495 uint32_t old_lifetime;
496 int use_ip0 = 0;
497 struct rfapi_rib_key rk;
498
499 if (advertise_tunnel)
500 *advertise_tunnel = 0;
501
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)) {
505 use_ip0 = 1;
506 assert(pfx_eth);
507
508 rc = skiplist_search(rfd->advertised.ip0_by_ether, &rk,
509 (void **)&adb);
510
511 } else {
512
513 /* find prefix in advertised prefixes list */
514 rc = skiplist_search(rfd->advertised.ipN_by_prefix, &rk,
515 (void **)&adb);
516 }
517
518 if (rc) {
519 return ENOENT;
520 }
521
522 old_lifetime = adb->lifetime;
523
524 if (use_ip0) {
525 rc = skiplist_delete(rfd->advertised.ip0_by_ether, &rk, NULL);
526 } else {
527 rc = skiplist_delete(rfd->advertised.ipN_by_prefix, &rk, NULL);
528 }
529 assert(!rc);
530
531 rc = skiplist_delete(rfd->advertised.by_lifetime, adb, NULL);
532 assert(!rc);
533
534 rfapiAdbFree(adb);
535
536 if (rfapiApAdjustLifetimeStats(rfd, &old_lifetime, NULL)) {
537 if (advertise_tunnel)
538 *advertise_tunnel = 1;
539 }
540
541 return 0;
542 }