Changeset View
Changeset View
Standalone View
Standalone View
sys/net/if_lagg.c
Show First 20 Lines • Show All 328 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
lagg_proto_detach(struct lagg_softc *sc) | lagg_proto_detach(struct lagg_softc *sc) | ||||
{ | { | ||||
lagg_proto pr; | lagg_proto pr; | ||||
LAGG_XLOCK_ASSERT(sc); | LAGG_XLOCK_ASSERT(sc); | ||||
LAGG_WLOCK_ASSERT(sc); | |||||
pr = sc->sc_proto; | pr = sc->sc_proto; | ||||
sc->sc_proto = LAGG_PROTO_NONE; | sc->sc_proto = LAGG_PROTO_NONE; | ||||
if (lagg_protos[pr].pr_detach != NULL) | if (lagg_protos[pr].pr_detach != NULL) | ||||
lagg_protos[pr].pr_detach(sc); | lagg_protos[pr].pr_detach(sc); | ||||
else | |||||
LAGG_WUNLOCK(sc); | |||||
} | } | ||||
static int | static int | ||||
lagg_proto_start(struct lagg_softc *sc, struct mbuf *m) | lagg_proto_start(struct lagg_softc *sc, struct mbuf *m) | ||||
{ | { | ||||
return (lagg_protos[sc->sc_proto].pr_start(sc, m)); | return (lagg_protos[sc->sc_proto].pr_start(sc, m)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | lagg_clone_destroy(struct ifnet *ifp) | ||||
EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); | EVENTHANDLER_DEREGISTER(vlan_config, sc->vlan_attach); | ||||
EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); | EVENTHANDLER_DEREGISTER(vlan_unconfig, sc->vlan_detach); | ||||
/* Shutdown and remove lagg ports */ | /* Shutdown and remove lagg ports */ | ||||
while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL) | while ((lp = SLIST_FIRST(&sc->sc_ports)) != NULL) | ||||
lagg_port_destroy(lp, 1); | lagg_port_destroy(lp, 1); | ||||
/* Unhook the aggregation protocol */ | /* Unhook the aggregation protocol */ | ||||
LAGG_WLOCK(sc); | |||||
lagg_proto_detach(sc); | lagg_proto_detach(sc); | ||||
LAGG_UNLOCK_ASSERT(sc); | |||||
LAGG_XUNLOCK(sc); | LAGG_XUNLOCK(sc); | ||||
ifmedia_removeall(&sc->sc_media); | ifmedia_removeall(&sc->sc_media); | ||||
ether_ifdetach(ifp); | ether_ifdetach(ifp); | ||||
if_free(ifp); | if_free(ifp); | ||||
LAGG_LIST_LOCK(); | LAGG_LIST_LOCK(); | ||||
SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries); | SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries); | ||||
LAGG_LIST_UNLOCK(); | LAGG_LIST_UNLOCK(); | ||||
LAGG_SX_DESTROY(sc); | LAGG_SX_DESTROY(sc); | ||||
LAGG_LOCK_DESTROY(sc); | |||||
free(sc, M_DEVBUF); | free(sc, M_DEVBUF); | ||||
} | } | ||||
static void | static void | ||||
lagg_capabilities(struct lagg_softc *sc) | lagg_capabilities(struct lagg_softc *sc) | ||||
{ | { | ||||
struct lagg_port *lp; | struct lagg_port *lp; | ||||
int cap, ena, pena; | int cap, ena, pena; | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | #endif | ||||
LAGG_LIST_UNLOCK(); | LAGG_LIST_UNLOCK(); | ||||
if_ref(ifp); | if_ref(ifp); | ||||
lp->lp_ifp = ifp; | lp->lp_ifp = ifp; | ||||
bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN); | bcopy(IF_LLADDR(ifp), lp->lp_lladdr, ETHER_ADDR_LEN); | ||||
lp->lp_ifcapenable = ifp->if_capenable; | lp->lp_ifcapenable = ifp->if_capenable; | ||||
if (SLIST_EMPTY(&sc->sc_ports)) { | if (SLIST_EMPTY(&sc->sc_ports)) { | ||||
LAGG_WLOCK(sc); | |||||
bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | bcopy(IF_LLADDR(ifp), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | ||||
lagg_proto_lladdr(sc); | lagg_proto_lladdr(sc); | ||||
LAGG_WUNLOCK(sc); | |||||
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | ||||
} else { | } else { | ||||
if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | if_setlladdr(ifp, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | ||||
} | } | ||||
lagg_setflags(lp, 1); | lagg_setflags(lp, 1); | ||||
LAGG_WLOCK(sc); | |||||
if (SLIST_EMPTY(&sc->sc_ports)) | if (SLIST_EMPTY(&sc->sc_ports)) | ||||
sc->sc_primary = lp; | sc->sc_primary = lp; | ||||
/* Change the interface type */ | /* Change the interface type */ | ||||
lp->lp_iftype = ifp->if_type; | lp->lp_iftype = ifp->if_type; | ||||
ifp->if_type = IFT_IEEE8023ADLAG; | ifp->if_type = IFT_IEEE8023ADLAG; | ||||
ifp->if_lagg = lp; | ifp->if_lagg = lp; | ||||
lp->lp_ioctl = ifp->if_ioctl; | lp->lp_ioctl = ifp->if_ioctl; | ||||
Show All 22 Lines | #endif | ||||
if (tlp != NULL) | if (tlp != NULL) | ||||
SLIST_INSERT_AFTER(tlp, lp, lp_entries); | SLIST_INSERT_AFTER(tlp, lp, lp_entries); | ||||
else | else | ||||
SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries); | SLIST_INSERT_HEAD(&sc->sc_ports, lp, lp_entries); | ||||
sc->sc_count++; | sc->sc_count++; | ||||
lagg_setmulti(lp); | lagg_setmulti(lp); | ||||
LAGG_WUNLOCK(sc); | |||||
if ((error = lagg_proto_addport(sc, lp)) != 0) { | if ((error = lagg_proto_addport(sc, lp)) != 0) { | ||||
/* Remove the port, without calling pr_delport. */ | /* Remove the port, without calling pr_delport. */ | ||||
LAGG_WLOCK(sc); | |||||
lagg_port_destroy(lp, 0); | lagg_port_destroy(lp, 0); | ||||
LAGG_UNLOCK_ASSERT(sc); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* Update lagg capabilities */ | /* Update lagg capabilities */ | ||||
lagg_capabilities(sc); | lagg_capabilities(sc); | ||||
lagg_linkstate(sc); | lagg_linkstate(sc); | ||||
return (0); | return (0); | ||||
Show All 25 Lines | lagg_port_destroy(struct lagg_port *lp, int rundelport) | ||||
struct lagg_softc *sc = lp->lp_softc; | struct lagg_softc *sc = lp->lp_softc; | ||||
struct lagg_port *lp_ptr, *lp0; | struct lagg_port *lp_ptr, *lp0; | ||||
struct ifnet *ifp = lp->lp_ifp; | struct ifnet *ifp = lp->lp_ifp; | ||||
uint64_t *pval, vdiff; | uint64_t *pval, vdiff; | ||||
int i; | int i; | ||||
LAGG_XLOCK_ASSERT(sc); | LAGG_XLOCK_ASSERT(sc); | ||||
if (rundelport) { | if (rundelport) | ||||
LAGG_WLOCK(sc); | |||||
lagg_proto_delport(sc, lp); | lagg_proto_delport(sc, lp); | ||||
} else | |||||
LAGG_WLOCK_ASSERT(sc); | |||||
if (lp->lp_detaching == 0) | if (lp->lp_detaching == 0) | ||||
lagg_clrmulti(lp); | lagg_clrmulti(lp); | ||||
/* Restore interface */ | /* Restore interface */ | ||||
ifp->if_type = lp->lp_iftype; | ifp->if_type = lp->lp_iftype; | ||||
ifp->if_ioctl = lp->lp_ioctl; | ifp->if_ioctl = lp->lp_ioctl; | ||||
ifp->if_output = lp->lp_output; | ifp->if_output = lp->lp_output; | ||||
Show All 17 Lines | if (lp == sc->sc_primary) { | ||||
if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL) | if ((lp0 = SLIST_FIRST(&sc->sc_ports)) == NULL) | ||||
bzero(&lladdr, ETHER_ADDR_LEN); | bzero(&lladdr, ETHER_ADDR_LEN); | ||||
else | else | ||||
bcopy(lp0->lp_lladdr, lladdr, ETHER_ADDR_LEN); | bcopy(lp0->lp_lladdr, lladdr, ETHER_ADDR_LEN); | ||||
sc->sc_primary = lp0; | sc->sc_primary = lp0; | ||||
if (sc->sc_destroying == 0) { | if (sc->sc_destroying == 0) { | ||||
bcopy(lladdr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | bcopy(lladdr, IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN); | ||||
lagg_proto_lladdr(sc); | lagg_proto_lladdr(sc); | ||||
LAGG_WUNLOCK(sc); | |||||
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); | ||||
} else | } | ||||
LAGG_WUNLOCK(sc); | |||||
/* | /* | ||||
* Update lladdr for each port (new primary needs update | * Update lladdr for each port (new primary needs update | ||||
* as well, to switch from old lladdr to its 'real' one) | * as well, to switch from old lladdr to its 'real' one) | ||||
*/ | */ | ||||
SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries) | SLIST_FOREACH(lp_ptr, &sc->sc_ports, lp_entries) | ||||
if_setlladdr(lp_ptr->lp_ifp, lladdr, ETHER_ADDR_LEN); | if_setlladdr(lp_ptr->lp_ifp, lladdr, ETHER_ADDR_LEN); | ||||
} else | } | ||||
LAGG_WUNLOCK(sc); | |||||
if (lp->lp_ifflags) | if (lp->lp_ifflags) | ||||
if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); | if_printf(ifp, "%s: lp_ifflags unclean\n", __func__); | ||||
if (lp->lp_detaching == 0) { | if (lp->lp_detaching == 0) { | ||||
lagg_setflags(lp, 0); | lagg_setflags(lp, 0); | ||||
lagg_setcaps(lp, lp->lp_ifcapenable); | lagg_setcaps(lp, lp->lp_ifcapenable); | ||||
if_setlladdr(ifp, lp->lp_lladdr, ETHER_ADDR_LEN); | if_setlladdr(ifp, lp->lp_lladdr, ETHER_ADDR_LEN); | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
* current counters data to detached_counters array. | * current counters data to detached_counters array. | ||||
*/ | */ | ||||
static uint64_t | static uint64_t | ||||
lagg_get_counter(struct ifnet *ifp, ift_counter cnt) | lagg_get_counter(struct ifnet *ifp, ift_counter cnt) | ||||
{ | { | ||||
struct lagg_softc *sc; | struct lagg_softc *sc; | ||||
struct lagg_port *lp; | struct lagg_port *lp; | ||||
struct ifnet *lpifp; | struct ifnet *lpifp; | ||||
struct rm_priotracker tracker; | |||||
uint64_t newval, oldval, vsum; | uint64_t newval, oldval, vsum; | ||||
struct rm_priotracker tracker; | |||||
/* Revise this when we've got non-generic counters. */ | /* Revise this when we've got non-generic counters. */ | ||||
KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); | KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); | ||||
sc = (struct lagg_softc *)ifp->if_softc; | sc = (struct lagg_softc *)ifp->if_softc; | ||||
LAGG_RLOCK(sc, &tracker); | LAGG_RLOCK(sc, &tracker); | ||||
vsum = 0; | vsum = 0; | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | case SIOCSLAGG: | ||||
if (error) | if (error) | ||||
break; | break; | ||||
if (ra->ra_proto >= LAGG_PROTO_MAX) { | if (ra->ra_proto >= LAGG_PROTO_MAX) { | ||||
error = EPROTONOSUPPORT; | error = EPROTONOSUPPORT; | ||||
break; | break; | ||||
} | } | ||||
LAGG_XLOCK(sc); | LAGG_XLOCK(sc); | ||||
LAGG_WLOCK(sc); | |||||
lagg_proto_detach(sc); | lagg_proto_detach(sc); | ||||
LAGG_UNLOCK_ASSERT(sc); | |||||
lagg_proto_attach(sc, ra->ra_proto); | lagg_proto_attach(sc, ra->ra_proto); | ||||
LAGG_XUNLOCK(sc); | LAGG_XUNLOCK(sc); | ||||
break; | break; | ||||
case SIOCGLAGGOPTS: | case SIOCGLAGGOPTS: | ||||
LAGG_SLOCK(sc); | LAGG_SLOCK(sc); | ||||
ro->ro_opts = sc->sc_opts; | ro->ro_opts = sc->sc_opts; | ||||
if (sc->sc_proto == LAGG_PROTO_LACP) { | if (sc->sc_proto == LAGG_PROTO_LACP) { | ||||
struct lacp_softc *lsc; | struct lacp_softc *lsc; | ||||
▲ Show 20 Lines • Show All 253 Lines • ▼ Show 20 Lines | if (!(ifp->if_flags & IFF_UP) && | ||||
*/ | */ | ||||
LAGG_XUNLOCK(sc); | LAGG_XUNLOCK(sc); | ||||
(*ifp->if_init)(sc); | (*ifp->if_init)(sc); | ||||
} else | } else | ||||
LAGG_XUNLOCK(sc); | LAGG_XUNLOCK(sc); | ||||
break; | break; | ||||
case SIOCADDMULTI: | case SIOCADDMULTI: | ||||
case SIOCDELMULTI: | case SIOCDELMULTI: | ||||
LAGG_WLOCK(sc); | LAGG_XLOCK(sc); | ||||
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { | SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) { | ||||
lagg_clrmulti(lp); | lagg_clrmulti(lp); | ||||
lagg_setmulti(lp); | lagg_setmulti(lp); | ||||
} | } | ||||
LAGG_WUNLOCK(sc); | LAGG_XUNLOCK(sc); | ||||
error = 0; | error = 0; | ||||
break; | break; | ||||
case SIOCSIFMEDIA: | case SIOCSIFMEDIA: | ||||
case SIOCGIFMEDIA: | case SIOCGIFMEDIA: | ||||
error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); | error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); | ||||
break; | break; | ||||
case SIOCSIFCAP: | case SIOCSIFCAP: | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct lagg_softc *sc = lp->lp_softc; | struct lagg_softc *sc = lp->lp_softc; | ||||
struct ifnet *ifp = lp->lp_ifp; | struct ifnet *ifp = lp->lp_ifp; | ||||
struct ifnet *scifp = sc->sc_ifp; | struct ifnet *scifp = sc->sc_ifp; | ||||
struct lagg_mc *mc; | struct lagg_mc *mc; | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
int error; | int error; | ||||
LAGG_WLOCK_ASSERT(sc); | LAGG_XLOCK_ASSERT(sc); | ||||
IF_ADDR_WLOCK(scifp); | IF_ADDR_WLOCK(scifp); | ||||
TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { | TAILQ_FOREACH(ifma, &scifp->if_multiaddrs, ifma_link) { | ||||
if (ifma->ifma_addr->sa_family != AF_LINK) | if (ifma->ifma_addr->sa_family != AF_LINK) | ||||
continue; | continue; | ||||
mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT); | mc = malloc(sizeof(struct lagg_mc), M_DEVBUF, M_NOWAIT); | ||||
if (mc == NULL) { | if (mc == NULL) { | ||||
IF_ADDR_WUNLOCK(scifp); | IF_ADDR_WUNLOCK(scifp); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
Show All 14 Lines | lagg_setmulti(struct lagg_port *lp) | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
lagg_clrmulti(struct lagg_port *lp) | lagg_clrmulti(struct lagg_port *lp) | ||||
{ | { | ||||
struct lagg_mc *mc; | struct lagg_mc *mc; | ||||
LAGG_WLOCK_ASSERT(lp->lp_softc); | LAGG_XLOCK_ASSERT(lp->lp_softc); | ||||
while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) { | while ((mc = SLIST_FIRST(&lp->lp_mc_head)) != NULL) { | ||||
SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); | SLIST_REMOVE(&lp->lp_mc_head, mc, lagg_mc, mc_entries); | ||||
if (mc->mc_ifma && lp->lp_detaching == 0) | if (mc->mc_ifma && lp->lp_detaching == 0) | ||||
if_delmulti_ifma(mc->mc_ifma); | if_delmulti_ifma(mc->mc_ifma); | ||||
free(mc, M_DEVBUF); | free(mc, M_DEVBUF); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | |||||
static struct mbuf * | static struct mbuf * | ||||
lagg_input(struct ifnet *ifp, struct mbuf *m) | lagg_input(struct ifnet *ifp, struct mbuf *m) | ||||
{ | { | ||||
struct lagg_port *lp = ifp->if_lagg; | struct lagg_port *lp = ifp->if_lagg; | ||||
struct lagg_softc *sc = lp->lp_softc; | struct lagg_softc *sc = lp->lp_softc; | ||||
struct ifnet *scifp = sc->sc_ifp; | struct ifnet *scifp = sc->sc_ifp; | ||||
struct rm_priotracker tracker; | struct rm_priotracker tracker; | ||||
LAGG_RLOCK(sc, &tracker); | LAGG_RLOCK(sc, &tracker); | ||||
mmacy: I don't think we want to be acquiring sleep locks in the data path. A more substantive… | |||||
Done Inline ActionsWhy do you think it is possible to have DELAY(1) on the datapath? melifaro: Why do you think it is possible to have DELAY(1) on the datapath? | |||||
Not Done Inline ActionsFixed (lagg_rlock() uses cpu_spinwait() now). shurd: Fixed (lagg_rlock() uses cpu_spinwait() now). | |||||
if ((scifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || | if ((scifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || | ||||
(lp->lp_flags & LAGG_PORT_DISABLED) || | (lp->lp_flags & LAGG_PORT_DISABLED) || | ||||
sc->sc_proto == LAGG_PROTO_NONE) { | sc->sc_proto == LAGG_PROTO_NONE) { | ||||
LAGG_RUNLOCK(sc, &tracker); | LAGG_RUNLOCK(sc, &tracker); | ||||
m_freem(m); | m_freem(m); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 321 Lines • ▼ Show 20 Lines | SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) | ||||
lagg_lb_port_create(lp); | lagg_lb_port_create(lp); | ||||
} | } | ||||
static void | static void | ||||
lagg_lb_detach(struct lagg_softc *sc) | lagg_lb_detach(struct lagg_softc *sc) | ||||
{ | { | ||||
struct lagg_lb *lb; | struct lagg_lb *lb; | ||||
LAGG_XLOCK_ASSERT(sc); | |||||
lb = (struct lagg_lb *)sc->sc_psc; | lb = (struct lagg_lb *)sc->sc_psc; | ||||
LAGG_WUNLOCK(sc); | |||||
if (lb != NULL) | if (lb != NULL) | ||||
free(lb, M_DEVBUF); | free(lb, M_DEVBUF); | ||||
} | } | ||||
static int | static int | ||||
lagg_lb_porttable(struct lagg_softc *sc, struct lagg_port *lp) | lagg_lb_porttable(struct lagg_softc *sc, struct lagg_port *lp) | ||||
{ | { | ||||
struct lagg_lb *lb = (struct lagg_lb *)sc->sc_psc; | struct lagg_lb *lb = (struct lagg_lb *)sc->sc_psc; | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
lagg_lacp_detach(struct lagg_softc *sc) | lagg_lacp_detach(struct lagg_softc *sc) | ||||
{ | { | ||||
struct lagg_port *lp; | struct lagg_port *lp; | ||||
void *psc; | void *psc; | ||||
LAGG_XLOCK_ASSERT(sc); | |||||
SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) | SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) | ||||
lacp_port_destroy(lp); | lacp_port_destroy(lp); | ||||
psc = sc->sc_psc; | psc = sc->sc_psc; | ||||
sc->sc_psc = NULL; | sc->sc_psc = NULL; | ||||
LAGG_WUNLOCK(sc); | |||||
lacp_detach(psc); | lacp_detach(psc); | ||||
} | } | ||||
static void | static void | ||||
lagg_lacp_lladdr(struct lagg_softc *sc) | lagg_lacp_lladdr(struct lagg_softc *sc) | ||||
{ | { | ||||
struct lagg_port *lp; | struct lagg_port *lp; | ||||
▲ Show 20 Lines • Show All 57 Lines • Show Last 20 Lines |
I don't think we want to be acquiring sleep locks in the data path. A more substantive refactoring is in order.