summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/net/if_bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/net/if_bridge.c')
-rw-r--r--freebsd/sys/net/if_bridge.c208
1 files changed, 108 insertions, 100 deletions
diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c
index aa56be48..18e0e7bf 100644
--- a/freebsd/sys/net/if_bridge.c
+++ b/freebsd/sys/net/if_bridge.c
@@ -228,7 +228,7 @@ struct bridge_softc {
struct bstp_state sc_stp; /* STP state */
uint32_t sc_brtexceeded; /* # of cache drops */
struct ifnet *sc_ifaddr; /* member mac copied from */
- u_char sc_defaddr[6]; /* Default MAC address */
+ struct ether_addr sc_defaddr; /* Default MAC address */
};
VNET_DEFINE_STATIC(struct mtx, bridge_list_mtx);
@@ -237,7 +237,8 @@ static eventhandler_tag bridge_detach_cookie;
int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD;
-uma_zone_t bridge_rtnode_zone;
+VNET_DEFINE_STATIC(uma_zone_t, bridge_rtnode_zone);
+#define V_bridge_rtnode_zone VNET(bridge_rtnode_zone)
static int bridge_clone_create(struct if_clone *, int, caddr_t);
static void bridge_clone_destroy(struct ifnet *);
@@ -529,6 +530,9 @@ static void
vnet_bridge_init(const void *unused __unused)
{
+ V_bridge_rtnode_zone = uma_zcreate("bridge_rtnode",
+ sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL,
+ UMA_ALIGN_PTR, 0);
BRIDGE_LIST_LOCK_INIT();
LIST_INIT(&V_bridge_list);
V_bridge_cloner = if_clone_simple(bridge_name,
@@ -544,6 +548,7 @@ vnet_bridge_uninit(const void *unused __unused)
if_clone_detach(V_bridge_cloner);
V_bridge_cloner = NULL;
BRIDGE_LIST_LOCK_DESTROY();
+ uma_zdestroy(V_bridge_rtnode_zone);
}
VNET_SYSUNINIT(vnet_bridge_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
vnet_bridge_uninit, NULL);
@@ -554,9 +559,6 @@ bridge_modevent(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
- bridge_rtnode_zone = uma_zcreate("bridge_rtnode",
- sizeof(struct bridge_rtnode), NULL, NULL, NULL, NULL,
- UMA_ALIGN_PTR, 0);
bridge_dn_p = bridge_dummynet;
bridge_detach_cookie = EVENTHANDLER_REGISTER(
ifnet_departure_event, bridge_ifdetach, NULL,
@@ -565,7 +567,6 @@ bridge_modevent(module_t mod, int type, void *data)
case MOD_UNLOAD:
EVENTHANDLER_DEREGISTER(ifnet_departure_event,
bridge_detach_cookie);
- uma_zdestroy(bridge_rtnode_zone);
bridge_dn_p = NULL;
break;
default:
@@ -672,16 +673,14 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
getcredhostid(curthread->td_ucred, &hostid);
do {
if (fb || hostid == 0) {
- arc4rand(sc->sc_defaddr, ETHER_ADDR_LEN, 1);
- sc->sc_defaddr[0] &= ~1;/* clear multicast bit */
- sc->sc_defaddr[0] |= 2; /* set the LAA bit */
+ ether_gen_addr(ifp, &sc->sc_defaddr);
} else {
- sc->sc_defaddr[0] = 0x2;
- sc->sc_defaddr[1] = (hostid >> 24) & 0xff;
- sc->sc_defaddr[2] = (hostid >> 16) & 0xff;
- sc->sc_defaddr[3] = (hostid >> 8 ) & 0xff;
- sc->sc_defaddr[4] = hostid & 0xff;
- sc->sc_defaddr[5] = ifp->if_dunit & 0xff;
+ sc->sc_defaddr.octet[0] = 0x2;
+ sc->sc_defaddr.octet[1] = (hostid >> 24) & 0xff;
+ sc->sc_defaddr.octet[2] = (hostid >> 16) & 0xff;
+ sc->sc_defaddr.octet[3] = (hostid >> 8 ) & 0xff;
+ sc->sc_defaddr.octet[4] = hostid & 0xff;
+ sc->sc_defaddr.octet[5] = ifp->if_dunit & 0xff;
}
fb = 1;
@@ -689,7 +688,7 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
BRIDGE_LIST_LOCK();
LIST_FOREACH(sc2, &V_bridge_list, sc_list) {
bifp = sc2->sc_ifp;
- if (memcmp(sc->sc_defaddr,
+ if (memcmp(sc->sc_defaddr.octet,
IF_LLADDR(bifp), ETHER_ADDR_LEN) == 0) {
retry = 1;
break;
@@ -699,7 +698,7 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
} while (retry == 1);
bstp_attach(&sc->sc_stp, &bridge_ops);
- ether_ifattach(ifp, sc->sc_defaddr);
+ ether_ifattach(ifp, sc->sc_defaddr.octet);
/* Now undo some of the damage... */
ifp->if_baudrate = 0;
ifp->if_type = IFT_BRIDGE;
@@ -734,6 +733,9 @@ bridge_clone_destroy(struct ifnet *ifp)
bridge_delete_span(sc, bif);
}
+ /* Tear down the routing table. */
+ bridge_rtable_fini(sc);
+
BRIDGE_UNLOCK(sc);
callout_drain(&sc->sc_brcallout);
@@ -746,9 +748,6 @@ bridge_clone_destroy(struct ifnet *ifp)
ether_ifdetach(ifp);
if_free(ifp);
- /* Tear down the routing table. */
- bridge_rtable_fini(sc);
-
BRIDGE_LOCK_DESTROY(sc);
free(sc, M_DEVBUF);
}
@@ -927,7 +926,7 @@ bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set)
{
struct ifnet *ifp = bif->bif_ifp;
struct ifreq ifr;
- int error;
+ int error, mask, stuck;
BRIDGE_UNLOCK_ASSERT(sc);
@@ -940,10 +939,12 @@ bridge_set_ifcap(struct bridge_softc *sc, struct bridge_iflist *bif, int set)
if_printf(sc->sc_ifp,
"error setting capabilities on %s: %d\n",
ifp->if_xname, error);
- if ((ifp->if_capenable & ~set) != 0)
+ mask = BRIDGE_IFCAPS_MASK | BRIDGE_IFCAPS_STRIP;
+ stuck = ifp->if_capenable & mask & ~set;
+ if (stuck != 0)
if_printf(sc->sc_ifp,
"can't disable some capabilities on %s: 0x%x\n",
- ifp->if_xname, ifp->if_capenable & ~set);
+ ifp->if_xname, stuck);
}
}
@@ -1018,7 +1019,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
*/
if (V_bridge_inherit_mac && sc->sc_ifaddr == ifs) {
if (LIST_EMPTY(&sc->sc_iflist)) {
- bcopy(sc->sc_defaddr,
+ bcopy(&sc->sc_defaddr,
IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
sc->sc_ifaddr = NULL;
} else {
@@ -1189,7 +1190,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
* the default randomly generated one.
*/
if (V_bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) &&
- !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) {
+ !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr.octet, ETHER_ADDR_LEN)) {
bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
sc->sc_ifaddr = ifs;
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
@@ -1972,9 +1973,9 @@ bridge_dummynet(struct mbuf *m, struct ifnet *ifp)
return;
}
- if (PFIL_HOOKED(&V_inet_pfil_hook)
+ if (PFIL_HOOKED_OUT(V_inet_pfil_head)
#ifdef INET6
- || PFIL_HOOKED(&V_inet6_pfil_hook)
+ || PFIL_HOOKED_OUT(V_inet6_pfil_head)
#endif
) {
if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0)
@@ -2001,7 +2002,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
struct rtentry *rt)
{
struct ether_header *eh;
- struct ifnet *dst_if;
+ struct ifnet *bifp, *dst_if;
struct bridge_softc *sc;
uint16_t vlan;
@@ -2016,13 +2017,14 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
vlan = VLANTAGOF(m);
BRIDGE_LOCK(sc);
+ bifp = sc->sc_ifp;
/*
* If bridge is down, but the original output interface is up,
* go ahead and send out that interface. Otherwise, the packet
* is dropped below.
*/
- if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ if ((bifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
dst_if = ifp;
goto sendunicast;
}
@@ -2035,6 +2037,9 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
dst_if = NULL;
else
dst_if = bridge_rtlookup(sc, eh->ether_dhost, vlan);
+ /* Tap any traffic not passing back out the originating interface */
+ if (dst_if != ifp)
+ ETHER_BPF_MTAP(bifp, m);
if (dst_if == NULL) {
struct bridge_iflist *bif;
struct mbuf *mc;
@@ -2072,7 +2077,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
} else {
mc = m_copypacket(m, M_NOWAIT);
if (mc == NULL) {
- if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
+ if_inc_counter(bifp, IFCOUNTER_OERRORS, 1);
continue;
}
}
@@ -2232,9 +2237,9 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
ETHER_BPF_MTAP(ifp, m);
/* run the packet filter */
- if (PFIL_HOOKED(&V_inet_pfil_hook)
+ if (PFIL_HOOKED_IN(V_inet_pfil_head)
#ifdef INET6
- || PFIL_HOOKED(&V_inet6_pfil_hook)
+ || PFIL_HOOKED_IN(V_inet6_pfil_head)
#endif
) {
BRIDGE_UNLOCK(sc);
@@ -2272,9 +2277,9 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif,
BRIDGE_UNLOCK(sc);
- if (PFIL_HOOKED(&V_inet_pfil_hook)
+ if (PFIL_HOOKED_OUT(V_inet_pfil_head)
#ifdef INET6
- || PFIL_HOOKED(&V_inet6_pfil_hook)
+ || PFIL_HOOKED_OUT(V_inet6_pfil_head)
#endif
) {
if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0)
@@ -2411,7 +2416,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
#ifdef INET6
# define OR_PFIL_HOOKED_INET6 \
- || PFIL_HOOKED(&V_inet6_pfil_hook)
+ || PFIL_HOOKED_IN(V_inet6_pfil_head)
#else
# define OR_PFIL_HOOKED_INET6
#endif
@@ -2423,22 +2428,6 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
if (memcmp(IF_LLADDR((iface)), eh->ether_dhost, ETHER_ADDR_LEN) == 0 \
OR_CARP_CHECK_WE_ARE_DST((iface)) \
) { \
- if ((iface)->if_type == IFT_BRIDGE) { \
- ETHER_BPF_MTAP(iface, m); \
- if_inc_counter(iface, IFCOUNTER_IPACKETS, 1); \
- if_inc_counter(iface, IFCOUNTER_IBYTES, m->m_pkthdr.len); \
- /* Filter on the physical interface. */ \
- if (V_pfil_local_phys && \
- (PFIL_HOOKED(&V_inet_pfil_hook) \
- OR_PFIL_HOOKED_INET6)) { \
- if (bridge_pfil(&m, NULL, ifp, \
- PFIL_IN) != 0 || m == NULL) { \
- BRIDGE_UNLOCK(sc); \
- return (NULL); \
- } \
- eh = mtod(m, struct ether_header *); \
- } \
- } \
if (bif->bif_flags & IFBIF_LEARNING) { \
error = bridge_rtupdate(sc, eh->ether_shost, \
vlan, bif, 0, IFBAF_DYNAMIC); \
@@ -2449,6 +2438,26 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
} \
} \
m->m_pkthdr.rcvif = iface; \
+ if ((iface) == ifp) { \
+ /* Skip bridge processing... src == dest */ \
+ BRIDGE_UNLOCK(sc); \
+ return (m); \
+ } \
+ /* It's passing over or to the bridge, locally. */ \
+ ETHER_BPF_MTAP(bifp, m); \
+ if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); \
+ if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); \
+ /* Filter on the physical interface. */ \
+ if (V_pfil_local_phys && (PFIL_HOOKED_IN(V_inet_pfil_head) \
+ OR_PFIL_HOOKED_INET6)) { \
+ if (bridge_pfil(&m, NULL, ifp, \
+ PFIL_IN) != 0 || m == NULL) { \
+ BRIDGE_UNLOCK(sc); \
+ return (NULL); \
+ } \
+ } \
+ if ((iface) != bifp) \
+ ETHER_BPF_MTAP(iface, m); \
BRIDGE_UNLOCK(sc); \
return (m); \
} \
@@ -2519,9 +2528,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
}
/* Filter on the bridge interface before broadcasting */
- if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook)
+ if (runfilt && (PFIL_HOOKED_OUT(V_inet_pfil_head)
#ifdef INET6
- || PFIL_HOOKED(&V_inet6_pfil_hook)
+ || PFIL_HOOKED_OUT(V_inet6_pfil_head)
#endif
)) {
if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0)
@@ -2566,9 +2575,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
* pointer so we do not redundantly filter on the bridge for
* each interface we broadcast on.
*/
- if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook)
+ if (runfilt && (PFIL_HOOKED_OUT(V_inet_pfil_head)
#ifdef INET6
- || PFIL_HOOKED(&V_inet6_pfil_hook)
+ || PFIL_HOOKED_OUT(V_inet6_pfil_head)
#endif
)) {
if (used == 0) {
@@ -2671,7 +2680,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan,
* initialize the expiration time and Ethernet
* address.
*/
- brt = uma_zalloc(bridge_rtnode_zone, M_NOWAIT | M_ZERO);
+ brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO);
if (brt == NULL)
return (ENOMEM);
@@ -2684,7 +2693,7 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst, uint16_t vlan,
brt->brt_vlan = vlan;
if ((error = bridge_rtnode_insert(sc, brt)) != 0) {
- uma_zfree(bridge_rtnode_zone, brt);
+ uma_zfree(V_bridge_rtnode_zone, brt);
return (error);
}
brt->brt_dst = bif;
@@ -2768,11 +2777,14 @@ bridge_timer(void *arg)
BRIDGE_LOCK_ASSERT(sc);
+ /* Destruction of rtnodes requires a proper vnet context */
+ CURVNET_SET(sc->sc_ifp->if_vnet);
bridge_rtage(sc);
if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
callout_reset(&sc->sc_brcallout,
bridge_rtable_prune_period * hz, bridge_timer, sc);
+ CURVNET_RESTORE();
}
/*
@@ -3030,7 +3042,7 @@ bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt)
LIST_REMOVE(brt, brt_list);
sc->sc_brtcnt--;
brt->brt_dst->bif_addrcnt--;
- uma_zfree(bridge_rtnode_zone, brt);
+ uma_zfree(V_bridge_rtnode_zone, brt);
}
/*
@@ -3044,6 +3056,7 @@ bridge_rtable_expire(struct ifnet *ifp, int age)
struct bridge_softc *sc = ifp->if_bridge;
struct bridge_rtnode *brt;
+ CURVNET_SET(ifp->if_vnet);
BRIDGE_LOCK(sc);
/*
@@ -3062,6 +3075,7 @@ bridge_rtable_expire(struct ifnet *ifp, int age)
}
}
BRIDGE_UNLOCK(sc);
+ CURVNET_RESTORE();
}
/*
@@ -3103,6 +3117,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
struct ip *ip;
struct llc llc1;
u_int16_t ether_type;
+ pfil_return_t rv;
snap = 0;
error = -1; /* Default error if not error == 0 */
@@ -3174,14 +3189,14 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
}
/* 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, 0,
- NULL);
-
- if (*mp == NULL || error != 0) /* packet consumed by filter */
- return (error);
+ if (PFIL_HOOKED_OUT(V_link_pfil_head) && V_pfil_ipfw != 0 &&
+ dir == PFIL_OUT && ifp != NULL) {
+ switch (pfil_run_hooks(V_link_pfil_head, mp, ifp, dir, NULL)) {
+ case PFIL_DROPPED:
+ return (EPERM);
+ case PFIL_CONSUMED:
+ return (0);
+ }
}
/* Strip off the Ethernet header and keep a copy. */
@@ -3219,6 +3234,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
/*
* Run the packet through pfil
*/
+ rv = PFIL_PASS;
switch (ether_type) {
case ETHERTYPE_IP:
/*
@@ -3228,25 +3244,19 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
* Keep the order:
* in_if -> bridge_if -> out_if
*/
- if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL)
- error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp,
- dir, 0, NULL);
-
- if (*mp == NULL || error != 0) /* filter may consume */
+ if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL && (rv =
+ pfil_run_hooks(V_inet_pfil_head, mp, bifp, dir, NULL)) !=
+ PFIL_PASS)
break;
- if (V_pfil_member && ifp != NULL)
- error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp,
- dir, 0, NULL);
-
- if (*mp == NULL || error != 0) /* filter may consume */
+ if (V_pfil_member && ifp != NULL && (rv =
+ pfil_run_hooks(V_inet_pfil_head, mp, ifp, dir, NULL)) !=
+ PFIL_PASS)
break;
- if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL)
- error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp,
- dir, 0, NULL);
-
- if (*mp == NULL || error != 0) /* filter may consume */
+ if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL && (rv =
+ pfil_run_hooks(V_inet_pfil_head, mp, bifp, dir, NULL)) !=
+ PFIL_PASS)
break;
/* check if we need to fragment the packet */
@@ -3282,35 +3292,33 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir)
break;
#ifdef INET6
case ETHERTYPE_IPV6:
- if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL)
- error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp,
- dir, 0, NULL);
-
- if (*mp == NULL || error != 0) /* filter may consume */
+ if (V_pfil_bridge && dir == PFIL_OUT && bifp != NULL && (rv =
+ pfil_run_hooks(V_inet6_pfil_head, mp, bifp, dir, NULL)) !=
+ PFIL_PASS)
break;
- if (V_pfil_member && ifp != NULL)
- error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp,
- dir, 0, NULL);
-
- if (*mp == NULL || error != 0) /* filter may consume */
+ if (V_pfil_member && ifp != NULL && (rv =
+ pfil_run_hooks(V_inet6_pfil_head, mp, ifp, dir, NULL)) !=
+ PFIL_PASS)
break;
- if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL)
- error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp,
- dir, 0, NULL);
+ if (V_pfil_bridge && dir == PFIL_IN && bifp != NULL && (rv =
+ pfil_run_hooks(V_inet6_pfil_head, mp, bifp, dir, NULL)) !=
+ PFIL_PASS)
+ break;
break;
#endif
+ }
+
+ switch (rv) {
+ case PFIL_CONSUMED:
+ return (0);
+ case PFIL_DROPPED:
+ return (EPERM);
default:
- error = 0;
break;
}
- if (*mp == NULL)
- return (error);
- if (error != 0)
- goto bad;
-
error = -1;
/*