On Tue, Jun 29, 2021 at 12:00:24PM +0200, Claudio Jeker wrote:
> This diff moves the rib_entry pointer re into the union to safe some
> space. For add-path I need to add a few more u_int32_t and that would
> blow the size of struct prefix from 128 to 132 bytes. malloc would round
> that up to 256bytes and that is bad for the struct that is allocted in
> millions in bgpd.
>
> To make this somewhat save introduce PREFIX_FLAG_ADJOUT to mark prefixes
> that live in the adj-rib-out. Those prefixes can not access the re pointer
> also use a wrapper prefix_re() which returns the re pointer or NULL.
> Also add some assertions to make sure that prefixes don't end up in the
> wrong tree.
>
> This change shrinks the struct back to 120bytes and gives me the space
> needed for add-path.
>
> Please test
Ping
--
:wq Claudio
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.530
diff -u -p -r1.530 rde.c
--- rde.c 25 Jun 2021 09:25:48 -0000 1.530
+++ rde.c 29 Jun 2021 08:28:33 -0000
@@ -2298,6 +2298,7 @@ rde_dump_rib_as(struct prefix *p, struct
struct ibuf *wbuf;
struct attr *a;
struct nexthop *nexthop;
+ struct rib_entry *re;
void *bp;
time_t staletime;
size_t aslen;
@@ -2330,7 +2331,8 @@ rde_dump_rib_as(struct prefix *p, struct
rib.origin = asp->origin;
rib.validation_state = p->validation_state;
rib.flags = 0;
- if (p->re != NULL && p->re->active == p)
+ re = prefix_re(p);
+ if (re != NULL && re->active == p)
rib.flags |= F_PREF_ACTIVE;
if (!prefix_peer(p)->conf.ebgp)
rib.flags |= F_PREF_INTERNAL;
@@ -2412,14 +2414,16 @@ static void
rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
{
struct rde_aspath *asp;
+ struct rib_entry *re;
if (!rde_match_peer(prefix_peer(p), &req->neighbor))
return;
asp = prefix_aspath(p);
+ re = prefix_re(p);
if (asp == NULL) /* skip pending withdraw in Adj-RIB-Out */
return;
- if ((req->flags & F_CTL_ACTIVE) && p->re->active != p)
+ if ((req->flags & F_CTL_ACTIVE) && re != NULL && re->active != p)
return;
if ((req->flags & F_CTL_INVALID) &&
(asp->flags & F_ATTR_PARSE_ERR) == 0)
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.240
diff -u -p -r1.240 rde.h
--- rde.h 17 Jun 2021 16:05:26 -0000 1.240
+++ rde.h 29 Jun 2021 08:33:18 -0000
@@ -56,10 +56,10 @@ struct rib {
struct filter_head *in_rules_tmp;
u_int rtableid;
u_int rtableid_tmp;
+ enum reconf_action state, fibstate;
+ u_int16_t id;
u_int16_t flags;
u_int16_t flags_tmp;
- u_int16_t id;
- enum reconf_action state, fibstate;
};
#define RIB_ADJ_IN 0
@@ -317,13 +317,13 @@ struct prefix {
union {
struct {
LIST_ENTRY(prefix) rib, nexthop;
+ struct rib_entry *re;
} list;
struct {
RB_ENTRY(prefix) index, update;
} tree;
} entry;
struct pt_entry *pt;
- struct rib_entry *re;
struct rde_aspath *aspath;
struct rde_community *communities;
struct rde_peer *peer;
@@ -338,6 +338,7 @@ struct prefix {
#define PREFIX_FLAG_DEAD 0x04 /* locked but removed */
#define PREFIX_FLAG_STALE 0x08 /* stale entry (graceful
reload) */
#define PREFIX_FLAG_MASK 0x0f /* mask for the prefix types */
+#define PREFIX_FLAG_ADJOUT 0x10 /* prefix is in the adj-out rib
*/
#define PREFIX_NEXTHOP_LINKED 0x40 /* prefix is linked onto
nexthop list */
#define PREFIX_FLAG_LOCKED 0x80 /* locked by rib walker */
};
@@ -637,6 +638,14 @@ static inline u_int8_t
prefix_vstate(struct prefix *p)
{
return (p->validation_state & ROA_MASK);
+}
+
+static inline struct rib_entry *
+prefix_re(struct prefix *p)
+{
+ if (p->flags & PREFIX_FLAG_ADJOUT)
+ return NULL;
+ return (p->entry.list.re);
}
void nexthop_init(u_int32_t);
Index: rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.222
diff -u -p -r1.222 rde_rib.c
--- rde_rib.c 17 Jun 2021 08:16:04 -0000 1.222
+++ rde_rib.c 29 Jun 2021 09:41:21 -0000
@@ -1031,6 +1031,9 @@ prefix_move(struct prefix *p, struct rde
{
struct prefix *np;
+ if (p->flags & PREFIX_FLAG_ADJOUT)
+ fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__);
+
if (peer != prefix_peer(p))
fatalx("prefix_move: cross peer move");
@@ -1040,7 +1043,7 @@ prefix_move(struct prefix *p, struct rde
np->aspath = path_ref(asp);
np->communities = communities_ref(comm);
np->peer = peer;
- np->re = p->re;
+ np->entry.list.re = prefix_re(p);
np->pt = p->pt; /* skip refcnt update since ref is moved */
np->validation_state = vstate;
np->nhflags = nhflags;
@@ -1056,7 +1059,7 @@ prefix_move(struct prefix *p, struct rde
* no need to update the peer prefix count because we are only moving
* the prefix without changing the peer.
*/
- prefix_evaluate(np->re, np, p);
+ prefix_evaluate(prefix_re(np), np, p);
/* remove possible pftable reference from old path first */
if (p->aspath && p->aspath->pftableid)
@@ -1071,8 +1074,8 @@ prefix_move(struct prefix *p, struct rde
p->nexthop = NULL;
p->aspath = NULL;
p->peer = NULL;
- p->re = NULL;
p->pt = NULL;
+ p->entry.list.re = NULL;
prefix_free(p);
return (0);
@@ -1093,6 +1096,8 @@ prefix_withdraw(struct rib *rib, struct
if (p == NULL) /* Got a dummy withdrawn request. */
return (0);
+ if (p->flags & PREFIX_FLAG_ADJOUT)
+ fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__);
asp = prefix_aspath(p);
if (asp && asp->pftableid)
/* only prefixes in the local RIB were pushed into pf */
@@ -1112,8 +1117,8 @@ prefix_add_eor(struct rde_peer *peer, u_
struct prefix *p;
p = prefix_alloc();
+ p->flags = PREFIX_FLAG_ADJOUT | PREFIX_FLAG_UPDATE;
p->eor = 1;
- p->flags = PREFIX_FLAG_UPDATE;
if (RB_INSERT(prefix_tree, &peer->updates[aid], p) != NULL)
/* no need to add if EoR marker already present */
prefix_free(p);
@@ -1134,6 +1139,9 @@ prefix_adjout_update(struct rde_peer *pe
int created = 0;
if ((p = prefix_lookup(peer, prefix, prefixlen)) != NULL) {
+ if ((p->flags & PREFIX_FLAG_ADJOUT) == 0)
+ fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit",
+ __func__);
/* prefix is already in the Adj-RIB-Out */
if (p->flags & PREFIX_FLAG_WITHDRAW) {
created = 1; /* consider this a new entry */
@@ -1171,6 +1179,7 @@ prefix_adjout_update(struct rde_peer *pe
/* peer and pt remain */
} else {
p = prefix_alloc();
+ p->flags |= PREFIX_FLAG_ADJOUT;
created = 1;
p->pt = pt_get(prefix, prefixlen);
@@ -1225,6 +1234,9 @@ prefix_adjout_withdraw(struct rde_peer *
if (p == NULL) /* Got a dummy withdrawn request. */
return (0);
+ if ((p->flags & PREFIX_FLAG_ADJOUT) == 0)
+ fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__);
+
/* already a withdraw, shortcut */
if (p->flags & PREFIX_FLAG_WITHDRAW) {
p->lastchange = getmonotime();
@@ -1285,6 +1297,9 @@ prefix_adjout_destroy(struct prefix *p)
{
struct rde_peer *peer = prefix_peer(p);
+ if ((p->flags & PREFIX_FLAG_ADJOUT) == 0)
+ fatalx("%s: prefix without PREFIX_FLAG_ADJOUT hit", __func__);
+
if (p->eor) {
/* EOR marker is not linked in the index */
prefix_free(p);
@@ -1486,8 +1501,10 @@ static void
prefix_evaluate_all(struct prefix *p, enum nexthop_state state,
enum nexthop_state oldstate)
{
+ struct rib_entry *re = prefix_re(p);
+
/* Skip non local-RIBs or RIBs that are flagged as noeval. */
- if (re_rib(p->re)->flags & F_RIB_NOEVALUATE) {
+ if (re_rib(re)->flags & F_RIB_NOEVALUATE) {
log_warnx("%s: prefix with F_RIB_NOEVALUATE hit", __func__);
return;
}
@@ -1500,15 +1517,15 @@ prefix_evaluate_all(struct prefix *p, en
* the routing decision so shortcut here.
*/
if (state == NEXTHOP_REACH) {
- if ((re_rib(p->re)->flags & F_RIB_NOFIB) == 0 &&
- p == p->re->active)
- rde_send_kroute(re_rib(p->re), p, NULL);
+ if ((re_rib(re)->flags & F_RIB_NOFIB) == 0 &&
+ p == re->active)
+ rde_send_kroute(re_rib(re), p, NULL);
}
return;
}
/* redo the route decision */
- prefix_evaluate(p->re, p, p);
+ prefix_evaluate(prefix_re(p), p, p);
}
/* kill a prefix. */
@@ -1516,7 +1533,7 @@ void
prefix_destroy(struct prefix *p)
{
/* make route decision */
- prefix_evaluate(p->re, NULL, p);
+ prefix_evaluate(prefix_re(p), NULL, p);
prefix_unlink(p);
prefix_free(p);
@@ -1530,11 +1547,14 @@ prefix_link(struct prefix *p, struct rib
struct rde_aspath *asp, struct rde_community *comm,
struct nexthop *nexthop, u_int8_t nhflags, u_int8_t vstate)
{
+ if (p->flags & PREFIX_FLAG_ADJOUT)
+ fatalx("%s: prefix with PREFIX_FLAG_ADJOUT hit", __func__);
+
+ p->entry.list.re = re;
p->aspath = path_ref(asp);
p->communities = communities_ref(comm);
p->peer = peer;
p->pt = pt_ref(re->prefix);
- p->re = re;
p->validation_state = vstate;
p->nhflags = nhflags;
p->nexthop = nexthop_ref(nexthop);
@@ -1555,7 +1575,7 @@ prefix_link(struct prefix *p, struct rib
static void
prefix_unlink(struct prefix *p)
{
- struct rib_entry *re = p->re;
+ struct rib_entry *re = prefix_re(p);
/* destroy all references to other objects */
nexthop_unlink(p);
@@ -1567,7 +1587,6 @@ prefix_unlink(struct prefix *p)
p->nexthop = NULL;
p->aspath = NULL;
p->peer = NULL;
- p->re = NULL;
p->pt = NULL;
if (re && rib_empty(re))
@@ -1795,7 +1814,7 @@ nexthop_link(struct prefix *p)
return;
/* no need to link prefixes in RIBs that have no decision process */
- if (re_rib(p->re)->flags & F_RIB_NOEVALUATE)
+ if (re_rib(prefix_re(p))->flags & F_RIB_NOEVALUATE)
return;
p->flags |= PREFIX_NEXTHOP_LINKED;