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