]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/rfapi/rfapi_ap.c
Merge pull request #6079 from sarav511/regstop_exp
[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 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 static int sl_adb_lifetime_cmp(const void *adb1, const void *adb2)
85 {
86 const struct rfapi_adb *a1 = adb1;
87 const struct rfapi_adb *a2 = adb2;
88
89 if (a1->lifetime < a2->lifetime)
90 return -1;
91 if (a1->lifetime > a2->lifetime)
92 return 1;
93
94 if (a1 < a2)
95 return -1;
96 if (a1 > a2)
97 return 1;
98
99 return 0;
100 }
101
102 void rfapiApInit(struct rfapi_advertised_prefixes *ap)
103 {
104 ap->ipN_by_prefix = skiplist_new(0, rfapi_rib_key_cmp, NULL);
105 ap->ip0_by_ether = skiplist_new(0, rfapi_rib_key_cmp, NULL);
106 ap->by_lifetime = skiplist_new(0, sl_adb_lifetime_cmp, NULL);
107 }
108
109 void rfapiApRelease(struct rfapi_advertised_prefixes *ap)
110 {
111 struct rfapi_adb *adb;
112
113 /* Free ADBs and lifetime items */
114 while (0 == skiplist_first(ap->by_lifetime, NULL, (void **)&adb)) {
115 rfapiAdbFree(adb);
116 skiplist_delete_first(ap->by_lifetime);
117 }
118
119 while (0 == skiplist_delete_first(ap->ipN_by_prefix))
120 ;
121 while (0 == skiplist_delete_first(ap->ip0_by_ether))
122 ;
123
124 /* Free lists */
125 skiplist_free(ap->ipN_by_prefix);
126 skiplist_free(ap->ip0_by_ether);
127 skiplist_free(ap->by_lifetime);
128
129 ap->ipN_by_prefix = NULL;
130 ap->ip0_by_ether = NULL;
131 ap->by_lifetime = NULL;
132 }
133
134 int rfapiApCount(struct rfapi_descriptor *rfd)
135 {
136 if (!rfd->advertised.by_lifetime)
137 return 0;
138
139 return skiplist_count(rfd->advertised.by_lifetime);
140 }
141
142 int rfapiApCountAll(struct bgp *bgp)
143 {
144 struct rfapi *h;
145 struct listnode *node;
146 struct rfapi_descriptor *rfd;
147 int total = 0;
148
149 h = bgp->rfapi;
150 if (h) {
151 for (ALL_LIST_ELEMENTS_RO(&h->descriptors, node, rfd)) {
152 total += rfapiApCount(rfd);
153 }
154 }
155 return total;
156 }
157
158
159 void rfapiApReadvertiseAll(struct bgp *bgp, struct rfapi_descriptor *rfd)
160 {
161 struct rfapi_adb *adb;
162 void *cursor = NULL;
163 int rc;
164
165 for (rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
166 (void **)&adb, &cursor);
167 rc == 0; rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
168 (void **)&adb, &cursor)) {
169
170 struct prefix_rd prd;
171 uint32_t local_pref = rfp_cost_to_localpref(adb->cost);
172
173 prd = rfd->rd;
174 prd.family = AF_UNSPEC;
175 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 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 &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 }
191
192 void rfapiApWithdrawAll(struct bgp *bgp, struct rfapi_descriptor *rfd)
193 {
194 struct rfapi_adb *adb;
195 void *cursor;
196 int rc;
197
198
199 cursor = NULL;
200 for (rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
201 (void **)&adb, &cursor);
202 rc == 0; rc = skiplist_next(rfd->advertised.by_lifetime, NULL,
203 (void **)&adb, &cursor)) {
204
205 struct prefix pfx_vn_buf;
206 struct prefix *pfx_ip;
207
208 if (!(RFAPI_0_PREFIX(&adb->u.s.prefix_ip)
209 && RFAPI_HOST_PREFIX(&adb->u.s.prefix_ip))) {
210
211 pfx_ip = &adb->u.s.prefix_ip;
212
213 } else {
214
215 pfx_ip = NULL;
216
217 /*
218 * 0/32 or 0/128 => mac advertisement
219 */
220 if (rfapiRaddr2Qprefix(&rfd->vn_addr, &pfx_vn_buf)) {
221 /*
222 * Bad: it means we can't delete the route
223 */
224 vnc_zlog_debug_verbose(
225 "%s: BAD: handle has bad vn_addr: skipping",
226 __func__);
227 continue;
228 }
229 }
230
231 del_vnc_route(rfd, rfd->peer, bgp, SAFI_MPLS_VPN,
232 pfx_ip ? pfx_ip : &pfx_vn_buf,
233 &adb->u.s.prd, /* RD to use (0 for ENCAP) */
234 ZEBRA_ROUTE_BGP, BGP_ROUTE_RFP, NULL, 0);
235 }
236 }
237
238 /*
239 * returns nonzero if tunnel readvertisement is needed, 0 otherwise
240 */
241 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 int advertise = 0;
247 int find_max = 0;
248 int find_min = 0;
249
250 vnc_zlog_debug_verbose("%s: rfd=%p, pOldLife=%p, pNewLife=%p", __func__,
251 rfd, old_lifetime, new_lifetime);
252 if (old_lifetime)
253 vnc_zlog_debug_verbose("%s: OldLife=%d", __func__,
254 *old_lifetime);
255 if (new_lifetime)
256 vnc_zlog_debug_verbose("%s: NewLife=%d", __func__,
257 *new_lifetime);
258
259 if (new_lifetime) {
260 /*
261 * Adding new lifetime
262 */
263 if (old_lifetime) {
264 /*
265 * replacing existing lifetime
266 */
267
268
269 /* old and new are same */
270 if (*old_lifetime == *new_lifetime)
271 return 0;
272
273 if (*old_lifetime == rfd->min_prefix_lifetime) {
274 find_min = 1;
275 }
276 if (*old_lifetime == rfd->max_prefix_lifetime) {
277 find_max = 1;
278 }
279
280 /* no need to search if new value is at or equals
281 * min|max */
282 if (*new_lifetime <= rfd->min_prefix_lifetime) {
283 rfd->min_prefix_lifetime = *new_lifetime;
284 find_min = 0;
285 }
286 if (*new_lifetime >= rfd->max_prefix_lifetime) {
287 rfd->max_prefix_lifetime = *new_lifetime;
288 advertise = 1;
289 find_max = 0;
290 }
291
292 } else {
293 /*
294 * Just adding new lifetime
295 */
296 if (*new_lifetime < rfd->min_prefix_lifetime) {
297 rfd->min_prefix_lifetime = *new_lifetime;
298 }
299 if (*new_lifetime > rfd->max_prefix_lifetime) {
300 advertise = 1;
301 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 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 if (!rfapiApCount(rfd)) {
330 rfd->max_prefix_lifetime = 0;
331 rfd->min_prefix_lifetime = UINT32_MAX;
332 }
333
334
335 } else {
336 if (old_lifetime) {
337 if (*old_lifetime == rfd->min_prefix_lifetime) {
338 find_min = 1;
339 }
340 if (*old_lifetime == rfd->max_prefix_lifetime) {
341 find_max = 1;
342 }
343 }
344 }
345 }
346
347 if (find_min || find_max) {
348 uint32_t min = UINT32_MAX;
349 uint32_t max = 0;
350
351 struct rfapi_adb *adb_min;
352 struct rfapi_adb *adb_max;
353
354 if (!skiplist_first(rfd->advertised.by_lifetime,
355 (void **)&adb_min, NULL)
356 && !skiplist_last(rfd->advertised.by_lifetime,
357 (void **)&adb_max, NULL)) {
358
359 /*
360 * This should always work
361 */
362 min = adb_min->lifetime;
363 max = adb_max->lifetime;
364
365 } else {
366
367 void *cursor;
368 struct rfapi_rib_key rk;
369 struct rfapi_adb *adb;
370 int rc;
371
372 vnc_zlog_debug_verbose(
373 "%s: walking to find new min/max", __func__);
374
375 cursor = NULL;
376 for (rc = skiplist_next(rfd->advertised.ipN_by_prefix,
377 (void **)&rk, (void **)&adb,
378 &cursor);
379 !rc;
380 rc = skiplist_next(rfd->advertised.ipN_by_prefix,
381 (void **)&rk, (void **)&adb,
382 &cursor)) {
383
384 uint32_t lt = adb->lifetime;
385
386 if (lt > max)
387 max = lt;
388 if (lt < min)
389 min = lt;
390 }
391 cursor = NULL;
392 for (rc = skiplist_next(rfd->advertised.ip0_by_ether,
393 (void **)&rk, (void **)&adb,
394 &cursor);
395 !rc;
396 rc = skiplist_next(rfd->advertised.ip0_by_ether,
397 (void **)&rk, (void **)&adb,
398 &cursor)) {
399
400 uint32_t lt = adb->lifetime;
401
402 if (lt > max)
403 max = lt;
404 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 if (max && rfd->max_prefix_lifetime != max)
415 advertise = 1;
416 rfd->max_prefix_lifetime = max;
417 rfd->min_prefix_lifetime = min;
418 }
419
420 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 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 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 int rc;
439 struct rfapi_adb *adb;
440 uint32_t old_lifetime = 0;
441 int use_ip0 = 0;
442 struct rfapi_rib_key rk;
443
444 rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
445 if (RFAPI_0_PREFIX(pfx_ip) && RFAPI_HOST_PREFIX(pfx_ip)) {
446 use_ip0 = 1;
447 assert(pfx_eth);
448 rc = skiplist_search(rfd->advertised.ip0_by_ether, &rk,
449 (void **)&adb);
450
451 } else {
452
453 /* find prefix in advertised prefixes list */
454 rc = skiplist_search(rfd->advertised.ipN_by_prefix, &rk,
455 (void **)&adb);
456 }
457
458
459 if (rc) {
460 /* Not found */
461 adb = XCALLOC(MTYPE_RFAPI_ADB, sizeof(struct rfapi_adb));
462 assert(adb);
463 adb->lifetime = lifetime;
464 adb->u.key = rk;
465
466 if (use_ip0) {
467 assert(pfx_eth);
468 skiplist_insert(rfd->advertised.ip0_by_ether,
469 &adb->u.key, adb);
470 } else {
471 skiplist_insert(rfd->advertised.ipN_by_prefix,
472 &adb->u.key, adb);
473 }
474
475 skiplist_insert(rfd->advertised.by_lifetime, adb, adb);
476 } else {
477 old_lifetime = adb->lifetime;
478 if (old_lifetime != lifetime) {
479 assert(!skiplist_delete(rfd->advertised.by_lifetime,
480 adb, NULL));
481 adb->lifetime = lifetime;
482 assert(!skiplist_insert(rfd->advertised.by_lifetime,
483 adb, adb));
484 }
485 }
486 adb->cost = cost;
487 if (l2o)
488 adb->l2o = *l2o;
489 else
490 memset(&adb->l2o, 0, sizeof(struct rfapi_l2address_option));
491
492 if (rfapiApAdjustLifetimeStats(rfd, (rc ? NULL : &old_lifetime),
493 &lifetime))
494 return 1;
495
496 return 0;
497 }
498
499 /*
500 * After this function returns successfully, caller should call
501 * rfapiAdjustLifetimeStats() and possibly rfapiTunnelRouteAnnounce()
502 */
503 int rfapiApDelete(struct bgp *bgp, struct rfapi_descriptor *rfd,
504 struct prefix *pfx_ip, struct prefix *pfx_eth,
505 struct prefix_rd *prd, int *advertise_tunnel) /* out */
506 {
507 int rc;
508 struct rfapi_adb *adb;
509 uint32_t old_lifetime;
510 int use_ip0 = 0;
511 struct rfapi_rib_key rk;
512
513 if (advertise_tunnel)
514 *advertise_tunnel = 0;
515
516 rfapi_rib_key_init(pfx_ip, prd, pfx_eth, &rk);
517 /* find prefix in advertised prefixes list */
518 if (RFAPI_0_PREFIX(pfx_ip) && RFAPI_HOST_PREFIX(pfx_ip)) {
519 use_ip0 = 1;
520 assert(pfx_eth);
521
522 rc = skiplist_search(rfd->advertised.ip0_by_ether, &rk,
523 (void **)&adb);
524
525 } else {
526
527 /* find prefix in advertised prefixes list */
528 rc = skiplist_search(rfd->advertised.ipN_by_prefix, &rk,
529 (void **)&adb);
530 }
531
532 if (rc) {
533 return ENOENT;
534 }
535
536 old_lifetime = adb->lifetime;
537
538 if (use_ip0) {
539 rc = skiplist_delete(rfd->advertised.ip0_by_ether, &rk, NULL);
540 } else {
541 rc = skiplist_delete(rfd->advertised.ipN_by_prefix, &rk, NULL);
542 }
543 assert(!rc);
544
545 rc = skiplist_delete(rfd->advertised.by_lifetime, adb, NULL);
546 assert(!rc);
547
548 rfapiAdbFree(adb);
549
550 if (rfapiApAdjustLifetimeStats(rfd, &old_lifetime, NULL)) {
551 if (advertise_tunnel)
552 *advertise_tunnel = 1;
553 }
554
555 return 0;
556 }