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:
Andrew Gallatin 2022-07-28 10:36:22 -04:00
parent a8a43edc0f
commit 713ceb99b6
2 changed files with 45 additions and 18 deletions

View File

@ -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 */

View File

@ -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 */