diff --git a/rescue/rescue/Makefile b/rescue/rescue/Makefile --- a/rescue/rescue/Makefile +++ b/rescue/rescue/Makefile @@ -137,8 +137,18 @@ CRUNCH_LIBS+= -l80211 -lalias -lcam -lncursesw -ldevstat -lipsec -llzma .if ${MK_ZFS} != "no" -CRUNCH_LIBS+= -lavl -lzpool -lzfs_core -lzfs -lnvpair -lpthread -luutil -lumem -CRUNCH_LIBS+= -lbe -lzfsbootenv -lzutil -ltpool -lspl -licp_rescue +CRUNCH_LIBS+= -lavl -lpthread -luutil -lumem -ltpool -lspl +CRUNCH_LIBS_zfs+= ${LIBBE} \ + ${LIBZPOOL} \ + ${LIBZUTIL} \ + ${LIBZFS} \ + ${LIBZFS_CORE} \ + ${LIBZFSBOOTENV} \ + ${LIBICP_RESCUE} \ + ${LIBNVPAIR} +CRUNCH_LIBS_bectl+= ${CRUNCH_LIBS_zfs} +CRUNCH_LIBS_zpool+= ${CRUNCH_LIBS_zfs} +CRUNCH_LIBS_zdb+= ${CRUNCH_LIBS_zfs} .else # liblzma needs pthread CRUNCH_LIBS+= -lpthread @@ -235,6 +245,8 @@ CRUNCH_LIBS+= ${OBJTOP}/lib/libifconfig/libifconfig.a CRUNCH_BUILDOPTS+= CRUNCH_CFLAGS+=-I${OBJTOP}/lib/libifconfig +CRUNCH_LIBS_ifconfig+= ${LIBNV} + CRUNCH_LIBS+= -lm .if ${MK_ISCSI} != "no" diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h --- a/sbin/ifconfig/ifconfig.h +++ b/sbin/ifconfig/ifconfig.h @@ -46,7 +46,10 @@ struct cmd; typedef void c_func(const char *cmd, int arg, int s, const struct afswtch *afp); -typedef void c_func2(const char *arg1, const char *arg2, int s, const struct afswtch *afp); +typedef void c_func2(const char *arg1, const char *arg2, int s, + const struct afswtch *afp); +typedef void c_func3(const char *cmd, const char *arg, int s, + const struct afswtch *afp); struct cmd { const char *c_name; @@ -54,9 +57,12 @@ #define NEXTARG 0xffffff /* has following arg */ #define NEXTARG2 0xfffffe /* has 2 following args */ #define OPTARG 0xfffffd /* has optional following arg */ +#define SPARAM 0xfffffc /* parameter is string c_sparameter */ + const char *c_sparameter; union { c_func *c_func; c_func2 *c_func2; + c_func3 *c_func3; } c_u; int c_iscloneop; struct cmd *c_next; @@ -72,15 +78,66 @@ #define DECL_CMD_FUNC(name, cmd, arg) \ void name(const char *cmd, int arg, int s, const struct afswtch *afp) #define DECL_CMD_FUNC2(name, arg1, arg2) \ - void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp) - -#define DEF_CMD(name, param, func) { name, param, { .c_func = func }, 0, NULL } -#define DEF_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 0, NULL } -#define DEF_CMD_OPTARG(name, func) { name, OPTARG, { .c_func = func }, 0, NULL } -#define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 0, NULL } -#define DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1, NULL } -#define DEF_CLONE_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 1, NULL } -#define DEF_CLONE_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 1, NULL } + void name(const char *arg1, const char *arg2, int s, \ + const struct afswtch *afp) + +#define DEF_CMD(name, param, func) { \ + .c_name = (name), \ + .c_parameter = (param), \ + .c_u = { .c_func = (func) }, \ + .c_iscloneop = 0, \ + .c_next = NULL, \ +} +#define DEF_CMD_ARG(name, func) { \ + .c_name = (name), \ + .c_parameter = NEXTARG, \ + .c_u = { .c_func = (func) }, \ + .c_iscloneop = 0, \ + .c_next = NULL, \ +} +#define DEF_CMD_OPTARG(name, func) { \ + .c_name = (name), \ + .c_parameter = OPTARG, \ + .c_u = { .c_func = (func) }, \ + .c_iscloneop = 0, \ + .c_next = NULL, \ +} +#define DEF_CMD_ARG2(name, func) { \ + .c_name = (name), \ + .c_parameter = NEXTARG2, \ + .c_u = { .c_func2 = (func) }, \ + .c_iscloneop = 0, \ + .c_next = NULL, \ +} +#define DEF_CMD_SARG(name, sparam, func) { \ + .c_name = (name), \ + .c_parameter = SPARAM, \ + .c_sparameter = (sparam), \ + .c_u = { .c_func3 = (func) }, \ + .c_iscloneop = 0, \ + .c_next = NULL, \ +} +#define DEF_CLONE_CMD(name, param, func) { \ + .c_name = (name), \ + .c_parameter = (param), \ + .c_u = { .c_func = (func) }, \ + .c_iscloneop = 1, \ + .c_next = NULL, \ +} +#define DEF_CLONE_CMD_ARG(name, func) { \ + .c_name = (name), \ + .c_parameter = NEXTARG, \ + .c_u = { .c_func = (func) }, \ + .c_iscloneop = 1, \ + .c_next = NULL, \ +} +#define DEF_CLONE_CMD_ARG2(name, func) { \ + .c_name = (name), \ + .c_parameter = NEXTARG2, \ + .c_u = { .c_func2 = (func) }, \ + .c_iscloneop = 1, \ + .c_next = NULL, \ +} struct ifaddrs; struct addrinfo; @@ -145,6 +202,8 @@ extern int exit_code; void setifcap(const char *, int value, int s, const struct afswtch *); +void setifcapnv(const char *vname, const char *arg, int s, + const struct afswtch *afp); void Perror(const char *cmd); void printb(const char *s, unsigned value, const char *bits); diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -991,6 +992,8 @@ p->c_name); p->c_u.c_func2(argv[1], argv[2], s, afp); argc -= 2, argv += 2; + } else if (p->c_parameter == SPARAM && p->c_u.c_func3) { + p->c_u.c_func3(*argv, p->c_sparameter, s, afp); } else if (p->c_u.c_func) p->c_u.c_func(*argv, p->c_parameter, s, afp); argc--, argv++; @@ -1251,6 +1254,41 @@ Perror(vname); } +void +setifcapnv(const char *vname, const char *arg, int s, const struct afswtch *afp) +{ + nvlist_t *nvcap; + void *buf; + char *marg, *mopt; + size_t nvbuflen; + bool neg; + + marg = strdup(arg); + if (marg == NULL) + Perror("strdup"); + nvcap = nvlist_create(0); + if (nvcap == NULL) + Perror("nvlist_create"); + while ((mopt = strsep(&marg, ",")) != NULL) { + neg = (*mopt == '-'); + if (neg) + mopt++; + nvlist_add_bool(nvcap, mopt, !neg); + } + buf = nvlist_pack(nvcap, &nvbuflen); + if (buf == NULL) { + errx(1, "nvlist_pack error"); + exit(1); + } + ifr.ifr_cap_nv.buf_length = ifr.ifr_cap_nv.length = nvbuflen; + ifr.ifr_cap_nv.buffer = buf; + if (ioctl(s, SIOCSIFCAPNV, (caddr_t)&ifr) < 0) + Perror(vname); + free(buf); + nvlist_destroy(nvcap); + free(marg); +} + static void setifmetric(const char *val, int dummy __unused, int s, const struct afswtch *afp) @@ -1375,8 +1413,12 @@ struct ifaddrs *ifa) { struct ifaddrs *ift; - int allfamilies, s; struct ifstat ifs; + nvlist_t *nvcap; + const char *nvname; + void *buf, *cookie; + int allfamilies, s, type; + bool first, val; if (afp == NULL) { allfamilies = 1; @@ -1421,13 +1463,58 @@ } if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { - if (ifr.ifr_curcap != 0) { + if ((ifr.ifr_curcap & IFCAP_NV) != 0) { + buf = malloc(IFR_CAP_NV_MAXBUFSIZE); + if (buf == NULL) + Perror("malloc"); + ifr.ifr_cap_nv.buffer = buf; + ifr.ifr_cap_nv.buf_length = IFR_CAP_NV_MAXBUFSIZE; + if (ioctl(s, SIOCGIFCAPNV, (caddr_t)&ifr) != 0) + Perror("ioctl (SIOCGIFCAPNV)"); + nvcap = nvlist_unpack(ifr.ifr_cap_nv.buffer, + ifr.ifr_cap_nv.length, 0); + if (nvcap == NULL) + Perror("nvlist_unpack"); + printf("\toptions"); + cookie = NULL; + for (first = true;; first = false) { + nvname = nvlist_next(nvcap, &type, &cookie); + if (nvname == NULL) { + printf("\n"); + break; + } + if (type == NV_TYPE_BOOL) { + val = nvlist_get_bool(nvcap, nvname); + if (val) { + printf("%c%s", + first ? ' ' : ',', nvname); + } + } + } + if (supmedia) { + cookie = NULL; + for (first = true;; first = false) { + nvname = nvlist_next(nvcap, &type, &cookie); + if (nvname == NULL) { + printf("\n"); + break; + } + if (first) + printf("\tcapabilities %s", nvname); + else + printf(",%s", nvname); + } + } + nvlist_destroy(nvcap); + free(buf); + } else if (ifr.ifr_curcap != 0) { printb("\toptions", ifr.ifr_curcap, IFCAPBITS); putchar('\n'); - } - if (supmedia && ifr.ifr_reqcap != 0) { - printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); - putchar('\n'); + + if (supmedia && ifr.ifr_reqcap != 0) { + printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); + putchar('\n'); + } } } @@ -1694,6 +1781,16 @@ DEF_CMD("-lro", -IFCAP_LRO, setifcap), DEF_CMD("txtls", IFCAP_TXTLS, setifcap), DEF_CMD("-txtls", -IFCAP_TXTLS, setifcap), + DEF_CMD("txtls4", IFCAP_TXTLS4, setifcap), + DEF_CMD("-txtls4", -IFCAP_TXTLS4, setifcap), + DEF_CMD("txtls6", IFCAP_TXTLS6, setifcap), + DEF_CMD("-txtls6", -IFCAP_TXTLS6, setifcap), + DEF_CMD_SARG("rxtls", IFCAP_RXTLS4_NAME "," IFCAP_RXTLS6_NAME, setifcapnv), + DEF_CMD_SARG("-rxtls", "-" IFCAP_RXTLS4_NAME ",-" IFCAP_RXTLS6_NAME, setifcapnv), + DEF_CMD_SARG("rxtls4", IFCAP_RXTLS4_NAME, setifcapnv), + DEF_CMD_SARG("-rxtls4", "-" IFCAP_RXTLS4_NAME, setifcapnv), + DEF_CMD_SARG("rxtls6", IFCAP_RXTLS6_NAME, setifcapnv), + DEF_CMD_SARG("-rxtls6", "-" IFCAP_RXTLS6_NAME, setifcapnv), DEF_CMD("wol", IFCAP_WOL, setifcap), DEF_CMD("-wol", -IFCAP_WOL, setifcap), DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap), diff --git a/share/man/man9/ifnet.9 b/share/man/man9/ifnet.9 --- a/share/man/man9/ifnet.9 +++ b/share/man/man9/ifnet.9 @@ -28,7 +28,7 @@ .\" .\" $FreeBSD$ .\" -.Dd September 28, 2020 +.Dd March 14, 2022 .Dt IFNET 9 .Os .Sh NAME @@ -1335,6 +1335,74 @@ .Va if_data.ifi_hwassist appropriately. .Pp +.It Dv SIOCGIFCAPNV +.Xr NV 9 +version of the +.Dv SIOCGIFCAP +ioctl. +Caller must provide the pointer to +.Vt struct ifreq_cap_nv +as +.Fa data , +where the member +.Dv buffer +points to some buffer containing +.Dv buf_length +bytes. +The serialized nvlist with description of the device capabilities +is written to the buffer. +If buffer is too short, then the structure is updated with +.Dv buffer +member set to +.Dv NULL, +.Dv length set to the minimal required length, +and error +.Er EFBIG +is returned. +.Pp +Elements of the returned nvlist for simple capabilities are boolean, +identified by names. +Presence of the boolean element means that corresponding capability is +supported by the interface. +Element's value describes the current configured state: +.Dv true +means that the capability is enabled, and +.Dv false +that it is disabled. +.Pp +Driver indicates support for both +.Dv SIOCGIFCAPNV +and +.Dv SIOCSIFCAPNV +requests by setting +.Dv IFCAP_NV +non-modifiable capability bit in +.Dv if_capabilities . +.Pp +.It Dv SIOCSIFCAPNV +.Xr NV 9 +version of the +.Dv SIOCSIFCAP +ioctl. +Caller must provide the pointer to +.Vt struct ifreq_cap_nv +as +.Fa data , +where the member +.Dv buffer +points to unpacked nvlist of +.Dv length +bytes. +Each element of nvlist describes a requested update of one capability, +identified by the element name. +For simple capabilities, the element must be boolean. +Its +.Dv true +value means that the caller asks to enable the capability, and +.Dv false +value to disable. +Only capabilities listed in the nvlist are affected by the call. +.Pp .It Dv SIOCSIFFIB Sets interface FIB. Caller must have appropriate privilege. diff --git a/share/mk/src.libnames.mk b/share/mk/src.libnames.mk --- a/share/mk/src.libnames.mk +++ b/share/mk/src.libnames.mk @@ -567,6 +567,9 @@ LIBIPFDIR= ${_LIB_OBJTOP}/sbin/ipf/libipf LIBIPF?= ${LIBIPFDIR}/libipf${PIE_SUFFIX}.a +LIBJNVDIR= ${_LIB_OBJTOP}/lib/libnv +LIBNV?= ${LIBNVDIR}/libnv${PIE_SUFFIX}.a + LIBISCSIUTILDIR= ${_LIB_OBJTOP}/lib/libiscsiutil LIBISCSIUTIL?= ${LIBISCSIUTILDIR}/libiscsiutil${PIE_SUFFIX}.a @@ -660,14 +663,23 @@ LIBCTFDIR= ${OBJTOP}/cddl/lib/libctf LIBDTRACEDIR= ${OBJTOP}/cddl/lib/libdtrace LIBICPDIR= ${OBJTOP}/cddl/lib/libicp +LIBICP_RESCUEDIR= ${OBJTOP}/cddl/lib/libicp_rescue +LIBICP_RESCUE?= ${LIBICP_RESCUEDIR}/libicp_rescue${PIE_SUFFIX}.a +LIBICP?= ${LIBICPDIR}/libicp${PIE_SUFFIX}.a LIBNVPAIRDIR= ${OBJTOP}/cddl/lib/libnvpair +LIBNVPAIR?= ${LIBNVPAIRDIR}/libnvpair${PIE_SUFFIX}.a LIBUMEMDIR= ${OBJTOP}/cddl/lib/libumem LIBUUTILDIR= ${OBJTOP}/cddl/lib/libuutil LIBZFSDIR= ${OBJTOP}/cddl/lib/libzfs +LIBZFS?= ${LIBZFSDIR}/libzfs${PIE_SUFFIX}.a LIBZFS_COREDIR= ${OBJTOP}/cddl/lib/libzfs_core +LIBZFS_CORE?= ${LIBZFS_COREDIR}/libzfs_core${PIE_SUFFIX}.a LIBZFSBOOTENVDIR= ${OBJTOP}/cddl/lib/libzfsbootenv +LIBZFSBOOTENV?= ${LIBZFSBOOTENVDIR}/libzfsbootenv${PIE_SUFFIX}.a LIBZPOOLDIR= ${OBJTOP}/cddl/lib/libzpool +LIBZPOOL?= ${LIBZPOOLDIR}/libzpool${PIE_SUFFIX}.a LIBZUTILDIR= ${OBJTOP}/cddl/lib/libzutil +LIBZUTIL?= ${LIBZUTILDIR}/libzutil${PIE_SUFFIX}.a LIBTPOOLDIR= ${OBJTOP}/cddl/lib/libtpool # OFED support diff --git a/sys/dev/mlx5/mlx5_en/en.h b/sys/dev/mlx5/mlx5_en/en.h --- a/sys/dev/mlx5/mlx5_en/en.h +++ b/sys/dev/mlx5/mlx5_en/en.h @@ -1149,6 +1149,10 @@ bool sw_is_port_buf_owner; struct pfil_head *pfil; + + bool ifcap_rxtls4 : 1; + bool ifcap_rxtls6 : 1; + struct mlx5e_channel channel[]; }; diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c --- a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c +++ b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c @@ -658,6 +658,7 @@ union if_snd_tag_alloc_params *params, struct m_snd_tag **ppmt) { + struct inpcb *inp; struct mlx5e_iq *iq; struct mlx5e_priv *priv; struct mlx5e_tls_rx_tag *ptag; @@ -672,6 +673,34 @@ params->hdr.flowtype == M_HASHTYPE_NONE)) return (EOPNOTSUPP); + inp = params->tls_rx.inp; + if (unlikely(inp == NULL)) + return (EINVAL); + + error = 0; + INP_RLOCK(inp); + switch (INP_SOCKAF(inp->inp_socket)) { +#ifdef INET + case AF_INET: + if (priv->ifcap_rxtls4 == 0) + error = EOPNOTSUPP; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (priv->ifcap_rxtls6 == 0) + error = EOPNOTSUPP; + break; +#endif + default: + error = EOPNOTSUPP; + break; + } + INP_RUNLOCK(inp); + + if (error != 0) + return (error); + /* allocate new tag from zone, if any */ ptag = uma_zalloc(priv->tls_rx.zone, M_NOWAIT); if (ptag == NULL) @@ -723,7 +752,7 @@ } } error = mlx5e_tls_rx_set_params( - ptag->crypto_params, params->tls_rx.inp, en); + ptag->crypto_params, inp, en); if (error) goto failure; break; @@ -741,7 +770,7 @@ } } error = mlx5e_tls_rx_set_params( - ptag->crypto_params, params->tls_rx.inp, en); + ptag->crypto_params, inp, en); if (error) goto failure; break; @@ -803,11 +832,11 @@ if (ifp->if_pcp != IFNET_PCP_NONE || params->tls_rx.vlan_id != 0) { /* create flow rule for TLS RX traffic (tagged) */ - flow_rule = mlx5e_accel_fs_add_inpcb(priv, params->tls_rx.inp, + flow_rule = mlx5e_accel_fs_add_inpcb(priv, inp, ptag->tirn, MLX5_FS_DEFAULT_FLOW_TAG, params->tls_rx.vlan_id); } else { /* create flow rule for TLS RX traffic (untagged) */ - flow_rule = mlx5e_accel_fs_add_inpcb(priv, params->tls_rx.inp, + flow_rule = mlx5e_accel_fs_add_inpcb(priv, inp, ptag->tirn, MLX5_FS_DEFAULT_FLOW_TAG, MLX5E_ACCEL_FS_ADD_INPCB_NO_VLAN); } diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c --- a/sys/dev/mlx5/mlx5_en/mlx5_en_main.c +++ b/sys/dev/mlx5/mlx5_en/mlx5_en_main.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -3425,6 +3426,151 @@ queue_work(priv->wq, &priv->set_rx_mode_work); } +static int +mlx5e_set_legacy_caps_locked(struct ifnet *ifp, unsigned mask, unsigned value) +{ + struct mlx5e_priv *priv = ifp->if_softc; + int error = 0; + + mask &= (value ^ ifp->if_capenable); + + if (mask & IFCAP_TXCSUM) { + ifp->if_capenable ^= IFCAP_TXCSUM; + ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); + + if (IFCAP_TSO4 & ifp->if_capenable && + !(IFCAP_TXCSUM & ifp->if_capenable)) { + mask &= ~IFCAP_TSO4; + ifp->if_capenable &= ~IFCAP_TSO4; + ifp->if_hwassist &= ~CSUM_IP_TSO; + mlx5_en_err(ifp, + "tso4 disabled due to -txcsum.\n"); + } + } + if (mask & IFCAP_TXCSUM_IPV6) { + ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; + ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); + + if (IFCAP_TSO6 & ifp->if_capenable && + !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { + mask &= ~IFCAP_TSO6; + ifp->if_capenable &= ~IFCAP_TSO6; + ifp->if_hwassist &= ~CSUM_IP6_TSO; + mlx5_en_err(ifp, + "tso6 disabled due to -txcsum6.\n"); + } + } + if (mask & IFCAP_MEXTPG) + ifp->if_capenable ^= IFCAP_MEXTPG; + if (mask & IFCAP_TXTLS4) + ifp->if_capenable ^= IFCAP_TXTLS4; + if (mask & IFCAP_TXTLS6) + ifp->if_capenable ^= IFCAP_TXTLS6; +#ifdef RATELIMIT + if (mask & IFCAP_TXTLS_RTLMT) + ifp->if_capenable ^= IFCAP_TXTLS_RTLMT; +#endif + if (mask & IFCAP_RXCSUM) + ifp->if_capenable ^= IFCAP_RXCSUM; + if (mask & IFCAP_RXCSUM_IPV6) + ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; + if (mask & IFCAP_TSO4) { + if (!(IFCAP_TSO4 & ifp->if_capenable) && + !(IFCAP_TXCSUM & ifp->if_capenable)) { + mlx5_en_err(ifp, "enable txcsum first.\n"); + error = EAGAIN; + } else { + ifp->if_capenable ^= IFCAP_TSO4; + ifp->if_hwassist ^= CSUM_IP_TSO; + } + } + if (mask & IFCAP_TSO6) { + if (!(IFCAP_TSO6 & ifp->if_capenable) && + !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { + mlx5_en_err(ifp, "enable txcsum6 first.\n"); + error = EAGAIN; + } else { + ifp->if_capenable ^= IFCAP_TSO6; + ifp->if_hwassist ^= CSUM_IP6_TSO; + } + } + if (mask & IFCAP_VLAN_HWTSO) + ifp->if_capenable ^= IFCAP_VLAN_HWTSO; + if (mask & IFCAP_VLAN_HWFILTER) { + if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) + mlx5e_disable_vlan_filter(priv); + else + mlx5e_enable_vlan_filter(priv); + + ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; + } + if (mask & IFCAP_VLAN_HWTAGGING) + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + if (mask & IFCAP_WOL_MAGIC) + ifp->if_capenable ^= IFCAP_WOL_MAGIC; + if (mask & IFCAP_VXLAN_HWCSUM) { + const bool was_enabled = + (ifp->if_capenable & IFCAP_VXLAN_HWCSUM) != 0; + if (was_enabled) + mlx5e_del_all_vxlan_rules(priv); + ifp->if_capenable ^= IFCAP_VXLAN_HWCSUM; + ifp->if_hwassist ^= CSUM_INNER_IP | CSUM_INNER_IP_UDP | + CSUM_INNER_IP_TCP | CSUM_INNER_IP6_UDP | + CSUM_INNER_IP6_TCP; + if (!was_enabled) { + int err = mlx5e_add_all_vxlan_rules(priv); + if (err != 0) { + mlx5_en_err(ifp, + "mlx5e_add_all_vxlan_rules() failed, %d (ignored)\n", err); + } + } + } + if (mask & IFCAP_VXLAN_HWTSO) { + ifp->if_capenable ^= IFCAP_VXLAN_HWTSO; + ifp->if_hwassist ^= CSUM_INNER_IP_TSO | + CSUM_INNER_IP6_TSO; + } + + VLAN_CAPABILITIES(ifp); + + /* turn off LRO means also turn of HW LRO - if it's on */ + if (mask & IFCAP_LRO) { + int was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); + bool need_restart = false; + + ifp->if_capenable ^= IFCAP_LRO; + + /* figure out if updating HW LRO is needed */ + if (!(ifp->if_capenable & IFCAP_LRO)) { + if (priv->params.hw_lro_en) { + priv->params.hw_lro_en = false; + need_restart = true; + } + } else { + if (priv->params.hw_lro_en == false && + priv->params_ethtool.hw_lro != 0) { + priv->params.hw_lro_en = true; + need_restart = true; + } + } + if (was_opened && need_restart) { + mlx5e_close_locked(ifp); + mlx5e_open_locked(ifp); + } + } + if (mask & IFCAP_HWRXTSTMP) { + ifp->if_capenable ^= IFCAP_HWRXTSTMP; + if (ifp->if_capenable & IFCAP_HWRXTSTMP) { + if (priv->clbr_done == 0) + mlx5e_reset_calibration_callout(priv); + } else { + callout_drain(&priv->tstmp_clbr); + priv->clbr_done = 0; + } + } + return (error); +} + static int mlx5e_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { @@ -3434,8 +3580,10 @@ struct ifi2creq i2c; struct ifrsskey *ifrk; struct ifrsshash *ifrh; + nvlist_t *nv; + unsigned mask; + unsigned value; int error = 0; - int mask = 0; int size_read = 0; int module_status; int module_num; @@ -3512,148 +3660,32 @@ ifr = (struct ifreq *)data; error = ifmedia_ioctl(ifp, ifr, &priv->media, command); break; + case SIOCGIFCAPNV: + nv = (nvlist_t *)data; + if_legacy_to_capnv(nv, ifp->if_capabilities, ifp->if_capenable); + nvlist_add_bool(nv, IFCAP_RXTLS4_NAME, priv->ifcap_rxtls4); + nvlist_add_bool(nv, IFCAP_RXTLS6_NAME, priv->ifcap_rxtls6); + break; + case SIOCSIFCAPNV: + nv = (nvlist_t *)data; + if_capnv_to_legacy(nv, &mask, &value); + + PRIV_LOCK(priv); + error = mlx5e_set_legacy_caps_locked(ifp, mask, value); + if (error == 0) { + if (nvlist_exists_bool(nv, IFCAP_RXTLS4_NAME)) + priv->ifcap_rxtls4 = nvlist_get_bool(nv, IFCAP_RXTLS4_NAME); + if (nvlist_exists_bool(nv, IFCAP_RXTLS6_NAME)) + priv->ifcap_rxtls6 = nvlist_get_bool(nv, IFCAP_RXTLS6_NAME); + } + PRIV_UNLOCK(priv); + break; case SIOCSIFCAP: ifr = (struct ifreq *)data; PRIV_LOCK(priv); - mask = ifr->ifr_reqcap ^ ifp->if_capenable; - - if (mask & IFCAP_TXCSUM) { - ifp->if_capenable ^= IFCAP_TXCSUM; - ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); - - if (IFCAP_TSO4 & ifp->if_capenable && - !(IFCAP_TXCSUM & ifp->if_capenable)) { - mask &= ~IFCAP_TSO4; - ifp->if_capenable &= ~IFCAP_TSO4; - ifp->if_hwassist &= ~CSUM_IP_TSO; - mlx5_en_err(ifp, - "tso4 disabled due to -txcsum.\n"); - } - } - if (mask & IFCAP_TXCSUM_IPV6) { - ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; - ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); - - if (IFCAP_TSO6 & ifp->if_capenable && - !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { - mask &= ~IFCAP_TSO6; - ifp->if_capenable &= ~IFCAP_TSO6; - ifp->if_hwassist &= ~CSUM_IP6_TSO; - mlx5_en_err(ifp, - "tso6 disabled due to -txcsum6.\n"); - } - } - if (mask & IFCAP_MEXTPG) - ifp->if_capenable ^= IFCAP_MEXTPG; - if (mask & IFCAP_TXTLS4) - ifp->if_capenable ^= IFCAP_TXTLS4; - if (mask & IFCAP_TXTLS6) - ifp->if_capenable ^= IFCAP_TXTLS6; -#ifdef RATELIMIT - if (mask & IFCAP_TXTLS_RTLMT) - ifp->if_capenable ^= IFCAP_TXTLS_RTLMT; -#endif - if (mask & IFCAP_RXCSUM) - ifp->if_capenable ^= IFCAP_RXCSUM; - if (mask & IFCAP_RXCSUM_IPV6) - ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; - if (mask & IFCAP_TSO4) { - if (!(IFCAP_TSO4 & ifp->if_capenable) && - !(IFCAP_TXCSUM & ifp->if_capenable)) { - mlx5_en_err(ifp, "enable txcsum first.\n"); - error = EAGAIN; - goto out; - } - ifp->if_capenable ^= IFCAP_TSO4; - ifp->if_hwassist ^= CSUM_IP_TSO; - } - if (mask & IFCAP_TSO6) { - if (!(IFCAP_TSO6 & ifp->if_capenable) && - !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { - mlx5_en_err(ifp, "enable txcsum6 first.\n"); - error = EAGAIN; - goto out; - } - ifp->if_capenable ^= IFCAP_TSO6; - ifp->if_hwassist ^= CSUM_IP6_TSO; - } - if (mask & IFCAP_VLAN_HWTSO) - ifp->if_capenable ^= IFCAP_VLAN_HWTSO; - if (mask & IFCAP_VLAN_HWFILTER) { - if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) - mlx5e_disable_vlan_filter(priv); - else - mlx5e_enable_vlan_filter(priv); - - ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; - } - if (mask & IFCAP_VLAN_HWTAGGING) - ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - if (mask & IFCAP_WOL_MAGIC) - ifp->if_capenable ^= IFCAP_WOL_MAGIC; - if (mask & IFCAP_VXLAN_HWCSUM) { - const bool was_enabled = - (ifp->if_capenable & IFCAP_VXLAN_HWCSUM) != 0; - if (was_enabled) - mlx5e_del_all_vxlan_rules(priv); - ifp->if_capenable ^= IFCAP_VXLAN_HWCSUM; - ifp->if_hwassist ^= CSUM_INNER_IP | CSUM_INNER_IP_UDP | - CSUM_INNER_IP_TCP | CSUM_INNER_IP6_UDP | - CSUM_INNER_IP6_TCP; - if (!was_enabled) { - int err = mlx5e_add_all_vxlan_rules(priv); - if (err != 0) { - mlx5_en_err(ifp, - "mlx5e_add_all_vxlan_rules() failed, %d (ignored)\n", err); - } - } - } - if (mask & IFCAP_VXLAN_HWTSO) { - ifp->if_capenable ^= IFCAP_VXLAN_HWTSO; - ifp->if_hwassist ^= CSUM_INNER_IP_TSO | - CSUM_INNER_IP6_TSO; - } - - VLAN_CAPABILITIES(ifp); - /* turn off LRO means also turn of HW LRO - if it's on */ - if (mask & IFCAP_LRO) { - int was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); - bool need_restart = false; - - ifp->if_capenable ^= IFCAP_LRO; - - /* figure out if updating HW LRO is needed */ - if (!(ifp->if_capenable & IFCAP_LRO)) { - if (priv->params.hw_lro_en) { - priv->params.hw_lro_en = false; - need_restart = true; - } - } else { - if (priv->params.hw_lro_en == false && - priv->params_ethtool.hw_lro != 0) { - priv->params.hw_lro_en = true; - need_restart = true; - } - } - if (was_opened && need_restart) { - mlx5e_close_locked(ifp); - mlx5e_open_locked(ifp); - } - } - if (mask & IFCAP_HWRXTSTMP) { - ifp->if_capenable ^= IFCAP_HWRXTSTMP; - if (ifp->if_capenable & IFCAP_HWRXTSTMP) { - if (priv->clbr_done == 0) - mlx5e_reset_calibration_callout(priv); - } else { - callout_drain(&priv->tstmp_clbr); - priv->clbr_done = 0; - } - } -out: + error = mlx5e_set_legacy_caps_locked(ifp, ifp->if_capabilities, ifr->ifr_reqcap); PRIV_UNLOCK(priv); break; - case SIOCGI2C: ifr = (struct ifreq *)data; @@ -4531,6 +4563,11 @@ ifp->if_capabilities |= IFCAP_TXRTLMT | IFCAP_TXTLS_RTLMT; #endif ifp->if_capabilities |= IFCAP_VXLAN_HWCSUM | IFCAP_VXLAN_HWTSO; + ifp->if_capabilities |= IFCAP_NV; + + priv->ifcap_rxtls4 = 1; + priv->ifcap_rxtls6 = 1; + ifp->if_snd_tag_alloc = mlx5e_snd_tag_alloc; #ifdef RATELIMIT ifp->if_ratelimit_query = mlx5e_ratelimit_query; diff --git a/sys/net/if.h b/sys/net/if.h --- a/sys/net/if.h +++ b/sys/net/if.h @@ -236,7 +236,7 @@ #define IFCAP_TOE4 0x04000 /* interface can offload TCP */ #define IFCAP_TOE6 0x08000 /* interface can offload TCP6 */ #define IFCAP_VLAN_HWFILTER 0x10000 /* interface hw can filter vlan tag */ -/* available 0x20000 */ +#define IFCAP_NV 0x20000 /* can do SIOCGIFCAPNV/SIOCSIFCAPNV */ #define IFCAP_VLAN_HWTSO 0x40000 /* can do IFCAP_TSO on VLANs */ #define IFCAP_LINKSTATE 0x80000 /* the runtime link state is dynamic */ #define IFCAP_NETMAP 0x100000 /* netmap mode supported/enabled */ @@ -260,7 +260,42 @@ #define IFCAP_TOE (IFCAP_TOE4 | IFCAP_TOE6) #define IFCAP_TXTLS (IFCAP_TXTLS4 | IFCAP_TXTLS6) -#define IFCAP_CANTCHANGE (IFCAP_NETMAP) +#define IFCAP_CANTCHANGE (IFCAP_NETMAP | IFCAP_NV) +#define IFCAP_ALLCAPS 0xffffffff + +#define IFCAP_RXCSUM_NAME "RXCSUM" +#define IFCAP_TXCSUM_NAME "TXCSUM" +#define IFCAP_NETCONS_NAME "NETCONS" +#define IFCAP_VLAN_MTU_NAME "VLAN_MTU" +#define IFCAP_VLAN_HWTAGGING_NAME "VLAN_HWTAGGING" +#define IFCAP_JUMBO_MTU_NAME "JUMBO_MTU" +#define IFCAP_POLLING_NAME "POLLING" +#define IFCAP_VLAN_HWCSUM_NAME "VLAN_HWCSUM" +#define IFCAP_TSO4_NAME "TSO4" +#define IFCAP_TSO6_NAME "TSO6" +#define IFCAP_LRO_NAME "LRO" +#define IFCAP_WOL_UCAST_NAME "WOL_UCAST" +#define IFCAP_WOL_MCAST_NAME "WOL_MCAST" +#define IFCAP_WOL_MAGIC_NAME "WOL_MAGIC" +#define IFCAP_TOE4_NAME "TOE4" +#define IFCAP_TOE6_NAME "TOE6" +#define IFCAP_VLAN_HWFILTER_NAME "VLAN_HWFILTER" +#define IFCAP_VLAN_HWTSO_NAME "VLAN_HWTSO" +#define IFCAP_LINKSTATE_NAME "LINKSTATE" +#define IFCAP_NETMAP_NAME "NETMAP" +#define IFCAP_RXCSUM_IPV6_NAME "RXCSUM_IPV6" +#define IFCAP_TXCSUM_IPV6_NAME "TXCSUM_IPV6" +#define IFCAP_HWSTATS_NAME "HWSTATS" +#define IFCAP_TXRTLMT_NAME "TXRTLMT" +#define IFCAP_HWRXTSTMP_NAME "HWRXTSTMP" +#define IFCAP_MEXTPG_NAME "MEXTPG" +#define IFCAP_TXTLS4_NAME "TXTLS4" +#define IFCAP_TXTLS6_NAME "TXTLS6" +#define IFCAP_VXLAN_HWCSUM_NAME "VXLAN_HWCSUM" +#define IFCAP_VXLAN_HWTSO_NAME "VXLAN_HWTSO" +#define IFCAP_TXTLS_RTLMT_NAME "TXTLS_RTLMT" +#define IFCAP_RXTLS4_NAME "RXTLS4" +#define IFCAP_RXTLS6_NAME "RXTLS6" #define IFQ_MAXLEN 50 #define IFNET_SLOWHZ 1 /* granularity is 1 second */ @@ -387,6 +422,15 @@ void *buffer; }; +struct ifreq_nv_req { + u_int buf_length; /* Total size of buffer, + u_int for ABI struct ifreq */ + u_int length; /* Length of the filled part */ + void *buffer; /* Buffer itself, containing packed nv */ +}; + +#define IFR_CAP_NV_MAXBUFSIZE (2 * 1024 * 1024) + /* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter @@ -411,6 +455,7 @@ int ifru_cap[2]; u_int ifru_fib; u_char ifru_vlan_pcp; + struct ifreq_nv_req ifru_nv; } ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ @@ -434,6 +479,7 @@ #define ifr_fib ifr_ifru.ifru_fib /* interface fib */ #define ifr_vlan_pcp ifr_ifru.ifru_vlan_pcp /* VLAN priority */ #define ifr_lan_pcp ifr_ifru.ifru_vlan_pcp /* VLAN priority */ +#define ifr_cap_nv ifr_ifru.ifru_nv /* nv-based cap interface */ }; #define _SIZEOF_ADDR_IFREQ(ifr) \ @@ -605,6 +651,10 @@ extern struct sx ifnet_detach_sxlock; +struct nvlist; +void if_capnv_to_legacy(const struct nvlist *nv, unsigned *pcap, unsigned *preq); +void if_legacy_to_capnv(struct nvlist *nv, unsigned cap, unsigned req); + #endif #ifndef _KERNEL diff --git a/sys/net/if.c b/sys/net/if.c --- a/sys/net/if.c +++ b/sys/net/if.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -2393,6 +2394,85 @@ return (ifrup->ifr.ifr_ifru.ifru_data); } +struct ifcap_nv_bit_name { + unsigned cap_bit; + const char *cap_name; +}; + +#define CAPNV(x) { \ + .cap_bit = IFCAP_##x, \ + .cap_name = IFCAP_##x##_NAME \ +} + +const struct ifcap_nv_bit_name ifcap_nv_bit_names[] = { + CAPNV(RXCSUM), + CAPNV(TXCSUM), + CAPNV(NETCONS), + CAPNV(VLAN_MTU), + CAPNV(VLAN_HWTAGGING), + CAPNV(JUMBO_MTU), + CAPNV(POLLING), + CAPNV(VLAN_HWCSUM), + CAPNV(TSO4), + CAPNV(TSO6), + CAPNV(LRO), + CAPNV(WOL_UCAST), + CAPNV(WOL_MCAST), + CAPNV(WOL_MAGIC), + CAPNV(TOE4), + CAPNV(TOE6), + CAPNV(VLAN_HWFILTER), + CAPNV(VLAN_HWTSO), + CAPNV(LINKSTATE), + CAPNV(NETMAP), + CAPNV(RXCSUM_IPV6), + CAPNV(TXCSUM_IPV6), + CAPNV(HWSTATS), + CAPNV(TXRTLMT), + CAPNV(HWRXTSTMP), + CAPNV(MEXTPG), + CAPNV(TXTLS4), + CAPNV(TXTLS6), + CAPNV(VXLAN_HWCSUM), + CAPNV(VXLAN_HWTSO), + CAPNV(TXTLS_RTLMT), +}; +#undef CAPNV + +void +if_capnv_to_legacy(const nvlist_t *nv, unsigned *pcap, unsigned *preq) +{ + const struct ifcap_nv_bit_name *nn; + unsigned res; + unsigned i; + + *pcap = *preq = IFCAP_NV; + + for (i = res = 0; i != nitems(ifcap_nv_bit_names); i++) { + nn = &ifcap_nv_bit_names[i]; + if (nvlist_exists_bool(nv, nn->cap_name) == false) + continue; + *pcap |= nn->cap_bit; + if (nvlist_get_bool(nv, nn->cap_name)) + *preq |= nn->cap_bit; + } +} + +void +if_legacy_to_capnv(nvlist_t *nv, unsigned ifr_cap, unsigned ifr_req) +{ + const struct ifcap_nv_bit_name *nn; + unsigned i; + + for (i = 0; i != nitems(ifcap_nv_bit_names); i++) { + nn = &ifcap_nv_bit_names[i]; + if ((nn->cap_bit & ifr_cap) == 0) + continue; + nvlist_add_bool(nv, nn->cap_name, + (nn->cap_bit & ifr_req) != 0); + } +} + /* * Hardware specific interface ioctls. */ @@ -2403,12 +2483,14 @@ int error = 0, do_ifup = 0; int new_flags, temp_flags; size_t namelen, onamelen; - size_t descrlen; + size_t descrlen, nvbuflen; char *descrbuf, *odescrbuf; char new_name[IFNAMSIZ]; char old_name[IFNAMSIZ], strbuf[IFNAMSIZ + 8]; struct ifaddr *ifa; struct sockaddr_dl *sdl; + nvlist_t *nvcap; + void *buf; ifr = (struct ifreq *)data; switch (cmd) { @@ -2423,8 +2505,51 @@ break; case SIOCGIFCAP: - ifr->ifr_reqcap = ifp->if_capabilities; - ifr->ifr_curcap = ifp->if_capenable; + if ((ifp->if_capabilities & IFCAP_NV) == 0) { + ifr->ifr_reqcap = ifp->if_capabilities; + ifr->ifr_curcap = ifp->if_capenable; + } else { + nvcap = nvlist_create(0); + error = (*ifp->if_ioctl)(ifp, SIOCGIFCAPNV, + __DECONST(caddr_t, nvcap)); + if (error == 0) + error = nvlist_error(nvcap); + if (error == 0) { + if_capnv_to_legacy(nvcap, + (unsigned *)&ifr->ifr_reqcap, + (unsigned *)&ifr->ifr_curcap); + } + nvlist_destroy(nvcap); + } + break; + + case SIOCGIFCAPNV: + if ((ifp->if_capabilities & IFCAP_NV) == 0) { + error = EINVAL; + break; + } + buf = NULL; + nvcap = nvlist_create(0); + error = (*ifp->if_ioctl)(ifp, SIOCGIFCAPNV, + __DECONST(caddr_t, nvcap)); + if (error == 0) { + buf = nvlist_pack(nvcap, &nvbuflen); + if (buf == NULL) + error = EDOOFUS; + } + if (error == 0) { + if (nvbuflen > ifr->ifr_cap_nv.buf_length) { + ifr->ifr_cap_nv.length = nvbuflen; + ifr->ifr_cap_nv.buffer = NULL; + error = EFBIG; + } + } + if (error == 0) { + ifr->ifr_cap_nv.length = nvbuflen; + error = copyout(buf, ifr->ifr_cap_nv.buffer, nvbuflen); + } + free(buf, M_NVLIST); + nvlist_destroy(nvcap); break; case SIOCGIFDATA: @@ -2565,13 +2690,51 @@ case SIOCSIFCAP: error = priv_check(td, PRIV_NET_SETIFCAP); - if (error) + if (error != 0) + return (error); + if (ifp->if_ioctl == NULL) + return (EOPNOTSUPP); + if ((ifp->if_capabilities & IFCAP_NV) == 0) { + if (ifr->ifr_reqcap & ~ifp->if_capabilities) + error = EINVAL; + else + error = (*ifp->if_ioctl)(ifp, cmd, data); + } else { + nvcap = nvlist_create(0); + if_legacy_to_capnv(nvcap, IFCAP_ALLCAPS, ifr->ifr_reqcap); + error = (*ifp->if_ioctl)(ifp, SIOCSIFCAPNV, + __DECONST(caddr_t, nvcap)); + nvlist_destroy(nvcap); + } + if (error == 0) + getmicrotime(&ifp->if_lastchange); + break; + + case SIOCSIFCAPNV: + error = priv_check(td, PRIV_NET_SETIFCAP); + if (error != 0) return (error); if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); - if (ifr->ifr_reqcap & ~ifp->if_capabilities) + if ((ifp->if_capabilities & IFCAP_NV) == 0) return (EINVAL); - error = (*ifp->if_ioctl)(ifp, cmd, data); + if (ifr->ifr_cap_nv.length > IFR_CAP_NV_MAXBUFSIZE) + return (EINVAL); + nvcap = NULL; + buf = malloc(ifr->ifr_cap_nv.length, M_TEMP, M_WAITOK); + error = copyin(ifr->ifr_cap_nv.buffer, + buf, ifr->ifr_cap_nv.length); + if (error == 0) { + nvcap = nvlist_unpack(buf, ifr->ifr_cap_nv.length, 0); + if (nvcap == NULL) + error = EINVAL; + } + if (error == 0) { + error = (*ifp->if_ioctl)(ifp, cmd, + __DECONST(caddr_t, nvcap)); + } + nvlist_destroy(nvcap); + free(buf, M_TEMP); if (error == 0) getmicrotime(&ifp->if_lastchange); break; diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -147,4 +147,7 @@ #define SIOCGIFDOWNREASON _IOWR('i', 154, struct ifdownreason) +#define SIOCSIFCAPNV _IOW('i', 155, struct ifreq) /* set IF features */ +#define SIOCGIFCAPNV _IOWR('i', 156, struct ifreq) /* get IF features */ + #endif /* !_SYS_SOCKIO_H_ */