-/* $OpenBSD: rde.c,v 1.375 2018/02/05 03:55:54 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.376 2018/02/05 23:29:59 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
if (peer == NULL)
fatal("peer_add");
- LIST_INIT(&peer->path_h);
+ TAILQ_INIT(&peer->path_h);
memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
peer->remote_bgpid = 0;
peer->rib = rib_find(peer->conf.rib);
up_down(peer);
/* walk through per peer RIB list and remove all prefixes. */
- for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = nasp) {
- nasp = LIST_NEXT(asp, peer_l);
+ for (asp = TAILQ_FIRST(&peer->path_h); asp != NULL; asp = nasp) {
+ nasp = TAILQ_NEXT(asp, peer_l);
path_remove(asp);
}
- LIST_INIT(&peer->path_h);
+ TAILQ_INIT(&peer->path_h);
peer->prefix_cnt = 0;
/* Deletions are performed in path_remove() */
rprefixes = 0;
/* walk through per peer RIB list and remove all stale prefixes. */
- for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = nasp) {
- nasp = LIST_NEXT(asp, peer_l);
+ for (asp = TAILQ_FIRST(&peer->path_h); asp != NULL; asp = nasp) {
+ nasp = TAILQ_NEXT(asp, peer_l);
rprefixes += path_remove_stale(asp, aid);
}
-/* $OpenBSD: rde.h,v 1.164 2018/02/05 03:55:54 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.165 2018/02/05 23:29:59 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
* Currently I assume that we can do that with the neighbor_ip...
*/
LIST_HEAD(rde_peer_head, rde_peer);
+LIST_HEAD(aspath_list, aspath);
+LIST_HEAD(attr_list, attr);
+LIST_HEAD(prefix_list, prefix);
+TAILQ_HEAD(prefix_queue, prefix);
LIST_HEAD(aspath_head, rde_aspath);
+TAILQ_HEAD(aspath_queue, rde_aspath);
RB_HEAD(uptree_prefix, update_prefix);
RB_HEAD(uptree_attr, update_attr);
+
struct rib_desc;
struct rib;
RB_HEAD(rib_tree, rib_entry);
struct rde_peer {
LIST_ENTRY(rde_peer) hash_l; /* hash list over all peers */
LIST_ENTRY(rde_peer) peer_l; /* list of all peers */
- struct aspath_head path_h; /* list of all as paths */
+ struct aspath_queue path_h; /* list of all as paths */
struct peer_config conf;
struct bgpd_addr remote_addr;
struct bgpd_addr local_v4_addr;
#define AS_CONFED_SET 4
#define ASPATH_HEADER_SIZE (sizeof(struct aspath) - sizeof(u_char))
-LIST_HEAD(aspath_list, aspath);
-
struct aspath {
LIST_ENTRY(aspath) entry;
int refcnt; /* reference count */
u_int16_t unreach_len;
};
-LIST_HEAD(attr_list, attr);
-
struct path_table {
struct aspath_head *path_hashtbl;
u_int32_t path_hashmask;
};
-LIST_HEAD(prefix_head, prefix);
-
#define F_ATTR_ORIGIN 0x00001
#define F_ATTR_ASPATH 0x00002
#define F_ATTR_NEXTHOP 0x00004
#define DEFAULT_LPREF 100
struct rde_aspath {
- LIST_ENTRY(rde_aspath) path_l, peer_l, nexthop_l;
- struct prefix_head prefix_h;
+ LIST_ENTRY(rde_aspath) path_l, nexthop_l;
+ TAILQ_ENTRY(rde_aspath) peer_l, update_l;
+ struct prefix_queue prefixes, updates;
struct attr **others;
struct rde_peer *peer;
struct aspath *aspath;
struct rib_entry {
RB_ENTRY(rib_entry) rib_e;
- struct prefix_head prefix_h;
+ struct prefix_list prefix_h;
struct prefix *active; /* for fast access */
struct pt_entry *prefix;
struct rib *__rib; /* mangled pointer with flags */
#define RIB_LOC_START 2
struct prefix {
- LIST_ENTRY(prefix) rib_l, path_l;
+ LIST_ENTRY(prefix) rib_l;
+ TAILQ_ENTRY(prefix) path_l;
struct rib_entry *re;
union {
struct rde_aspath *_aspath;
-/* $OpenBSD: rde_rib.c,v 1.156 2018/02/05 03:55:54 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.157 2018/02/05 23:29:59 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
for (hs = 1; hs < hashsize; hs <<= 1)
;
- pathtable.path_hashtbl = calloc(hs, sizeof(struct aspath_head));
+ pathtable.path_hashtbl = calloc(hs, sizeof(struct aspath_queue));
if (pathtable.path_hashtbl == NULL)
fatal("path_init");
path_remove(struct rde_aspath *asp)
{
struct prefix *p, *np;
+ int has_updates;
- for (p = LIST_FIRST(&asp->prefix_h); p != NULL; p = np) {
- np = LIST_NEXT(p, path_l);
+ /*
+ * Must check if we actually have updates before removing prefixes
+ * because if this is the case than the last prefix on prefixes will
+ * free the asp and so the access to updates is a use after free.
+ */
+ has_updates = !TAILQ_EMPTY(&asp->updates);
+
+ for (p = TAILQ_FIRST(&asp->prefixes); p != NULL; p = np) {
+ np = TAILQ_NEXT(p, path_l);
if (asp->pftableid) {
struct bgpd_addr addr;
}
prefix_destroy(p);
}
+ if (has_updates)
+ for (p = TAILQ_FIRST(&asp->updates); p != NULL; p = np) {
+ np = TAILQ_NEXT(p, path_l);
+ /* no need to worry about pftable on Adj-RIB-Out */
+ prefix_destroy(p);
+ }
}
/* remove all stale routes or if staletime is 0 remove all routes for
struct prefix *p, *np;
time_t staletime;
u_int32_t rprefixes;
+ int has_updates;
rprefixes=0;
staletime = asp->peer->staletime[aid];
- for (p = LIST_FIRST(&asp->prefix_h); p != NULL; p = np) {
- np = LIST_NEXT(p, path_l);
+ /*
+ * Same magic as in path_remove() but probably not needed here.
+ * This is called when a session flapped and during that time
+ * the pending updates for that peer are getting reset.
+ */
+ has_updates = !TAILQ_EMPTY(&asp->updates);
+ for (p = TAILQ_FIRST(&asp->prefixes); p != NULL; p = np) {
+ np = TAILQ_NEXT(p, path_l);
if (p->re->prefix->aid != aid)
continue;
prefix_destroy(p);
}
+ if (has_updates)
+ for (p = TAILQ_FIRST(&asp->updates); p != NULL; p = np) {
+ np = TAILQ_NEXT(p, path_l);
+ if (p->re->prefix->aid != aid)
+ continue;
+
+ if (staletime && p->lastchange > staletime)
+ continue;
+
+ /* no need to worry about pftable on Adj-RIB-Out */
+ prefix_destroy(p);
+ }
return (rprefixes);
}
-/* this function is only called by prefix_remove and path_remove */
+/*
+ * This function can only called when all prefix have been removed first.
+ * Normally this happens directly out of the prefix removal functions.
+ */
void
path_destroy(struct rde_aspath *asp)
{
nexthop_unlink(asp);
LIST_REMOVE(asp, path_l);
- LIST_REMOVE(asp, peer_l);
+ TAILQ_REMOVE(&asp->peer->path_h, asp, peer_l);
asp->peer = NULL;
asp->nexthop = NULL;
asp->flags &= ~F_ATTR_LINKED;
int
path_empty(struct rde_aspath *asp)
{
- return LIST_EMPTY(&asp->prefix_h);
+ return TAILQ_EMPTY(&asp->prefixes) && TAILQ_EMPTY(&asp->updates);
}
/*
head = PATH_HASH(asp->aspath);
LIST_INSERT_HEAD(head, asp, path_l);
- LIST_INSERT_HEAD(&peer->path_h, asp, peer_l);
+ TAILQ_INSERT_TAIL(&peer->path_h, asp, peer_l);
asp->peer = peer;
nexthop_link(asp);
asp->flags |= F_ATTR_LINKED;
fatal("path_alloc");
rdemem.path_cnt++;
- LIST_INIT(&asp->prefix_h);
+ TAILQ_INIT(&asp->prefixes);
+ TAILQ_INIT(&asp->updates);
asp->origin = ORIGIN_INCOMPLETE;
asp->lpref = DEFAULT_LPREF;
/* med = 0 */
np->lastchange = time(NULL);
/* add to new as path */
- LIST_INSERT_HEAD(&asp->prefix_h, np, path_l);
+ TAILQ_INSERT_HEAD(&asp->prefixes, np, path_l);
PREFIX_COUNT(asp, 1);
/*
* no need to update the peer prefix count because we are only moving
/* remove old prefix node */
oasp = prefix_aspath(p);
- LIST_REMOVE(p, path_l);
+ TAILQ_REMOVE(&oasp->prefixes, p, path_l);
PREFIX_COUNT(oasp, -1);
/* as before peer count needs no update because of move */
{
struct prefix *p;
- LIST_FOREACH(p, &asp->prefix_h, path_l) {
+ TAILQ_FOREACH(p, &asp->prefixes, path_l) {
/*
- * skip non local-RIBs or RIBs that are flagged as noeval.
+ * Skip non local-RIBs or RIBs that are flagged as noeval.
+ * There is no need to run over updates since that is only
+ * used on the Adj-RIB-Out.
*/
if (re_rib(p->re)->flags & F_RIB_NOEVALUATE)
continue;
struct rde_aspath *asp;
asp = prefix_aspath(p);
+ PREFIX_COUNT(asp, -1);
+
prefix_unlink(p);
prefix_free(p);
struct rde_aspath *asp, *xasp;
struct prefix *p, *xp;
- for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = xasp) {
- xasp = LIST_NEXT(asp, peer_l);
+ for (asp = TAILQ_FIRST(&peer->path_h); asp != NULL; asp = xasp) {
+ xasp = TAILQ_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);
+ for (p = TAILQ_FIRST(&asp->prefixes); p != NULL; p = xp) {
+ xp = TAILQ_NEXT(p, path_l);
if (reloadtime > p->lastchange) {
+ PREFIX_COUNT(asp, -1);
prefix_unlink(p);
prefix_free(p);
}
static void
prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp)
{
- LIST_INSERT_HEAD(&asp->prefix_h, pref, path_l);
+ TAILQ_INSERT_HEAD(&asp->prefixes, pref, path_l);
PREFIX_COUNT(asp, 1);
pref->_p._aspath = asp;
prefix_unlink(struct prefix *pref)
{
struct rib_entry *re = pref->re;
+ struct prefix_queue *pq;
/* make route decision */
LIST_REMOVE(pref, rib_l);
prefix_evaluate(NULL, re);
- LIST_REMOVE(pref, path_l);
- PREFIX_COUNT(prefix_aspath(pref), -1);
+ pq = &prefix_aspath(pref)->prefixes;
+ TAILQ_REMOVE(pq, pref, path_l);
if (rib_empty(re))
rib_remove(re);
pref->re = NULL;
/*
- * It's the caller's duty to remove empty aspath structures.
- * Also freeing the unlinked prefix is the caller's duty.
+ * It's the caller's duty to do accounting and remove empty aspath
+ * structures. Also freeing the unlinked prefix is the caller's duty.
*/
}