diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-05-17 12:25:16 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-05-17 12:25:16 +0000 |
commit | d0639da8e997204d85f43940c8f7fd5363f5353b (patch) | |
tree | d1034cbc5d45af05eb70883725729e0babb01437 /usr.sbin/bgpd/rde_rib.c | |
parent | a0ffb8889701c4cf39c676b95379748401b916b9 (diff) |
Rework most of the RDE to allow multiple RIBs. This is mostly preparation
work by changing the way the RDE DB is built. struct prefix and struct
pt_entry are simplified and extended with a rib_entry where the decision
tree is run on. From now on a prefix can only reside on one particular RIB
which simplifies the code a bit. Currently there are two fixed ribs
(adj-rib-in and the local-rib) which needs to be made more dynamic in
upcomming commits.
This is work in progress, the RDE seems to work for me and sthen@ (no flames
comming out of our testrouters but there is still a lot missing)
Move into the tree to simplify developement -- henning@
Diffstat (limited to 'usr.sbin/bgpd/rde_rib.c')
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 517 |
1 files changed, 352 insertions, 165 deletions
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c index 299cea252a1..2f651d6f1e3 100644 --- a/usr.sbin/bgpd/rde_rib.c +++ b/usr.sbin/bgpd/rde_rib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_rib.c,v 1.98 2009/04/23 19:23:27 claudio Exp $ */ +/* $OpenBSD: rde_rib.c,v 1.99 2009/05/17 12:25:15 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -33,14 +33,260 @@ * Therefore one thing needs to be absolutely avoided, long table walks. * This is achieved by heavily linking the different parts together. */ +u_int16_t rib_size; +struct rib *ribs; + +struct rib_entry *rib_add(struct rib *, struct bgpd_addr *, int); +int rib_compare(const struct rib_entry *, const struct rib_entry *); +void rib_remove(struct rib_entry *); +int rib_empty(struct rib_entry *); +struct rib_entry *rib_restart(struct rib_context *); + +RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare); +RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare); + + +/* RIB specific functions */ +void +rib_init(void) +{ + if ((ribs = calloc(1, sizeof(struct rib))) == NULL) + fatal("rib_init"); + rib_new("DEFAULT"); +} + +u_int16_t +rib_new(char *name) +{ + struct rib *xribs; + size_t newsize; + u_int16_t id; + + id = rib_name2id(name); + + if (id >= rib_size) { + newsize = sizeof(struct rib) * (id + 1); + if ((xribs = realloc(ribs, newsize)) == NULL) { + /* XXX this is not clever */ + fatal("rib_add"); + } + ribs = xribs; + rib_size = id + 1; + } + + bzero(&ribs[id], sizeof(struct rib)); + strlcpy(ribs[id].name, name, sizeof(ribs[id].name)); + RB_INIT(&ribs[id].rib); + ribs[id].state = RIB_ACTIVE; + ribs[id].id = id; + + return (id); +} + +void +rib_free(struct rib *rib) +{ + /* XXX */ + //bzero(rib, sizeof(struct rib)); +} + +int +rib_compare(const struct rib_entry *a, const struct rib_entry *b) +{ + return (pt_prefix_cmp(a->prefix, b->prefix)); +} + +struct rib_entry * +rib_get(struct rib *rib, struct bgpd_addr *prefix, int prefixlen) +{ + struct rib_entry xre; + struct pt_entry *pte; + + pte = pt_fill(prefix, prefixlen); + bzero(&xre, sizeof(xre)); + xre.prefix = pte; + + return (RB_FIND(rib_tree, &rib->rib, &xre)); +} + +struct rib_entry * +rib_lookup(struct rib *rib, struct bgpd_addr *addr) +{ + struct rib_entry *re; + int i; + + switch (addr->af) { + case AF_INET: + for (i = 32; i >= 0; i--) { + re = rib_get(rib, addr, i); + if (re != NULL) + return (re); + } + break; + case AF_INET6: + for (i = 128; i >= 0; i--) { + re = rib_get(rib, addr, i); + if (re != NULL) + return (re); + } + break; + default: + fatalx("rib_lookup: unknown af"); + } + return (NULL); +} + + +struct rib_entry * +rib_add(struct rib *rib, struct bgpd_addr *prefix, int prefixlen) +{ + struct pt_entry *pte; + struct rib_entry *re; + + pte = pt_get(prefix, prefixlen); + if (pte == NULL) + pte = pt_add(prefix, prefixlen); + + if ((re = calloc(1, sizeof(*re))) == NULL) + fatal("rib_add"); + + LIST_INIT(&re->prefix_h); + re->prefix = pte; + re->rib = rib; + + if (RB_INSERT(rib_tree, &rib->rib, re) != NULL) { + log_warnx("rib_add: insert failed"); + return (NULL); + } + + pt_ref(pte); + + rdemem.rib_cnt++; + + return (re); +} + +void +rib_remove(struct rib_entry *re) +{ + if (!rib_empty(re)) + fatalx("rib_remove: entry not empty"); + + pt_unref(re->prefix); + if (pt_empty(re->prefix)) + pt_remove(re->prefix); + + if (RB_REMOVE(rib_tree, &re->rib->rib, re) == NULL) + log_warnx("rib_remove: remove failed."); + + free(re); + rdemem.rib_cnt--; +} + +int +rib_empty(struct rib_entry *re) +{ + return LIST_EMPTY(&re->prefix_h); +} + +void +rib_dump(struct rib *rib, void (*upcall)(struct rib_entry *, void *), + void *arg, sa_family_t af) +{ + struct rib_context ctx; + + bzero(&ctx, sizeof(ctx)); + ctx.ctx_rib = rib; + ctx.ctx_upcall = upcall; + ctx.ctx_arg = arg; + ctx.ctx_af = af; + rib_dump_r(&ctx); +} + +void +rib_dump_r(struct rib_context *ctx) +{ + struct rib_entry *re; + unsigned int i; + + if (ctx->ctx_p == NULL) { + re = RB_MIN(rib_tree, &ctx->ctx_rib->rib); + LIST_INSERT_HEAD(&ctx->ctx_rib->ctxts, ctx, entry); + } else + re = rib_restart(ctx); + + for (i = 0; re != NULL; re = RB_NEXT(rib_tree, unused, re)) { + if (ctx->ctx_count && i++ >= ctx->ctx_count) { + /* store next start point */ + ctx->ctx_p = re->prefix; + pt_ref(ctx->ctx_p); + return; + } + ctx->ctx_upcall(re, ctx->ctx_arg); + } + + LIST_REMOVE(ctx, entry); + if (ctx->ctx_done) + ctx->ctx_done(ctx->ctx_arg); +} + +struct rib_entry * +rib_restart(struct rib_context *ctx) +{ + struct rib_entry *tmp, *prev = NULL; + int comp; + + /* first unref the pt_entry and check if the table is still around */ + pt_unref(ctx->ctx_p); + if (pt_empty(ctx->ctx_p)) + pt_remove(ctx->ctx_p); + + if (ctx->ctx_rib == NULL) + return NULL; + + /* then try to find the element */ + tmp = RB_ROOT(&ctx->ctx_rib->rib); + while (tmp) { + prev = tmp; + comp = pt_prefix_cmp(ctx->ctx_p, tmp->prefix); + if (comp < 0) + tmp = RB_LEFT(tmp, rib_e); + else if (comp > 0) + tmp = RB_RIGHT(tmp, rib_e); + else + return (tmp); + } + + /* no match, empty tree */ + if (prev == NULL) + return (NULL); + + /* + * no perfect match + * if last element was bigger use that as new start point + */ + if (comp < 0) + return (prev); + + /* backtrack until parent is bigger */ + do { + prev = RB_PARENT(prev, rib_e); + if (prev == NULL) + /* all elements in the tree are smaler */ + return (NULL); + comp = pt_prefix_cmp(ctx->ctx_p, prev->prefix); + } while (comp > 0); + + return (prev); +} /* used to bump correct prefix counters */ -#define PREFIX_COUNT(x, f, op) \ +#define PREFIX_COUNT(x, id, op) \ do { \ - if (f & F_LOCAL) \ + if (id == 1) \ (x)->prefix_cnt += (op); \ - if (f & F_ORIGINAL) \ - (x)->adjrib_cnt += (op); \ + else \ + (x)->rib_cnt += (op); \ } while (0) /* path specific functions */ @@ -84,61 +330,31 @@ path_shutdown(void) } void -path_update(struct rde_peer *peer, struct rde_aspath *nasp, - struct bgpd_addr *prefix, int prefixlen, u_int32_t flags) +path_update(struct rib *rib, struct rde_peer *peer, struct rde_aspath *nasp, + struct bgpd_addr *prefix, int prefixlen) { struct rde_aspath *asp; - struct prefix *p, *oldp = NULL; + struct prefix *p; +#if 0 + /* XXX NEEDS SOMETHING BETTER HERE */ if (flags & F_LOCAL) { rde_send_pftable(nasp->pftableid, prefix, prefixlen, 0); rde_send_pftable_commit(); } +#endif /* - * First try to find a prefix in the specified RIB or in the - * Adj-RIB-In. This works because Local-RIB has precedence over the - * Adj-RIB-In. In the end this saves use some additional lookups. + * First try to find a prefix in the specified RIB. */ - if ((p = prefix_get(peer, prefix, prefixlen, flags | F_ORIGINAL)) != - NULL) { - do { - if (path_compare(nasp, p->aspath) == 0) { - if ((p->flags & flags & F_RIB_MASK) == 0) { - if (oldp != NULL) { - asp = oldp->aspath; - prefix_destroy(oldp); - if (path_empty(asp)) - path_destroy(asp); - } - p->flags |= flags & F_RIB_MASK; - PREFIX_COUNT(p->aspath, flags, 1); - PREFIX_COUNT(peer, flags, 1); - - /* re-evaluate prefix */ - LIST_REMOVE(p, prefix_l); - prefix_evaluate(p, p->prefix); - } - /* update last change */ - p->lastchange = time(NULL); - return; - } - /* - * If the prefix is not already part of the Adj-RIB-In - * do a lookup in there. But keep the original prefix - * around so that it can be removed later. - */ - if (p->flags & F_ORIGINAL) - break; - oldp = p; - p = prefix_get(peer, prefix, prefixlen, F_ORIGINAL); - } while (p != NULL); + if ((p = prefix_get(rib, peer, prefix, prefixlen, 0)) != NULL) { + if (path_compare(nasp, p->aspath) == 0) { + /* no change, update last change */ + p->lastchange = time(NULL); + return; + } } - /* Do not try to move a prefix that is in the wrong RIB. */ - if (p == NULL || (p->flags & flags & F_RIB_MASK) == 0) - p = oldp; - /* * Either the prefix does not exist or the path changed. * In both cases lookup the new aspath to make sure it is not @@ -152,9 +368,9 @@ path_update(struct rde_peer *peer, struct rde_aspath *nasp, /* If the prefix was found move it else add it to the aspath. */ if (p != NULL) - prefix_move(asp, p, flags); + prefix_move(asp, p); else - prefix_add(asp, prefix, prefixlen, flags); + prefix_add(rib, asp, prefix, prefixlen); } int @@ -221,14 +437,18 @@ void path_remove(struct rde_aspath *asp) { struct prefix *p; - struct bgpd_addr addr; while ((p = LIST_FIRST(&asp->prefix_h)) != NULL) { +#if 0 /* Commit is done in peer_down() */ + /* XXX AGAIN NEEDS A BETTER SOLUTION */ + struct bgpd_addr addr; + pt_getaddr(p->prefix, &addr); if (p->flags & F_LOCAL) rde_send_pftable(p->aspath->pftableid, &addr, p->prefix->prefixlen, 1); +#endif prefix_destroy(p); } @@ -241,7 +461,7 @@ path_destroy(struct rde_aspath *asp) { /* path_destroy can only unlink and free empty rde_aspath */ if (asp->prefix_cnt != 0 || asp->active_cnt != 0 || - asp->adjrib_cnt != 0) + asp->rib_cnt != 0) log_warnx("path_destroy: prefix count out of sync"); nexthop_unlink(asp); @@ -354,8 +574,8 @@ path_put(struct rde_aspath *asp) static struct prefix *prefix_alloc(void); static void prefix_free(struct prefix *); -static void prefix_link(struct prefix *, struct pt_entry *, - struct rde_aspath *, u_int32_t); +static void prefix_link(struct prefix *, struct rib_entry *, + struct rde_aspath *); static void prefix_unlink(struct prefix *); int @@ -404,51 +624,51 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, * search for specified prefix of a peer. Returns NULL if not found. */ struct prefix * -prefix_get(struct rde_peer *peer, struct bgpd_addr *prefix, int prefixlen, - u_int32_t flags) +prefix_get(struct rib *rib, struct rde_peer *peer, struct bgpd_addr *prefix, + int prefixlen, u_int32_t flags) { - struct pt_entry *pte; + struct rib_entry *re; - pte = pt_get(prefix, prefixlen); - if (pte == NULL) + re = rib_get(rib, prefix, prefixlen); + if (re == NULL) return (NULL); - return (prefix_bypeer(pte, peer, flags)); + return (prefix_bypeer(re, peer, flags)); } /* * Adds or updates a prefix. */ -struct pt_entry * -prefix_add(struct rde_aspath *asp, struct bgpd_addr *prefix, int prefixlen, - u_int32_t flags) +void +prefix_add(struct rib *rib, struct rde_aspath *asp, struct bgpd_addr *prefix, + int prefixlen) { - struct prefix *p; - struct pt_entry *pte; + struct prefix *p; + struct rib_entry *re; - pte = pt_get(prefix, prefixlen); - if (pte == NULL) - pte = pt_add(prefix, prefixlen); + re = rib_get(rib, prefix, prefixlen); + if (re == NULL) + re = rib_add(rib, prefix, prefixlen); - p = prefix_bypeer(pte, asp->peer, flags); + p = prefix_bypeer(re, asp->peer, asp->flags); if (p == NULL) { p = prefix_alloc(); - prefix_link(p, pte, asp, flags); + prefix_link(p, re, asp); } else { - if (p->aspath != asp) + if (p->aspath != asp) { /* prefix belongs to a different aspath so move */ - return (prefix_move(asp, p, flags)); + prefix_move(asp, p); + return; + } p->lastchange = time(NULL); } - - return (pte); } /* * Move the prefix to the specified as path, removes the old asp if needed. */ -struct pt_entry * -prefix_move(struct rde_aspath *asp, struct prefix *p, u_int32_t flags) +void +prefix_move(struct rde_aspath *asp, struct prefix *p) { struct prefix *np; struct rde_aspath *oasp; @@ -461,45 +681,18 @@ prefix_move(struct rde_aspath *asp, struct prefix *p, u_int32_t flags) np->aspath = asp; /* peer and prefix pointers are still equal */ np->prefix = p->prefix; + np->rib = p->rib; np->lastchange = time(NULL); - np->flags = flags; /* add to new as path */ LIST_INSERT_HEAD(&asp->prefix_h, np, path_l); - PREFIX_COUNT(asp, flags, 1); + PREFIX_COUNT(asp, p->rib->rib->id, 1); /* * no need to update the peer prefix count because we are only moving * the prefix without changing the peer. */ /* - * fiddle around with the flags. If the p->flags is not equal - * to flags the old prefix p may not be removed but instead p->flags - * needs to be adjusted. - */ - if ((p->flags & F_RIB_MASK) != (flags & F_RIB_MASK)) { - if ((p->flags & flags & F_RIB_MASK) == 0) - fatalx("prefix_move: " - "prefix is not part of desired RIB"); - - p->flags &= ~(flags & F_RIB_MASK); - PREFIX_COUNT(p->aspath, flags, -1); - /* as before peer count needs no update because of move */ - - /* redo the route decision for p */ - LIST_REMOVE(p, prefix_l); - /* If the prefix is the active one remove it first. */ - if (p == p->prefix->active) - prefix_evaluate(NULL, p->prefix); - prefix_evaluate(p, p->prefix); - - /* and now for np */ - prefix_evaluate(np, np->prefix); - - return (np->prefix); - } - - /* * First kick the old prefix node out of the prefix list, * afterwards run the route decision for new prefix node. * Because of this only one update is generated if the prefix @@ -507,25 +700,24 @@ prefix_move(struct rde_aspath *asp, struct prefix *p, u_int32_t flags) * This is save because we create a new prefix and so the change * is noticed by prefix_evaluate(). */ - LIST_REMOVE(p, prefix_l); - prefix_evaluate(np, np->prefix); + LIST_REMOVE(p, rib_l); + prefix_evaluate(np, np->rib); /* remove old prefix node */ oasp = p->aspath; LIST_REMOVE(p, path_l); - PREFIX_COUNT(oasp, flags, -1); + PREFIX_COUNT(oasp, p->rib->rib->id, -1); /* as before peer count needs no update because of move */ /* destroy all references to other objects and free the old prefix */ p->aspath = NULL; p->prefix = NULL; + p->rib = NULL; prefix_free(p); /* destroy old path if empty */ if (path_empty(oasp)) path_destroy(oasp); - - return (np->prefix); } /* @@ -533,50 +725,37 @@ prefix_move(struct rde_aspath *asp, struct prefix *p, u_int32_t flags) * pt_entry -- become empty remove them too. */ void -prefix_remove(struct rde_peer *peer, struct bgpd_addr *prefix, int prefixlen, - u_int32_t flags) +prefix_remove(struct rib *rib, struct rde_peer *peer, struct bgpd_addr *prefix, + int prefixlen, u_int32_t flags) { struct prefix *p; - struct pt_entry *pte; + struct rib_entry *re; struct rde_aspath *asp; - pte = pt_get(prefix, prefixlen); - if (pte == NULL) /* Got a dummy withdrawn request */ + re = rib_get(rib, prefix, prefixlen); + if (re == NULL) /* Got a dummy withdrawn request */ return; - p = prefix_bypeer(pte, peer, flags); + p = prefix_bypeer(re, peer, flags); if (p == NULL) /* Got a dummy withdrawn request. */ return; asp = p->aspath; +#if 0 + /* XXX AGAIN THIS NEEDS A BETTER SOLUTION */ if (p->flags & F_LOCAL) { /* only prefixes in the local RIB were pushed into pf */ rde_send_pftable(asp->pftableid, prefix, prefixlen, 1); rde_send_pftable_commit(); } - - /* if prefix belongs to more than one RIB just remove one instance */ - if ((p->flags & F_RIB_MASK) != (flags & F_RIB_MASK)) { - p->flags &= ~(flags & F_RIB_MASK); - - PREFIX_COUNT(p->aspath, flags, -1); - PREFIX_COUNT(peer, flags, -1); - - /* redo the route decision for p */ - LIST_REMOVE(p, prefix_l); - /* If the prefix is the active one remove it first. */ - if (p == p->prefix->active) - prefix_evaluate(NULL, p->prefix); - prefix_evaluate(p, p->prefix); - return; - } +#endif prefix_unlink(p); prefix_free(p); - if (pt_empty(pte)) - pt_remove(pte); + if (rib_empty(re)) + rib_remove(re); if (path_empty(asp)) path_destroy(asp); } @@ -604,22 +783,23 @@ prefix_write(u_char *buf, int len, struct bgpd_addr *prefix, u_int8_t plen) * belonging to the peer peer. Returns NULL if no match found. */ struct prefix * -prefix_bypeer(struct pt_entry *pte, struct rde_peer *peer, u_int32_t flags) +prefix_bypeer(struct rib_entry *re, struct rde_peer *peer, u_int32_t flags) { struct prefix *p; - LIST_FOREACH(p, &pte->prefix_h, prefix_l) { - if (p->aspath->peer != peer || - (p->flags & flags & F_RIB_MASK) == 0) + LIST_FOREACH(p, &re->prefix_h, rib_l) { + if (p->aspath->peer != peer) continue; - if (flags & F_PREFIX_ANNOUNCED && - (flags & F_ANN_DYNAMIC) != (p->flags & F_ANN_DYNAMIC)) + if (p->aspath->flags & flags && + (flags & F_ANN_DYNAMIC) != + (p->aspath->flags & F_ANN_DYNAMIC)) continue; return (p); } return (NULL); } +/* XXX this completely wrong somewhat */ void prefix_updateall(struct rde_aspath *asp, enum nexthop_state state, enum nexthop_state oldstate) @@ -632,11 +812,10 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state, LIST_FOREACH(p, &asp->prefix_h, path_l) { /* + * XXX THIS IS MISSING AT THE MOMENT * skip non local-RIB nodes, only local-RIB prefixes are * eligible. Both F_LOCAL and F_ORIGINAL may be set. */ - if (!(p->flags & F_LOCAL)) - continue; if (oldstate == state && state == NEXTHOP_REACH) { /* @@ -645,13 +824,13 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state, * or other internal infos. This will not change * the routing decision so shortcut here. */ - if (p == p->prefix->active) + if (p == p->rib->active) rde_send_kroute(p, NULL); continue; } /* redo the route decision */ - LIST_REMOVE(p, prefix_l); + LIST_REMOVE(p, rib_l); /* * If the prefix is the active one remove it first, * this has to be done because we can not detect when @@ -660,9 +839,9 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state, * prefix_evaluate() will generate no update because * the nexthop is unreachable or ineligible. */ - if (p == p->prefix->active) - prefix_evaluate(NULL, p->prefix); - prefix_evaluate(p, p->prefix); + if (p == p->rib->active) + prefix_evaluate(NULL, p->rib); + prefix_evaluate(p, p->rib); } } @@ -670,14 +849,14 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state, void prefix_destroy(struct prefix *p) { - struct pt_entry *pte; + struct rib_entry *re; - pte = p->prefix; + re = p->rib; prefix_unlink(p); prefix_free(p); - if (pt_empty(pte)) - pt_remove(pte); + if (rib_empty(re)) + rib_remove(re); } /* @@ -692,10 +871,11 @@ prefix_network_clean(struct rde_peer *peer, time_t reloadtime, u_int32_t flags) for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = xasp) { xasp = LIST_NEXT(asp, peer_l); + if ((asp->flags & F_ANN_DYNAMIC) == flags) + continue; for (p = LIST_FIRST(&asp->prefix_h); p != NULL; p = xp) { xp = LIST_NEXT(p, path_l); - if (reloadtime > p->lastchange && - (p->flags & F_ANN_DYNAMIC) == flags) { + if (reloadtime > p->lastchange) { pte = p->prefix; prefix_unlink(p); prefix_free(p); @@ -713,20 +893,20 @@ prefix_network_clean(struct rde_peer *peer, time_t reloadtime, u_int32_t flags) * Link a prefix into the different parent objects. */ static void -prefix_link(struct prefix *pref, struct pt_entry *pte, struct rde_aspath *asp, - u_int32_t flags) +prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp) { LIST_INSERT_HEAD(&asp->prefix_h, pref, path_l); - PREFIX_COUNT(asp, flags, 1); - PREFIX_COUNT(asp->peer, flags, 1); + PREFIX_COUNT(asp, re->rib->id, 1); + PREFIX_COUNT(asp->peer, re->rib->id, 1); pref->aspath = asp; - pref->prefix = pte; + pref->rib = re; + pref->prefix = re->prefix; + pt_ref(pref->prefix); pref->lastchange = time(NULL); - pref->flags = flags; /* make route decision */ - prefix_evaluate(pref, pte); + prefix_evaluate(pref, re); } /* @@ -735,17 +915,24 @@ prefix_link(struct prefix *pref, struct pt_entry *pte, struct rde_aspath *asp, static void prefix_unlink(struct prefix *pref) { - /* make route decision */ - LIST_REMOVE(pref, prefix_l); - prefix_evaluate(NULL, pref->prefix); + if (pref->rib) { + /* make route decision */ + LIST_REMOVE(pref, rib_l); + prefix_evaluate(NULL, pref->rib); + } LIST_REMOVE(pref, path_l); - PREFIX_COUNT(pref->aspath, pref->flags, -1); - PREFIX_COUNT(pref->aspath->peer, pref->flags, -1); + PREFIX_COUNT(pref->aspath, pref->rib->rib->id, -1); + PREFIX_COUNT(pref->aspath->peer, pref->rib->rib->id, -1); + + pt_unref(pref->prefix); + if (pt_empty(pref->prefix)) + pt_remove(pref->prefix); /* destroy all references to other objects */ pref->aspath = NULL; pref->prefix = NULL; + pref->rib = NULL; /* * It's the caller's duty to remove empty aspath respectively pt_entry |