From ea0a6b3db3538dd59e809e25d26f1ba590a83d85 Mon Sep 17 00:00:00 2001 From: dlg Date: Sun, 21 Feb 2021 03:35:17 +0000 Subject: [PATCH] cut bpe(4) over to using the common etherbridge code. it's pretty straightforward since etherbridge was mostly based on this code in the first place. the etherbridge_ops that bpe provides to etherbridge set entries up to point at mac addresses in the underlay network. ok patrick@ jmatthew@ --- sys/conf/files | 4 +- sys/net/if_bpe.c | 415 ++++++++++++++--------------------------------- 2 files changed, 127 insertions(+), 292 deletions(-) diff --git a/sys/conf/files b/sys/conf/files index efa0609f4de..0aedbec05f3 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.695 2021/02/21 03:26:46 dlg Exp $ +# $OpenBSD: files,v 1.696 2021/02/21 03:35:17 dlg Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -569,7 +569,7 @@ pseudo-device tpmr: ifnet, ether, ifmedia pseudo-device mpe: ifnet, mpls pseudo-device mpw: ifnet, mpls, ether pseudo-device mpip: ifnet, mpls -pseudo-device bpe: ifnet, ether, ifmedia +pseudo-device bpe: ifnet, ether, ifmedia, etherbridge pseudo-device vether: ifnet, ether pseudo-device pppx: ifnet pseudo-device vxlan: ifnet, ether, ifmedia diff --git a/sys/net/if_bpe.c b/sys/net/if_bpe.c index 64acc3429df..98c23c1a6d7 100644 --- a/sys/net/if_bpe.c +++ b/sys/net/if_bpe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bpe.c,v 1.15 2021/01/19 07:30:19 mvs Exp $ */ +/* $OpenBSD: if_bpe.c,v 1.16 2021/02/21 03:35:17 dlg Exp $ */ /* * Copyright (c) 2018 David Gwynne * @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,7 @@ /* for bridge stuff */ #include - +#include #if NBPFILTER > 0 #include @@ -74,42 +75,17 @@ static inline int bpe_cmp(const struct bpe_key *, const struct bpe_key *); RBT_PROTOTYPE(bpe_tree, bpe_key, k_entry, bpe_cmp); RBT_GENERATE(bpe_tree, bpe_key, k_entry, bpe_cmp); -struct bpe_entry { - struct ether_addr be_c_da; /* customer address - must be first */ - struct ether_addr be_b_da; /* bridge address */ - unsigned int be_type; -#define BPE_ENTRY_DYNAMIC 0 -#define BPE_ENTRY_STATIC 1 - struct refcnt be_refs; - time_t be_age; - - RBT_ENTRY(bpe_entry) be_entry; -}; - -RBT_HEAD(bpe_map, bpe_entry); - -static inline int bpe_entry_cmp(const struct bpe_entry *, - const struct bpe_entry *); - -RBT_PROTOTYPE(bpe_map, bpe_entry, be_entry, bpe_entry_cmp); -RBT_GENERATE(bpe_map, bpe_entry, be_entry, bpe_entry_cmp); - struct bpe_softc { struct bpe_key sc_key; /* must be first */ struct arpcom sc_ac; int sc_txhprio; int sc_rxhprio; - uint8_t sc_group[ETHER_ADDR_LEN]; + struct ether_addr sc_group; struct task sc_ltask; struct task sc_dtask; - struct bpe_map sc_bridge_map; - struct rwlock sc_bridge_lock; - unsigned int sc_bridge_num; - unsigned int sc_bridge_max; - int sc_bridge_tmo; /* seconds */ - struct timeout sc_bridge_age; + struct etherbridge sc_eb; }; void bpeattach(int); @@ -132,16 +108,26 @@ static void bpe_link_hook(void *); static void bpe_link_state(struct bpe_softc *, u_char, uint64_t); static void bpe_detach_hook(void *); -static void bpe_input_map(struct bpe_softc *, - const uint8_t *, const uint8_t *); -static void bpe_bridge_age(void *); - static struct if_clone bpe_cloner = IF_CLONE_INITIALIZER("bpe", bpe_clone_create, bpe_clone_destroy); +static int bpe_eb_port_eq(void *, void *, void *); +static void *bpe_eb_port_take(void *, void *); +static void bpe_eb_port_rele(void *, void *); +static size_t bpe_eb_port_ifname(void *, char *, size_t, void *); +static void bpe_eb_port_sa(void *, struct sockaddr_storage *, void *); + +static const struct etherbridge_ops bpe_etherbridge_ops = { + bpe_eb_port_eq, + bpe_eb_port_take, + bpe_eb_port_rele, + bpe_eb_port_ifname, + bpe_eb_port_sa, +}; + static struct bpe_tree bpe_interfaces = RBT_INITIALIZER(); static struct rwlock bpe_lock = RWLOCK_INITIALIZER("bpeifs"); -static struct pool bpe_entry_pool; +static struct pool bpe_endpoint_pool; void bpeattach(int count) @@ -154,18 +140,27 @@ bpe_clone_create(struct if_clone *ifc, int unit) { struct bpe_softc *sc; struct ifnet *ifp; + int error; - if (bpe_entry_pool.pr_size == 0) { - pool_init(&bpe_entry_pool, sizeof(struct bpe_entry), 0, + if (bpe_endpoint_pool.pr_size == 0) { + pool_init(&bpe_endpoint_pool, sizeof(struct ether_addr), 0, IPL_NONE, 0, "bpepl", NULL); } sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); + ifp = &sc->sc_ac.ac_if; snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", ifc->ifc_name, unit); + error = etherbridge_init(&sc->sc_eb, ifp->if_xname, + &bpe_etherbridge_ops, sc); + if (error == -1) { + free(sc, M_DEVBUF, sizeof(*sc)); + return (error); + } + sc->sc_key.k_if = 0; sc->sc_key.k_isid = 0; bpe_set_group(sc, 0); @@ -176,13 +171,6 @@ bpe_clone_create(struct if_clone *ifc, int unit) task_set(&sc->sc_ltask, bpe_link_hook, sc); task_set(&sc->sc_dtask, bpe_detach_hook, sc); - rw_init(&sc->sc_bridge_lock, "bpebr"); - RBT_INIT(bpe_map, &sc->sc_bridge_map); - sc->sc_bridge_num = 0; - sc->sc_bridge_max = 100; /* XXX */ - sc->sc_bridge_tmo = 240; - timeout_set_proc(&sc->sc_bridge_age, bpe_bridge_age, sc); - ifp->if_softc = sc; ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; ifp->if_ioctl = bpe_ioctl; @@ -211,25 +199,9 @@ bpe_clone_destroy(struct ifnet *ifp) ether_ifdetach(ifp); if_detach(ifp); - free(sc, M_DEVBUF, sizeof(*sc)); + etherbridge_destroy(&sc->sc_eb); - return (0); -} - -static inline int -bpe_entry_valid(struct bpe_softc *sc, const struct bpe_entry *be) -{ - time_t diff; - - if (be == NULL) - return (0); - - if (be->be_type == BPE_ENTRY_STATIC) - return (1); - - diff = getuptime() - be->be_age; - if (diff < sc->sc_bridge_tmo) - return (1); + free(sc, M_DEVBUF, sizeof(*sc)); return (0); } @@ -287,23 +259,21 @@ bpe_start(struct ifnet *ifp) beh = mtod(m, struct ether_header *); if (ETHER_IS_BROADCAST(ceh->ether_dhost)) { - memcpy(beh->ether_dhost, sc->sc_group, + memcpy(beh->ether_dhost, &sc->sc_group, sizeof(beh->ether_dhost)); } else { - struct bpe_entry *be; - - rw_enter_read(&sc->sc_bridge_lock); - be = RBT_FIND(bpe_map, &sc->sc_bridge_map, - (struct bpe_entry *)ceh->ether_dhost); - if (bpe_entry_valid(sc, be)) { - memcpy(beh->ether_dhost, &be->be_b_da, - sizeof(beh->ether_dhost)); - } else { + struct ether_addr *endpoint; + + smr_read_enter(); + endpoint = etherbridge_resolve(&sc->sc_eb, + (struct ether_addr *)ceh->ether_dhost); + if (endpoint == NULL) { /* "flood" to unknown hosts */ - memcpy(beh->ether_dhost, sc->sc_group, - sizeof(beh->ether_dhost)); + endpoint = &sc->sc_group; } - rw_exit_read(&sc->sc_bridge_lock); + memcpy(beh->ether_dhost, endpoint, + sizeof(beh->ether_dhost)); + smr_read_leave(); } memcpy(beh->ether_shost, ((struct arpcom *)ifp0)->ac_enaddr, @@ -326,121 +296,6 @@ done: if_put(ifp0); } -static void -bpe_bridge_age(void *arg) -{ - struct bpe_softc *sc = arg; - struct bpe_entry *be, *nbe; - time_t diff; - - timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO); - - rw_enter_write(&sc->sc_bridge_lock); - RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) { - if (be->be_type != BPE_ENTRY_DYNAMIC) - continue; - - diff = getuptime() - be->be_age; - if (diff < sc->sc_bridge_tmo) - continue; - - sc->sc_bridge_num--; - RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be); - if (refcnt_rele(&be->be_refs)) - pool_put(&bpe_entry_pool, be); - } - rw_exit_write(&sc->sc_bridge_lock); -} - -static int -bpe_rtfind(struct bpe_softc *sc, struct ifbaconf *baconf) -{ - struct ifnet *ifp = &sc->sc_ac.ac_if; - struct bpe_entry *be; - struct ifbareq bareq; - caddr_t uaddr, end; - int error; - time_t age; - struct sockaddr_dl *sdl; - - if (baconf->ifbac_len == 0) { - /* single read is atomic */ - baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq); - return (0); - } - - uaddr = baconf->ifbac_buf; - end = uaddr + baconf->ifbac_len; - - rw_enter_read(&sc->sc_bridge_lock); - RBT_FOREACH(be, bpe_map, &sc->sc_bridge_map) { - if (uaddr >= end) - break; - - memcpy(bareq.ifba_name, ifp->if_xname, - sizeof(bareq.ifba_name)); - memcpy(bareq.ifba_ifsname, ifp->if_xname, - sizeof(bareq.ifba_ifsname)); - memcpy(&bareq.ifba_dst, &be->be_c_da, - sizeof(bareq.ifba_dst)); - - memset(&bareq.ifba_dstsa, 0, sizeof(bareq.ifba_dstsa)); - - bzero(&bareq.ifba_dstsa, sizeof(bareq.ifba_dstsa)); - sdl = (struct sockaddr_dl *)&bareq.ifba_dstsa; - sdl->sdl_len = sizeof(sdl); - sdl->sdl_family = AF_LINK; - sdl->sdl_index = 0; - sdl->sdl_type = IFT_ETHER; - sdl->sdl_nlen = 0; - sdl->sdl_alen = sizeof(be->be_b_da); - CTASSERT(sizeof(sdl->sdl_data) >= sizeof(be->be_b_da)); - memcpy(sdl->sdl_data, &be->be_b_da, sizeof(be->be_b_da)); - - switch (be->be_type) { - case BPE_ENTRY_DYNAMIC: - age = getuptime() - be->be_age; - bareq.ifba_age = MIN(age, 0xff); - bareq.ifba_flags = IFBAF_DYNAMIC; - break; - case BPE_ENTRY_STATIC: - bareq.ifba_age = 0; - bareq.ifba_flags = IFBAF_STATIC; - break; - } - - error = copyout(&bareq, uaddr, sizeof(bareq)); - if (error != 0) { - rw_exit_read(&sc->sc_bridge_lock); - return (error); - } - - uaddr += sizeof(bareq); - } - baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq); - rw_exit_read(&sc->sc_bridge_lock); - - return (0); -} - -static void -bpe_flush_map(struct bpe_softc *sc, uint32_t flags) -{ - struct bpe_entry *be, *nbe; - - rw_enter_write(&sc->sc_bridge_lock); - RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) { - if (flags == IFBF_FLUSHDYN && - be->be_type != BPE_ENTRY_DYNAMIC) - continue; - - RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be); - if (refcnt_rele(&be->be_refs)) - pool_put(&bpe_entry_pool, be); - } - rw_exit_write(&sc->sc_bridge_lock); -} - static int bpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -510,16 +365,10 @@ bpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (error != 0) break; - if (bparam->ifbrp_csize < 1) { - error = EINVAL; - break; - } - - /* commit */ - sc->sc_bridge_max = bparam->ifbrp_csize; + error = etherbridge_set_max(&sc->sc_eb, bparam); break; case SIOCBRDGGCACHE: - bparam->ifbrp_csize = sc->sc_bridge_max; + error = etherbridge_get_max(&sc->sc_eb, bparam); break; case SIOCBRDGSTO: @@ -527,26 +376,22 @@ bpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) if (error != 0) break; - if (bparam->ifbrp_ctime < 8 || - bparam->ifbrp_ctime > 3600) { - error = EINVAL; - break; - } - sc->sc_bridge_tmo = bparam->ifbrp_ctime; + error = etherbridge_set_tmo(&sc->sc_eb, bparam); break; case SIOCBRDGGTO: - bparam->ifbrp_ctime = sc->sc_bridge_tmo; + error = etherbridge_get_tmo(&sc->sc_eb, bparam); break; case SIOCBRDGRTS: - error = bpe_rtfind(sc, (struct ifbaconf *)data); + error = etherbridge_rtfind(&sc->sc_eb, + (struct ifbaconf *)data); break; case SIOCBRDGFLUSH: error = suser(curproc); if (error != 0) break; - bpe_flush_map(sc, + etherbridge_flush(&sc->sc_eb, ((struct ifbreq *)data)->ifbr_ifsflags); break; @@ -580,16 +425,22 @@ bpe_up(struct bpe_softc *sc) struct ifnet *ifp = &sc->sc_ac.ac_if; struct ifnet *ifp0; struct bpe_softc *osc; - int error = 0; + int error; u_int hardmtu; u_int hlen = sizeof(struct ether_header) + sizeof(uint32_t); KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING)); NET_ASSERT_LOCKED(); + error = etherbridge_up(&sc->sc_eb); + if (error != 0) + return (error); + ifp0 = if_get(sc->sc_key.k_if); - if (ifp0 == NULL) - return (ENXIO); + if (ifp0 == NULL) { + error = ENXIO; + goto down; + } /* check again if bpe will work on top of the parent */ if (ifp0->if_type != IFT_ETHER) { @@ -643,8 +494,6 @@ bpe_up(struct bpe_softc *sc) if_put(ifp0); - timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO); - return (0); remove: @@ -656,6 +505,8 @@ scrub: ifp->if_hardmtu = 0xffff; put: if_put(ifp0); +down: + etherbridge_down(&sc->sc_eb); return (error); } @@ -685,6 +536,8 @@ bpe_down(struct bpe_softc *sc) CLR(ifp->if_flags, IFF_SIMPLEX); ifp->if_hardmtu = 0xffff; + etherbridge_down(&sc->sc_eb); + return (0); } @@ -702,7 +555,7 @@ bpe_multi(struct bpe_softc *sc, struct ifnet *ifp0, u_long cmd) CTASSERT(sizeof(sa->sa_data) >= sizeof(sc->sc_group)); sa->sa_family = AF_UNSPEC; - memcpy(sa->sa_data, sc->sc_group, sizeof(sc->sc_group)); + memcpy(sa->sa_data, &sc->sc_group, sizeof(sc->sc_group)); return ((*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)&ifr)); } @@ -710,7 +563,7 @@ bpe_multi(struct bpe_softc *sc, struct ifnet *ifp0, u_long cmd) static void bpe_set_group(struct bpe_softc *sc, uint32_t isid) { - uint8_t *group = sc->sc_group; + uint8_t *group = sc->sc_group.ether_addr_octet; group[0] = 0x01; group[1] = 0x1e; @@ -740,7 +593,7 @@ bpe_set_vnetid(struct bpe_softc *sc, const struct ifreq *ifr) /* commit */ sc->sc_key.k_isid = isid; bpe_set_group(sc, isid); - bpe_flush_map(sc, IFBF_FLUSHALL); + etherbridge_flush(&sc->sc_eb, IFBF_FLUSHALL); return (0); } @@ -771,7 +624,7 @@ bpe_set_parent(struct bpe_softc *sc, const struct if_parent *p) /* commit */ sc->sc_key.k_if = ifp0->if_index; - bpe_flush_map(sc, IFBF_FLUSHALL); + etherbridge_flush(&sc->sc_eb, IFBF_FLUSHALL); put: if_put(ifp0); @@ -804,7 +657,7 @@ bpe_del_parent(struct bpe_softc *sc) /* commit */ sc->sc_key.k_if = 0; - bpe_flush_map(sc, IFBF_FLUSHALL); + etherbridge_flush(&sc->sc_eb, IFBF_FLUSHALL); return (0); } @@ -822,75 +675,6 @@ bpe_find(struct ifnet *ifp0, uint32_t isid) return (sc); } -static void -bpe_input_map(struct bpe_softc *sc, const uint8_t *ba, const uint8_t *ca) -{ - struct bpe_entry *be; - int new = 0; - - if (ETHER_IS_MULTICAST(ca)) - return; - - /* remember where it came from */ - rw_enter_read(&sc->sc_bridge_lock); - be = RBT_FIND(bpe_map, &sc->sc_bridge_map, (struct bpe_entry *)ca); - if (be == NULL) - new = 1; - else { - be->be_age = getuptime(); /* only a little bit racy */ - - if (be->be_type != BPE_ENTRY_DYNAMIC || - ETHER_IS_EQ(ba, &be->be_b_da)) - be = NULL; - else - refcnt_take(&be->be_refs); - } - rw_exit_read(&sc->sc_bridge_lock); - - if (new) { - struct bpe_entry *obe; - unsigned int num; - - be = pool_get(&bpe_entry_pool, PR_NOWAIT); - if (be == NULL) { - /* oh well */ - return; - } - - memcpy(&be->be_c_da, ca, sizeof(be->be_c_da)); - memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); - be->be_type = BPE_ENTRY_DYNAMIC; - refcnt_init(&be->be_refs); - be->be_age = getuptime(); - - rw_enter_write(&sc->sc_bridge_lock); - num = sc->sc_bridge_num; - if (++num > sc->sc_bridge_max) - obe = be; - else { - /* try and give the ref to the map */ - obe = RBT_INSERT(bpe_map, &sc->sc_bridge_map, be); - if (obe == NULL) { - /* count the insert */ - sc->sc_bridge_num = num; - } - } - rw_exit_write(&sc->sc_bridge_lock); - - if (obe != NULL) - pool_put(&bpe_entry_pool, obe); - } else if (be != NULL) { - rw_enter_write(&sc->sc_bridge_lock); - memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); - rw_exit_write(&sc->sc_bridge_lock); - - if (refcnt_rele(&be->be_refs)) { - /* ioctl may have deleted the entry */ - pool_put(&bpe_entry_pool, be); - } - } -} - void bpe_input(struct ifnet *ifp0, struct mbuf *m) { @@ -928,7 +712,8 @@ bpe_input(struct ifnet *ifp0, struct mbuf *m) ceh = (struct ether_header *)(itagp + 1); - bpe_input_map(sc, beh->ether_shost, ceh->ether_shost); + etherbridge_map(&sc->sc_eb, ceh->ether_shost, + (struct ether_addr *)beh->ether_shost); m_adj(m, sizeof(*beh) + sizeof(*itagp)); @@ -1035,12 +820,62 @@ bpe_cmp(const struct bpe_key *a, const struct bpe_key *b) return (1); if (a->k_isid < b->k_isid) return (-1); - + return (0); } -static inline int -bpe_entry_cmp(const struct bpe_entry *a, const struct bpe_entry *b) +static int +bpe_eb_port_eq(void *arg, void *a, void *b) +{ + struct ether_addr *ea = a, *eb = b; + + return (memcmp(ea, eb, sizeof(*ea)) == 0); +} + +static void * +bpe_eb_port_take(void *arg, void *port) +{ + struct ether_addr *ea = port; + struct ether_addr *endpoint; + + endpoint = pool_get(&bpe_endpoint_pool, PR_NOWAIT); + if (endpoint == NULL) + return (NULL); + + memcpy(endpoint, ea, sizeof(*endpoint)); + + return (endpoint); +} + +static void +bpe_eb_port_rele(void *arg, void *port) +{ + struct ether_addr *endpoint = port; + + pool_put(&bpe_endpoint_pool, endpoint); +} + +static size_t +bpe_eb_port_ifname(void *arg, char *dst, size_t len, void *port) { - return memcmp(&a->be_c_da, &b->be_c_da, sizeof(a->be_c_da)); + struct bpe_softc *sc = arg; + + return (strlcpy(dst, sc->sc_ac.ac_if.if_xname, len)); +} + +static void +bpe_eb_port_sa(void *arg, struct sockaddr_storage *ss, void *port) +{ + struct ether_addr *endpoint = port; + struct sockaddr_dl *sdl; + + sdl = (struct sockaddr_dl *)ss; + sdl->sdl_len = sizeof(sdl); + sdl->sdl_family = AF_LINK; + sdl->sdl_index = 0; + sdl->sdl_type = IFT_ETHER; + sdl->sdl_nlen = 0; + sdl->sdl_alen = sizeof(*endpoint); + CTASSERT(sizeof(sdl->sdl_data) >= sizeof(*endpoint)); + memcpy(sdl->sdl_data, endpoint, sizeof(*endpoint)); } -- 2.20.1