summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/rde.c97
-rw-r--r--usr.sbin/bgpd/rde.h7
-rw-r--r--usr.sbin/bgpd/rde_peer.c10
-rw-r--r--usr.sbin/bgpd/rde_rib.c29
4 files changed, 101 insertions, 42 deletions
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index e000e9ef1e2..0656c32204f 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.506 2020/11/05 14:44:59 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.507 2020/12/04 11:57:13 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -69,6 +69,7 @@ void rde_dump_ctx_terminate(pid_t);
void rde_dump_mrt_new(struct mrt *, pid_t, int);
int rde_l3vpn_import(struct rde_community *, struct l3vpn *);
+static void rde_commit_pftable(void);
void rde_reload_done(void);
static void rde_softreconfig_in_done(void *, u_int8_t);
static void rde_softreconfig_out_done(void *, u_int8_t);
@@ -296,6 +297,8 @@ rde_main(int debug, int verbose)
for (aid = AID_INET6; aid < AID_MAX; aid++)
rde_update6_queue_runner(aid);
}
+ /* commit pftable once per poll loop */
+ rde_commit_pftable();
}
/* do not clean up on shutdown on production, it takes ages. */
@@ -497,8 +500,6 @@ badnetdel:
RDE_RUNNER_ROUNDS, peerself, network_flush_upcall,
NULL, NULL) == -1)
log_warn("rde_dispatch: IMSG_NETWORK_FLUSH");
- /* Deletions were performed in network_flush_upcall */
- rde_send_pftable_commit();
break;
case IMSG_FILTER_SET:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -1389,7 +1390,6 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
done:
rde_filterstate_clean(&state);
- rde_send_pftable_commit();
}
int
@@ -2950,10 +2950,31 @@ rde_update6_queue_runner(u_int8_t aid)
/*
* pf table specific functions
*/
+struct rde_pftable_node {
+ RB_ENTRY(rde_pftable_node) entry;
+ struct pt_entry *prefix;
+ int refcnt;
+ u_int16_t id;
+};
+RB_HEAD(rde_pftable_tree, rde_pftable_node);
+
+static inline int
+rde_pftable_cmp(struct rde_pftable_node *a, struct rde_pftable_node *b)
+{
+ if (a->prefix > b->prefix)
+ return 1;
+ if (a->prefix < b->prefix)
+ return -1;
+ return (a->id - b->id);
+}
+
+RB_GENERATE_STATIC(rde_pftable_tree, rde_pftable_node, entry, rde_pftable_cmp);
+
+struct rde_pftable_tree pftable_tree = RB_INITIALIZER(&pftable_tree);
int need_commit;
-void
-rde_send_pftable(u_int16_t id, struct bgpd_addr *addr,
- u_int8_t len, int del)
+
+static void
+rde_pftable_send(u_int16_t id, struct pt_entry *pt, int del)
{
struct pftable_msg pfm;
@@ -2966,8 +2987,8 @@ rde_send_pftable(u_int16_t id, struct bgpd_addr *addr,
bzero(&pfm, sizeof(pfm));
strlcpy(pfm.pftable, pftable_id2name(id), sizeof(pfm.pftable));
- memcpy(&pfm.addr, addr, sizeof(pfm.addr));
- pfm.len = len;
+ pt_getaddr(pt, &pfm.addr);
+ pfm.len = pt->prefixlen;
if (imsg_compose(ibuf_main,
del ? IMSG_PFTABLE_REMOVE : IMSG_PFTABLE_ADD,
@@ -2978,7 +2999,55 @@ rde_send_pftable(u_int16_t id, struct bgpd_addr *addr,
}
void
-rde_send_pftable_commit(void)
+rde_pftable_add(u_int16_t id, struct prefix *p)
+{
+ struct rde_pftable_node *pfn, node;
+
+ memset(&node, 0, sizeof(node));
+ node.prefix = p->pt;
+ node.id = id;
+
+ pfn = RB_FIND(rde_pftable_tree, &pftable_tree, &node);
+ if (pfn == NULL) {
+ if ((pfn = calloc(1, sizeof(*pfn))) == NULL)
+ fatal("%s", __func__);
+ pfn->prefix = pt_ref(p->pt);
+ pfn->id = id;
+
+ if (RB_INSERT(rde_pftable_tree, &pftable_tree, pfn) != NULL)
+ fatalx("%s: tree corrupt", __func__);
+
+ rde_pftable_send(id, p->pt, 0);
+ }
+ pfn->refcnt++;
+}
+
+void
+rde_pftable_del(u_int16_t id, struct prefix *p)
+{
+ struct rde_pftable_node *pfn, node;
+
+ memset(&node, 0, sizeof(node));
+ node.prefix = p->pt;
+ node.id = id;
+
+ pfn = RB_FIND(rde_pftable_tree, &pftable_tree, &node);
+ if (pfn == NULL)
+ return;
+
+ if (--pfn->refcnt <= 0) {
+ rde_pftable_send(id, p->pt, 1);
+
+ if (RB_REMOVE(rde_pftable_tree, &pftable_tree, pfn) == NULL)
+ fatalx("%s: tree corrupt", __func__);
+
+ pt_unref(pfn->prefix);
+ free(pfn);
+ }
+}
+
+void
+rde_commit_pftable(void)
{
/* do not run while cleaning up */
if (rde_quit)
@@ -3165,9 +3234,6 @@ rde_reload_done(void)
free_rde_prefixsets(&originsets_old);
as_sets_free(&as_sets_old);
- /* Deletions may have been performed in rib_free() */
- rde_send_pftable_commit();
-
log_info("RDE reconfigured");
if (reload > 0) {
@@ -3196,8 +3262,6 @@ rde_softreconfig_in_done(void *arg, u_int8_t dummy)
log_info("softreconfig in done");
}
- /* Changes may have been performed during softreconfig_in run */
- rde_send_pftable_commit();
/* now do the Adj-RIB-Out sync and a possible FIB sync */
softreconfig = 0;
@@ -3621,7 +3685,6 @@ network_add(struct network_config *nc, struct filterstate *state)
nc->prefixlen, vstate);
}
filterset_free(&nc->attrset);
- rde_send_pftable_commit();
}
void
@@ -3688,8 +3751,6 @@ network_delete(struct network_config *nc)
if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, &nc->prefix,
nc->prefixlen))
peerself->prefix_cnt--;
-
- rde_send_pftable_commit();
}
static void
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 1a4e753b11f..c91594a4584 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.234 2020/06/05 19:50:59 denis Exp $ */
+/* $OpenBSD: rde.h,v 1.235 2020/12/04 11:57:13 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -368,9 +368,8 @@ void rde_update_log(const char *, u_int16_t,
void rde_send_kroute_flush(struct rib *);
void rde_send_kroute(struct rib *, struct prefix *, struct prefix *);
void rde_send_nexthop(struct bgpd_addr *, int);
-void rde_send_pftable(u_int16_t, struct bgpd_addr *,
- u_int8_t, int);
-void rde_send_pftable_commit(void);
+void rde_pftable_add(u_int16_t, struct prefix *);
+void rde_pftable_del(u_int16_t, struct prefix *);
void rde_generate_updates(struct rib *, struct prefix *,
struct prefix *);
diff --git a/usr.sbin/bgpd/rde_peer.c b/usr.sbin/bgpd/rde_peer.c
index c164cb05f66..8f9dd053836 100644
--- a/usr.sbin/bgpd/rde_peer.c
+++ b/usr.sbin/bgpd/rde_peer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_peer.c,v 1.5 2020/02/12 10:33:56 claudio Exp $ */
+/* $OpenBSD: rde_peer.c,v 1.6 2020/12/04 11:57:13 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
@@ -236,9 +236,8 @@ peer_flush_upcall(struct rib_entry *re, void *arg)
rp = prefix_get(rib, peer, &addr, prefixlen);
if (rp) {
asp = prefix_aspath(rp);
- if (asp->pftableid)
- rde_send_pftable(asp->pftableid, &addr,
- prefixlen, 1);
+ if (asp && asp->pftableid)
+ rde_pftable_del(asp->pftableid, rp);
prefix_destroy(rp);
rde_update_log("flush", i, peer, NULL,
@@ -385,9 +384,6 @@ peer_flush(struct rde_peer *peer, u_int8_t aid, time_t staletime)
NULL, NULL) == -1)
fatal("%s: rib_dump_new", __func__);
- /* Deletions may have been performed in peer_flush_upcall */
- rde_send_pftable_commit();
-
/* every route is gone so reset staletime */
if (aid == AID_UNSPEC) {
u_int8_t i;
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index 1c321989b90..a172d3fd8b3 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.217 2020/11/05 11:51:13 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.218 2020/12/04 11:57:13 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -252,14 +252,8 @@ rib_free(struct rib *rib)
*/
while ((p = LIST_FIRST(&re->prefix_h))) {
struct rde_aspath *asp = prefix_aspath(p);
- if (asp && asp->pftableid) {
- struct bgpd_addr addr;
-
- pt_getaddr(p->pt, &addr);
- /* Commit is done in rde_reload_done() */
- rde_send_pftable(asp->pftableid, &addr,
- p->pt->prefixlen, 1);
- }
+ if (asp && asp->pftableid)
+ rde_pftable_del(asp->pftableid, p);
prefix_destroy(p);
}
}
@@ -967,9 +961,6 @@ prefix_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
struct rde_community *comm, *ncomm = &state->communities;
struct prefix *p;
- if (nasp->pftableid)
- rde_send_pftable(nasp->pftableid, prefix, prefixlen, 0);
-
/*
* First try to find a prefix in the specified RIB.
*/
@@ -1056,6 +1047,10 @@ prefix_move(struct prefix *p, struct rde_peer *peer,
nexthop_link(np);
np->lastchange = getmonotime();
+ /* add possible pftable reference from new aspath */
+ if (asp && asp->pftableid)
+ rde_pftable_add(asp->pftableid, np);
+
/*
* no need to update the peer prefix count because we are only moving
* the prefix without changing the peer.
@@ -1075,6 +1070,10 @@ prefix_move(struct prefix *p, struct rde_peer *peer,
/* remove old prefix node */
/* as before peer count needs no update because of move */
+ /* remove possible pftable reference first */
+ if (p->aspath && p->aspath->pftableid)
+ rde_pftable_del(p->aspath->pftableid, p);
+
/* destroy all references to other objects and free the old prefix */
nexthop_unlink(p);
nexthop_unref(p->nexthop);
@@ -1109,7 +1108,7 @@ prefix_withdraw(struct rib *rib, struct rde_peer *peer,
asp = prefix_aspath(p);
if (asp && asp->pftableid)
/* only prefixes in the local RIB were pushed into pf */
- rde_send_pftable(asp->pftableid, prefix, prefixlen, 1);
+ rde_pftable_del(asp->pftableid, p);
prefix_destroy(p);
@@ -1597,6 +1596,10 @@ prefix_link(struct prefix *p, struct rib_entry *re, struct rde_peer *peer,
nexthop_link(p);
p->lastchange = getmonotime();
+ /* add possible pftable reference from aspath */
+ if (asp && asp->pftableid)
+ rde_pftable_add(asp->pftableid, p);
+
/* make route decision */
prefix_evaluate(p, re);
}