diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1317,6 +1317,11 @@ iflibdd.9 ifdi_detach.9 \ iflibdd.9 ifdi_get_counter.9 \ iflibdd.9 ifdi_i2c_req.9 \ + iflibdd.9 ifdi_get_rss_hash.9 \ + iflibdd.9 ifdi_get_rss_key.9 \ + iflibdd.9 ifdi_get_rss_table.9 \ + iflibdd.9 ifdi_set_rss_key.9 \ + iflibdd.9 ifdi_set_rss_table.9 \ iflibdd.9 ifdi_init.9 \ iflibdd.9 ifdi_intr_enable.9 \ iflibdd.9 ifdi_intr_disable.9 \ diff --git a/share/man/man9/iflibdd.9 b/share/man/man9/iflibdd.9 --- a/share/man/man9/iflibdd.9 +++ b/share/man/man9/iflibdd.9 @@ -1,4 +1,4 @@ -.Dd September 11, 2026 +.Dd September 19, 2026 .Dt IFLIBDD 9 .Os .Sh NAME @@ -194,6 +194,31 @@ .Fa "if_ctx_t ctx" .Fa "struct ifi2creq *req" .Fc +.Ft int +.Fo ifdi_get_rss_key +.Fa "if_ctx_t ctx" +.Fa "struct ifrsskey *key" +.Fc +.Ft int +.Fo ifdi_set_rss_key +.Fa "if_ctx_t ctx" +.Fa "struct ifrsskey *key" +.Fc +.Ft int +.Fo ifdi_get_rss_hash +.Fa "if_ctx_t ctx" +.Fa "struct ifrsshash *hash" +.Fc +.Ft int +.Fo ifdi_get_rss_table +.Fa "if_ctx_t ctx" +.Fa "struct ifrsstable *table" +.Fc +.Ft int +.Fo ifdi_set_rss_table +.Fa "if_ctx_t ctx" +.Fa "struct ifrsstable *table" +.Fc .Sh FUNCTIONS The above named functions are device dependent configuration functions. These routines are registered with iflib by the driver and are called from the @@ -364,7 +389,68 @@ .It Fn ifdi_led_func .It Fn ifdi_sysctl_int_delay .It Fn ifdi_i2c_req +.It Fn ifdi_get_rss_key +Optional function that reports the hash function, key length and key the +device is programmed with, for +.Dv SIOCGIFRSSKEY . +.It Fn ifdi_set_rss_key +Optional function that programs a hash key, for +.Dv SIOCSIFRSSKEY . +iflib has checked that the requested function is +.Dv RSS_FUNC_TOEPLITZ +and that the length fits the buffer, and has cleared the bytes past the +key; reject a length the device cannot use with +.Er EINVAL . +The key must survive +.Fn ifdi_init . +.It Fn ifdi_get_rss_hash +Optional function that reports the hash function and the +.Dv RSS_TYPE_ +selections the device is programmed with, for +.Dv SIOCGIFRSSHASH . +.It Fn ifdi_get_rss_table +Optional function that stores the receive queue of each indirection table +entry in +.Va ifrt_table +and sets +.Va ifrt_nentries +to +.Va isc_rss_table_size , +for +.Dv SIOCGIFRSSTABLE . +iflib fills in +.Va ifrt_nqueues . +.It Fn ifdi_set_rss_table +Optional function that programs the indirection table, for +.Dv SIOCSIFRSSTABLE . +iflib has checked that +.Va ifrt_nentries +equals +.Va isc_rss_table_size +and that every entry names an existing receive queue. +The table must survive +.Fn ifdi_init . .El +.Pp +The five RSS functions run with the context lock held. +A driver that does not provide one returns +.Er EOPNOTSUPP ; +one whose state is not available yet should return +.Er ENXIO . +iflib itself returns +.Er ENXIO +for all five until +.Fn ifdi_attach_post +has completed, so a driver need not track that. +iflib clears a query's buffer past the interface name before the driver +fills it, and checks a request before calling a setter, so a malformed +request is refused with +.Er EINVAL +whether or not the driver provides the setter; probe for support with a +query. +A driver implementing the table functions must set +.Va isc_rss_table_size , +which iflib takes as the table length. .Sh SEE ALSO .Xr ifconfig 8 , .Xr iflibdi 9 , diff --git a/sys/net/ifdi_if.m b/sys/net/ifdi_if.m --- a/sys/net/ifdi_if.m +++ b/sys/net/ifdi_if.m @@ -132,12 +132,32 @@ return (EOPNOTSUPP); } + static int + null_set_rss_key(if_ctx_t _ctx __unused, struct ifrsskey *_key __unused) + { + return (EOPNOTSUPP); + } + static int null_get_rss_hash(if_ctx_t _ctx __unused, struct ifrsshash *_hash __unused) { return (EOPNOTSUPP); } + static int + null_get_rss_table(if_ctx_t _ctx __unused, + struct ifrsstable *_table __unused) + { + return (EOPNOTSUPP); + } + + static int + null_set_rss_table(if_ctx_t _ctx __unused, + struct ifrsstable *_table __unused) + { + return (EOPNOTSUPP); + } + static int null_vf_status(if_ctx_t _ctx __unused, struct if_vf_status **_status __unused) @@ -362,19 +382,35 @@ # # -# Report the programmed RSS key and hash selections under the context lock. -# Unsupported queries return EOPNOTSUPP; unavailable state returns an error. +# Report or program the RSS key, hash selections and indirection table under +# the context lock. iflib validates what it hands to the setters. +# Unsupported methods return EOPNOTSUPP; unavailable state returns an error. # METHOD int get_rss_key { if_ctx_t _ctx; struct ifrsskey *_key; } DEFAULT null_get_rss_key; +METHOD int set_rss_key { + if_ctx_t _ctx; + struct ifrsskey *_key; +} DEFAULT null_set_rss_key; + METHOD int get_rss_hash { if_ctx_t _ctx; struct ifrsshash *_hash; } DEFAULT null_get_rss_hash; +METHOD int get_rss_table { + if_ctx_t _ctx; + struct ifrsstable *_table; +} DEFAULT null_get_rss_table; + +METHOD int set_rss_table { + if_ctx_t _ctx; + struct ifrsstable *_table; +} DEFAULT null_set_rss_table; + METHOD int i2c_req { if_ctx_t _ctx; struct ifi2creq *_req; diff --git a/sys/net/iflib.c b/sys/net/iflib.c --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -4985,15 +4985,111 @@ break; } case SIOCGIFRSSKEY: + { + struct ifrsskey *ifrk = (struct ifrsskey *)data; + + memset(&ifrk->ifrk_func, 0, sizeof(*ifrk) - + __offsetof(struct ifrsskey, ifrk_func)); CTX_LOCK(ctx); - err = IFDI_GET_RSS_KEY(ctx, (struct ifrsskey *)data); + if ((ctx->ifc_flags & IFC_INIT_DONE) != 0) + err = IFDI_GET_RSS_KEY(ctx, ifrk); + else + err = ENXIO; CTX_UNLOCK(ctx); break; + } case SIOCGIFRSSHASH: + { + struct ifrsshash *ifrh = (struct ifrsshash *)data; + + memset(&ifrh->ifrh_func, 0, sizeof(*ifrh) - + __offsetof(struct ifrsshash, ifrh_func)); + CTX_LOCK(ctx); + if ((ctx->ifc_flags & IFC_INIT_DONE) != 0) + err = IFDI_GET_RSS_HASH(ctx, ifrh); + else + err = ENXIO; + CTX_UNLOCK(ctx); + break; + } + case SIOCSIFRSSKEY: + { + struct ifrsskey *ifrk = (struct ifrsskey *)data; + + if (ifrk->ifrk_func != RSS_FUNC_TOEPLITZ || + ifrk->ifrk_spare0 != 0 || + ifrk->ifrk_keylen == 0 || + ifrk->ifrk_keylen > sizeof(ifrk->ifrk_key)) { + err = EINVAL; + break; + } + memset(&ifrk->ifrk_key[ifrk->ifrk_keylen], 0, + sizeof(ifrk->ifrk_key) - ifrk->ifrk_keylen); + CTX_LOCK(ctx); + if ((ctx->ifc_flags & IFC_INIT_DONE) != 0) + err = IFDI_SET_RSS_KEY(ctx, ifrk); + else + err = ENXIO; + CTX_UNLOCK(ctx); + break; + } + case SIOCGIFRSSTABLE: + { + struct ifrsstable *ifrt = (struct ifrsstable *)data; + if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; + + if (scctx->isc_rss_table_size > RSS_TABLELEN) { + err = EMSGSIZE; + break; + } + memset(&ifrt->ifrt_nentries, 0, sizeof(*ifrt) - + __offsetof(struct ifrsstable, ifrt_nentries)); CTX_LOCK(ctx); - err = IFDI_GET_RSS_HASH(ctx, (struct ifrsshash *)data); + if ((ctx->ifc_flags & IFC_INIT_DONE) != 0) + err = IFDI_GET_RSS_TABLE(ctx, ifrt); + else + err = ENXIO; CTX_UNLOCK(ctx); + if (err == 0 && + ifrt->ifrt_nentries != scctx->isc_rss_table_size) + err = EINVAL; + if (err == 0) + ifrt->ifrt_nqueues = scctx->isc_nrxqsets; break; + } + case SIOCSIFRSSTABLE: + { + struct ifrsstable *ifrt = (struct ifrsstable *)data; + if_softc_ctx_t scctx = &ctx->ifc_softc_ctx; + uint16_t i; + + if (scctx->isc_rss_table_size > RSS_TABLELEN) { + err = EMSGSIZE; + break; + } + if (ifrt->ifrt_nentries != scctx->isc_rss_table_size) { + err = EINVAL; + break; + } + for (i = 0; i < ifrt->ifrt_nentries; i++) { + if (ifrt->ifrt_table[i] >= scctx->isc_nrxqsets) + break; + } + if (i < ifrt->ifrt_nentries) { + err = EINVAL; + break; + } + memset(&ifrt->ifrt_table[ifrt->ifrt_nentries], 0, + sizeof(ifrt->ifrt_table) - + ifrt->ifrt_nentries * sizeof(ifrt->ifrt_table[0])); + CTX_LOCK(ctx); + if ((ctx->ifc_flags & IFC_INIT_DONE) != 0) + err = IFDI_SET_RSS_TABLE(ctx, ifrt); + else + err = ENXIO; + CTX_UNLOCK(ctx); + break; + } case SIOCGPRIVATE_0: case SIOCSDRVSPEC: case SIOCGDRVSPEC: