-/* $OpenBSD: rde.c,v 1.384 2018/07/05 10:25:26 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.385 2018/07/09 14:08:48 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
rde_update_update(struct rde_peer *peer, struct rde_aspath *asp,
struct bgpd_addr *prefix, u_int8_t prefixlen)
{
- struct rde_aspath *fasp;
+ struct filterstate state;
struct prefix *p;
enum filter_actions action;
u_int16_t i;
for (i = RIB_LOC_START; i < rib_size; i++) {
if (*ribs[i].name == '\0')
break;
+ rde_filterstate_prep(&state, asp);
/* input filter */
- action = rde_filter(ribs[i].in_rules, peer, &fasp, p);
-
- if (fasp == NULL)
- fasp = asp;
+ action = rde_filter(ribs[i].in_rules, peer, p, &state);
if (action == ACTION_ALLOW) {
rde_update_log("update", i, peer,
- &fasp->nexthop->exit_nexthop, prefix, prefixlen);
- path_update(&ribs[i].rib, peer, fasp, prefix,
+ &state.aspath.nexthop->exit_nexthop, prefix,
+ prefixlen);
+ path_update(&ribs[i].rib, peer, &state.aspath, prefix,
prefixlen, 0);
} else if (prefix_remove(&ribs[i].rib, peer, prefix, prefixlen,
0)) {
NULL, prefix, prefixlen);
}
- /* free modified aspath */
- if (fasp != asp)
- path_put(fasp);
+ /* clear state */
+ rde_filterstate_clean(&state);
}
}
rde_dump_filterout(struct rde_peer *peer, struct prefix *p,
struct ctl_show_rib_request *req)
{
- struct bgpd_addr addr;
- struct rde_aspath *fasp;
+ struct filterstate state;
enum filter_actions a;
if (up_test_update(peer, p) != 1)
return;
- pt_getaddr(p->re->prefix, &addr);
- a = rde_filter(out_rules, peer, &fasp, p);
- if (fasp == NULL)
- fasp = prefix_aspath(p);
+ rde_filterstate_prep(&state, prefix_aspath(p));
+ a = rde_filter(out_rules, peer, p, &state);
if (a == ACTION_ALLOW)
- rde_dump_rib_as(p, fasp, req->pid, req->flags);
+ rde_dump_rib_as(p, &state.aspath, req->pid, req->flags);
- if (fasp != prefix_aspath(p))
- path_put(fasp);
+ rde_filterstate_clean(&state);
}
void
void
rde_softreconfig_in(struct rib_entry *re, void *ptr)
{
+ struct filterstate state;
struct rib_desc *rib = ptr;
struct prefix *p, *np;
struct pt_entry *pt;
struct rde_peer *peer;
- struct rde_aspath *asp, *fasp;
+ struct rde_aspath *asp;
enum filter_actions action;
struct bgpd_addr addr;
asp = prefix_aspath(p);
peer = asp->peer;
- action = rde_filter(rib->in_rules, peer, &fasp, p);
- fasp = fasp != NULL ? fasp : asp;
+ rde_filterstate_prep(&state, asp);
+ action = rde_filter(rib->in_rules, peer, p, &state);
if (action == ACTION_ALLOW) {
/* update Local-RIB */
- path_update(&rib->rib, peer, fasp, &addr,
+ path_update(&rib->rib, peer, &state.aspath, &addr,
pt->prefixlen, 0);
} else if (action == ACTION_DENY) {
/* remove from Local-RIB */
prefix_remove(&rib->rib, peer, &addr, pt->prefixlen, 0);
}
- if (fasp != asp)
- path_put(fasp);
+ rde_filterstate_clean(&state);
}
}
void
rde_softreconfig_out(struct rib_entry *re, void *ptr)
{
+ struct filterstate ostate, nstate;
struct prefix *p = re->active;
struct pt_entry *pt;
struct rde_peer *peer = ptr;
- struct rde_aspath *oasp, *nasp;
enum filter_actions oa, na;
struct bgpd_addr addr;
if (up_test_update(peer, p) != 1)
return;
- oa = rde_filter(out_rules_tmp, peer, &oasp, p);
- na = rde_filter(out_rules, peer, &nasp, p);
- oasp = oasp != NULL ? oasp : prefix_aspath(p);
- nasp = nasp != NULL ? nasp : prefix_aspath(p);
+ rde_filterstate_prep(&ostate, prefix_aspath(p));
+ rde_filterstate_prep(&nstate, prefix_aspath(p));
+ oa = rde_filter(out_rules_tmp, peer, p, &ostate);
+ na = rde_filter(out_rules, peer, p, &nstate);
/* go through all 4 possible combinations */
/* if (oa == ACTION_DENY && na == ACTION_DENY) */
/* nothing todo */
if (oa == ACTION_DENY && na == ACTION_ALLOW) {
/* send update */
- up_generate(peer, nasp, &addr, pt->prefixlen);
+ up_generate(peer, &nstate.aspath, &addr, pt->prefixlen);
} else if (oa == ACTION_ALLOW && na == ACTION_DENY) {
/* send withdraw */
up_generate(peer, NULL, &addr, pt->prefixlen);
} else if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
/* send update if path attributes changed */
- if (path_compare(nasp, oasp) != 0)
- up_generate(peer, nasp, &addr, pt->prefixlen);
+ if (path_compare(&nstate.aspath, &ostate.aspath) != 0)
+ up_generate(peer, &nstate.aspath, &addr, pt->prefixlen);
}
- if (oasp != prefix_aspath(p))
- path_put(oasp);
- if (nasp != prefix_aspath(p))
- path_put(nasp);
+ rde_filterstate_clean(&ostate);
+ rde_filterstate_clean(&nstate);
}
void
rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr)
{
+ struct filterstate ostate;
struct rde_peer *peer = ptr;
struct prefix *p = re->active;
struct pt_entry *pt;
- struct rde_aspath *oasp;
- enum filter_actions oa;
struct bgpd_addr addr;
pt = re->prefix;
if (up_test_update(peer, p) != 1)
return;
- oa = rde_filter(out_rules_tmp, peer, &oasp, p);
- oasp = oasp != NULL ? oasp : prefix_aspath(p);
-
- if (oa == ACTION_DENY)
- /* nothing todo */
- goto done;
-
- /* send withdraw */
- up_generate(peer, NULL, &addr, pt->prefixlen);
-done:
- if (oasp != prefix_aspath(p))
- path_put(oasp);
+ rde_filterstate_prep(&ostate, prefix_aspath(p));
+ if (rde_filter(out_rules_tmp, peer, p, &ostate) != ACTION_DENY) {
+ /* send withdraw */
+ up_generate(peer, NULL, &addr, pt->prefixlen);
+ }
+ rde_filterstate_clean(&ostate);
}
/*
void
network_add(struct network_config *nc, int flagstatic)
{
+ struct filterstate state;
struct rdomain *rd;
struct rde_aspath *asp;
struct filter_set_head *vpnset = NULL;
}
if (!flagstatic)
asp->flags |= F_ANN_DYNAMIC;
- rde_apply_set(&nc->attrset, asp, nc->prefix.aid, peerself, peerself);
+ rde_filterstate_prep(&state, asp);
+ rde_apply_set(&nc->attrset, &state, nc->prefix.aid, peerself, peerself);
if (vpnset)
- rde_apply_set(vpnset, asp, nc->prefix.aid, peerself, peerself);
+ rde_apply_set(vpnset, &state, nc->prefix.aid, peerself,
+ peerself);
for (i = RIB_LOC_START; i < rib_size; i++) {
if (*ribs[i].name == '\0')
break;
path_update(&ribs[i].rib, peerself, asp, &nc->prefix,
nc->prefixlen, 0);
}
+ rde_filterstate_clean(&state);
path_put(asp);
filterset_free(&nc->attrset);
}
-/* $OpenBSD: rde.h,v 1.175 2018/06/29 11:45:50 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.176 2018/07/09 14:08:48 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
#define F_PREFIX_USE_UPDATES 0x01 /* linked onto the updates list */
+struct filterstate {
+ struct rde_aspath aspath;
+};
+
extern struct rde_memstats rdemem;
/* prototypes */
void prefix_evaluate(struct prefix *, struct rib_entry *);
/* rde_filter.c */
+void rde_filterstate_prep(struct filterstate *, struct rde_aspath *);
+void rde_filterstate_clean(struct filterstate *);
enum filter_actions rde_filter(struct filter_head *, struct rde_peer *,
- struct rde_aspath **, struct prefix *);
-void rde_apply_set(struct filter_set_head *, struct rde_aspath *,
+ struct prefix *, struct filterstate *);
+void rde_apply_set(struct filter_set_head *, struct filterstate *,
u_int8_t, struct rde_peer *, struct rde_peer *);
int rde_filter_equal(struct filter_head *, struct filter_head *,
struct rde_peer *, struct prefixset_head *);
struct rde_aspath *path_copy(struct rde_aspath *, const struct rde_aspath *);
struct rde_aspath *path_prep(struct rde_aspath *);
struct rde_aspath *path_get(void);
+void path_clean(struct rde_aspath *);
void path_put(struct rde_aspath *);
#define PREFIX_SIZE(x) (((x) + 7) / 8 + 1)
-/* $OpenBSD: rde_filter.c,v 1.94 2018/06/29 11:45:50 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.95 2018/07/09 14:08:48 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
int filterset_equal(struct filter_set_head *, struct filter_set_head *);
void
-rde_apply_set(struct filter_set_head *sh, struct rde_aspath *asp,
+rde_apply_set(struct filter_set_head *sh, struct filterstate *state,
u_int8_t aid, struct rde_peer *from, struct rde_peer *peer)
{
struct filter_set *set;
u_int16_t nl;
u_int8_t prepend;
- if (asp == NULL)
+ if (state == NULL)
return;
- if (asp->flags & F_ATTR_LINKED)
- fatalx("rde_apply_set: trying to modify linked asp");
-
TAILQ_FOREACH(set, sh, entry) {
switch (set->type) {
case ACTION_SET_LOCALPREF:
- asp->lpref = set->action.metric;
+ state->aspath.lpref = set->action.metric;
break;
case ACTION_SET_RELATIVE_LOCALPREF:
if (set->action.relative > 0) {
- if (set->action.relative + asp->lpref <
- asp->lpref)
- asp->lpref = UINT_MAX;
+ if (set->action.relative + state->aspath.lpref <
+ state->aspath.lpref)
+ state->aspath.lpref = UINT_MAX;
else
- asp->lpref += set->action.relative;
+ state->aspath.lpref +=
+ set->action.relative;
} else {
if ((u_int32_t)-set->action.relative >
- asp->lpref)
- asp->lpref = 0;
+ state->aspath.lpref)
+ state->aspath.lpref = 0;
else
- asp->lpref += set->action.relative;
+ state->aspath.lpref +=
+ set->action.relative;
}
break;
case ACTION_SET_MED:
- asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
- asp->med = set->action.metric;
+ state->aspath.flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
+ state->aspath.med = set->action.metric;
break;
case ACTION_SET_RELATIVE_MED:
- asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
+ state->aspath.flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
if (set->action.relative > 0) {
- if (set->action.relative + asp->med <
- asp->med)
- asp->med = UINT_MAX;
+ if (set->action.relative + state->aspath.med <
+ state->aspath.med)
+ state->aspath.med = UINT_MAX;
else
- asp->med += set->action.relative;
+ state->aspath.med +=
+ set->action.relative;
} else {
if ((u_int32_t)-set->action.relative >
- asp->med)
- asp->med = 0;
+ state->aspath.med)
+ state->aspath.med = 0;
else
- asp->med += set->action.relative;
+ state->aspath.med +=
+ set->action.relative;
}
break;
case ACTION_SET_WEIGHT:
- asp->weight = set->action.metric;
+ state->aspath.weight = set->action.metric;
break;
case ACTION_SET_RELATIVE_WEIGHT:
if (set->action.relative > 0) {
- if (set->action.relative + asp->weight <
- asp->weight)
- asp->weight = UINT_MAX;
+ if (set->action.relative + state->aspath.weight <
+ state->aspath.weight)
+ state->aspath.weight = UINT_MAX;
else
- asp->weight += set->action.relative;
+ state->aspath.weight +=
+ set->action.relative;
} else {
if ((u_int32_t)-set->action.relative >
- asp->weight)
- asp->weight = 0;
+ state->aspath.weight)
+ state->aspath.weight = 0;
else
- asp->weight += set->action.relative;
+ state->aspath.weight +=
+ set->action.relative;
}
break;
case ACTION_SET_PREPEND_SELF:
prep_as = peer->conf.local_as;
prepend = set->action.prepend;
- np = aspath_prepend(asp->aspath, prep_as, prepend, &nl);
- aspath_put(asp->aspath);
- asp->aspath = aspath_get(np, nl);
+ np = aspath_prepend(state->aspath.aspath, prep_as,
+ prepend, &nl);
+ aspath_put(state->aspath.aspath);
+ state->aspath.aspath = aspath_get(np, nl);
free(np);
break;
case ACTION_SET_PREPEND_PEER:
break;
prep_as = from->conf.remote_as;
prepend = set->action.prepend;
- np = aspath_prepend(asp->aspath, prep_as, prepend, &nl);
- aspath_put(asp->aspath);
- asp->aspath = aspath_get(np, nl);
+ np = aspath_prepend(state->aspath.aspath, prep_as,
+ prepend, &nl);
+ aspath_put(state->aspath.aspath);
+ state->aspath.aspath = aspath_get(np, nl);
free(np);
break;
case ACTION_SET_NEXTHOP:
case ACTION_SET_NEXTHOP_NOMODIFY:
case ACTION_SET_NEXTHOP_SELF:
nexthop_modify(set->action.nh, set->type, aid,
- &asp->nexthop, &asp->flags);
+ &state->aspath.nexthop, &state->aspath.flags);
break;
case ACTION_SET_COMMUNITY:
switch (set->action.community.as) {
break;
}
- community_set(asp, as, type);
+ community_set(&state->aspath, as, type);
break;
case ACTION_DEL_COMMUNITY:
switch (set->action.community.as) {
break;
}
- community_delete(asp, as, type);
+ community_delete(&state->aspath, as, type);
break;
case ACTION_SET_LARGE_COMMUNITY:
switch (set->action.large_community.as) {
break;
}
- community_large_set(asp, las, ld1, ld2);
+ community_large_set(&state->aspath, las, ld1, ld2);
break;
case ACTION_DEL_LARGE_COMMUNITY:
switch (set->action.large_community.as) {
break;
}
- community_large_delete(asp, las, ld1, ld2);
+ community_large_delete(&state->aspath, las, ld1, ld2);
break;
case ACTION_PFTABLE:
/* convert pftable name to an id */
set->type = ACTION_PFTABLE_ID;
/* FALLTHROUGH */
case ACTION_PFTABLE_ID:
- pftable_unref(asp->pftableid);
- asp->pftableid = pftable_ref(set->action.id);
+ pftable_unref(state->aspath.pftableid);
+ state->aspath.pftableid = pftable_ref(set->action.id);
break;
case ACTION_RTLABEL:
/* convert the route label to an id for faster access */
set->type = ACTION_RTLABEL_ID;
/* FALLTHROUGH */
case ACTION_RTLABEL_ID:
- rtlabel_unref(asp->rtlabelid);
- asp->rtlabelid = rtlabel_ref(set->action.id);
+ rtlabel_unref(state->aspath.rtlabelid);
+ state->aspath.rtlabelid = rtlabel_ref(set->action.id);
break;
case ACTION_SET_ORIGIN:
- asp->origin = set->action.origin;
+ state->aspath.origin = set->action.origin;
break;
case ACTION_SET_EXT_COMMUNITY:
- community_ext_set(asp, &set->action.ext_community,
+ community_ext_set(&state->aspath, &set->action.ext_community,
peer->conf.remote_as);
break;
case ACTION_DEL_EXT_COMMUNITY:
- community_ext_delete(asp, &set->action.ext_community,
+ community_ext_delete(&state->aspath, &set->action.ext_community,
peer->conf.remote_as);
break;
}
return (1);
}
+void
+rde_filterstate_prep(struct filterstate *state, struct rde_aspath *asp)
+{
+ memset(state, 0, sizeof(*state));
+
+ path_copy(path_prep(&state->aspath), asp);
+}
+
+void
+rde_filterstate_clean(struct filterstate *state)
+{
+ path_clean(&state->aspath);
+}
+
void
filterlist_free(struct filter_head *fh)
{
enum filter_actions
rde_filter(struct filter_head *rules, struct rde_peer *peer,
- struct rde_aspath **new, struct prefix *p)
+ struct prefix *p, struct filterstate *state)
{
struct filter_rule *f;
struct rde_aspath *asp = prefix_aspath(p);
enum filter_actions action = ACTION_DENY; /* default deny */
- if (new != NULL)
- *new = NULL;
-
if (asp->flags & F_ATTR_PARSE_ERR)
/*
* don't try to filter bad updates just deny them
f->skip[RDE_FILTER_SKIP_PEERID].ptr);
if (rde_filter_match(f, peer, asp, p)) {
- if (asp != NULL && new != NULL) {
- /* asp may get modified so create a copy */
- if (*new == NULL) {
- *new = path_copy(path_get(), asp);
- /* ... and use the copy from now on */
- asp = *new;
- }
- rde_apply_set(&f->set, asp, p->re->prefix->aid,
- prefix_peer(p), peer);
+ if (state != NULL) {
+ rde_apply_set(&f->set, state,
+ p->re->prefix->aid, prefix_peer(p), peer);
}
if (f->action != ACTION_NONE)
action = f->action;
-/* $OpenBSD: rde_rib.c,v 1.165 2018/06/29 11:45:50 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.166 2018/07/09 14:08:48 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
return (path_prep(asp));
}
-/* free an unlinked element */
void
-path_put(struct rde_aspath *asp)
+path_clean(struct rde_aspath *asp)
{
- if (asp == NULL)
- return;
-
if (asp->flags & F_ATTR_LINKED)
fatalx("path_put: linked object");
aspath_put(asp->aspath);
nexthop_put(asp->nexthop);
attr_freeall(asp);
+}
+
+/* free an unlinked element */
+void
+path_put(struct rde_aspath *asp)
+{
+ if (asp == NULL)
+ return;
+
+ path_clean(asp);
+
rdemem.path_cnt--;
free(asp);
}
-/* $OpenBSD: rde_update.c,v 1.93 2018/06/28 09:54:48 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.94 2018/07/09 14:08:48 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
up_generate_updates(struct filter_head *rules, struct rde_peer *peer,
struct prefix *new, struct prefix *old)
{
- struct rde_aspath *asp, *fasp;
- struct bgpd_addr addr;
+ struct filterstate state;
+ struct bgpd_addr addr;
if (peer->state != PEER_UP)
return;
return;
pt_getaddr(old->re->prefix, &addr);
- if (rde_filter(rules, peer, NULL, old) == ACTION_DENY)
+ if (rde_filter(rules, peer, old, NULL) == ACTION_DENY)
return;
/* withdraw prefix */
return;
}
- asp = prefix_aspath(new);
- if (rde_filter(rules, peer, &fasp, new) == ACTION_DENY) {
- path_put(fasp);
+ rde_filterstate_prep(&state, prefix_aspath(new));
+ if (rde_filter(rules, peer, new, &state) == ACTION_DENY) {
+ rde_filterstate_clean(&state);
goto withdraw;
}
- if (fasp == NULL)
- fasp = asp;
pt_getaddr(new->re->prefix, &addr);
- up_generate(peer, fasp, &addr, new->re->prefix->prefixlen);
+ up_generate(peer, &state.aspath, &addr,
+ new->re->prefix->prefixlen);
- /* free modified aspath */
- if (fasp != asp)
- path_put(fasp);
+ rde_filterstate_clean(&state);
}
}
up_generate_default(struct filter_head *rules, struct rde_peer *peer,
u_int8_t aid)
{
- struct rde_aspath *asp, *fasp;
+ struct filterstate state;
+ struct rde_aspath *asp;
struct prefix p;
struct rib_entry *re;
struct bgpd_addr addr;
p.flags = 0;
/* filter as usual */
- if (rde_filter(rules, peer, &fasp, &p) == ACTION_DENY) {
- path_put(fasp);
- path_put(asp);
+ rde_filterstate_prep(&state, asp);
+ if (rde_filter(rules, peer, &p, &state) == ACTION_DENY) {
+ rde_filterstate_clean(&state);
return;
}
- if (fasp == NULL)
- fasp = asp;
-
- up_generate(peer, fasp, &addr, 0);
+ up_generate(peer, &state.aspath, &addr, 0);
/* no longer needed */
- if (fasp != asp)
- path_put(fasp);
+ rde_filterstate_clean(&state);
path_put(asp);
if (rib_empty(re))