-/* $OpenBSD: rde.c,v 1.376 2018/02/05 23:29:59 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.377 2018/02/07 00:02:02 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
peer->prefix_rcvd_update++;
/* add original path to the Adj-RIB-In */
- if (path_update(&ribs[RIB_ADJ_IN].rib, peer, asp, prefix, prefixlen))
+ if (path_update(&ribs[RIB_ADJ_IN].rib, peer, asp, prefix, prefixlen, 0))
peer->prefix_cnt++;
for (i = RIB_LOC_START; i < rib_size; i++) {
rde_update_log("update", i, peer,
&fasp->nexthop->exit_nexthop, prefix, prefixlen);
path_update(&ribs[i].rib, peer, fasp, prefix,
- prefixlen);
+ prefixlen, 0);
} else if (prefix_remove(&ribs[i].rib, peer, prefix, prefixlen,
0)) {
rde_update_log("filtered withdraw", i, peer,
if (oa == ACTION_DENY && na == ACTION_ALLOW) {
/* update Local-RIB */
path_update(&rib->rib, peer, nasp, &addr,
- pt->prefixlen);
+ pt->prefixlen, 0);
} else if (oa == ACTION_ALLOW && na == ACTION_DENY) {
/* remove from Local-RIB */
prefix_remove(&rib->rib, peer, &addr, pt->prefixlen, 0);
if (path_compare(nasp, oasp) != 0)
/* send update */
path_update(&rib->rib, peer, nasp, &addr,
- pt->prefixlen);
+ pt->prefixlen, 0);
}
if (oasp != asp)
if (*ribs[i].name == '\0')
break;
path_update(&ribs[i].rib, peerself, asp, &nc->prefix,
- nc->prefixlen);
+ nc->prefixlen, 0);
}
path_put(asp);
filterset_free(&nc->attrset);
-/* $OpenBSD: rde.h,v 1.165 2018/02/05 23:29:59 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.166 2018/02/07 00:02:02 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
#define F_NEXTHOP_BLACKHOLE 0x04000
#define F_NEXTHOP_NOMODIFY 0x08000
#define F_NEXTHOP_MASK 0x0f000
-#define F_ATTR_PARSE_ERR 0x10000
-#define F_ATTR_LINKED 0x20000
+#define F_ATTR_PARSE_ERR 0x10000 /* parse error, not eligable */
+#define F_ATTR_LINKED 0x20000 /* if set path is on various lists */
+#define F_ATTR_UPDATE 0x20000 /* if set linked on update_l */
#define ORIGIN_IGP 0
struct rib_entry *re;
union {
struct rde_aspath *_aspath;
- } _p;
+ } _p;
time_t lastchange;
+ int flags;
};
+#define F_PREFIX_USE_UPDATES 0x01 /* linked onto the updates list */
+
extern struct rde_memstats rdemem;
/* prototypes */
void path_init(u_int32_t);
void path_shutdown(void);
int path_update(struct rib *, struct rde_peer *,
- struct rde_aspath *, struct bgpd_addr *, int);
+ struct rde_aspath *, struct bgpd_addr *, int, int);
int path_compare(struct rde_aspath *, struct rde_aspath *);
-struct rde_aspath *path_lookup(struct rde_aspath *, struct rde_peer *);
void path_remove(struct rde_aspath *);
u_int32_t path_remove_stale(struct rde_aspath *, u_int8_t);
void path_destroy(struct rde_aspath *);
void path_put(struct rde_aspath *);
#define PREFIX_SIZE(x) (((x) + 7) / 8 + 1)
-struct prefix *prefix_get(struct rib *, struct rde_peer *,
- struct bgpd_addr *, int, u_int32_t);
-int prefix_add(struct rib *, struct rde_aspath *,
- struct bgpd_addr *, int);
-void prefix_move(struct rde_aspath *, struct prefix *);
int prefix_remove(struct rib *, struct rde_peer *,
struct bgpd_addr *, int, u_int32_t);
int prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t);
-/* $OpenBSD: rde_rib.c,v 1.157 2018/02/05 23:29:59 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.158 2018/02/07 00:02:02 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare);
RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare);
+struct prefix *prefix_get(struct rib *, struct rde_peer *,
+ struct bgpd_addr *, int, u_int32_t);
+int prefix_add(struct rib *, struct rde_aspath *,
+ struct bgpd_addr *, int, int);
+void prefix_move(struct rde_aspath *, struct prefix *, int);
+
static inline void
re_lock(struct rib_entry *re)
{
/* path specific functions */
+static struct rde_aspath *path_lookup(struct rde_aspath *, struct rde_peer *);
static void path_link(struct rde_aspath *, struct rde_peer *);
struct path_table pathtable;
int
path_update(struct rib *rib, struct rde_peer *peer, struct rde_aspath *nasp,
- struct bgpd_addr *prefix, int prefixlen)
+ struct bgpd_addr *prefix, int prefixlen, int flag)
{
struct rde_aspath *asp;
struct prefix *p;
+ int pflag = 0;
if (nasp->pftableid) {
rde_send_pftable(nasp->pftableid, prefix, prefixlen, 0);
/* If the prefix was found move it else add it to the aspath. */
if (p != NULL)
- prefix_move(asp, p);
+ prefix_move(asp, p, pflag);
else
- return (prefix_add(rib, asp, prefix, prefixlen));
+ return (prefix_add(rib, asp, prefix, prefixlen, pflag));
return (0);
}
{
int r;
- if (a->origin > b->origin)
+ if (a == NULL && b == NULL)
+ return (0);
+ else if (b == NULL)
return (1);
- if (a->origin < b->origin)
+ else if (a == NULL)
return (-1);
- if ((a->flags & ~F_ATTR_LINKED) > (b->flags & ~F_ATTR_LINKED))
+ if ((a->flags & ~(F_ATTR_LINKED | F_ATTR_UPDATE)) >
+ (b->flags & ~(F_ATTR_LINKED | F_ATTR_UPDATE)))
return (1);
- if ((a->flags & ~F_ATTR_LINKED) < (b->flags & ~F_ATTR_LINKED))
+ if ((a->flags & ~(F_ATTR_LINKED | F_ATTR_UPDATE)) <
+ (b->flags & ~(F_ATTR_LINKED | F_ATTR_UPDATE)))
+ return (-1);
+ if (a->origin > b->origin)
+ return (1);
+ if (a->origin < b->origin)
return (-1);
if (a->med > b->med)
return (1);
return (attr_compare(a, b));
}
-struct rde_aspath *
+static struct rde_aspath *
path_lookup(struct rde_aspath *aspath, struct rde_peer *peer)
{
struct aspath_head *head;
nasp->pftableid = asp->pftableid;
pftable_ref(nasp->pftableid);
- nasp->flags = asp->flags & ~F_ATTR_LINKED;
+ nasp->flags = asp->flags & ~(F_ATTR_LINKED | F_ATTR_UPDATE);
attr_copy(nasp, asp);
return (nasp);
static struct prefix *prefix_alloc(void);
static void prefix_free(struct prefix *);
static void prefix_link(struct prefix *, struct rib_entry *,
- struct rde_aspath *);
+ struct rde_aspath *, int);
static void prefix_unlink(struct prefix *);
/*
*/
int
prefix_add(struct rib *rib, struct rde_aspath *asp, struct bgpd_addr *prefix,
- int prefixlen)
+ int prefixlen, int flag)
{
struct prefix *p;
p = prefix_bypeer(re, asp->peer, asp->flags);
if (p == NULL) {
p = prefix_alloc();
- prefix_link(p, re, asp);
+ prefix_link(p, re, asp, flag);
return (1);
} else {
if (prefix_aspath(p) != asp) {
/* prefix belongs to a different aspath so move */
- prefix_move(asp, p);
+ prefix_move(asp, p, flag);
} else
p->lastchange = time(NULL);
return (0);
* Move the prefix to the specified as path, removes the old asp if needed.
*/
void
-prefix_move(struct rde_aspath *asp, struct prefix *p)
+prefix_move(struct rde_aspath *asp, struct prefix *p, int flag)
{
struct prefix *np;
struct rde_aspath *oasp;
/* create new prefix node */
np = prefix_alloc();
np->_p._aspath = asp;
- /* peer and prefix pointers are still equal */
np->re = p->re;
np->lastchange = time(NULL);
+ np->flags = flag;
/* add to new as path */
- TAILQ_INSERT_HEAD(&asp->prefixes, np, path_l);
+ if (np->flags & F_PREFIX_USE_UPDATES)
+ TAILQ_INSERT_HEAD(&asp->updates, np, path_l);
+ else
+ 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);
- TAILQ_REMOVE(&oasp->prefixes, p, path_l);
+ if (p->flags & F_PREFIX_USE_UPDATES)
+ TAILQ_REMOVE(&oasp->updates, p, path_l);
+ else
+ TAILQ_REMOVE(&oasp->prefixes, p, path_l);
PREFIX_COUNT(oasp, -1);
/* as before peer count needs no update because of move */
* Link a prefix into the different parent objects.
*/
static void
-prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp)
+prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_aspath *asp,
+ int flag)
{
- TAILQ_INSERT_HEAD(&asp->prefixes, pref, path_l);
+ if (flag & F_PREFIX_USE_UPDATES)
+ TAILQ_INSERT_HEAD(&asp->updates, pref, path_l);
+ else
+ TAILQ_INSERT_HEAD(&asp->prefixes, pref, path_l);
PREFIX_COUNT(asp, 1);
pref->_p._aspath = asp;
pref->re = re;
pref->lastchange = time(NULL);
+ pref->flags = flag;
/* make route decision */
prefix_evaluate(pref, re);
LIST_REMOVE(pref, rib_l);
prefix_evaluate(NULL, re);
- pq = &prefix_aspath(pref)->prefixes;
- TAILQ_REMOVE(pq, pref, path_l);
+ if (pref->flags & F_PREFIX_USE_UPDATES)
+ pq = &prefix_aspath(pref)->updates;
+ else
+ pq = &prefix_aspath(pref)->prefixes;
+ TAILQ_REMOVE(pq, pref, path_l);
if (rib_empty(re))
rib_remove(re);
/* destroy all references to other objects */
pref->_p._aspath = NULL;
pref->re = NULL;
+ pref->flags = 0;
/*
* It's the caller's duty to do accounting and remove empty aspath