diff options
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r-- | usr.sbin/bgpd/rde.c | 97 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 7 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_peer.c | 10 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 29 |
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); } |