lagg: fix lagg ifioctl after SIOCSIFCAPNV
Lagg was broken by SIOCSIFCAPNV when all underlying devices support SIOCSIFCAPNV. This change updates lagg to work with SIOCSIFCAPNV and if_capabilities2. Reviewed by: kib, hselasky Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D35865
This commit is contained in:
parent
a8a43edc0f
commit
713ceb99b6
@ -157,7 +157,7 @@ static void lagg_ratelimit_query(struct ifnet *,
|
|||||||
#endif
|
#endif
|
||||||
static int lagg_setmulti(struct lagg_port *);
|
static int lagg_setmulti(struct lagg_port *);
|
||||||
static int lagg_clrmulti(struct lagg_port *);
|
static int lagg_clrmulti(struct lagg_port *);
|
||||||
static int lagg_setcaps(struct lagg_port *, int cap);
|
static void lagg_setcaps(struct lagg_port *, int cap, int cap2);
|
||||||
static int lagg_setflag(struct lagg_port *, int, int,
|
static int lagg_setflag(struct lagg_port *, int, int,
|
||||||
int (*func)(struct ifnet *, int));
|
int (*func)(struct ifnet *, int));
|
||||||
static int lagg_setflags(struct lagg_port *, int status);
|
static int lagg_setflags(struct lagg_port *, int status);
|
||||||
@ -664,17 +664,20 @@ 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, cap2, ena, ena2, pena, pena2;
|
||||||
uint64_t hwa;
|
uint64_t hwa;
|
||||||
struct ifnet_hw_tsomax hw_tsomax;
|
struct ifnet_hw_tsomax hw_tsomax;
|
||||||
|
|
||||||
LAGG_XLOCK_ASSERT(sc);
|
LAGG_XLOCK_ASSERT(sc);
|
||||||
|
|
||||||
/* Get common enabled capabilities for the lagg ports */
|
/* Get common enabled capabilities for the lagg ports */
|
||||||
ena = ~0;
|
ena = ena2 = ~0;
|
||||||
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
|
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||||
ena &= lp->lp_ifp->if_capenable;
|
ena &= lp->lp_ifp->if_capenable;
|
||||||
ena = (ena == ~0 ? 0 : ena);
|
ena2 &= lp->lp_ifp->if_capenable2;
|
||||||
|
}
|
||||||
|
if (CK_SLIST_FIRST(&sc->sc_ports) == NULL)
|
||||||
|
ena = ena2 = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Apply common enabled capabilities back to the lagg ports.
|
* Apply common enabled capabilities back to the lagg ports.
|
||||||
@ -682,30 +685,36 @@ lagg_capabilities(struct lagg_softc *sc)
|
|||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
pena = ena;
|
pena = ena;
|
||||||
|
pena2 = ena2;
|
||||||
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||||
lagg_setcaps(lp, ena);
|
lagg_setcaps(lp, ena, ena2);
|
||||||
ena &= lp->lp_ifp->if_capenable;
|
ena &= lp->lp_ifp->if_capenable;
|
||||||
|
ena2 &= lp->lp_ifp->if_capenable2;
|
||||||
}
|
}
|
||||||
} while (pena != ena);
|
} while (pena != ena || pena2 != ena2);
|
||||||
|
|
||||||
/* Get other capabilities from the lagg ports */
|
/* Get other capabilities from the lagg ports */
|
||||||
cap = ~0;
|
cap = cap2 = ~0;
|
||||||
hwa = ~(uint64_t)0;
|
hwa = ~(uint64_t)0;
|
||||||
memset(&hw_tsomax, 0, sizeof(hw_tsomax));
|
memset(&hw_tsomax, 0, sizeof(hw_tsomax));
|
||||||
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||||
cap &= lp->lp_ifp->if_capabilities;
|
cap &= lp->lp_ifp->if_capabilities;
|
||||||
|
cap2 &= lp->lp_ifp->if_capabilities2;
|
||||||
hwa &= lp->lp_ifp->if_hwassist;
|
hwa &= lp->lp_ifp->if_hwassist;
|
||||||
if_hw_tsomax_common(lp->lp_ifp, &hw_tsomax);
|
if_hw_tsomax_common(lp->lp_ifp, &hw_tsomax);
|
||||||
}
|
}
|
||||||
cap = (cap == ~0 ? 0 : cap);
|
if (CK_SLIST_FIRST(&sc->sc_ports) == NULL)
|
||||||
hwa = (hwa == ~(uint64_t)0 ? 0 : hwa);
|
cap = cap2 = hwa = 0;
|
||||||
|
|
||||||
if (sc->sc_ifp->if_capabilities != cap ||
|
if (sc->sc_ifp->if_capabilities != cap ||
|
||||||
sc->sc_ifp->if_capenable != ena ||
|
sc->sc_ifp->if_capenable != ena ||
|
||||||
|
sc->sc_ifp->if_capenable2 != ena2 ||
|
||||||
sc->sc_ifp->if_hwassist != hwa ||
|
sc->sc_ifp->if_hwassist != hwa ||
|
||||||
if_hw_tsomax_update(sc->sc_ifp, &hw_tsomax) != 0) {
|
if_hw_tsomax_update(sc->sc_ifp, &hw_tsomax) != 0) {
|
||||||
sc->sc_ifp->if_capabilities = cap;
|
sc->sc_ifp->if_capabilities = cap;
|
||||||
|
sc->sc_ifp->if_capabilities2 = cap2;
|
||||||
sc->sc_ifp->if_capenable = ena;
|
sc->sc_ifp->if_capenable = ena;
|
||||||
|
sc->sc_ifp->if_capenable2 = ena2;
|
||||||
sc->sc_ifp->if_hwassist = hwa;
|
sc->sc_ifp->if_hwassist = hwa;
|
||||||
getmicrotime(&sc->sc_ifp->if_lastchange);
|
getmicrotime(&sc->sc_ifp->if_lastchange);
|
||||||
|
|
||||||
@ -982,7 +991,7 @@ lagg_port_destroy(struct lagg_port *lp, int rundelport)
|
|||||||
|
|
||||||
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, lp->lp_ifcapenable2);
|
||||||
if_setlladdr(ifp, lp->lp_lladdr, ifp->if_addrlen);
|
if_setlladdr(ifp, lp->lp_lladdr, ifp->if_addrlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1038,6 +1047,7 @@ lagg_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SIOCSIFCAP:
|
case SIOCSIFCAP:
|
||||||
|
case SIOCSIFCAPNV:
|
||||||
if (lp->lp_ioctl == NULL) {
|
if (lp->lp_ioctl == NULL) {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
break;
|
break;
|
||||||
@ -1690,6 +1700,7 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SIOCSIFCAP:
|
case SIOCSIFCAP:
|
||||||
|
case SIOCSIFCAPNV:
|
||||||
LAGG_XLOCK(sc);
|
LAGG_XLOCK(sc);
|
||||||
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||||
if (lp->lp_ioctl != NULL)
|
if (lp->lp_ioctl != NULL)
|
||||||
@ -1701,6 +1712,10 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
|||||||
error = 0;
|
error = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SIOCGIFCAPNV:
|
||||||
|
error = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
case SIOCSIFMTU:
|
case SIOCSIFMTU:
|
||||||
LAGG_XLOCK(sc);
|
LAGG_XLOCK(sc);
|
||||||
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
CK_SLIST_FOREACH(lp, &sc->sc_ports, lp_entries) {
|
||||||
@ -2013,17 +2028,28 @@ lagg_clrmulti(struct lagg_port *lp)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
lagg_setcaps(struct lagg_port *lp, int cap)
|
lagg_setcaps(struct lagg_port *lp, int cap, int cap2)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
struct siocsifcapnv_driver_data drv_ioctl_data;
|
||||||
|
|
||||||
if (lp->lp_ifp->if_capenable == cap)
|
if (lp->lp_ifp->if_capenable == cap &&
|
||||||
return (0);
|
lp->lp_ifp->if_capenable2 == cap2)
|
||||||
|
return;
|
||||||
if (lp->lp_ioctl == NULL)
|
if (lp->lp_ioctl == NULL)
|
||||||
return (ENXIO);
|
return;
|
||||||
ifr.ifr_reqcap = cap;
|
/* XXX */
|
||||||
return ((*lp->lp_ioctl)(lp->lp_ifp, SIOCSIFCAP, (caddr_t)&ifr));
|
if ((lp->lp_ifp->if_capabilities & IFCAP_NV) != 0) {
|
||||||
|
drv_ioctl_data.reqcap = cap;
|
||||||
|
drv_ioctl_data.reqcap2 = cap2;
|
||||||
|
drv_ioctl_data.nvcap = NULL;
|
||||||
|
(*lp->lp_ioctl)(lp->lp_ifp, SIOCSIFCAPNV,
|
||||||
|
(caddr_t)&drv_ioctl_data);
|
||||||
|
} else {
|
||||||
|
ifr.ifr_reqcap = cap;
|
||||||
|
(*lp->lp_ioctl)(lp->lp_ifp, SIOCSIFCAP, (caddr_t)&ifr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle a ref counted flag that should be set on the lagg port as well */
|
/* Handle a ref counted flag that should be set on the lagg port as well */
|
||||||
|
@ -273,6 +273,7 @@ struct lagg_port {
|
|||||||
uint32_t lp_flags; /* port flags */
|
uint32_t lp_flags; /* port flags */
|
||||||
int lp_ifflags; /* saved ifp flags */
|
int lp_ifflags; /* saved ifp flags */
|
||||||
int lp_ifcapenable; /* saved ifp capenable */
|
int lp_ifcapenable; /* saved ifp capenable */
|
||||||
|
int lp_ifcapenable2;/* saved ifp capenable2 */
|
||||||
void *lh_cookie; /* if state hook */
|
void *lh_cookie; /* if state hook */
|
||||||
void *lp_psc; /* protocol data */
|
void *lp_psc; /* protocol data */
|
||||||
int lp_detaching; /* ifnet is detaching */
|
int lp_detaching; /* ifnet is detaching */
|
||||||
|
Loading…
Reference in New Issue
Block a user