summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd/rde.c
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2020-12-04 11:57:14 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2020-12-04 11:57:14 +0000
commit1c6f38a6000a63a317349e4ac8317672a5b887cf (patch)
tree3a1d4d4249bc3aac3a3a147e5e51fa371248ee79 /usr.sbin/bgpd/rde.c
parent19c63ad7a82bf6db0835fee0fd00d55857a0bd41 (diff)
Reference count prefixes added to a pftable. This allows to export
prefixes from multiple sessions into the same table. Before a prefix was removed from the table on the first withdraw (even though there was an alternative around). Requested by, tested and OK dlg@
Diffstat (limited to 'usr.sbin/bgpd/rde.c')
-rw-r--r--usr.sbin/bgpd/rde.c97
1 files changed, 79 insertions, 18 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