back to topotato report
topotato coverage report
Current view: top level - bgpd/rfapi - rfapi_ap.c (source / functions) Hit Total Coverage
Test: test_bgp_minimum_holdtime.py::TestBGPMinimumHoldtime Lines: 0 204 0.0 %
Date: 2023-02-24 18:37:25 Functions: 0 10 0.0 %

          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             : }

Generated by: LCOV version v1.16-topotato