rte_eth_dev_configure() sets the MTU from rxmode.mtu without calling
mtu_set, and keeps Rx queues that are already set up when the queue
count doesn't change. Stopping the port and reconfiguring it with a
larger MTU, or without RTE_ETH_RX_OFFLOAD_SCATTER, therefore skipped
both the MTU change check and the Rx queue setup check, and GQI went
on to chain large frames for an application that hadn't enabled
scatter.
Move the check into gve_rx_check_scatter() and call it from
gve_dev_start() as well as gve_dev_mtu_set(), so starting such a
configuration fails with an error log instead.
Fixes: cffdca824388 ("net/gve: refuse an MTU that needs Rx scatter when it is
off")
Cc: [email protected]
Reported-by: Stephen Hemminger <[email protected]>
Signed-off-by: Ryan Wolfe <[email protected]>
---
Built with -Dwerror=true (gcc and clang); not yet run on gVNIC.
drivers/net/gve/gve_ethdev.c | 53 ++++++++++++++++++++++++------------
1 file changed, 36 insertions(+), 17 deletions(-)
diff --git a/drivers/net/gve/gve_ethdev.c b/drivers/net/gve/gve_ethdev.c
index 7506c46d9a..269950fde0 100644
--- a/drivers/net/gve/gve_ethdev.c
+++ b/drivers/net/gve/gve_ethdev.c
@@ -459,6 +459,32 @@ gve_start_queues(struct rte_eth_dev *dev)
return ret;
}
+/* GQI chains a frame larger than one Rx buffer into a multi-segment
+ * mbuf. No Rx offload is per-queue here, so check the port offloads.
+ */
+static int
+gve_rx_check_scatter(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ struct gve_priv *priv = dev->data->dev_private;
+ uint16_t i;
+
+ if (!gve_is_gqi(priv) ||
+ (dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SCATTER))
+ return 0;
+
+ for (i = 0; i < dev->data->nb_rx_queues; i++) {
+ struct gve_rx_queue *rxq = dev->data->rx_queues[i];
+
+ if (rxq != NULL && gve_rx_gqi_needs_scatter(mtu,
rxq->rx_buf_len)) {
+ PMD_DRV_LOG(ERR, "MTU %u needs Rx scatter with %u byte
Rx buffers",
+ mtu, rxq->rx_buf_len);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static int
gve_dev_start(struct rte_eth_dev *dev)
{
@@ -471,6 +497,13 @@ gve_dev_start(struct rte_eth_dev *dev)
return -EPERM;
}
+ /* rte_eth_dev_configure() sets the MTU and the Rx offloads without
+ * calling mtu_set, and keeps Rx queues already set up, so check again.
+ */
+ ret = gve_rx_check_scatter(dev, dev->data->mtu);
+ if (ret != 0)
+ return ret;
+
ret = gve_start_queues(dev);
if (ret != 0) {
PMD_DRV_LOG(ERR, "Failed to start queues");
@@ -1031,23 +1064,9 @@ gve_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
return -EBUSY;
}
- /* GQI chains a frame larger than one Rx buffer into a multi-segment
- * mbuf. No Rx offload is per-queue here, so check the port offloads.
- */
- if (gve_is_gqi(priv) &&
- !(dev->data->dev_conf.rxmode.offloads &
RTE_ETH_RX_OFFLOAD_SCATTER)) {
- for (uint16_t i = 0; i < dev->data->nb_rx_queues; i++) {
- struct gve_rx_queue *rxq = dev->data->rx_queues[i];
-
- if (rxq != NULL &&
- gve_rx_gqi_needs_scatter(mtu, rxq->rx_buf_len)) {
- PMD_DRV_LOG(ERR,
- "MTU %u needs Rx scatter with %u
byte Rx buffers",
- mtu, rxq->rx_buf_len);
- return -EINVAL;
- }
- }
- }
+ err = gve_rx_check_scatter(dev, mtu);
+ if (err != 0)
+ return err;
err = process_priv->ctrl_ops->set_mtu(priv, mtu);
if (err) {
--
2.56.0.218.g1ec904b173-goog