diff --git a/share/man/man4/if_bridge.4 b/share/man/man4/if_bridge.4 index 09425f89c2de..41821132ce50 100644 --- a/share/man/man4/if_bridge.4 +++ b/share/man/man4/if_bridge.4 @@ -146,6 +146,9 @@ as on the interface on which the packet arrives or departs. .Pp The MTU of the first member interface to be added is used as the bridge MTU, all additional members are required to have exactly the same value. +.Pp +The TXCSUM capability is disabled for any interface added to the bridge, this +is restored when the interface is removed again. .Sh EXAMPLES The following when placed in the file .Pa /etc/rc.conf diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index ad462ae9caf1..1b0875b22621 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -170,6 +170,11 @@ __FBSDID("$FreeBSD$"); #define BRIDGE_RTABLE_PRUNE_PERIOD (5 * 60) #endif +/* + * List of capabilities to mask on the member interface. + */ +#define BRIDGE_IFCAPS_MASK IFCAP_TXCSUM + static struct mtx bridge_list_mtx; eventhandler_tag bridge_detach_cookie = NULL; @@ -181,6 +186,7 @@ static int bridge_clone_create(struct if_clone *, int); static void bridge_clone_destroy(struct ifnet *); static int bridge_ioctl(struct ifnet *, u_long, caddr_t); +static void bridge_mutecaps(struct bridge_iflist *, int); static void bridge_ifdetach(void *arg __unused, struct ifnet *); static void bridge_init(void *); static void bridge_dummynet(struct mbuf *, struct ifnet *); @@ -664,6 +670,42 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return (error); } +/* + * bridge_mutecaps: + * + * Clear or restore unwanted capabilities on the member interface + */ +static void +bridge_mutecaps(struct bridge_iflist *bif, int mute) +{ + struct ifnet *ifp = bif->bif_ifp; + struct ifreq ifr; + int error; + + if (ifp->if_ioctl == NULL) + return; + + bzero(&ifr, sizeof ifr); + ifr.ifr_reqcap = ifp->if_capenable; + + if (mute) { + /* mask off and save capabilities */ + bif->bif_mutecap = ifr.ifr_reqcap & BRIDGE_IFCAPS_MASK; + if (bif->bif_mutecap != 0) + ifr.ifr_reqcap &= ~BRIDGE_IFCAPS_MASK; + } else + /* restore muted capabilities */ + ifr.ifr_reqcap |= bif->bif_mutecap; + + + if (bif->bif_mutecap != 0) { + IFF_LOCKGIANT(ifp); + error = (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr); + IFF_UNLOCKGIANT(ifp); + } +} + + /* * bridge_lookup_member: * @@ -727,6 +769,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif, * Take the interface out of promiscuous mode. */ (void) ifpromisc(ifs, 0); + bridge_mutecaps(bif, 0); break; case IFT_GIF: @@ -810,6 +853,11 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) if (bif == NULL) return (ENOMEM); + bif->bif_ifp = ifs; + bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; + bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY; + bif->bif_path_cost = BSTP_DEFAULT_PATH_COST; + switch (ifs->if_type) { case IFT_ETHER: case IFT_L2VLAN: @@ -819,6 +867,8 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) error = ifpromisc(ifs, 1); if (error) goto out; + + bridge_mutecaps(bif, 1); break; case IFT_GIF: @@ -829,11 +879,6 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) goto out; } - bif->bif_ifp = ifs; - bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; - bif->bif_priority = BSTP_DEFAULT_PORT_PRIORITY; - bif->bif_path_cost = BSTP_DEFAULT_PATH_COST; - ifs->if_bridge = sc; /* * XXX: XLOCK HERE!?! @@ -1436,11 +1481,6 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) int len, err; short mflags; - /* - * Clear any in-bound checksum flags for this packet. - */ - m->m_pkthdr.csum_flags = 0; - len = m->m_pkthdr.len; mflags = m->m_flags; diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h index d54cb56d36a5..c512880bc1d5 100644 --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -248,6 +248,7 @@ struct bridge_iflist { uint8_t bif_priority; struct ifnet *bif_ifp; /* member if */ uint32_t bif_flags; /* member if flags */ + int bif_mutecap; /* member muted caps */ }; /*