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.c113
1 files changed, 91 insertions, 22 deletions
diff --git a/freebsd/sys/net/if_bridge.c b/freebsd/sys/net/if_bridge.c
index 5c15a78f..52146381 100644
--- a/freebsd/sys/net/if_bridge.c
+++ b/freebsd/sys/net/if_bridge.c
@@ -87,6 +87,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/protosw.h>
#include <sys/systm.h>
+#include <sys/jail.h>
#include <rtems/bsd/sys/time.h>
#include <sys/socket.h> /* for net/if.h */
#include <sys/sockio.h>
@@ -145,10 +146,10 @@ __FBSDID("$FreeBSD$");
#define BRIDGE_RTHASH_MASK (BRIDGE_RTHASH_SIZE - 1)
/*
- * Maximum number of addresses to cache.
+ * Default maximum number of addresses to cache.
*/
#ifndef BRIDGE_RTABLE_MAX
-#define BRIDGE_RTABLE_MAX 100
+#define BRIDGE_RTABLE_MAX 2000
#endif
/*
@@ -334,6 +335,10 @@ static int bridge_ip6_checkbasic(struct mbuf **mp);
#endif /* INET6 */
static int bridge_fragment(struct ifnet *, struct mbuf *,
struct ether_header *, int, struct llc *);
+static void bridge_linkstate(struct ifnet *ifp);
+static void bridge_linkcheck(struct bridge_softc *sc);
+
+extern void (*bridge_linkstate_p)(struct ifnet *ifp);
/* The default bridge vlan is 1 (IEEE 802.1Q-2003 Table 9-2) */
#define VLANTAGOF(_m) \
@@ -356,19 +361,26 @@ 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,
"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,
"Inherit MAC address from the first bridge member");
@@ -490,6 +502,7 @@ bridge_modevent(module_t mod, int type, void *data)
bridge_input_p = bridge_input;
bridge_output_p = bridge_output;
bridge_dn_p = bridge_dummynet;
+ bridge_linkstate_p = bridge_linkstate;
bridge_detach_cookie = EVENTHANDLER_REGISTER(
ifnet_departure_event, bridge_ifdetach, NULL,
EVENTHANDLER_PRI_ANY);
@@ -502,6 +515,7 @@ bridge_modevent(module_t mod, int type, void *data)
bridge_input_p = NULL;
bridge_output_p = NULL;
bridge_dn_p = NULL;
+ bridge_linkstate_p = NULL;
mtx_destroy(&bridge_list_mtx);
break;
default:
@@ -562,7 +576,8 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
{
struct bridge_softc *sc, *sc2;
struct ifnet *bifp, *ifp;
- int retry;
+ int fb, retry;
+ unsigned long hostid;
sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
@@ -595,17 +610,30 @@ bridge_clone_create(struct if_clone *ifc, int unit, caddr_t params)
IFQ_SET_READY(&ifp->if_snd);
/*
- * Generate a random ethernet address with a locally administered
- * address.
+ * Generate an ethernet address with a locally administered address.
*
* Since we are using random ethernet addresses for the bridge, it is
* possible that we might have address collisions, so make sure that
* this hardware address isn't already in use on another bridge.
+ * The first try uses the hostid and falls back to arc4rand().
*/
+ fb = 0;
+ getcredhostid(curthread->td_ucred, &hostid);
for (retry = 1; retry != 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 */
+ 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 */
+ } 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;
+ }
+
+ fb = 1;
retry = 0;
mtx_lock(&bridge_list_mtx);
LIST_FOREACH(sc2, &bridge_list, sc_list) {
@@ -939,6 +967,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
}
+ bridge_linkcheck(sc);
bridge_mutecaps(sc); /* recalcuate now this interface is removed */
bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
KASSERT(bif->bif_addrcnt == 0,
@@ -1066,17 +1095,16 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
/* Set interface capabilities to the intersection set of all members */
bridge_mutecaps(sc);
+ bridge_linkcheck(sc);
+ /* Place the interface into promiscuous mode */
switch (ifs->if_type) {
- case IFT_ETHER:
- case IFT_L2VLAN:
- /*
- * Place the interface into promiscuous mode.
- */
- BRIDGE_UNLOCK(sc);
- error = ifpromisc(ifs, 1);
- BRIDGE_LOCK(sc);
- break;
+ case IFT_ETHER:
+ case IFT_L2VLAN:
+ BRIDGE_UNLOCK(sc);
+ error = ifpromisc(ifs, 1);
+ BRIDGE_LOCK(sc);
+ break;
}
if (error)
bridge_delete_member(sc, bif, 0);
@@ -2195,11 +2223,9 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
/* Tap off 802.1D packets; they do not get forwarded. */
if (memcmp(eh->ether_dhost, bstp_etheraddr,
ETHER_ADDR_LEN) == 0) {
- m = bstp_input(&bif->bif_stp, ifp, m);
- if (m == NULL) {
- BRIDGE_UNLOCK(sc);
- return (NULL);
- }
+ bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */
+ BRIDGE_UNLOCK(sc);
+ return (NULL);
}
if ((bif->bif_flags & IFBIF_STP) &&
@@ -3456,3 +3482,46 @@ out:
m_freem(m);
return (error);
}
+
+static void
+bridge_linkstate(struct ifnet *ifp)
+{
+ struct bridge_softc *sc = ifp->if_bridge;
+ struct bridge_iflist *bif;
+
+ BRIDGE_LOCK(sc);
+ bif = bridge_lookup_member_if(sc, ifp);
+ if (bif == NULL) {
+ BRIDGE_UNLOCK(sc);
+ return;
+ }
+ bridge_linkcheck(sc);
+ BRIDGE_UNLOCK(sc);
+
+ bstp_linkstate(&bif->bif_stp);
+}
+
+static void
+bridge_linkcheck(struct bridge_softc *sc)
+{
+ struct bridge_iflist *bif;
+ int new_link, hasls;
+
+ BRIDGE_LOCK_ASSERT(sc);
+ new_link = LINK_STATE_DOWN;
+ hasls = 0;
+ /* Our link is considered up if at least one of our ports is active */
+ LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
+ if (bif->bif_ifp->if_capabilities & IFCAP_LINKSTATE)
+ hasls++;
+ if (bif->bif_ifp->if_link_state == LINK_STATE_UP) {
+ new_link = LINK_STATE_UP;
+ break;
+ }
+ }
+ if (!LIST_EMPTY(&sc->sc_iflist) && !hasls) {
+ /* If no interfaces support link-state then we default to up */
+ new_link = LINK_STATE_UP;
+ }
+ if_link_state_change(sc->sc_ifp, new_link);
+}