On Sun, Oct 28, 2012 at 01:26:42PM +0100, Claudio Jeker wrote:
> On Sat, Oct 13, 2012 at 08:40:35PM +0200, Claudio Jeker wrote:
> > Hi,
> >
> > this is the first step in making bgpd faster and non locking on reloads.
> > The filters are now split into input and output chains. The input chains
> > are also split per RIB. This should result in faster filtering and allows
> > to only run softreconfig on those tables that need it. People with
> > multiple RIBs will benefit the most at the moment.
> >
> > I did some basic tests and I'm fairly confident that it should work but
> > this is a huge change in the reload logic and needs a good broad testing
> > and I don't mind some review of the code.
> >
>
> No comments on this? Should I just commit it?
>
OK, benno@ found an issue where the RDE was crashing. I think I found the
cause, there was a stupid off by one in one of the for loops.
This version should fix that.
--
:wq Claudio
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.273
diff -u -p -r1.273 bgpd.h
--- bgpd.h 18 Sep 2012 10:10:00 -0000 1.273
+++ bgpd.h 20 Sep 2012 08:06:06 -0000
@@ -103,6 +103,7 @@ enum reconf_action {
RECONF_NONE,
RECONF_KEEP,
RECONF_REINIT,
+ RECONF_RELOAD,
RECONF_DELETE
};
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.321
diff -u -p -r1.321 rde.c
--- rde.c 18 Sep 2012 10:10:00 -0000 1.321
+++ rde.c 29 Oct 2012 07:16:51 -0000
@@ -85,12 +85,11 @@ void rde_dump_mrt_new(struct mrt *, pi
void rde_dump_done(void *);
int rde_rdomain_import(struct rde_aspath *, struct rdomain *);
-void rde_up_dump_upcall(struct rib_entry *, void *);
+void rde_reload_done(void);
void rde_softreconfig_out(struct rib_entry *, void *);
void rde_softreconfig_in(struct rib_entry *, void *);
-void rde_softreconfig_load(struct rib_entry *, void *);
-void rde_softreconfig_load_peer(struct rib_entry *, void *);
void rde_softreconfig_unload_peer(struct rib_entry *, void *);
+void rde_up_dump_upcall(struct rib_entry *, void *);
void rde_update_queue_runner(void);
void rde_update6_queue_runner(u_int8_t);
@@ -119,7 +118,7 @@ struct bgpd_config *conf, *nconf;
time_t reloadtime;
struct rde_peer_head peerlist;
struct rde_peer *peerself;
-struct filter_head *rules_l, *newrules;
+struct filter_head *out_rules, *out_rules_tmp;
struct rdomain_head *rdomains_l, *newdomains;
struct imsgbuf *ibuf_se;
struct imsgbuf *ibuf_se_ctl;
@@ -224,10 +223,10 @@ rde_main(int pipe_m2r[2], int pipe_s2r[2
nexthop_init(nexthophashsize);
peer_init(peerhashsize);
- rules_l = calloc(1, sizeof(struct filter_head));
- if (rules_l == NULL)
+ out_rules = calloc(1, sizeof(struct filter_head));
+ if (out_rules == NULL)
fatal(NULL);
- TAILQ_INIT(rules_l);
+ TAILQ_INIT(out_rules);
rdomains_l = calloc(1, sizeof(struct rdomain_head));
if (rdomains_l == NULL)
fatal(NULL);
@@ -645,11 +644,11 @@ rde_dispatch_imsg_parent(struct imsgbuf
struct rde_rib rn;
struct rde_peer *peer;
struct peer_config *pconf;
+ struct filter_head *nr;
struct filter_rule *r;
struct filter_set *s;
struct nexthop *nh;
- int n, fd, reconf_in = 0, reconf_out = 0,
- reconf_rib = 0;
+ int n, fd;
u_int16_t rid;
if ((n = imsg_read(ibuf)) == -1)
@@ -693,10 +692,10 @@ rde_dispatch_imsg_parent(struct imsgbuf
sizeof(struct bgpd_config))
fatalx("IMSG_RECONF_CONF bad len");
reloadtime = time(NULL);
- newrules = calloc(1, sizeof(struct filter_head));
- if (newrules == NULL)
+ out_rules_tmp = calloc(1, sizeof(struct filter_head));
+ if (out_rules_tmp == NULL)
fatal(NULL);
- TAILQ_INIT(newrules);
+ TAILQ_INIT(out_rules_tmp);
newdomains = calloc(1, sizeof(struct rdomain_head));
if (newdomains == NULL)
fatal(NULL);
@@ -746,7 +745,19 @@ rde_dispatch_imsg_parent(struct imsgbuf
TAILQ_INIT(&r->set);
r->peer.ribid = rib_find(r->rib);
parent_set = &r->set;
- TAILQ_INSERT_TAIL(newrules, r, entry);
+ if (r->dir == DIR_IN) {
+ nr = ribs[r->peer.ribid].in_rules_tmp;
+ if (nr == NULL) {
+ nr = calloc(1,
+ sizeof(struct filter_head));
+ if (nr == NULL)
+ fatal(NULL);
+ TAILQ_INIT(nr);
+ ribs[r->peer.ribid].in_rules_tmp = nr;
+ }
+ TAILQ_INSERT_TAIL(nr, r, entry);
+ } else
+ TAILQ_INSERT_TAIL(out_rules_tmp, r, entry);
break;
case IMSG_RECONF_RDOMAIN:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -781,110 +792,9 @@ rde_dispatch_imsg_parent(struct imsgbuf
case IMSG_RECONF_DONE:
if (nconf == NULL)
fatalx("got IMSG_RECONF_DONE but no config");
- if ((nconf->flags & BGPD_FLAG_NO_EVALUATE)
- != (conf->flags & BGPD_FLAG_NO_EVALUATE)) {
- log_warnx("change to/from route-collector "
- "mode ignored");
- if (conf->flags & BGPD_FLAG_NO_EVALUATE)
- nconf->flags |= BGPD_FLAG_NO_EVALUATE;
- else
- nconf->flags &= ~BGPD_FLAG_NO_EVALUATE;
- }
- memcpy(conf, nconf, sizeof(struct bgpd_config));
- conf->listen_addrs = NULL;
- conf->csock = NULL;
- conf->rcsock = NULL;
- free(nconf);
- nconf = NULL;
parent_set = NULL;
- /* sync peerself with conf */
- peerself->remote_bgpid = ntohl(conf->bgpid);
- peerself->conf.local_as = conf->as;
- peerself->conf.remote_as = conf->as;
- peerself->short_as = conf->short_as;
-
- /* apply new set of rdomain, sync will be done later */
- while ((rd = SIMPLEQ_FIRST(rdomains_l)) != NULL) {
- SIMPLEQ_REMOVE_HEAD(rdomains_l, entry);
- filterset_free(&rd->import);
- filterset_free(&rd->export);
- free(rd);
- }
- free(rdomains_l);
- rdomains_l = newdomains;
-
- /* check if filter changed */
- LIST_FOREACH(peer, &peerlist, peer_l) {
- if (peer->conf.id == 0)
- continue;
- peer->reconf_out = 0;
- peer->reconf_in = 0;
- peer->reconf_rib = 0;
- if (peer->conf.softreconfig_in &&
- !rde_filter_equal(rules_l, newrules, peer,
- DIR_IN)) {
- peer->reconf_in = 1;
- reconf_in = 1;
- }
- if (peer->ribid != rib_find(peer->conf.rib)) {
- rib_dump(&ribs[peer->ribid],
- rde_softreconfig_unload_peer, peer,
- AID_UNSPEC);
- peer->ribid = rib_find(peer->conf.rib);
- peer->reconf_rib = 1;
- reconf_rib = 1;
- continue;
- }
- if (peer->conf.softreconfig_out &&
- !rde_filter_equal(rules_l, newrules, peer,
- DIR_OUT)) {
- peer->reconf_out = 1;
- reconf_out = 1;
- }
- }
- /* bring ribs in sync before softreconfig dance */
- for (rid = 0; rid < rib_size; rid++) {
- if (ribs[rid].state == RECONF_DELETE)
- rib_free(&ribs[rid]);
- else if (ribs[rid].state == RECONF_REINIT)
- rib_dump(&ribs[0],
- rde_softreconfig_load, &ribs[rid],
- AID_UNSPEC);
- }
- /* sync local-RIBs first */
- if (reconf_in)
- rib_dump(&ribs[0], rde_softreconfig_in, NULL,
- AID_UNSPEC);
- /* then sync peers */
- if (reconf_out) {
- int i;
- for (i = 1; i < rib_size; i++) {
- if (ribs[i].state == RECONF_REINIT)
- /* already synced by _load */
- continue;
- rib_dump(&ribs[i], rde_softreconfig_out,
- NULL, AID_UNSPEC);
- }
- }
- if (reconf_rib) {
- LIST_FOREACH(peer, &peerlist, peer_l) {
- rib_dump(&ribs[peer->ribid],
- rde_softreconfig_load_peer,
- peer, AID_UNSPEC);
- }
- }
-
- while ((r = TAILQ_FIRST(rules_l)) != NULL) {
- TAILQ_REMOVE(rules_l, r, entry);
- filterset_free(&r->set);
- free(r);
- }
- free(rules_l);
- rules_l = newrules;
- log_info("RDE reconfigured");
- imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0,
- -1, NULL, 0);
+ rde_reload_done();
break;
case IMSG_NEXTHOP_UPDATE:
nexthop_update(imsg.data);
@@ -1377,8 +1287,8 @@ rde_update_update(struct rde_peer *peer,
for (i = 1; i < rib_size; i++) {
/* input filter */
- action = rde_filter(i, &fasp, rules_l, peer, asp, prefix,
- prefixlen, peer, DIR_IN);
+ action = rde_filter(ribs[i].in_rules, &fasp, peer, asp, prefix,
+ prefixlen, peer);
if (fasp == NULL)
fasp = asp;
@@ -2310,8 +2220,8 @@ rde_dump_filterout(struct rde_peer *peer
return;
pt_getaddr(p->prefix, &addr);
- a = rde_filter(1 /* XXX */, &asp, rules_l, peer, p->aspath, &addr,
- p->prefix->prefixlen, p->aspath->peer, DIR_OUT);
+ a = rde_filter(out_rules, &asp, peer, p->aspath, &addr,
+ p->prefix->prefixlen, p->aspath->peer);
if (asp)
asp->peer = p->aspath->peer;
else
@@ -2647,196 +2557,228 @@ rde_send_nexthop(struct bgpd_addr *next,
* soft reconfig specific functions
*/
void
-rde_softreconfig_out(struct rib_entry *re, void *ptr)
+rde_reload_done(void)
{
- struct prefix *p = re->active;
- struct pt_entry *pt;
+ struct rdomain *rd;
struct rde_peer *peer;
- struct rde_aspath *oasp, *nasp;
- enum filter_actions oa, na;
- struct bgpd_addr addr;
+ struct filter_head *fh;
+ u_int16_t rid;
- if (p == NULL)
- return;
+ /* first merge the main config */
+ if ((nconf->flags & BGPD_FLAG_NO_EVALUATE)
+ != (conf->flags & BGPD_FLAG_NO_EVALUATE)) {
+ log_warnx("change to/from route-collector "
+ "mode ignored");
+ if (conf->flags & BGPD_FLAG_NO_EVALUATE)
+ nconf->flags |= BGPD_FLAG_NO_EVALUATE;
+ else
+ nconf->flags &= ~BGPD_FLAG_NO_EVALUATE;
+ }
+ memcpy(conf, nconf, sizeof(struct bgpd_config));
+ conf->listen_addrs = NULL;
+ conf->csock = NULL;
+ conf->rcsock = NULL;
+ free(nconf);
+ nconf = NULL;
+
+ /* sync peerself with conf */
+ peerself->remote_bgpid = ntohl(conf->bgpid);
+ peerself->conf.local_as = conf->as;
+ peerself->conf.remote_as = conf->as;
+ peerself->short_as = conf->short_as;
+
+ /* apply new set of rdomain, sync will be done later */
+ while ((rd = SIMPLEQ_FIRST(rdomains_l)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(rdomains_l, entry);
+ filterset_free(&rd->import);
+ filterset_free(&rd->export);
+ free(rd);
+ }
+ free(rdomains_l);
+ rdomains_l = newdomains;
+ /* XXX WHERE IS THE SYNC ??? */
- pt = re->prefix;
- pt_getaddr(pt, &addr);
+ /*
+ * make the new filter rules the active one but keep the old for
+ * softrconfig. This is needed so that changes happening are using
+ * the right filters.
+ */
+ fh = out_rules;
+ out_rules = out_rules_tmp;
+ out_rules_tmp = fh;
+
+ /* check if filter changed */
LIST_FOREACH(peer, &peerlist, peer_l) {
if (peer->conf.id == 0)
continue;
- if (peer->ribid != re->ribid)
- continue;
- if (peer->reconf_out == 0)
+ peer->reconf_out = 0;
+ peer->reconf_rib = 0;
+ if (peer->ribid != rib_find(peer->conf.rib)) {
+ rib_dump(&ribs[peer->ribid],
+ rde_softreconfig_unload_peer, peer, AID_UNSPEC);
+ peer->ribid = rib_find(peer->conf.rib);
+ peer->reconf_rib = 1;
continue;
- if (up_test_update(peer, p) != 1)
- continue;
-
- oa = rde_filter(re->ribid, &oasp, rules_l, peer, p->aspath,
- &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
- na = rde_filter(re->ribid, &nasp, newrules, peer, p->aspath,
- &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
- oasp = oasp != NULL ? oasp : p->aspath;
- nasp = nasp != NULL ? nasp : p->aspath;
-
- if (oa == ACTION_DENY && na == ACTION_DENY)
- /* nothing todo */
- goto done;
- if (oa == ACTION_DENY && na == ACTION_ALLOW) {
- /* send update */
- up_generate(peer, nasp, &addr, pt->prefixlen);
- goto done;
}
- if (oa == ACTION_ALLOW && na == ACTION_DENY) {
- /* send withdraw */
- up_generate(peer, NULL, &addr, pt->prefixlen);
- goto done;
- }
- if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
- if (path_compare(nasp, oasp) == 0)
- goto done;
- /* send update */
- up_generate(peer, nasp, &addr, pt->prefixlen);
+ if (peer->conf.softreconfig_out &&
+ !rde_filter_equal(out_rules, out_rules_tmp, peer)) {
+ peer->reconf_out = 1;
+ }
+ }
+ /* bring ribs in sync */
+ for (rid = 0; rid < rib_size; rid++) {
+ /* flip rules, make new active */
+ fh = ribs[rid].in_rules;
+ ribs[rid].in_rules = ribs[rid].in_rules_tmp;
+ ribs[rid].in_rules_tmp = fh;
+
+ switch (ribs[rid].state) {
+ case RECONF_DELETE:
+ rib_free(&ribs[rid]);
+ break;
+ case RECONF_KEEP:
+ if (rde_filter_equal(ribs[rid].in_rules,
+ ribs[rid].in_rules_tmp, NULL))
+ /* rib is in sync */
+ break;
+ ribs[rid].state = RECONF_RELOAD;
+ /* FALLTHROUGH */
+ case RECONF_REINIT:
+ rib_dump(&ribs[0], rde_softreconfig_in, &ribs[rid],
+ AID_UNSPEC);
+ break;
+ case RECONF_RELOAD:
+ case RECONF_NONE:
+ log_warnx("Bad rib reload state");
+ break;
}
-
-done:
- if (oasp != p->aspath)
- path_put(oasp);
- if (nasp != p->aspath)
- path_put(nasp);
}
+ LIST_FOREACH(peer, &peerlist, peer_l) {
+ if (peer->reconf_out)
+ rib_dump(&ribs[peer->ribid], rde_softreconfig_out,
+ peer, AID_UNSPEC);
+ else if (peer->reconf_rib)
+ /* dump the full table to neighbors that changed rib */
+ peer_dump(peer->conf.id, AID_UNSPEC);
+ }
+ rde_free_filter(out_rules_tmp);
+ out_rules_tmp = NULL;
+ for (rid = 0; rid < rib_size; rid++) {
+ rde_free_filter(ribs[rid].in_rules_tmp);
+ ribs[rid].in_rules_tmp = NULL;
+ ribs[rid].state = RECONF_NONE;
+ }
+
+ log_info("RDE reconfigured");
+ imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0,
+ -1, NULL, 0);
}
void
rde_softreconfig_in(struct rib_entry *re, void *ptr)
{
+ struct rib *rib = ptr;
struct prefix *p, *np;
struct pt_entry *pt;
struct rde_peer *peer;
struct rde_aspath *asp, *oasp, *nasp;
enum filter_actions oa, na;
struct bgpd_addr addr;
- u_int16_t i;
pt = re->prefix;
pt_getaddr(pt, &addr);
for (p = LIST_FIRST(&re->prefix_h); p != NULL; p = np) {
+ /*
+ * prefix_remove() and path_update() may change the object
+ * so cache the values.
+ */
np = LIST_NEXT(p, rib_l);
-
- /* store aspath as prefix may change till we're done */
asp = p->aspath;
peer = asp->peer;
- /* XXX how can this happen ??? */
- if (peer->reconf_in == 0)
- continue;
-
- for (i = 1; i < rib_size; i++) {
- /* only active ribs need a softreconfig rerun */
- if (ribs[i].state != RECONF_KEEP)
- continue;
-
- /* check if prefix changed */
- oa = rde_filter(i, &oasp, rules_l, peer, asp, &addr,
- pt->prefixlen, peer, DIR_IN);
- na = rde_filter(i, &nasp, newrules, peer, asp, &addr,
- pt->prefixlen, peer, DIR_IN);
+ /* check if prefix changed */
+ if (rib->state == RECONF_RELOAD) {
+ oa = rde_filter(rib->in_rules_tmp, &oasp, peer,
+ asp, &addr, pt->prefixlen, peer);
oasp = oasp != NULL ? oasp : asp;
- nasp = nasp != NULL ? nasp : asp;
-
- if (oa == ACTION_DENY && na == ACTION_DENY)
- /* nothing todo */
- goto done;
- if (oa == ACTION_DENY && na == ACTION_ALLOW) {
- /* update Local-RIB */
- path_update(&ribs[i], peer, nasp, &addr,
- pt->prefixlen);
- goto done;
- }
- if (oa == ACTION_ALLOW && na == ACTION_DENY) {
- /* remove from Local-RIB */
- prefix_remove(&ribs[i], peer, &addr,
- pt->prefixlen, 0);
- goto done;
- }
- if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
- if (path_compare(nasp, oasp) == 0)
- goto done;
- /* send update */
- path_update(&ribs[i], peer, nasp, &addr,
- pt->prefixlen);
- }
-
-done:
- if (oasp != asp)
- path_put(oasp);
- if (nasp != asp)
- path_put(nasp);
+ } else {
+ /* make sure we update everything for RECONF_REINIT */
+ oa = ACTION_DENY;
+ oasp = asp;
}
- }
-}
-
-void
-rde_softreconfig_load(struct rib_entry *re, void *ptr)
-{
- struct rib *rib = ptr;
- struct prefix *p, *np;
- struct pt_entry *pt;
- struct rde_peer *peer;
- struct rde_aspath *asp, *nasp;
- enum filter_actions action;
- struct bgpd_addr addr;
-
- pt = re->prefix;
- pt_getaddr(pt, &addr);
- for (p = LIST_FIRST(&re->prefix_h); p != NULL; p = np) {
- np = LIST_NEXT(p, rib_l);
-
- /* store aspath as prefix may change till we're done */
- asp = p->aspath;
- peer = asp->peer;
-
- action = rde_filter(rib->id, &nasp, newrules, peer, asp, &addr,
- pt->prefixlen, peer, DIR_IN);
+ na = rde_filter(rib->in_rules, &nasp, peer, asp,
+ &addr, pt->prefixlen, peer);
nasp = nasp != NULL ? nasp : asp;
- if (action == ACTION_ALLOW) {
+ /* go through all 4 possible combinations */
+ /* if (oa == ACTION_DENY && na == ACTION_DENY) */
+ /* nothing todo */
+ if (oa == ACTION_DENY && na == ACTION_ALLOW) {
/* update Local-RIB */
path_update(rib, peer, nasp, &addr, pt->prefixlen);
+ } else if (oa == ACTION_ALLOW && na == ACTION_DENY) {
+ /* remove from Local-RIB */
+ prefix_remove(rib, peer, &addr, pt->prefixlen, 0);
+ } else if (oa == ACTION_ALLOW && na == ACTION_ALLOW) {
+ if (path_compare(nasp, oasp) != 0)
+ /* send update */
+ path_update(rib, peer, nasp, &addr,
+ pt->prefixlen);
}
+ if (oasp != asp)
+ path_put(oasp);
if (nasp != asp)
path_put(nasp);
}
}
void
-rde_softreconfig_load_peer(struct rib_entry *re, void *ptr)
+rde_softreconfig_out(struct rib_entry *re, void *ptr)
{
- struct rde_peer *peer = ptr;
struct prefix *p = re->active;
struct pt_entry *pt;
- struct rde_aspath *nasp;
- enum filter_actions na;
+ struct rde_peer *peer = ptr;
+ struct rde_aspath *oasp, *nasp;
+ enum filter_actions oa, na;
struct bgpd_addr addr;
+ if (peer->conf.id == 0)
+ fatalx("King Bula troubled by bad peer");
+
+ if (p == NULL)
+ return;
+
pt = re->prefix;
pt_getaddr(pt, &addr);
- /* check if prefix was announced */
if (up_test_update(peer, p) != 1)
return;
- na = rde_filter(re->ribid, &nasp, newrules, peer, p->aspath,
- &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
+ oa = rde_filter(out_rules_tmp, &oasp, peer, p->aspath,
+ &addr, pt->prefixlen, p->aspath->peer);
+ na = rde_filter(out_rules, &nasp, peer, p->aspath,
+ &addr, pt->prefixlen, p->aspath->peer);
+ oasp = oasp != NULL ? oasp : p->aspath;
nasp = nasp != NULL ? nasp : p->aspath;
- if (na == ACTION_DENY)
+ /* go through all 4 possible combinations */
+ /* if (oa == ACTION_DENY && na == ACTION_DENY) */
/* nothing todo */
- goto done;
+ if (oa == ACTION_DENY && na == ACTION_ALLOW) {
+ /* send update */
+ up_generate(peer, nasp, &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);
+ }
- /* send update */
- up_generate(peer, nasp, &addr, pt->prefixlen);
-done:
+ if (oasp != p->aspath)
+ path_put(oasp);
if (nasp != p->aspath)
path_put(nasp);
}
@@ -2858,8 +2800,8 @@ rde_softreconfig_unload_peer(struct rib_
if (up_test_update(peer, p) != 1)
return;
- oa = rde_filter(re->ribid, &oasp, rules_l, peer, p->aspath,
- &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
+ oa = rde_filter(out_rules_tmp, &oasp, peer, p->aspath,
+ &addr, pt->prefixlen, p->aspath->peer);
oasp = oasp != NULL ? oasp : p->aspath;
if (oa == ACTION_DENY)
@@ -2887,7 +2829,7 @@ rde_up_dump_upcall(struct rib_entry *re,
fatalx("King Bula: monstrous evil horror.");
if (re->active == NULL)
return;
- up_generate_updates(rules_l, peer, re->active, NULL);
+ up_generate_updates(out_rules, peer, re->active, NULL);
}
void
@@ -2910,7 +2852,7 @@ rde_generate_updates(u_int16_t ribid, st
continue;
if (peer->state != PEER_UP)
continue;
- up_generate_updates(rules_l, peer, new, old);
+ up_generate_updates(out_rules, peer, new, old);
}
}
@@ -3342,7 +3284,7 @@ peer_dump(u_int32_t id, u_int8_t aid)
}
if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
- up_generate_default(rules_l, peer, aid);
+ up_generate_default(out_rules, peer, aid);
else
rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, peer, aid);
if (peer->capa.grestart.restart)
@@ -3543,7 +3485,6 @@ void
rde_shutdown(void)
{
struct rde_peer *p;
- struct filter_rule *r;
u_int32_t i;
/*
@@ -3559,12 +3500,10 @@ rde_shutdown(void)
peer_down(p->conf.id);
/* free filters */
- while ((r = TAILQ_FIRST(rules_l)) != NULL) {
- TAILQ_REMOVE(rules_l, r, entry);
- filterset_free(&r->set);
- free(r);
+ rde_free_filter(out_rules);
+ for (i = 0; i < rib_size; i++) {
+ rde_free_filter(ribs[i].in_rules);
}
- free(rules_l);
nexthop_shutdown();
path_shutdown();
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.144
diff -u -p -r1.144 rde.h
--- rde.h 12 Sep 2012 05:56:22 -0000 1.144
+++ rde.h 12 Oct 2012 06:28:07 -0000
@@ -76,7 +76,6 @@ struct rde_peer {
u_int16_t ribid;
u_int16_t short_as;
u_int16_t mrt_idx;
- u_int8_t reconf_in; /* in filter changed */
u_int8_t reconf_out; /* out filter changed */
u_int8_t reconf_rib; /* rib changed */
};
@@ -287,6 +286,8 @@ struct rib_entry {
struct rib {
char name[PEER_DESCR_LEN];
struct rib_tree rib;
+ struct filter_head *in_rules;
+ struct filter_head *in_rules_tmp;
u_int rtableid;
u_int16_t flags;
u_int16_t id;
@@ -325,6 +326,7 @@ u_int32_t rde_local_as(void);
int rde_noevaluate(void);
int rde_decisionflags(void);
int rde_as4byte(struct rde_peer *);
+void rde_free_filter(struct filter_head *);
/* rde_attr.c */
int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
@@ -379,14 +381,13 @@ int community_ext_conv(struct filter_e
void prefix_evaluate(struct prefix *, struct rib_entry *);
/* rde_filter.c */
-enum filter_actions rde_filter(u_int16_t, struct rde_aspath **,
- struct filter_head *, struct rde_peer *,
- struct rde_aspath *, struct bgpd_addr *, u_int8_t,
- struct rde_peer *, enum directions);
+enum filter_actions rde_filter(struct filter_head *, struct rde_aspath **,
+ struct rde_peer *, struct rde_aspath *,
+ struct bgpd_addr *, u_int8_t, struct rde_peer *);
void rde_apply_set(struct rde_aspath *, struct filter_set_head *,
u_int8_t, struct rde_peer *, struct rde_peer *);
int rde_filter_equal(struct filter_head *, struct filter_head *,
- struct rde_peer *, enum directions);
+ struct rde_peer *);
/* rde_prefix.c */
#define pt_empty(pt) ((pt)->refcnt == 0)
Index: rde_filter.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v
retrieving revision 1.67
diff -u -p -r1.67 rde_filter.c
--- rde_filter.c 20 Sep 2011 21:19:06 -0000 1.67
+++ rde_filter.c 12 Oct 2012 06:25:28 -0000
@@ -30,9 +30,9 @@ int rde_filter_match(struct filter_rule
int filterset_equal(struct filter_set_head *, struct filter_set_head *);
enum filter_actions
-rde_filter(u_int16_t ribid, struct rde_aspath **new, struct filter_head *rules,
+rde_filter(struct filter_head *rules, struct rde_aspath **new,
struct rde_peer *peer, struct rde_aspath *asp, struct bgpd_addr *prefix,
- u_int8_t prefixlen, struct rde_peer *from, enum directions dir)
+ u_int8_t prefixlen, struct rde_peer *from)
{
struct filter_rule *f;
enum filter_actions action = ACTION_ALLOW; /* default allow */
@@ -47,11 +47,10 @@ rde_filter(u_int16_t ribid, struct rde_a
*/
return (ACTION_DENY);
+ if (rules == NULL)
+ return (action);
+
TAILQ_FOREACH(f, rules, entry) {
- if (dir != f->dir)
- continue;
- if (dir == DIR_IN && f->peer.ribid != ribid)
- continue;
if (f->peer.groupid != 0 &&
f->peer.groupid != peer->conf.groupid)
continue;
@@ -391,42 +390,32 @@ rde_filter_match(struct filter_rule *f,
int
rde_filter_equal(struct filter_head *a, struct filter_head *b,
- struct rde_peer *peer, enum directions dir)
+ struct rde_peer *peer)
{
struct filter_rule *fa, *fb;
- fa = TAILQ_FIRST(a);
- fb = TAILQ_FIRST(b);
+ fa = a ? TAILQ_FIRST(a) : NULL;
+ fb = b ? TAILQ_FIRST(b) : NULL;
while (fa != NULL || fb != NULL) {
- /* skip all rules with wrong direction */
- if (fa != NULL && dir != fa->dir) {
- fa = TAILQ_NEXT(fa, entry);
- continue;
- }
- if (fb != NULL && dir != fb->dir) {
- fb = TAILQ_NEXT(fb, entry);
- continue;
- }
-
/* skip all rules with wrong peer */
- if (fa != NULL && fa->peer.groupid != 0 &&
+ if (peer != NULL && fa != NULL && fa->peer.groupid != 0 &&
fa->peer.groupid != peer->conf.groupid) {
fa = TAILQ_NEXT(fa, entry);
continue;
}
- if (fa != NULL && fa->peer.peerid != 0 &&
+ if (peer != NULL && fa != NULL && fa->peer.peerid != 0 &&
fa->peer.peerid != peer->conf.id) {
fa = TAILQ_NEXT(fa, entry);
continue;
}
- if (fb != NULL && fb->peer.groupid != 0 &&
+ if (peer != NULL && fb != NULL && fb->peer.groupid != 0 &&
fb->peer.groupid != peer->conf.groupid) {
fb = TAILQ_NEXT(fb, entry);
continue;
}
- if (fb != NULL && fb->peer.peerid != 0 &&
+ if (peer != NULL && fb != NULL && fb->peer.peerid != 0 &&
fb->peer.peerid != peer->conf.id) {
fb = TAILQ_NEXT(fb, entry);
continue;
@@ -450,6 +439,22 @@ rde_filter_equal(struct filter_head *a,
fb = TAILQ_NEXT(fb, entry);
}
return (1);
+}
+
+void
+rde_free_filter(struct filter_head *fh)
+{
+ struct filter_rule *r;
+
+ if (fh == NULL)
+ return;
+
+ while ((r = TAILQ_FIRST(fh)) != NULL) {
+ TAILQ_REMOVE(fh, r, entry);
+ filterset_free(&r->set);
+ free(r);
+ }
+ free(fh);
}
/* free a filterset and take care of possible name2id references */
Index: rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.134
diff -u -p -r1.134 rde_rib.c
--- rde_rib.c 12 Sep 2012 05:56:22 -0000 1.134
+++ rde_rib.c 19 Sep 2012 10:48:42 -0000
@@ -82,6 +82,11 @@ rib_new(char *name, u_int rtableid, u_in
ribs[id].flags = flags;
ribs[id].rtableid = rtableid;
+ ribs[id].in_rules = calloc(1, sizeof(struct filter_head));
+ if (ribs[id].in_rules == NULL)
+ fatal(NULL);
+ TAILQ_INIT(ribs[id].in_rules);
+
return (id);
}
Index: rde_update.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
retrieving revision 1.80
diff -u -p -r1.80 rde_update.c
--- rde_update.c 12 Apr 2012 17:31:05 -0000 1.80
+++ rde_update.c 19 Sep 2012 10:58:21 -0000
@@ -411,9 +411,8 @@ up_generate_updates(struct filter_head *
return;
pt_getaddr(old->prefix, &addr);
- if (rde_filter(peer->ribid, NULL, rules, peer, old->aspath,
- &addr, old->prefix->prefixlen, old->aspath->peer,
- DIR_OUT) == ACTION_DENY)
+ if (rde_filter(rules, NULL, peer, old->aspath, &addr,
+ old->prefix->prefixlen, old->aspath->peer) == ACTION_DENY)
return;
/* withdraw prefix */
@@ -430,9 +429,8 @@ up_generate_updates(struct filter_head *
}
pt_getaddr(new->prefix, &addr);
- if (rde_filter(peer->ribid, &asp, rules, peer, new->aspath,
- &addr, new->prefix->prefixlen, new->aspath->peer,
- DIR_OUT) == ACTION_DENY) {
+ if (rde_filter(rules, &asp, peer, new->aspath, &addr,
+ new->prefix->prefixlen, new->aspath->peer) == ACTION_DENY) {
path_put(asp);
up_generate_updates(rules, peer, NULL, old);
return;
@@ -474,8 +472,8 @@ up_generate_default(struct filter_head *
bzero(&addr, sizeof(addr));
addr.aid = aid;
- if (rde_filter(peer->ribid, &fasp, rules, peer, asp, &addr, 0, NULL,
- DIR_OUT) == ACTION_DENY) {
+ if (rde_filter(rules, &fasp, peer, asp, &addr, 0, NULL) ==
+ ACTION_DENY) {
path_put(fasp);
path_put(asp);
return;