MFC the lagg(4) driver which provides link aggregation, failover and fault
tolerance.
This commit is contained in:
parent
6e8d84bf2d
commit
1a4d003586
@ -1,7 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <bsd.own.mk>
|
||||
|
||||
.PATH: ${.CURDIR}/../../net
|
||||
KMOD= if_lagg
|
||||
SRCS= if_lagg.c ieee8023ad_lacp.c opt_inet.h opt_inet6.h
|
||||
@ -10,7 +8,7 @@ SRCS= if_lagg.c ieee8023ad_lacp.c opt_inet.h opt_inet6.h
|
||||
opt_inet.h:
|
||||
echo "#define INET 1" > ${.TARGET}
|
||||
|
||||
.if ${MK_INET6_SUPPORT} != "no"
|
||||
.if !defined(NO_INET6)
|
||||
opt_inet6.h:
|
||||
echo "#define INET6 1" > ${.TARGET}
|
||||
.endif
|
||||
|
@ -38,9 +38,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/socket.h> /* for net/if.h */
|
||||
#include <sys/sockio.h>
|
||||
#include <machine/stdarg.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
@ -114,9 +111,6 @@ static void lacp_aggregator_delref(struct lacp_softc *,
|
||||
|
||||
/* receive machine */
|
||||
|
||||
static void lacp_dequeue(void *, int);
|
||||
static int lacp_pdu_input(struct lagg_port *, struct mbuf *);
|
||||
static int lacp_marker_input(struct lagg_port *, struct mbuf *);
|
||||
static void lacp_sm_rx(struct lacp_port *, const struct lacpdu *);
|
||||
static void lacp_sm_rx_timer(struct lacp_port *);
|
||||
static void lacp_sm_rx_set_expired(struct lacp_port *);
|
||||
@ -208,66 +202,17 @@ static const lacp_timer_func_t lacp_timer_funcs[LACP_NTIMER] = {
|
||||
[LACP_TIMER_WAIT_WHILE] = lacp_sm_mux_timer,
|
||||
};
|
||||
|
||||
void
|
||||
lacp_input(struct lagg_port *lgp, struct mbuf *m)
|
||||
{
|
||||
struct lagg_softc *lgs = lgp->lp_lagg;
|
||||
struct lacp_softc *lsc = LACP_SOFTC(lgs);
|
||||
uint8_t subtype;
|
||||
|
||||
if (m->m_pkthdr.len < sizeof(struct ether_header) + sizeof(subtype)) {
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
|
||||
m_copydata(m, sizeof(struct ether_header), sizeof(subtype), &subtype);
|
||||
switch (subtype) {
|
||||
case SLOWPROTOCOLS_SUBTYPE_LACP:
|
||||
IF_HANDOFF(&lsc->lsc_queue, m, NULL);
|
||||
taskqueue_enqueue(taskqueue_swi, &lsc->lsc_qtask);
|
||||
break;
|
||||
|
||||
case SLOWPROTOCOLS_SUBTYPE_MARKER:
|
||||
lacp_marker_input(lgp, m);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unknown LACP packet type */
|
||||
m_freem(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lacp_dequeue(void *arg, int pending)
|
||||
{
|
||||
struct lacp_softc *lsc = (struct lacp_softc *)arg;
|
||||
struct lagg_softc *sc = lsc->lsc_lagg;
|
||||
struct lagg_port *lgp;
|
||||
struct mbuf *m;
|
||||
|
||||
LAGG_WLOCK(sc);
|
||||
for (;;) {
|
||||
IF_DEQUEUE(&lsc->lsc_queue, m);
|
||||
if (m == NULL)
|
||||
break;
|
||||
lgp = m->m_pkthdr.rcvif->if_lagg;
|
||||
lacp_pdu_input(lgp, m);
|
||||
}
|
||||
LAGG_WUNLOCK(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* lacp_pdu_input: process lacpdu
|
||||
* lacp_input: process lacpdu
|
||||
*/
|
||||
static int
|
||||
lacp_pdu_input(struct lagg_port *lgp, struct mbuf *m)
|
||||
int
|
||||
lacp_input(struct lagg_port *lgp, struct mbuf *m)
|
||||
{
|
||||
struct lacp_port *lp = LACP_PORT(lgp);
|
||||
struct lacpdu *du;
|
||||
int error = 0;
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgp->lp_lagg);
|
||||
LAGG_LOCK_ASSERT(lgp->lp_lagg);
|
||||
|
||||
if (__predict_false(lp->lp_flags & LACP_PORT_DETACHING)) {
|
||||
goto bad;
|
||||
@ -277,10 +222,6 @@ lacp_pdu_input(struct lagg_port *lgp, struct mbuf *m)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if ((m->m_flags & M_MCAST) == 0) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (m->m_len < sizeof(*du)) {
|
||||
m = m_pullup(m, sizeof(*du));
|
||||
if (m == NULL) {
|
||||
@ -358,7 +299,7 @@ lacp_xmit_lacpdu(struct lacp_port *lp)
|
||||
struct lacpdu *du;
|
||||
int error;
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgp->lp_lagg);
|
||||
LAGG_LOCK_ASSERT(lgp->lp_lagg);
|
||||
|
||||
m = m_gethdr(M_DONTWAIT, MT_DATA);
|
||||
if (m == NULL) {
|
||||
@ -415,7 +356,7 @@ lacp_linkstate(struct lagg_port *lgp)
|
||||
uint8_t old_state;
|
||||
uint16_t old_key;
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgp->lp_lagg);
|
||||
LAGG_LOCK_ASSERT(lgp->lp_lagg);
|
||||
|
||||
bzero((char *)&ifmr, sizeof(ifmr));
|
||||
error = (*ifp->if_ioctl)(ifp, SIOCGIFMEDIA, (caddr_t)&ifmr);
|
||||
@ -452,10 +393,8 @@ static void
|
||||
lacp_tick(void *arg)
|
||||
{
|
||||
struct lacp_softc *lsc = arg;
|
||||
struct lagg_softc *sc = lsc->lsc_lagg;
|
||||
struct lacp_port *lp;
|
||||
|
||||
LAGG_WLOCK(sc);
|
||||
LIST_FOREACH(lp, &lsc->lsc_ports, lp_next) {
|
||||
if ((lp->lp_state & LACP_STATE_AGGREGATION) == 0)
|
||||
continue;
|
||||
@ -467,7 +406,6 @@ lacp_tick(void *arg)
|
||||
lacp_sm_tx(lp);
|
||||
lacp_sm_ptx_tx_schedule(lp);
|
||||
}
|
||||
LAGG_WUNLOCK(sc);
|
||||
callout_reset(&lsc->lsc_callout, hz, lacp_tick, lsc);
|
||||
}
|
||||
|
||||
@ -485,7 +423,7 @@ lacp_port_create(struct lagg_port *lgp)
|
||||
boolean_t active = TRUE; /* XXX should be configurable */
|
||||
boolean_t fast = FALSE; /* XXX should be configurable */
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgs);
|
||||
LAGG_LOCK_ASSERT(lgs);
|
||||
|
||||
bzero((char *)&sdl, sizeof(sdl));
|
||||
sdl.sdl_len = sizeof(sdl);
|
||||
@ -511,7 +449,6 @@ lacp_port_create(struct lagg_port *lgp)
|
||||
lp->lp_ifp = ifp;
|
||||
lp->lp_lagg = lgp;
|
||||
lp->lp_lsc = lsc;
|
||||
lp->lp_ifma = rifma;
|
||||
|
||||
LIST_INSERT_HEAD(&lsc->lsc_ports, lp, lp_next);
|
||||
|
||||
@ -530,9 +467,11 @@ void
|
||||
lacp_port_destroy(struct lagg_port *lgp)
|
||||
{
|
||||
struct lacp_port *lp = LACP_PORT(lgp);
|
||||
int i;
|
||||
struct ifnet *ifp = lgp->lp_ifp;
|
||||
struct sockaddr_dl sdl;
|
||||
int i, error;
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgp->lp_lagg);
|
||||
LAGG_LOCK_ASSERT(lgp->lp_lagg);
|
||||
|
||||
for (i = 0; i < LACP_NTIMER; i++) {
|
||||
LACP_TIMER_DISARM(lp, i);
|
||||
@ -543,9 +482,18 @@ lacp_port_destroy(struct lagg_port *lgp)
|
||||
lacp_unselect(lp);
|
||||
lgp->lp_flags &= ~LAGG_PORT_DISABLED;
|
||||
|
||||
/* The address may have already been removed by if_purgemaddrs() */
|
||||
if (!lgp->lp_detaching)
|
||||
if_delmulti_ifma(lp->lp_ifma);
|
||||
bzero((char *)&sdl, sizeof(sdl));
|
||||
sdl.sdl_len = sizeof(sdl);
|
||||
sdl.sdl_family = AF_LINK;
|
||||
sdl.sdl_index = ifp->if_index;
|
||||
sdl.sdl_type = IFT_ETHER;
|
||||
sdl.sdl_alen = ETHER_ADDR_LEN;
|
||||
|
||||
bcopy(ðermulticastaddr_slowprotocols,
|
||||
LLADDR(&sdl), ETHER_ADDR_LEN);
|
||||
error = if_delmulti(ifp, (struct sockaddr *)&sdl);
|
||||
if (error)
|
||||
printf("%s: DELMULTI failed on %s\n", __func__, lgp->lp_ifname);
|
||||
|
||||
LIST_REMOVE(lp, lp_next);
|
||||
free(lp, M_DEVBUF);
|
||||
@ -597,7 +545,7 @@ lacp_disable_distributing(struct lacp_port *lp)
|
||||
char buf[LACP_LAGIDSTR_MAX+1];
|
||||
#endif /* defined(LACP_DEBUG) */
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgp->lp_lagg);
|
||||
LAGG_LOCK_ASSERT(lgp->lp_lagg);
|
||||
|
||||
if (la == NULL || (lp->lp_state & LACP_STATE_DISTRIBUTING) == 0) {
|
||||
return;
|
||||
@ -635,7 +583,7 @@ lacp_enable_distributing(struct lacp_port *lp)
|
||||
char buf[LACP_LAGIDSTR_MAX+1];
|
||||
#endif /* defined(LACP_DEBUG) */
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgp->lp_lagg);
|
||||
LAGG_LOCK_ASSERT(lgp->lp_lagg);
|
||||
|
||||
if ((lp->lp_state & LACP_STATE_DISTRIBUTING) != 0) {
|
||||
return;
|
||||
@ -674,7 +622,7 @@ lacp_attach(struct lagg_softc *lgs)
|
||||
{
|
||||
struct lacp_softc *lsc;
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgs);
|
||||
LAGG_LOCK_ASSERT(lgs);
|
||||
|
||||
lsc = malloc(sizeof(struct lacp_softc),
|
||||
M_DEVBUF, M_NOWAIT|M_ZERO);
|
||||
@ -689,12 +637,8 @@ lacp_attach(struct lagg_softc *lgs)
|
||||
TAILQ_INIT(&lsc->lsc_aggregators);
|
||||
LIST_INIT(&lsc->lsc_ports);
|
||||
|
||||
TASK_INIT(&lsc->lsc_qtask, 0, lacp_dequeue, lsc);
|
||||
mtx_init(&lsc->lsc_queue.ifq_mtx, "lacp queue", NULL, MTX_DEF);
|
||||
lsc->lsc_queue.ifq_maxlen = ifqmaxlen;
|
||||
|
||||
callout_init(&lsc->lsc_transit_callout, CALLOUT_MPSAFE);
|
||||
callout_init(&lsc->lsc_callout, CALLOUT_MPSAFE);
|
||||
callout_init_mtx(&lsc->lsc_transit_callout, &lgs->sc_mtx, 0);
|
||||
callout_init_mtx(&lsc->lsc_callout, &lgs->sc_mtx, 0);
|
||||
|
||||
/* if the lagg is already up then do the same */
|
||||
if (lgs->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
|
||||
@ -716,9 +660,6 @@ lacp_detach(struct lagg_softc *lgs)
|
||||
lgs->sc_psc = NULL;
|
||||
callout_drain(&lsc->lsc_transit_callout);
|
||||
callout_drain(&lsc->lsc_callout);
|
||||
taskqueue_drain(taskqueue_swi, &lsc->lsc_qtask);
|
||||
IF_DRAIN(&lsc->lsc_queue);
|
||||
mtx_destroy(&lsc->lsc_queue.ifq_mtx);
|
||||
|
||||
free(lsc, M_DEVBUF);
|
||||
return (0);
|
||||
@ -750,7 +691,7 @@ lacp_select_tx_port(struct lagg_softc *lgs, struct mbuf *m)
|
||||
uint32_t hash;
|
||||
int nports;
|
||||
|
||||
LAGG_WLOCK_ASSERT(lgs);
|
||||
LAGG_LOCK_ASSERT(lgs);
|
||||
|
||||
if (__predict_false(lsc->lsc_suppress_distributing)) {
|
||||
LACP_DPRINTF((NULL, "%s: waiting transit\n", __func__));
|
||||
@ -1603,7 +1544,7 @@ lacp_marker_input(struct lagg_port *lgp, struct mbuf *m)
|
||||
struct markerdu *mdu;
|
||||
int error = 0;
|
||||
|
||||
LAGG_RLOCK_ASSERT(lgp->lp_lagg);
|
||||
LAGG_LOCK_ASSERT(lgp->lp_lagg);
|
||||
|
||||
if (__predict_false(lp->lp_flags & LACP_PORT_DETACHING)) {
|
||||
goto bad;
|
||||
@ -1613,10 +1554,6 @@ lacp_marker_input(struct lagg_port *lgp, struct mbuf *m)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if ((m->m_flags & M_MCAST) == 0) {
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (m->m_len < sizeof(*mdu)) {
|
||||
m = m_pullup(m, sizeof(*mdu));
|
||||
if (m == NULL) {
|
||||
|
@ -190,7 +190,6 @@ struct lacp_port {
|
||||
int lp_flags;
|
||||
u_int lp_media; /* XXX redundant */
|
||||
int lp_timer[LACP_NTIMER];
|
||||
struct ifmultiaddr *lp_ifma;
|
||||
|
||||
struct lacp_aggregator *lp_aggregator;
|
||||
};
|
||||
@ -214,8 +213,6 @@ struct lacp_softc {
|
||||
struct callout lsc_callout;
|
||||
LIST_HEAD(, lacp_port) lsc_ports;
|
||||
u_int32_t lsc_hashkey;
|
||||
struct task lsc_qtask;
|
||||
struct ifqueue lsc_queue; /* pdu input queue */
|
||||
};
|
||||
|
||||
#define LACP_TYPE_ACTORINFO 1
|
||||
@ -264,7 +261,8 @@ struct markerdu {
|
||||
#define LACP_PORT(_lp) ((struct lacp_port *)(_lp)->lp_psc)
|
||||
#define LACP_SOFTC(_sc) ((struct lacp_softc *)(_sc)->sc_psc)
|
||||
|
||||
void lacp_input(struct lagg_port *, struct mbuf *);
|
||||
int lacp_input(struct lagg_port *, struct mbuf *);
|
||||
int lacp_marker_input(struct lagg_port *, struct mbuf *);
|
||||
struct lagg_port *lacp_select_tx_port(struct lagg_softc *, struct mbuf *);
|
||||
int lacp_attach(struct lagg_softc *);
|
||||
int lacp_detach(struct lagg_softc *);
|
||||
|
@ -95,6 +95,7 @@ SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW,
|
||||
|
||||
void (*bstp_linkstate_p)(struct ifnet *ifp, int state);
|
||||
void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
|
||||
void (*lagg_linkstate_p)(struct ifnet *ifp, int state);
|
||||
|
||||
struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
|
||||
|
||||
@ -1133,6 +1134,10 @@ do_link_state_change(void *arg, int pending)
|
||||
KASSERT(bstp_linkstate_p != NULL,("if_bridge bstp not loaded!"));
|
||||
(*bstp_linkstate_p)(ifp, link_state);
|
||||
}
|
||||
if (ifp->if_lagg) {
|
||||
KASSERT(lagg_linkstate_p != NULL,("if_lagg not loaded!"));
|
||||
(*lagg_linkstate_p)(ifp, link_state);
|
||||
}
|
||||
|
||||
devctl_notify("IFNET", ifp->if_xname,
|
||||
(link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN", NULL);
|
||||
@ -2184,6 +2189,7 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
|
||||
*/
|
||||
/* FALLTHROUGH */
|
||||
case IFT_ARCNET:
|
||||
case IFT_IEEE8023ADLAG:
|
||||
bcopy(lladdr, LLADDR(sdl), len);
|
||||
break;
|
||||
default:
|
||||
|
@ -120,6 +120,9 @@ int (*bridge_output_p)(struct ifnet *, struct mbuf *,
|
||||
struct sockaddr *, struct rtentry *);
|
||||
void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
|
||||
|
||||
/* if_lagg(4) support */
|
||||
struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
|
||||
|
||||
static const u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
|
||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
@ -589,6 +592,17 @@ ether_input(struct ifnet *ifp, struct mbuf *m)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle input from a lagg(4) port */
|
||||
if (ifp->if_type == IFT_IEEE8023ADLAG) {
|
||||
KASSERT(lagg_input_p != NULL,
|
||||
("%s: if_lagg not loaded!", __func__));
|
||||
m = (*lagg_input_p)(ifp, m);
|
||||
if (m != NULL)
|
||||
ifp = m->m_pkthdr.rcvif;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle ng_ether(4) processing, if any */
|
||||
if (IFP2AC(ifp)->ac_netgraph != NULL) {
|
||||
(*ng_ether_input_p)(ifp, &m);
|
||||
|
@ -31,12 +31,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/hash.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
@ -79,7 +75,7 @@ SLIST_HEAD(__trhead, lagg_softc) lagg_list; /* list of laggs */
|
||||
static struct mtx lagg_list_mtx;
|
||||
eventhandler_tag lagg_detach_cookie = NULL;
|
||||
|
||||
static int lagg_clone_create(struct if_clone *, int, caddr_t);
|
||||
static int lagg_clone_create(struct if_clone *, int);
|
||||
static void lagg_clone_destroy(struct ifnet *);
|
||||
static void lagg_lladdr(struct lagg_softc *, uint8_t *);
|
||||
static int lagg_capabilities(struct lagg_softc *);
|
||||
@ -100,6 +96,7 @@ static void lagg_stop(struct lagg_softc *);
|
||||
static int lagg_ioctl(struct ifnet *, u_long, caddr_t);
|
||||
static int lagg_ether_setmulti(struct lagg_softc *);
|
||||
static int lagg_ether_cmdmulti(struct lagg_port *, int);
|
||||
static void lagg_ether_purgemulti(struct lagg_softc *);
|
||||
static int lagg_setflag(struct lagg_port *, int, int,
|
||||
int (*func)(struct ifnet *, int));
|
||||
static int lagg_setflags(struct lagg_port *, int status);
|
||||
@ -158,6 +155,24 @@ static const struct {
|
||||
{ LAGG_PROTO_NONE, NULL }
|
||||
};
|
||||
|
||||
/*
|
||||
* Return a 32-bit hash of the given buffer.
|
||||
* XXX Taken from sys/sys/hash.h. This file can not be included directly due to
|
||||
* compiler warnings that need an API change to fix.
|
||||
*/
|
||||
#define HASHSTEP(x,c) (((x << 5) + x) + (c))
|
||||
static __inline uint32_t
|
||||
hash32_buf(const void *buf, size_t len, uint32_t hash)
|
||||
{
|
||||
const unsigned char *p = buf;
|
||||
|
||||
while (len--)
|
||||
hash = HASHSTEP(hash, *p++);
|
||||
|
||||
return hash;
|
||||
}
|
||||
#undef HASHSTEP
|
||||
|
||||
static int
|
||||
lagg_modevent(module_t mod, int type, void *data)
|
||||
{
|
||||
@ -177,6 +192,8 @@ lagg_modevent(module_t mod, int type, void *data)
|
||||
EVENTHANDLER_DEREGISTER(ifnet_departure_event,
|
||||
lagg_detach_cookie);
|
||||
if_clone_detach(&lagg_cloner);
|
||||
while (!SLIST_EMPTY(&lagg_list))
|
||||
lagg_clone_destroy(SLIST_FIRST(&lagg_list)->sc_ifp);
|
||||
lagg_input_p = NULL;
|
||||
lagg_linkstate_p = NULL;
|
||||
mtx_destroy(&lagg_list_mtx);
|
||||
@ -196,7 +213,7 @@ static moduledata_t lagg_mod = {
|
||||
DECLARE_MODULE(if_lagg, lagg_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
|
||||
|
||||
static int
|
||||
lagg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
|
||||
lagg_clone_create(struct if_clone *ifc, int unit)
|
||||
{
|
||||
struct lagg_softc *sc;
|
||||
struct ifnet *ifp;
|
||||
@ -264,7 +281,7 @@ lagg_clone_destroy(struct ifnet *ifp)
|
||||
struct lagg_softc *sc = (struct lagg_softc *)ifp->if_softc;
|
||||
struct lagg_port *lp;
|
||||
|
||||
LAGG_WLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
|
||||
lagg_stop(sc);
|
||||
ifp->if_flags &= ~IFF_UP;
|
||||
@ -276,7 +293,10 @@ lagg_clone_destroy(struct ifnet *ifp)
|
||||
if (sc->sc_detach != NULL)
|
||||
(*sc->sc_detach)(sc);
|
||||
|
||||
LAGG_WUNLOCK(sc);
|
||||
/* Remove any multicast groups that we may have joined. */
|
||||
lagg_ether_purgemulti(sc);
|
||||
|
||||
LAGG_UNLOCK(sc);
|
||||
|
||||
ifmedia_removeall(&sc->sc_media);
|
||||
ether_ifdetach(ifp);
|
||||
@ -311,7 +331,7 @@ lagg_capabilities(struct lagg_softc *sc)
|
||||
struct lagg_port *lp;
|
||||
int cap = ~0, priv;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
/* Preserve private capabilities */
|
||||
priv = sc->sc_capabilities & IFCAP_LAGG_MASK;
|
||||
@ -336,7 +356,7 @@ lagg_port_lladdr(struct lagg_port *lp, uint8_t *lladdr)
|
||||
struct lagg_llq *llq;
|
||||
int pending = 0;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
if (lp->lp_detaching ||
|
||||
memcmp(lladdr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0)
|
||||
@ -378,10 +398,10 @@ lagg_port_setlladdr(void *arg, int pending)
|
||||
int error;
|
||||
|
||||
/* Grab a local reference of the queue and remove it from the softc */
|
||||
LAGG_WLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
head = SLIST_FIRST(&sc->sc_llq_head);
|
||||
SLIST_FIRST(&sc->sc_llq_head) = NULL;
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
|
||||
/*
|
||||
* Traverse the queue and set the lladdr on each ifp. It is safe to do
|
||||
@ -408,7 +428,7 @@ lagg_port_create(struct lagg_softc *sc, struct ifnet *ifp)
|
||||
struct lagg_port *lp;
|
||||
int error = 0;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
/* Limit the maximal number of lagg ports */
|
||||
if (sc->sc_count >= LAGG_MAX_PORTS)
|
||||
@ -502,7 +522,7 @@ lagg_port_checkstacking(struct lagg_softc *sc)
|
||||
struct lagg_port *lp;
|
||||
int m = 0;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||
if (lp->lp_flags & LAGG_PORT_STACK) {
|
||||
@ -522,7 +542,7 @@ lagg_port_destroy(struct lagg_port *lp, int runpd)
|
||||
struct lagg_llq *llq;
|
||||
struct ifnet *ifp = lp->lp_ifp;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
if (runpd && sc->sc_port_destroy != NULL)
|
||||
(*sc->sc_port_destroy)(lp);
|
||||
@ -603,7 +623,7 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCGLAGGPORT:
|
||||
LAGG_RLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
if (rp->rp_portname[0] == '\0' ||
|
||||
ifunit(rp->rp_portname) != ifp) {
|
||||
error = EINVAL;
|
||||
@ -616,7 +636,7 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
}
|
||||
|
||||
lagg_port2req(lp, rp);
|
||||
LAGG_RUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
break;
|
||||
default:
|
||||
goto fallback;
|
||||
@ -672,10 +692,10 @@ lagg_port_ifdetach(void *arg __unused, struct ifnet *ifp)
|
||||
|
||||
sc = lp->lp_lagg;
|
||||
|
||||
LAGG_WLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
lp->lp_detaching = 1;
|
||||
lagg_port_destroy(lp, 1);
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -719,7 +739,7 @@ lagg_init(void *xsc)
|
||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
|
||||
return;
|
||||
|
||||
LAGG_WLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
|
||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
/* Update the port lladdrs */
|
||||
@ -729,7 +749,7 @@ lagg_init(void *xsc)
|
||||
if (sc->sc_init != NULL)
|
||||
(*sc->sc_init)(sc);
|
||||
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -737,7 +757,7 @@ lagg_stop(struct lagg_softc *sc)
|
||||
{
|
||||
struct ifnet *ifp = sc->sc_ifp;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
|
||||
return;
|
||||
@ -760,7 +780,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
struct thread *td = curthread;
|
||||
int i, error = 0, unlock = 1;
|
||||
|
||||
LAGG_WLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
|
||||
bzero(&rpbuf, sizeof(rpbuf));
|
||||
|
||||
@ -782,7 +802,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
}
|
||||
break;
|
||||
case SIOCSLAGG:
|
||||
error = priv_check(td, PRIV_NET_LAGG);
|
||||
error = suser(td);
|
||||
if (error)
|
||||
break;
|
||||
if (ra->ra_proto >= LAGG_PROTO_MAX) {
|
||||
@ -836,7 +856,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
lagg_port2req(lp, rp);
|
||||
break;
|
||||
case SIOCSLAGGPORT:
|
||||
error = priv_check(td, PRIV_NET_LAGG);
|
||||
error = suser(td);
|
||||
if (error)
|
||||
break;
|
||||
if (rp->rp_portname[0] == '\0' ||
|
||||
@ -847,7 +867,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
error = lagg_port_create(sc, tpif);
|
||||
break;
|
||||
case SIOCSLAGGDELPORT:
|
||||
error = priv_check(td, PRIV_NET_LAGG);
|
||||
error = suser(td);
|
||||
if (error)
|
||||
break;
|
||||
if (rp->rp_portname[0] == '\0' ||
|
||||
@ -883,7 +903,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
* If interface is marked up and it is stopped, then
|
||||
* start it.
|
||||
*/
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
unlock = 0;
|
||||
(*ifp->if_init)(sc);
|
||||
}
|
||||
@ -894,12 +914,12 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
break;
|
||||
case SIOCSIFMEDIA:
|
||||
case SIOCGIFMEDIA:
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
unlock = 0;
|
||||
error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
|
||||
break;
|
||||
default:
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
unlock = 0;
|
||||
error = ether_ioctl(ifp, cmd, data);
|
||||
break;
|
||||
@ -907,23 +927,55 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
|
||||
out:
|
||||
if (unlock)
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
lagg_ether_setmulti(struct lagg_softc *sc)
|
||||
{
|
||||
struct lagg_port *lp;
|
||||
struct ifnet *trifp = sc->sc_ifp;
|
||||
struct ifnet *ifp;
|
||||
struct ifmultiaddr *ifma, *rifma = NULL;
|
||||
struct lagg_port *lp;
|
||||
struct lagg_mc *mc;
|
||||
struct sockaddr_dl sdl;
|
||||
int error;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||
/* First, remove any existing filter entries. */
|
||||
lagg_ether_cmdmulti(lp, 0);
|
||||
/* copy all addresses from the lagg interface to the port */
|
||||
lagg_ether_cmdmulti(lp, 1);
|
||||
bzero((char *)&sdl, sizeof(sdl));
|
||||
sdl.sdl_len = sizeof(sdl);
|
||||
sdl.sdl_family = AF_LINK;
|
||||
sdl.sdl_type = IFT_ETHER;
|
||||
sdl.sdl_alen = ETHER_ADDR_LEN;
|
||||
|
||||
/* First, remove any existing filter entries. */
|
||||
lagg_ether_purgemulti(sc);
|
||||
|
||||
/* Now program new ones. */
|
||||
TAILQ_FOREACH(ifma, &trifp->if_multiaddrs, ifma_link) {
|
||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||
continue;
|
||||
mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT);
|
||||
if (mc == NULL)
|
||||
return (ENOMEM);
|
||||
bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
|
||||
(char *)&mc->mc_addr, ETHER_ADDR_LEN);
|
||||
SLIST_INSERT_HEAD(&sc->sc_mc_head, mc, mc_entries);
|
||||
bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
|
||||
LLADDR(&sdl), ETHER_ADDR_LEN);
|
||||
|
||||
/* do all the ports */
|
||||
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||
ifp = lp->lp_ifp;
|
||||
sdl.sdl_index = ifp->if_index;
|
||||
error = if_addmulti(ifp, (struct sockaddr *)&sdl, &rifma);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -931,14 +983,13 @@ static int
|
||||
lagg_ether_cmdmulti(struct lagg_port *lp, int set)
|
||||
{
|
||||
struct lagg_softc *sc = lp->lp_lagg;
|
||||
struct ifnet *ifp = lp->lp_ifp;
|
||||
struct ifnet *trifp = sc->sc_ifp;
|
||||
struct lagg_mc *mc;
|
||||
struct ifmultiaddr *ifma, *rifma = NULL;
|
||||
struct sockaddr_dl sdl;
|
||||
int error;
|
||||
struct ifnet *ifp = lp->lp_ifp;;
|
||||
struct lagg_mc *mc;
|
||||
struct ifmultiaddr *rifma = NULL;
|
||||
struct sockaddr_dl sdl;
|
||||
int error;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
bzero((char *)&sdl, sizeof(sdl));
|
||||
sdl.sdl_len = sizeof(sdl);
|
||||
@ -947,32 +998,41 @@ lagg_ether_cmdmulti(struct lagg_port *lp, int set)
|
||||
sdl.sdl_alen = ETHER_ADDR_LEN;
|
||||
sdl.sdl_index = ifp->if_index;
|
||||
|
||||
if (set) {
|
||||
TAILQ_FOREACH(ifma, &trifp->if_multiaddrs, ifma_link) {
|
||||
if (ifma->ifma_addr->sa_family != AF_LINK)
|
||||
continue;
|
||||
bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
|
||||
LLADDR(&sdl), ETHER_ADDR_LEN);
|
||||
SLIST_FOREACH(mc, &sc->sc_mc_head, mc_entries) {
|
||||
bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
|
||||
|
||||
if (set)
|
||||
error = if_addmulti(ifp, (struct sockaddr *)&sdl, &rifma);
|
||||
if (error)
|
||||
return (error);
|
||||
mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT);
|
||||
if (mc == NULL)
|
||||
return (ENOMEM);
|
||||
mc->mc_ifma = rifma;
|
||||
SLIST_INSERT_HEAD(&lp->lp_mc_head, mc, mc_entries);
|
||||
}
|
||||
} else {
|
||||
while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) {
|
||||
SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries);
|
||||
if_delmulti_ifma(mc->mc_ifma);
|
||||
free(mc, M_DEVBUF);
|
||||
else
|
||||
error = if_delmulti(ifp, (struct sockaddr *)&sdl);
|
||||
|
||||
if (error) {
|
||||
printf("cmdmulti error on %s, set = %d\n",
|
||||
ifp->if_xname, set);
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
lagg_ether_purgemulti(struct lagg_softc *sc)
|
||||
{
|
||||
struct lagg_port *lp;
|
||||
struct lagg_mc *mc;
|
||||
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
/* remove from ports */
|
||||
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
|
||||
lagg_ether_cmdmulti(lp, 0);
|
||||
|
||||
while ((mc = SLIST_FIRST(&sc->sc_mc_head)) != NULL) {
|
||||
SLIST_REMOVE(&sc->sc_mc_head, mc, lagg_mc, mc_entries);
|
||||
free(mc, M_DEVBUF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle a ref counted flag that should be set on the lagg port as well */
|
||||
static int
|
||||
lagg_setflag(struct lagg_port *lp, int flag, int status,
|
||||
@ -983,7 +1043,7 @@ lagg_setflag(struct lagg_port *lp, int flag, int status,
|
||||
struct ifnet *ifp = lp->lp_ifp;
|
||||
int error;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
|
||||
status = status ? (trifp->if_flags & flag) : 0;
|
||||
/* Now "status" contains the flag value or 0 */
|
||||
@ -1033,7 +1093,6 @@ lagg_start(struct ifnet *ifp)
|
||||
struct mbuf *m;
|
||||
int error = 0;
|
||||
|
||||
LAGG_RLOCK(sc);
|
||||
for (;; error = 0) {
|
||||
IFQ_DEQUEUE(&ifp->if_snd, m);
|
||||
if (m == NULL)
|
||||
@ -1041,9 +1100,11 @@ lagg_start(struct ifnet *ifp)
|
||||
|
||||
BPF_MTAP(ifp, m);
|
||||
|
||||
if (sc->sc_proto != LAGG_PROTO_NONE)
|
||||
if (sc->sc_proto != LAGG_PROTO_NONE) {
|
||||
LAGG_LOCK(sc);
|
||||
error = (*sc->sc_start)(sc, m);
|
||||
else
|
||||
LAGG_UNLOCK(sc);
|
||||
} else
|
||||
m_free(m);
|
||||
|
||||
if (error == 0)
|
||||
@ -1051,7 +1112,6 @@ lagg_start(struct ifnet *ifp)
|
||||
else
|
||||
ifp->if_oerrors++;
|
||||
}
|
||||
LAGG_RUNLOCK(sc);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -1070,7 +1130,7 @@ lagg_input(struct ifnet *ifp, struct mbuf *m)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
LAGG_RLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
BPF_MTAP(trifp, m);
|
||||
|
||||
m = (*sc->sc_input)(sc, lp, m);
|
||||
@ -1082,7 +1142,7 @@ lagg_input(struct ifnet *ifp, struct mbuf *m)
|
||||
trifp->if_ibytes += m->m_pkthdr.len;
|
||||
}
|
||||
|
||||
LAGG_RUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
return (m);
|
||||
}
|
||||
|
||||
@ -1107,12 +1167,12 @@ lagg_media_status(struct ifnet *ifp, struct ifmediareq *imr)
|
||||
imr->ifm_status = IFM_AVALID;
|
||||
imr->ifm_active = IFM_ETHER | IFM_AUTO;
|
||||
|
||||
LAGG_RLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||
if (LAGG_PORTACTIVE(lp))
|
||||
imr->ifm_status |= IFM_ACTIVE;
|
||||
}
|
||||
LAGG_RUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1126,10 +1186,10 @@ lagg_port_state(struct ifnet *ifp, int state)
|
||||
if (sc == NULL)
|
||||
return;
|
||||
|
||||
LAGG_WLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
if (sc->sc_linkstate != NULL)
|
||||
(*sc->sc_linkstate)(lp);
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
}
|
||||
|
||||
struct lagg_port *
|
||||
@ -1138,7 +1198,7 @@ lagg_link_active(struct lagg_softc *sc, struct lagg_port *lp)
|
||||
struct lagg_port *lp_next, *rval = NULL;
|
||||
// int new_link = LINK_STATE_DOWN;
|
||||
|
||||
LAGG_WLOCK_ASSERT(sc);
|
||||
LAGG_LOCK_ASSERT(sc);
|
||||
/*
|
||||
* Search a port which reports an active link state.
|
||||
*/
|
||||
@ -1204,6 +1264,8 @@ lagg_hashmbuf(struct mbuf *m, uint32_t key)
|
||||
struct ether_header *eh;
|
||||
struct ether_vlan_header vlanbuf;
|
||||
const struct ether_vlan_header *vlan;
|
||||
struct m_tag *mtag;
|
||||
u_int tag;
|
||||
#ifdef INET
|
||||
const struct ip *ip;
|
||||
struct ip ipbuf;
|
||||
@ -1224,8 +1286,11 @@ lagg_hashmbuf(struct mbuf *m, uint32_t key)
|
||||
|
||||
/* Special handling for encapsulating VLAN frames */
|
||||
if (m->m_flags & M_VLANTAG) {
|
||||
p = hash32_buf(&m->m_pkthdr.ether_vtag,
|
||||
sizeof(m->m_pkthdr.ether_vtag), p);
|
||||
mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
|
||||
KASSERT(mtag != NULL,
|
||||
("%s: M_VLANTAG without m_tag", __func__));
|
||||
tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
|
||||
p = hash32_buf(&tag, sizeof(tag), p);
|
||||
} else if (etype == ETHERTYPE_VLAN) {
|
||||
vlan = lagg_gethdr(m, off, sizeof(*vlan), &vlanbuf);
|
||||
if (vlan == NULL)
|
||||
@ -1563,9 +1628,9 @@ lagg_lacp_detach(struct lagg_softc *sc)
|
||||
lacp_port_destroy(lp);
|
||||
|
||||
/* unlocking is safe here */
|
||||
LAGG_WUNLOCK(sc);
|
||||
LAGG_UNLOCK(sc);
|
||||
error = lacp_detach(sc);
|
||||
LAGG_WLOCK(sc);
|
||||
LAGG_LOCK(sc);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -1603,13 +1668,33 @@ lagg_lacp_input(struct lagg_softc *sc, struct lagg_port *lp, struct mbuf *m)
|
||||
struct ifnet *ifp = sc->sc_ifp;
|
||||
struct ether_header *eh;
|
||||
u_short etype;
|
||||
uint8_t subtype;
|
||||
|
||||
eh = mtod(m, struct ether_header *);
|
||||
etype = ntohs(eh->ether_type);
|
||||
|
||||
/* Tap off LACP control messages */
|
||||
if (etype == ETHERTYPE_SLOW) {
|
||||
lacp_input(lp, m);
|
||||
if (m->m_pkthdr.len < sizeof(*eh) + sizeof(subtype)) {
|
||||
m_freem(m);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
m_copydata(m, sizeof(*eh), sizeof(subtype), &subtype);
|
||||
switch (subtype) {
|
||||
case SLOWPROTOCOLS_SUBTYPE_LACP:
|
||||
lacp_input(lp, m);
|
||||
break;
|
||||
|
||||
case SLOWPROTOCOLS_SUBTYPE_MARKER:
|
||||
lacp_marker_input(lp, m);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Unknown LACP packet type */
|
||||
m_freem(m);
|
||||
break;
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
@ -136,8 +136,12 @@ struct lagg_lb {
|
||||
};
|
||||
|
||||
struct lagg_mc {
|
||||
struct ifmultiaddr *mc_ifma;
|
||||
SLIST_ENTRY(lagg_mc) mc_entries;
|
||||
union {
|
||||
struct ether_multi *mcu_enm;
|
||||
} mc_u;
|
||||
struct sockaddr_storage mc_addr;
|
||||
|
||||
SLIST_ENTRY(lagg_mc) mc_entries;
|
||||
};
|
||||
|
||||
/* List of interfaces to have the MAC address modified */
|
||||
@ -149,7 +153,7 @@ struct lagg_llq {
|
||||
|
||||
struct lagg_softc {
|
||||
struct ifnet *sc_ifp; /* virtual interface */
|
||||
struct rwlock sc_mtx;
|
||||
struct mtx sc_mtx;
|
||||
int sc_proto; /* lagg protocol */
|
||||
u_int sc_count; /* number of ports */
|
||||
struct lagg_port *sc_primary; /* primary port */
|
||||
@ -159,6 +163,7 @@ struct lagg_softc {
|
||||
SLIST_HEAD(__tplhd, lagg_port) sc_ports; /* list of interfaces */
|
||||
SLIST_ENTRY(lagg_softc) sc_entries;
|
||||
|
||||
SLIST_HEAD(__mclhd, lagg_mc) sc_mc_head; /* multicast addresses */
|
||||
struct task sc_lladdr_task;
|
||||
SLIST_HEAD(__llqhd, lagg_llq) sc_llq_head; /* interfaces to program
|
||||
the lladdr on */
|
||||
@ -189,8 +194,6 @@ struct lagg_port {
|
||||
caddr_t lp_psc; /* protocol data */
|
||||
int lp_detaching; /* ifnet is detaching */
|
||||
|
||||
SLIST_HEAD(__mclhd, lagg_mc) lp_mc_head; /* multicast addresses */
|
||||
|
||||
/* Redirected callbacks */
|
||||
int (*lp_ioctl)(struct ifnet *, u_long, caddr_t);
|
||||
int (*lp_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
|
||||
@ -199,14 +202,13 @@ struct lagg_port {
|
||||
SLIST_ENTRY(lagg_port) lp_entries;
|
||||
};
|
||||
|
||||
#define LAGG_LOCK_INIT(_sc) rw_init(&(_sc)->sc_mtx, "if_lagg rwlock")
|
||||
#define LAGG_LOCK_DESTROY(_sc) rw_destroy(&(_sc)->sc_mtx)
|
||||
#define LAGG_RLOCK(_sc) rw_rlock(&(_sc)->sc_mtx)
|
||||
#define LAGG_WLOCK(_sc) rw_wlock(&(_sc)->sc_mtx)
|
||||
#define LAGG_RUNLOCK(_sc) rw_runlock(&(_sc)->sc_mtx)
|
||||
#define LAGG_WUNLOCK(_sc) rw_wunlock(&(_sc)->sc_mtx)
|
||||
#define LAGG_RLOCK_ASSERT(_sc) rw_assert(&(_sc)->sc_mtx, RA_RLOCKED)
|
||||
#define LAGG_WLOCK_ASSERT(_sc) rw_assert(&(_sc)->sc_mtx, RA_WLOCKED)
|
||||
#define LAGG_LOCK_INIT(_tr) mtx_init(&(_tr)->sc_mtx, "if_lagg", NULL, \
|
||||
MTX_DEF)
|
||||
#define LAGG_LOCK_DESTROY(_tr) mtx_destroy(&(_tr)->sc_mtx)
|
||||
#define LAGG_LOCK(_tr) mtx_lock(&(_tr)->sc_mtx)
|
||||
#define LAGG_UNLOCK(_tr) mtx_unlock(&(_tr)->sc_mtx)
|
||||
#define LAGG_LOCKED(_tr) mtx_owned(&(_tr)->sc_mtx)
|
||||
#define LAGG_LOCK_ASSERT(_tr) mtx_assert(&(_tr)->sc_mtx, MA_OWNED)
|
||||
|
||||
extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
|
||||
extern void (*lagg_linkstate_p)(struct ifnet *, int );
|
||||
|
@ -158,7 +158,7 @@ struct ifnet {
|
||||
(void *);
|
||||
int (*if_resolvemulti) /* validate/resolve multicast */
|
||||
(struct ifnet *, struct sockaddr **, struct sockaddr *);
|
||||
void *if_spare1; /* spare pointer 1 */
|
||||
void *if_lagg; /* lagg glue */
|
||||
void *if_spare2; /* spare pointer 2 */
|
||||
void *if_spare3; /* spare pointer 3 */
|
||||
int if_drv_flags; /* driver-managed status flags */
|
||||
|
Loading…
Reference in New Issue
Block a user