]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/rfapi/rfapi_ap.c
bgpd: Fix CONFDATE to 2019 for a couple of items.
[mirror_frr.git] / bgpd / rfapi / rfapi_ap.c
CommitLineData
d62a17ae 1/*
65efcfce
LB
2 *
3 * Copyright 2009-2016, LabN Consulting, L.L.C.
4 *
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
65efcfce
LB
19 */
20
21#include <errno.h>
22
f8b6f499
LB
23#include "lib/zebra.h"
24#include "lib/prefix.h"
25#include "lib/table.h"
26#include "lib/vty.h"
27#include "lib/memory.h"
28#include "lib/routemap.h"
29#include "lib/log.h"
30#include "lib/linklist.h"
31#include "lib/command.h"
32#include "lib/stream.h"
65efcfce 33
f8b6f499
LB
34#include "bgpd/bgpd.h"
35#include "bgpd/bgp_ecommunity.h"
36#include "bgpd/bgp_attr.h"
65efcfce 37
f8b6f499
LB
38#include "bgpd/rfapi/bgp_rfapi_cfg.h"
39#include "bgpd/rfapi/rfapi.h"
40#include "bgpd/rfapi/rfapi_backend.h"
65efcfce 41
f8b6f499 42#include "bgpd/bgp_route.h"
c016b6c7 43#include "bgpd/bgp_mplsvpn.h"
f8b6f499
LB
44#include "bgpd/bgp_aspath.h"
45#include "bgpd/bgp_advertise.h"
65efcfce 46
f8b6f499
LB
47#include "bgpd/rfapi/rfapi_import.h"
48#include "bgpd/rfapi/rfapi_private.h"
49#include "bgpd/rfapi/rfapi_monitor.h"
50#include "bgpd/rfapi/rfapi_vty.h"
51#include "bgpd/rfapi/vnc_export_bgp.h"
52#include "bgpd/rfapi/vnc_export_bgp_p.h"
53#include "bgpd/rfapi/vnc_zebra.h"
54#include "bgpd/rfapi/vnc_import_bgp.h"
55#include "bgpd/rfapi/rfapi_rib.h"
65efcfce 56
f8b6f499 57#include "bgpd/rfapi/rfapi_ap.h"
a3b55c25 58#include "bgpd/rfapi/vnc_debug.h"
65efcfce
LB
59
60/*
61 * Per-NVE Advertised prefixes
62 *
63 * We maintain a list of prefixes advertised by each NVE.
64 * There are two indices: by prefix and by lifetime.
65 *
66 * BY-PREFIX skiplist
67 *
68 * key: ptr to struct prefix (when storing, point to prefix that
69 * is part of rfapi_adb).
70 *
71 * value: ptr to struct rfapi_adb
72 *
73 * BY-LIFETIME skiplist
74 *
75 * key: ptr to struct rfapi_adb
76 * value: ptr to struct rfapi_adb
77 *
78 */
79
80/*
81 * Skiplist sort function that sorts first according to lifetime
82 * and then according to adb pointer value. The adb pointer
83 * is used to spread out the sort for adbs with the same lifetime
84 * and thereby make the skip list operations more efficient.
85 */
d62a17ae 86static int sl_adb_lifetime_cmp(void *adb1, void *adb2)
65efcfce 87{
d62a17ae 88 struct rfapi_adb *a1 = adb1;
89 struct rfapi_adb *a2 = adb2;
65efcfce 90
d62a17ae 91 if (a1->lifetime < a2->lifetime)
92 return -1;
93 if (a1->lifetime > a2->lifetime)
94 return 1;
65efcfce 95
d62a17ae 96 if (a1 < a2)
97 return -1;
98 if (a1 > a2)
99 return 1;
65efcfce 100
d62a17ae 101 return 0;
65efcfce
LB
102}
103
d62a17ae 104void rfapiApInit(struct rfapi_advertised_prefixes *ap)
65efcfce 105{
d62a17ae 106 ap->ipN_by_prefix = skiplist_new(0, rfapi_rib_key_cmp, NULL);
107 ap->ip0_by_ether = skiplist_new(0, rfapi_rib_key_cmp, NULL);
108 ap->by_lifetime = skiplist_new(0, sl_adb_lifetime_cmp, NULL);
65efcfce
LB
109}
110
d62a17ae 111void rfapiApRelease(struct rfapi_advertised_prefixes *ap)
65efcfce 112{
d62a17ae 113 struct rfapi_adb *adb;
114
115 /* Free ADBs and lifetime items */
116 while (0 == skiplist_first(ap->by_lifetime, NULL, (void **)&adb)) {
117 rfapiAdbFree(adb);
118 skiplist_delete_first(ap->by_lifetime);
119 }
120
121 while (0 == skiplist_delete_first(ap->ipN_by_prefix))
122 ;
123 while (0 == skiplist_delete_first(ap->ip0_by_ether))
124 ;
125
126 /* Free lists */
127 skiplist_free(ap->ipN_by_prefix);
128 skiplist_free(ap->ip0_by_ether);
129 skiplist_free(ap->by_lifetime);
130
131 ap->ipN_by_prefix = NULL;
132 ap->ip0_by_ether = NULL;
133 ap->by_lifetime = NULL;
65efcfce
LB
134}
135
d62a17ae 136int rfapiApCount(struct rfapi_descriptor *rfd)
65efcfce 137{
d62a17ae 138 if (!rfd->advertised.by_lifetime)
139 return 0;
65efcfce 140
d62a17ae 141 return skiplist_count(rfd->advertised.by_lifetime);
65efcfce
LB
142}
143
d62a17ae 144int rfapiApCountAll(struct bgp *bgp)
65efcfce 145{
d62a17ae 146 struct rfapi *h;
147 struct listnode *node;
148 struct rfapi_descriptor *rfd;
149 int total = 0;
150
151 h = bgp->rfapi;
152 if (h) {
153 for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) {
154 total += rfapiApCount(rfd);
155 }
156 }
157 return total;
65efcfce
LB
158}
159
160
d62a17ae 161void rfapiApReadvertiseAll(struct bgp *bgp, struct rfapi_descriptor *rfd)
65efcfce 162{
d62a17ae 163 struct rfapi_adb *adb;
164 void *cursor = NULL;
165 int rc;
166
167 for (rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
168 (void **)&adb, &cursor);
169 rc == 0; rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
170 (void **)&adb, &cursor)) {
171
172 struct prefix_rd prd;
173 uint32_t local_pref = rfp_cost_to_localpref(adb->cost);
174
175 prd = rfd->rd;
176 prd.family = AF_UNSPEC;
177 prd.prefixlen = 64;
178
179 /*
180 * TBD this is not quite right. When pfx_ip is 0/32 or 0/128,
181 * we need to substitute the VN address as the prefix
182 */
183 add_vnc_route(rfd, bgp, SAFI_MPLS_VPN, &adb->u.s.prefix_ip,
184 &prd, /* RD to use (0 for ENCAP) */
185 &rfd->vn_addr, /* nexthop */
186 &local_pref, &adb->lifetime, NULL,
187 NULL, /* struct rfapi_un_option */
188 NULL, /* struct rfapi_vn_option */
189 rfd->rt_export_list, NULL, /* med */
190 NULL, ZEBRA_ROUTE_BGP, BGP_ROUTE_RFP, 0);
191 }
65efcfce
LB
192}
193
d62a17ae 194void rfapiApWithdrawAll(struct bgp *bgp, struct rfapi_descriptor *rfd)
65efcfce 195{
d62a17ae 196 struct rfapi_adb *adb;
197 void *cursor;
198 int rc;
199
200
201 cursor = NULL;
202 for (rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
203 (void **)&adb, &cursor);
204 rc == 0; rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
205 (void **)&adb, &cursor)) {
206
207 struct prefix pfx_vn_buf;
208 struct prefix *pfx_ip;
209
210 if (!(RFAPI_0_PREFIX(&adb->u.s.prefix_ip)
211 && RFAPI_HOST_PREFIX(&adb->u.s.prefix_ip))) {
212
213 pfx_ip = &adb->u.s.prefix_ip;
214
215 } else {
216
217 pfx_ip = NULL;
218
219 /*
220 * 0/32 or 0/128 => mac advertisement
221 */
222 if (rfapiRaddr2Qprefix(&rfd->vn_addr, &pfx_vn_buf)) {
223 /*
224 * Bad: it means we can't delete the route
225 */
226 vnc_zlog_debug_verbose(
227 "%s: BAD: handle has bad vn_addr: skipping",
228 __func__);
229 continue;
230 }
231 }
232
233 del_vnc_route(rfd, rfd->peer, bgp, SAFI_MPLS_VPN,
234 pfx_ip ? pfx_ip : &pfx_vn_buf,
235 &adb->u.s.prd, /* RD to use (0 for ENCAP) */
236 ZEBRA_ROUTE_BGP, BGP_ROUTE_RFP, NULL, 0);
237 }
65efcfce
LB
238}
239
240/*
241 * returns nonzero if tunnel readvertisement is needed, 0 otherwise
242 */
d62a17ae 243static int rfapiApAdjustLifetimeStats(
244 struct rfapi_descriptor *rfd,
245 uint32_t *old_lifetime, /* set if removing/replacing */
246 uint32_t *new_lifetime) /* set if replacing/adding */
65efcfce 247{
d62a17ae 248 int advertise = 0;
249 int find_max = 0;
250 int find_min = 0;
251
252 vnc_zlog_debug_verbose("%s: rfd=%p, pOldLife=%p, pNewLife=%p", __func__,
253 rfd, old_lifetime, new_lifetime);
254 if (old_lifetime)
255 vnc_zlog_debug_verbose("%s: OldLife=%d", __func__,
256 *old_lifetime);
257 if (new_lifetime)
258 vnc_zlog_debug_verbose("%s: NewLife=%d", __func__,
259 *new_lifetime);
260
261 if (new_lifetime) {
262 /*
263 * Adding new lifetime
264 */
265 if (old_lifetime) {
266 /*
267 * replacing existing lifetime
268 */
269
270
271 /* old and new are same */
272 if (*old_lifetime == *new_lifetime)
273 return 0;
274
275 if (*old_lifetime == rfd->min_prefix_lifetime) {
276 find_min = 1;
277 }
278 if (*old_lifetime == rfd->max_prefix_lifetime) {
279 find_max = 1;
280 }
281
282 /* no need to search if new value is at or equals
283 * min|max */
284 if (*new_lifetime <= rfd->min_prefix_lifetime) {
285 rfd->min_prefix_lifetime = *new_lifetime;
286 find_min = 0;
287 }
288 if (*new_lifetime >= rfd->max_prefix_lifetime) {
289 rfd->max_prefix_lifetime = *new_lifetime;
290 advertise = 1;
291 find_max = 0;
292 }
293
294 } else {
295 /*
296 * Just adding new lifetime
297 */
298 if (*new_lifetime < rfd->min_prefix_lifetime) {
299 rfd->min_prefix_lifetime = *new_lifetime;
300 }
301 if (*new_lifetime > rfd->max_prefix_lifetime) {
302 advertise = 1;
303 rfd->max_prefix_lifetime = *new_lifetime;
304 }
305 }
306 } else {
307 /*
308 * Deleting
309 */
310
311 /*
312 * See if the max prefix lifetime for this NVE has decreased.
313 * The easy optimization: track min & max; walk the table only
314 * if they are different.
315 * The general optimization: index the advertised_prefixes
316 * table by lifetime.
317 *
318 * Note: for a given nve_descriptor, only one of the
319 * advertised_prefixes[] tables will be used: viz., the
320 * address family that matches the VN address.
321 *
322 */
323 if (rfd->max_prefix_lifetime == rfd->min_prefix_lifetime) {
324
325 /*
326 * Common case: all lifetimes are the same. Only
327 * thing we need to do here is check if there are
328 * no exported routes left. In that case, reinitialize
329 * the max and min values.
330 */
331 if (!rfapiApCount(rfd)) {
332 rfd->max_prefix_lifetime = 0;
333 rfd->min_prefix_lifetime = UINT32_MAX;
334 }
335
336
337 } else {
338 if (old_lifetime) {
339 if (*old_lifetime == rfd->min_prefix_lifetime) {
340 find_min = 1;
341 }
342 if (*old_lifetime == rfd->max_prefix_lifetime) {
343 find_max = 1;
344 }
345 }
346 }
347 }
348
349 if (find_min || find_max) {
350 uint32_t min = UINT32_MAX;
351 uint32_t max = 0;
352
353 struct rfapi_adb *adb_min;
354 struct rfapi_adb *adb_max;
355
356 if (!skiplist_first(rfd->advertised.by_lifetime,
357 (void **)&adb_min, NULL)
358 && !skiplist_last(rfd->advertised.by_lifetime,
359 (void **)&adb_max, NULL)) {
360
361 /*
362 * This should always work
363 */
364 min = adb_min->lifetime;
365 max = adb_max->lifetime;
366
367 } else {
368
369 void *cursor;
370 struct rfapi_rib_key rk;
371 struct rfapi_adb *adb;
372 int rc;
373
374 vnc_zlog_debug_verbose(
375 "%s: walking to find new min/max", __func__);
376
377 cursor = NULL;
378 for (rc = skiplist_next(rfd->advertised.ipN_by_prefix,
379 (void **)&rk, (void **)&adb,
380 &cursor);
381 !rc;
382 rc = skiplist_next(rfd->advertised.ipN_by_prefix,
383 (void **)&rk, (void **)&adb,
384 &cursor)) {
385
386 uint32_t lt = adb->lifetime;
387
388 if (lt > max)
389 max = lt;
390 if (lt < min)
391 min = lt;
392 }
393 cursor = NULL;
394 for (rc = skiplist_next(rfd->advertised.ip0_by_ether,
395 (void **)&rk, (void **)&adb,
396 &cursor);
397 !rc;
398 rc = skiplist_next(rfd->advertised.ip0_by_ether,
399 (void **)&rk, (void **)&adb,
400 &cursor)) {
401
402 uint32_t lt = adb->lifetime;
403
404 if (lt > max)
405 max = lt;
406 if (lt < min)
407 min = lt;
408 }
409 }
410
411 /*
412 * trigger tunnel route update
413 * but only if we found a VPN route and it had
414 * a lifetime greater than 0
415 */
416 if (max && rfd->max_prefix_lifetime != max)
417 advertise = 1;
418 rfd->max_prefix_lifetime = max;
419 rfd->min_prefix_lifetime = min;
420 }
421
422 vnc_zlog_debug_verbose("%s: returning advertise=%d, min=%d, max=%d",
423 __func__, advertise, rfd->min_prefix_lifetime,
424 rfd->max_prefix_lifetime);
425
426 return (advertise != 0);
65efcfce
LB
427}
428
d62a17ae 429/*
65efcfce
LB
430 * Return Value
431 *
432 * 0 No need to advertise tunnel route
433 * non-0 advertise tunnel route
434 */
d62a17ae 435int rfapiApAdd(struct bgp *bgp, struct rfapi_descriptor *rfd,
436 struct prefix *pfx_ip, struct prefix *pfx_eth,
437 struct prefix_rd *prd, uint32_t lifetime, uint8_t cost,
438 struct rfapi_l2address_option *l2o) /* other options TBD */
65efcfce 439{
d62a17ae 440 int rc;
441 struct rfapi_adb *adb;
442 uint32_t old_lifetime = 0;
443 int use_ip0 = 0;
444 struct rfapi_rib_key rk;
445
446 rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
447 if (RFAPI_0_PREFIX(pfx_ip) && RFAPI_HOST_PREFIX(pfx_ip)) {
448 use_ip0 = 1;
449 assert(pfx_eth);
450 rc = skiplist_search(rfd->advertised.ip0_by_ether, &rk,
451 (void **)&adb);
452
453 } else {
454
455 /* find prefix in advertised prefixes list */
456 rc = skiplist_search(rfd->advertised.ipN_by_prefix, &rk,
457 (void **)&adb);
458 }
459
460
461 if (rc) {
462 /* Not found */
463 adb = XCALLOC(MTYPE_RFAPI_ADB, sizeof(struct rfapi_adb));
464 assert(adb);
465 adb->lifetime = lifetime;
466 adb->u.key = rk;
467
468 if (use_ip0) {
469 assert(pfx_eth);
470 skiplist_insert(rfd->advertised.ip0_by_ether,
471 &adb->u.key, adb);
472 } else {
473 skiplist_insert(rfd->advertised.ipN_by_prefix,
474 &adb->u.key, adb);
475 }
476
477 skiplist_insert(rfd->advertised.by_lifetime, adb, adb);
478 } else {
479 old_lifetime = adb->lifetime;
480 if (old_lifetime != lifetime) {
481 assert(!skiplist_delete(rfd->advertised.by_lifetime,
482 adb, NULL));
483 adb->lifetime = lifetime;
484 assert(!skiplist_insert(rfd->advertised.by_lifetime,
485 adb, adb));
486 }
487 }
488 adb->cost = cost;
489 if (l2o)
490 adb->l2o = *l2o;
491 else
492 memset(&adb->l2o, 0, sizeof(struct rfapi_l2address_option));
493
494 if (rfapiApAdjustLifetimeStats(rfd, (rc ? NULL : &old_lifetime),
495 &lifetime))
496 return 1;
497
498 return 0;
65efcfce
LB
499}
500
501/*
502 * After this function returns successfully, caller should call
503 * rfapiAdjustLifetimeStats() and possibly rfapiTunnelRouteAnnounce()
504 */
d62a17ae 505int rfapiApDelete(struct bgp *bgp, struct rfapi_descriptor *rfd,
506 struct prefix *pfx_ip, struct prefix *pfx_eth,
507 struct prefix_rd *prd, int *advertise_tunnel) /* out */
65efcfce 508{
d62a17ae 509 int rc;
510 struct rfapi_adb *adb;
511 uint32_t old_lifetime;
512 int use_ip0 = 0;
513 struct rfapi_rib_key rk;
514
515 if (advertise_tunnel)
516 *advertise_tunnel = 0;
517
518 rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
519 /* find prefix in advertised prefixes list */
520 if (RFAPI_0_PREFIX(pfx_ip) && RFAPI_HOST_PREFIX(pfx_ip)) {
521 use_ip0 = 1;
522 assert(pfx_eth);
523
524 rc = skiplist_search(rfd->advertised.ip0_by_ether, &rk,
525 (void **)&adb);
526
527 } else {
528
529 /* find prefix in advertised prefixes list */
530 rc = skiplist_search(rfd->advertised.ipN_by_prefix, &rk,
531 (void **)&adb);
532 }
533
534 if (rc) {
535 return ENOENT;
536 }
537
538 old_lifetime = adb->lifetime;
539
540 if (use_ip0) {
541 rc = skiplist_delete(rfd->advertised.ip0_by_ether, &rk, NULL);
542 } else {
543 rc = skiplist_delete(rfd->advertised.ipN_by_prefix, &rk, NULL);
544 }
545 assert(!rc);
546
547 rc = skiplist_delete(rfd->advertised.by_lifetime, adb, NULL);
548 assert(!rc);
549
550 rfapiAdbFree(adb);
551
552 if (rfapiApAdjustLifetimeStats(rfd, &old_lifetime, NULL)) {
553 if (advertise_tunnel)
554 *advertise_tunnel = 1;
555 }
556
557 return 0;
65efcfce 558}