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