diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-10-07 15:10:20 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-01-10 09:53:31 +0100 |
commit | c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch) | |
tree | ad4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sys/net/if_bridge.c | |
parent | userspace-header-gen.py: Simplify program ports (diff) | |
download | rtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2 |
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sys/net/if_bridge.c')
-rw-r--r-- | freebsd/sys/net/if_bridge.c | 476 |
1 files changed, 235 insertions, 241 deletions
diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c index 65553092..77b376b9 100644 --- a/freebsd/sys/net/if_bridge.c +++ b/freebsd/sys/net/if_bridge.c @@ -73,7 +73,7 @@ * - Currently only supports Ethernet-like interfaces (Ethernet, * 802.11, VLANs on Ethernet, etc.) Figure out a nice way * to bridge other types of interfaces (FDDI-FDDI, and maybe - * consider heterogenous bridges). + * consider heterogeneous bridges). */ #include <sys/cdefs.h> @@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_inet6.h> #include <rtems/bsd/sys/param.h> +#include <sys/eventhandler.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <sys/protosw.h> @@ -102,7 +103,6 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <rtems/bsd/sys/lock.h> #include <sys/mutex.h> -#include <sys/rwlock.h> #include <net/bpf.h> #include <net/if.h> @@ -113,7 +113,7 @@ __FBSDID("$FreeBSD$"); #include <net/pfil.h> #include <net/vnet.h> -#include <netinet/in.h> /* for struct arpcom */ +#include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/in_var.h> #include <netinet/ip.h> @@ -127,15 +127,13 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip_carp.h> #endif #include <machine/in_cksum.h> -#include <netinet/if_ether.h> /* for struct arpcom */ +#include <netinet/if_ether.h> #include <net/bridgestp.h> #include <net/if_bridgevar.h> #include <net/if_llc.h> #include <net/if_vlan_var.h> #include <net/route.h> -#include <netinet/ip_fw.h> -#include <netpfil/ipfw/ip_fw_private.h> /* * Size of the route hash table. Must be a power of two. @@ -170,7 +168,8 @@ __FBSDID("$FreeBSD$"); /* * List of capabilities to possibly mask on the member interface. */ -#define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM) +#define BRIDGE_IFCAPS_MASK (IFCAP_TOE|IFCAP_TSO|IFCAP_TXCSUM|\ + IFCAP_TXCSUM_IPV6) /* * List of capabilities to strip @@ -230,8 +229,9 @@ struct bridge_softc { u_char sc_defaddr[6]; /* Default MAC address */ }; -static struct mtx bridge_list_mtx; -eventhandler_tag bridge_detach_cookie = NULL; +static VNET_DEFINE(struct mtx, bridge_list_mtx); +#define V_bridge_list_mtx VNET(bridge_list_mtx) +static eventhandler_tag bridge_detach_cookie; int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; @@ -248,11 +248,12 @@ static void bridge_ifdetach(void *arg __unused, struct ifnet *); static void bridge_init(void *); static void bridge_dummynet(struct mbuf *, struct ifnet *); static void bridge_stop(struct ifnet *, int); -static void bridge_start(struct ifnet *); +static int bridge_transmit(struct ifnet *, struct mbuf *); +static void bridge_qflush(struct ifnet *); static struct mbuf *bridge_input(struct ifnet *, struct mbuf *); static int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); -static void bridge_enqueue(struct bridge_softc *, struct ifnet *, +static int bridge_enqueue(struct bridge_softc *, struct ifnet *, struct mbuf *); static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int); @@ -275,7 +276,7 @@ static void bridge_rtflush(struct bridge_softc *, int); static int bridge_rtdaddr(struct bridge_softc *, const uint8_t *, uint16_t); -static int bridge_rtable_init(struct bridge_softc *); +static void bridge_rtable_init(struct bridge_softc *); static void bridge_rtable_fini(struct bridge_softc *); static int bridge_rtnode_addr_cmp(const uint8_t *, const uint8_t *); @@ -353,43 +354,64 @@ static struct bstp_cb_ops bridge_ops = { SYSCTL_DECL(_net_link); static SYSCTL_NODE(_net_link, IFT_BRIDGE, bridge, CTLFLAG_RW, 0, "Bridge"); -static int pfil_onlyip = 1; /* only pass IP[46] packets when pfil is enabled */ -static int pfil_bridge = 1; /* run pfil hooks on the bridge interface */ -static int pfil_member = 1; /* run pfil hooks on the member interface */ -static int pfil_ipfw = 0; /* layer2 filter with ipfw */ -static int pfil_ipfw_arp = 0; /* layer2 filter with ipfw */ -static int pfil_local_phys = 0; /* run pfil hooks on the physical interface for - locally destined packets */ -static int log_stp = 0; /* log STP state changes */ -static int bridge_inherit_mac = 0; /* share MAC with first bridge member */ -TUNABLE_INT("net.link.bridge.pfil_onlyip", &pfil_onlyip); -SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, CTLFLAG_RW, - &pfil_onlyip, 0, "Only pass IP packets when pfil is enabled"); -TUNABLE_INT("net.link.bridge.ipfw_arp", &pfil_ipfw_arp); -SYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp, CTLFLAG_RW, - &pfil_ipfw_arp, 0, "Filter ARP packets through IPFW layer2"); -TUNABLE_INT("net.link.bridge.pfil_bridge", &pfil_bridge); -SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, CTLFLAG_RW, - &pfil_bridge, 0, "Packet filter on the bridge interface"); -TUNABLE_INT("net.link.bridge.pfil_member", &pfil_member); -SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, CTLFLAG_RW, - &pfil_member, 0, "Packet filter on the member interface"); -TUNABLE_INT("net.link.bridge.pfil_local_phys", &pfil_local_phys); -SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, CTLFLAG_RW, - &pfil_local_phys, 0, +/* only pass IP[46] packets when pfil is enabled */ +static VNET_DEFINE(int, pfil_onlyip) = 1; +#define V_pfil_onlyip VNET(pfil_onlyip) +SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_onlyip, + CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_onlyip), 0, + "Only pass IP packets when pfil is enabled"); + +/* run pfil hooks on the bridge interface */ +static VNET_DEFINE(int, pfil_bridge) = 1; +#define V_pfil_bridge VNET(pfil_bridge) +SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_bridge, + CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_bridge), 0, + "Packet filter on the bridge interface"); + +/* layer2 filter with ipfw */ +static VNET_DEFINE(int, pfil_ipfw); +#define V_pfil_ipfw VNET(pfil_ipfw) + +/* layer2 ARP filter with ipfw */ +static VNET_DEFINE(int, pfil_ipfw_arp); +#define V_pfil_ipfw_arp VNET(pfil_ipfw_arp) +SYSCTL_INT(_net_link_bridge, OID_AUTO, ipfw_arp, + CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_ipfw_arp), 0, + "Filter ARP packets through IPFW layer2"); + +/* run pfil hooks on the member interface */ +static VNET_DEFINE(int, pfil_member) = 1; +#define V_pfil_member VNET(pfil_member) +SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_member, + CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_member), 0, + "Packet filter on the member interface"); + +/* run pfil hooks on the physical interface for locally destined packets */ +static VNET_DEFINE(int, pfil_local_phys); +#define V_pfil_local_phys VNET(pfil_local_phys) +SYSCTL_INT(_net_link_bridge, OID_AUTO, pfil_local_phys, + CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(pfil_local_phys), 0, "Packet filter on the physical interface for locally destined packets"); -TUNABLE_INT("net.link.bridge.log_stp", &log_stp); -SYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, CTLFLAG_RW, - &log_stp, 0, "Log STP state changes"); -TUNABLE_INT("net.link.bridge.inherit_mac", &bridge_inherit_mac); -SYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac, CTLFLAG_RW, - &bridge_inherit_mac, 0, + +/* log STP state changes */ +static VNET_DEFINE(int, log_stp); +#define V_log_stp VNET(log_stp) +SYSCTL_INT(_net_link_bridge, OID_AUTO, log_stp, + CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(log_stp), 0, + "Log STP state changes"); + +/* share MAC with first bridge member */ +static VNET_DEFINE(int, bridge_inherit_mac); +#define V_bridge_inherit_mac VNET(bridge_inherit_mac) +SYSCTL_INT(_net_link_bridge, OID_AUTO, inherit_mac, + CTLFLAG_RWTUN | CTLFLAG_VNET, &VNET_NAME(bridge_inherit_mac), 0, "Inherit MAC address from the first bridge member"); static VNET_DEFINE(int, allow_llz_overlap) = 0; #define V_allow_llz_overlap VNET(allow_llz_overlap) -SYSCTL_VNET_INT(_net_link_bridge, OID_AUTO, allow_llz_overlap, CTLFLAG_RW, - &VNET_NAME(allow_llz_overlap), 0, "Allow overlap of link-local scope " +SYSCTL_INT(_net_link_bridge, OID_AUTO, allow_llz_overlap, + CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(allow_llz_overlap), 0, + "Allow overlap of link-local scope " "zones of a bridge interface and the member interfaces"); struct bridge_control { @@ -487,12 +509,43 @@ const struct bridge_control bridge_control_table[] = { BC_F_COPYIN|BC_F_SUSER }, }; -const int bridge_control_table_size = - sizeof(bridge_control_table) / sizeof(bridge_control_table[0]); +const int bridge_control_table_size = nitems(bridge_control_table); + +static VNET_DEFINE(LIST_HEAD(, bridge_softc), bridge_list); +#define V_bridge_list VNET(bridge_list) +#define BRIDGE_LIST_LOCK_INIT(x) mtx_init(&V_bridge_list_mtx, \ + "if_bridge list", NULL, MTX_DEF) +#define BRIDGE_LIST_LOCK_DESTROY(x) mtx_destroy(&V_bridge_list_mtx) +#define BRIDGE_LIST_LOCK(x) mtx_lock(&V_bridge_list_mtx) +#define BRIDGE_LIST_UNLOCK(x) mtx_unlock(&V_bridge_list_mtx) + +static VNET_DEFINE(struct if_clone *, bridge_cloner); +#define V_bridge_cloner VNET(bridge_cloner) -LIST_HEAD(, bridge_softc) bridge_list; +static const char bridge_name[] = "bridge"; + +static void +vnet_bridge_init(const void *unused __unused) +{ + + BRIDGE_LIST_LOCK_INIT(); + LIST_INIT(&V_bridge_list); + V_bridge_cloner = if_clone_simple(bridge_name, + bridge_clone_create, bridge_clone_destroy, 0); +} +VNET_SYSINIT(vnet_bridge_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_bridge_init, NULL); + +static void +vnet_bridge_uninit(const void *unused __unused) +{ -IFC_SIMPLE_DECLARE(bridge, 0); + if_clone_detach(V_bridge_cloner); + V_bridge_cloner = NULL; + BRIDGE_LIST_LOCK_DESTROY(); +} +VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, + vnet_bridge_uninit, NULL); static int bridge_modevent(module_t mod, int type, void *data) @@ -500,12 +553,9 @@ bridge_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: - mtx_init(&bridge_list_mtx, "if_bridge list", NULL, MTX_DEF); - if_clone_attach(&bridge_cloner); bridge_rtnode_zone = uma_zcreate("bridge_rtnode", sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - LIST_INIT(&bridge_list); bridge_input_p = bridge_input; bridge_output_p = bridge_output; bridge_dn_p = bridge_dummynet; @@ -517,13 +567,11 @@ bridge_modevent(module_t mod, int type, void *data) case MOD_UNLOAD: EVENTHANDLER_DEREGISTER(ifnet_departure_event, bridge_detach_cookie); - if_clone_detach(&bridge_cloner); uma_zdestroy(bridge_rtnode_zone); bridge_input_p = NULL; bridge_output_p = NULL; bridge_dn_p = NULL; bridge_linkstate_p = NULL; - mtx_destroy(&bridge_list_mtx); break; default: return (EOPNOTSUPP); @@ -541,19 +589,19 @@ DECLARE_MODULE(if_bridge, bridge_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); MODULE_DEPEND(if_bridge, bridgestp, 1, 1, 1); /* - * handler for net.link.bridge.pfil_ipfw + * handler for net.link.bridge.ipfw */ static int sysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS) { - int enable = pfil_ipfw; + int enable = V_pfil_ipfw; int error; error = sysctl_handle_int(oidp, &enable, 0, req); - enable = (enable) ? 1 : 0; + enable &= 1; - if (enable != pfil_ipfw) { - pfil_ipfw = enable; + if (enable != V_pfil_ipfw) { + V_pfil_ipfw = enable; /* * Disable pfil so that ipfw doesnt run twice, if the user @@ -561,17 +609,19 @@ sysctl_pfil_ipfw(SYSCTL_HANDLER_ARGS) * pfil_member. Also allow non-ip packets as ipfw can filter by * layer2 type. */ - if (pfil_ipfw) { - pfil_onlyip = 0; - pfil_bridge = 0; - pfil_member = 0; + if (V_pfil_ipfw) { + V_pfil_onlyip = 0; + V_pfil_bridge = 0; + V_pfil_member = 0; } } return (error); } -SYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, CTLTYPE_INT|CTLFLAG_RW, - &pfil_ipfw, 0, &sysctl_pfil_ipfw, "I", "Layer2 filter with IPFW"); +SYSCTL_PROC(_net_link_bridge, OID_AUTO, ipfw, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_VNET, + &VNET_NAME(pfil_ipfw), 0, &sysctl_pfil_ipfw, "I", + "Layer2 filter with IPFW"); /* * bridge_clone_create: @@ -606,15 +656,13 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) LIST_INIT(&sc->sc_spanlist); ifp->if_softc = sc; - if_initname(ifp, ifc->ifc_name, unit); + if_initname(ifp, bridge_name, unit); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = bridge_ioctl; - ifp->if_start = bridge_start; + ifp->if_transmit = bridge_transmit; + ifp->if_qflush = bridge_qflush; ifp->if_init = bridge_init; ifp->if_type = IFT_BRIDGE; - IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); - ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; - IFQ_SET_READY(&ifp->if_snd); /* * Generate an ethernet address with a locally administered address. @@ -626,7 +674,7 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) */ fb = 0; getcredhostid(curthread->td_ucred, &hostid); - for (retry = 1; retry != 0;) { + do { if (fb || hostid == 0) { arc4rand(sc->sc_defaddr, ETHER_ADDR_LEN, 1); sc->sc_defaddr[0] &= ~1;/* clear multicast bit */ @@ -642,15 +690,17 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) fb = 1; retry = 0; - mtx_lock(&bridge_list_mtx); - LIST_FOREACH(sc2, &bridge_list, sc_list) { + BRIDGE_LIST_LOCK(); + LIST_FOREACH(sc2, &V_bridge_list, sc_list) { bifp = sc2->sc_ifp; if (memcmp(sc->sc_defaddr, - IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) + IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) { retry = 1; + break; + } } - mtx_unlock(&bridge_list_mtx); - } + BRIDGE_LIST_UNLOCK(); + } while (retry == 1); bstp_attach(&sc->sc_stp, &bridge_ops); ether_ifattach(ifp, sc->sc_defaddr); @@ -658,9 +708,9 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params) ifp->if_baudrate = 0; ifp->if_type = IFT_BRIDGE; - mtx_lock(&bridge_list_mtx); - LIST_INSERT_HEAD(&bridge_list, sc, sc_list); - mtx_unlock(&bridge_list_mtx); + BRIDGE_LIST_LOCK(); + LIST_INSERT_HEAD(&V_bridge_list, sc, sc_list); + BRIDGE_LIST_UNLOCK(); return (0); } @@ -692,13 +742,13 @@ bridge_clone_destroy(struct ifnet *ifp) callout_drain(&sc->sc_brcallout); - mtx_lock(&bridge_list_mtx); + BRIDGE_LIST_LOCK(); LIST_REMOVE(sc, sc_list); - mtx_unlock(&bridge_list_mtx); + BRIDGE_LIST_UNLOCK(); bstp_detach(&sc->sc_stp); ether_ifdetach(ifp); - if_free_type(ifp, IFT_ETHER); + if_free(ifp); /* Tear down the routing table. */ bridge_rtable_fini(sc); @@ -818,7 +868,7 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) BRIDGE_LOCK(sc); LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { if (bif->bif_ifp->if_mtu != ifr->ifr_mtu) { - log(LOG_NOTICE, "%s: invalid MTU: %lu(%s)" + log(LOG_NOTICE, "%s: invalid MTU: %u(%s)" " != %d\n", sc->sc_ifp->if_xname, bif->bif_ifp->if_mtu, bif->bif_ifp->if_xname, ifr->ifr_mtu); @@ -960,7 +1010,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, * the mac address of the bridge to the address of the next member, or * to its default address if no members are left. */ - if (bridge_inherit_mac && sc->sc_ifaddr == ifs) { + if (V_bridge_inherit_mac && sc->sc_ifaddr == ifs) { if (LIST_EMPTY(&sc->sc_iflist)) { bcopy(sc->sc_defaddr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); @@ -986,9 +1036,12 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, case IFT_ETHER: case IFT_L2VLAN: /* - * Take the interface out of promiscuous mode. + * Take the interface out of promiscuous mode, but only + * if it was promiscuous in the first place. It might + * not be if we're in the bridge_ioctl_add() error path. */ - (void) ifpromisc(ifs, 0); + if (ifs->if_flags & IFF_PROMISC) + (void) ifpromisc(ifs, 0); break; case IFT_GIF: @@ -1108,7 +1161,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) if (LIST_EMPTY(&sc->sc_iflist)) sc->sc_ifp->if_mtu = ifs->if_mtu; else if (sc->sc_ifp->if_mtu != ifs->if_mtu) { - if_printf(sc->sc_ifp, "invalid MTU: %lu(%s) != %lu\n", + if_printf(sc->sc_ifp, "invalid MTU: %u(%s) != %u\n", ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu); return (EINVAL); } @@ -1126,7 +1179,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) * member and the MAC address of the bridge has not been changed from * the default randomly generated one. */ - if (bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) && + if (V_bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) && !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) { bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); sc->sc_ifaddr = ifs; @@ -1156,10 +1209,8 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) break; } - if (error) { + if (error) bridge_delete_member(sc, bif, 0); - free(bif, M_DEVBUF); - } return (error); } @@ -1751,7 +1802,13 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp) if (ifp->if_flags & IFF_RENAMING) return; - + if (V_bridge_cloner == NULL) { + /* + * This detach handler can be called after + * vnet_bridge_uninit(). Just return in that case. + */ + return; + } /* Check if the interface is a bridge member */ if (sc != NULL) { BRIDGE_LOCK(sc); @@ -1765,8 +1822,8 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp) } /* Check if the interface is a span port */ - mtx_lock(&bridge_list_mtx); - LIST_FOREACH(sc, &bridge_list, sc_list) { + BRIDGE_LIST_LOCK(); + LIST_FOREACH(sc, &V_bridge_list, sc_list) { BRIDGE_LOCK(sc); LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) if (ifp == bif->bif_ifp) { @@ -1776,7 +1833,7 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp) BRIDGE_UNLOCK(sc); } - mtx_unlock(&bridge_list_mtx); + BRIDGE_LIST_UNLOCK(); } /* @@ -1832,20 +1889,19 @@ bridge_stop(struct ifnet *ifp, int disable) * Enqueue a packet on a bridge member interface. * */ -static void +static int bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) { int len, err = 0; short mflags; struct mbuf *m0; - len = m->m_pkthdr.len; - mflags = m->m_flags; - /* We may be sending a fragment so traverse the mbuf */ for (; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = NULL; + len = m->m_pkthdr.len; + mflags = m->m_flags; /* * If underlying interface can not do VLAN tag insertion itself @@ -1857,7 +1913,7 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) if (m == NULL) { if_printf(dst_ifp, "unable to prepend VLAN header\n"); - dst_ifp->if_oerrors++; + if_inc_counter(dst_ifp, IFCOUNTER_OERRORS, 1); continue; } m->m_flags &= ~M_VLANTAG; @@ -1865,16 +1921,17 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) if ((err = dst_ifp->if_transmit(dst_ifp, m))) { m_freem(m0); + if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); break; } - } - if (err == 0) { - sc->sc_ifp->if_opackets++; - sc->sc_ifp->if_obytes += len; + if_inc_counter(sc->sc_ifp, IFCOUNTER_OPACKETS, 1); + if_inc_counter(sc->sc_ifp, IFCOUNTER_OBYTES, len); if (mflags & M_MCAST) - sc->sc_ifp->if_omcasts++; + if_inc_counter(sc->sc_ifp, IFCOUNTER_OMCASTS, 1); } + + return (err); } /* @@ -2000,9 +2057,9 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, used = 1; mc = m; } else { - mc = m_copypacket(m, M_DONTWAIT); + mc = m_copypacket(m, M_NOWAIT); if (mc == NULL) { - sc->sc_ifp->if_oerrors++; + if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); continue; } } @@ -2033,44 +2090,42 @@ sendunicast: } /* - * bridge_start: + * bridge_transmit: * - * Start output on a bridge. + * Do output on a bridge. * */ -static void -bridge_start(struct ifnet *ifp) +static int +bridge_transmit(struct ifnet *ifp, struct mbuf *m) { struct bridge_softc *sc; - struct mbuf *m; struct ether_header *eh; struct ifnet *dst_if; + int error = 0; sc = ifp->if_softc; - ifp->if_drv_flags |= IFF_DRV_OACTIVE; - for (;;) { - IFQ_DEQUEUE(&ifp->if_snd, m); - if (m == 0) - break; - ETHER_BPF_MTAP(ifp, m); + ETHER_BPF_MTAP(ifp, m); - eh = mtod(m, struct ether_header *); - dst_if = NULL; + eh = mtod(m, struct ether_header *); - BRIDGE_LOCK(sc); - if ((m->m_flags & (M_BCAST|M_MCAST)) == 0) { - dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1); - } + BRIDGE_LOCK(sc); + if (((m->m_flags & (M_BCAST|M_MCAST)) == 0) && + (dst_if = bridge_rtlookup(sc, eh->ether_dhost, 1)) != NULL) { + BRIDGE_UNLOCK(sc); + error = bridge_enqueue(sc, dst_if, m); + } else + bridge_broadcast(sc, ifp, m, 0); - if (dst_if == NULL) - bridge_broadcast(sc, ifp, m, 0); - else { - BRIDGE_UNLOCK(sc); - bridge_enqueue(sc, dst_if, m); - } - } - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + return (error); +} + +/* + * The ifp->if_qflush entry point for if_bridge(4) is no-op. + */ +static void +bridge_qflush(struct ifnet *ifp __unused) +{ } /* @@ -2094,8 +2149,8 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, src_if = m->m_pkthdr.rcvif; ifp = sc->sc_ifp; - ifp->if_ipackets++; - ifp->if_ibytes += m->m_pkthdr.len; + if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); + if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); vlan = VLANTAGOF(m); if ((sbif->bif_flags & IFBIF_STP) && @@ -2147,7 +2202,7 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, goto drop; /* ...forward it to all interfaces. */ - ifp->if_imcasts++; + if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); dst_if = NULL; } @@ -2255,8 +2310,8 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) if ((bifp->if_flags & IFF_MONITOR) != 0) { m->m_pkthdr.rcvif = bifp; ETHER_BPF_MTAP(bifp, m); - bifp->if_ipackets++; - bifp->if_ibytes += m->m_pkthdr.len; + if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); + if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); m_freem(m); return (NULL); } @@ -2291,7 +2346,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) * for bridge processing; return the original packet for * local processing. */ - mc = m_dup(m, M_DONTWAIT); + mc = m_dup(m, M_NOWAIT); if (mc == NULL) { BRIDGE_UNLOCK(sc); return (m); @@ -2308,7 +2363,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) */ KASSERT(bifp->if_bridge == NULL, ("loop created in bridge_input")); - mc2 = m_dup(m, M_DONTWAIT); + mc2 = m_dup(m, M_NOWAIT); if (mc2 != NULL) { /* Keep the layer3 header aligned */ int i = min(mc2->m_pkthdr.len, max_protohdr); @@ -2357,9 +2412,10 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) ) { \ if ((iface)->if_type == IFT_BRIDGE) { \ ETHER_BPF_MTAP(iface, m); \ - iface->if_ipackets++; \ + if_inc_counter(iface, IFCOUNTER_IPACKETS, 1); \ + if_inc_counter(iface, IFCOUNTER_IBYTES, m->m_pkthdr.len); \ /* Filter on the physical interface. */ \ - if (pfil_local_phys && \ + if (V_pfil_local_phys && \ (PFIL_HOOKED(&V_inet_pfil_hook) \ OR_PFIL_HOOKED_INET6)) { \ if (bridge_pfil(&m, NULL, ifp, \ @@ -2485,9 +2541,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, mc = m; used = 1; } else { - mc = m_dup(m, M_DONTWAIT); + mc = m_dup(m, M_NOWAIT); if (mc == NULL) { - sc->sc_ifp->if_oerrors++; + if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); continue; } } @@ -2507,7 +2563,7 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, i = min(mc->m_pkthdr.len, max_protohdr); mc = m_copyup(mc, i, ETHER_ALIGN); if (mc == NULL) { - sc->sc_ifp->if_oerrors++; + if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); continue; } } @@ -2548,9 +2604,9 @@ bridge_span(struct bridge_softc *sc, struct mbuf *m) if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) continue; - mc = m_copypacket(m, M_DONTWAIT); + mc = m_copypacket(m, M_NOWAIT); if (mc == NULL) { - sc->sc_ifp->if_oerrors++; + if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); continue; } @@ -2793,24 +2849,19 @@ bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int full) * * Initialize the route table for this bridge. */ -static int +static void bridge_rtable_init(struct bridge_softc *sc) { int i; sc->sc_rthash = malloc(sizeof(*sc->sc_rthash) * BRIDGE_RTHASH_SIZE, - M_DEVBUF, M_NOWAIT); - if (sc->sc_rthash == NULL) - return (ENOMEM); + M_DEVBUF, M_WAITOK); for (i = 0; i < BRIDGE_RTHASH_SIZE; i++) LIST_INIT(&sc->sc_rthash[i]); sc->sc_rthash_key = arc4random(); - LIST_INIT(&sc->sc_rtlist); - - return (0); } /* @@ -3018,9 +3069,11 @@ bridge_state_change(struct ifnet *ifp, int state) "discarding" }; - if (log_stp) + CURVNET_SET(ifp->if_vnet); + if (V_log_stp) log(LOG_NOTICE, "%s: state changed to %s on %s\n", sc->sc_ifp->if_xname, stpstates[state], ifp->if_xname); + CURVNET_RESTORE(); } /* @@ -3034,7 +3087,6 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) { int snap, error, i, hlen; struct ether_header *eh1, eh2; - struct ip_fw_args args; struct ip *ip; struct llc llc1; u_int16_t ether_type; @@ -3047,7 +3099,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) KASSERT(M_WRITABLE(*mp), ("%s: modifying a shared mbuf", __func__)); #endif - if (pfil_bridge == 0 && pfil_member == 0 && pfil_ipfw == 0) + if (V_pfil_bridge == 0 && V_pfil_member == 0 && V_pfil_ipfw == 0) return (0); /* filtering is disabled */ i = min((*mp)->m_pkthdr.len, max_protohdr); @@ -3089,7 +3141,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) switch (ether_type) { case ETHERTYPE_ARP: case ETHERTYPE_REVARP: - if (pfil_ipfw_arp == 0) + if (V_pfil_ipfw_arp == 0) return (0); /* Automatically pass */ break; @@ -3104,10 +3156,20 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) * packets, these will not be checked by pfil(9) and * passed unconditionally so the default is to drop. */ - if (pfil_onlyip) + if (V_pfil_onlyip) goto bad; } + /* Run the packet through pfil before stripping link headers */ + if (PFIL_HOOKED(&V_link_pfil_hook) && V_pfil_ipfw != 0 && + dir == PFIL_OUT && ifp != NULL) { + + error = pfil_run_hooks(&V_link_pfil_hook, mp, ifp, dir, NULL); + + if (*mp == NULL || error != 0) /* packet consumed by filter */ + return (error); + } + /* Strip off the Ethernet header and keep a copy. */ m_copydata(*mp, 0, ETHER_HDR_LEN, (caddr_t) &eh2); m_adj(*mp, ETHER_HDR_LEN); @@ -3138,63 +3200,6 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) goto bad; } - /* XXX this section is also in if_ethersubr.c */ - // XXX PFIL_OUT or DIR_OUT ? - if (V_ip_fw_chk_ptr && pfil_ipfw != 0 && - dir == PFIL_OUT && ifp != NULL) { - struct m_tag *mtag; - - error = -1; - /* fetch the start point from existing tags, if any */ - mtag = m_tag_locate(*mp, MTAG_IPFW_RULE, 0, NULL); - if (mtag == NULL) { - args.rule.slot = 0; - } else { - struct ipfw_rule_ref *r; - - /* XXX can we free the tag after use ? */ - mtag->m_tag_id = PACKET_TAG_NONE; - r = (struct ipfw_rule_ref *)(mtag + 1); - /* packet already partially processed ? */ - if (r->info & IPFW_ONEPASS) - goto ipfwpass; - args.rule = *r; - } - - args.m = *mp; - args.oif = ifp; - args.next_hop = NULL; - args.next_hop6 = NULL; - args.eh = &eh2; - args.inp = NULL; /* used by ipfw uid/gid/jail rules */ - i = V_ip_fw_chk_ptr(&args); - *mp = args.m; - - if (*mp == NULL) - return (error); - - if (ip_dn_io_ptr && (i == IP_FW_DUMMYNET)) { - - /* put the Ethernet header back on */ - M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); - if (*mp == NULL) - return (error); - bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN); - - /* - * Pass the pkt to dummynet, which consumes it. The - * packet will return to us via bridge_dummynet(). - */ - args.oif = ifp; - ip_dn_io_ptr(mp, DIR_FWD | PROTO_IFB, &args); - return (error); - } - - if (i != IP_FW_PASS) /* drop */ - goto bad; - } - -ipfwpass: error = 0; /* @@ -3203,36 +3208,27 @@ ipfwpass: switch (ether_type) { case ETHERTYPE_IP: /* - * before calling the firewall, swap fields the same as - * IP does. here we assume the header is contiguous - */ - ip = mtod(*mp, struct ip *); - - ip->ip_len = ntohs(ip->ip_len); - ip->ip_off = ntohs(ip->ip_off); - - /* * Run pfil on the member interface and the bridge, both can * be skipped by clearing pfil_member or pfil_bridge. * * Keep the order: * in_if -> bridge_if -> out_if */ - if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) + if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL) error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; - if (pfil_member && ifp != NULL) + if (V_pfil_member && ifp != NULL) error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; - if (pfil_bridge && dir == PFIL_IN && bifp != NULL) + if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL) error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, dir, NULL); @@ -3240,7 +3236,7 @@ ipfwpass: break; /* check if we need to fragment the packet */ - if (pfil_member && ifp != NULL && dir == PFIL_OUT) { + if (V_pfil_member && ifp != NULL && dir == PFIL_OUT) { i = (*mp)->m_pkthdr.len; if (i > ifp->if_mtu) { error = bridge_fragment(ifp, *mp, &eh2, snap, @@ -3249,20 +3245,18 @@ ipfwpass: } } - /* Recalculate the ip checksum and restore byte ordering */ + /* Recalculate the ip checksum. */ ip = mtod(*mp, struct ip *); hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) goto bad; if (hlen > (*mp)->m_len) { - if ((*mp = m_pullup(*mp, hlen)) == 0) + if ((*mp = m_pullup(*mp, hlen)) == NULL) goto bad; ip = mtod(*mp, struct ip *); if (ip == NULL) goto bad; } - ip->ip_len = htons(ip->ip_len); - ip->ip_off = htons(ip->ip_off); ip->ip_sum = 0; if (hlen == sizeof(struct ip)) ip->ip_sum = in_cksum_hdr(ip); @@ -3272,21 +3266,21 @@ ipfwpass: break; #ifdef INET6 case ETHERTYPE_IPV6: - if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) + if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL) error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; - if (pfil_member && ifp != NULL) + if (V_pfil_member && ifp != NULL) error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; - if (pfil_bridge && dir == PFIL_IN && bifp != NULL) + if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL) error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, dir, NULL); break; @@ -3307,13 +3301,13 @@ ipfwpass: * Finally, put everything back the way it was and return */ if (snap) { - M_PREPEND(*mp, sizeof(struct llc), M_DONTWAIT); + M_PREPEND(*mp, sizeof(struct llc), M_NOWAIT); if (*mp == NULL) return (error); bcopy(&llc1, mtod(*mp, caddr_t), sizeof(struct llc)); } - M_PREPEND(*mp, ETHER_HDR_LEN, M_DONTWAIT); + M_PREPEND(*mp, ETHER_HDR_LEN, M_NOWAIT); if (*mp == NULL) return (error); bcopy(&eh2, mtod(*mp, caddr_t), ETHER_HDR_LEN); @@ -3375,7 +3369,7 @@ bridge_ip_checkbasic(struct mbuf **mp) goto bad; } if (hlen > m->m_len) { - if ((m = m_pullup(m, hlen)) == 0) { + if ((m = m_pullup(m, hlen)) == NULL) { KMOD_IPSTAT_INC(ips_badhlen); goto bad; } @@ -3499,8 +3493,8 @@ bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh, goto out; ip = mtod(m, struct ip *); - error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist, - CSUM_DELAY_IP); + m->m_pkthdr.csum_flags |= CSUM_IP; + error = ip_fragment(ip, &m, ifp->if_mtu, ifp->if_hwassist); if (error) goto out; @@ -3508,7 +3502,7 @@ bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh, for (m0 = m; m0; m0 = m0->m_nextpkt) { if (error == 0) { if (snap) { - M_PREPEND(m0, sizeof(struct llc), M_DONTWAIT); + M_PREPEND(m0, sizeof(struct llc), M_NOWAIT); if (m0 == NULL) { error = ENOBUFS; continue; @@ -3516,7 +3510,7 @@ bridge_fragment(struct ifnet *ifp, struct mbuf *m, struct ether_header *eh, bcopy(llc, mtod(m0, caddr_t), sizeof(struct llc)); } - M_PREPEND(m0, ETHER_HDR_LEN, M_DONTWAIT); + M_PREPEND(m0, ETHER_HDR_LEN, M_NOWAIT); if (m0 == NULL) { error = ENOBUFS; continue; |