.. _dpdk-testpmd:
+vhost-user-client tx retries config
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For vhost-user-client interfaces, the max amount of retries can be changed from
+the default 8 by setting ``tx-retries-max``.
+
+The minimum is 0 which means there will be no retries and if any packets in
+each batch cannot be sent immediately they will be dropped. The maximum is 32,
+which would mean that after the first packet(s) in the batch was sent there
+could be a maximum of 32 more retries.
+
+Retries can help with avoiding packet loss when temporarily unable to send to a
+vhost interface because the virtqueue is full. However, spending more time
+retrying to send to one interface, will reduce the time available for rx/tx and
+processing packets on other interfaces, so some tuning may be required for best
+performance.
+
+Tx retries max can be set for vhost-user-client ports::
+
+ $ ovs-vsctl set Interface vhost-client-1 options:tx-retries-max=0
+
+.. note::
+
+ Configurable vhost tx retries are not supported with vhost-user ports.
+
DPDK in the Guest
-----------------
packets can be sent, it may mean the guest is not accepting packets, so there
are no (more) retries.
+For information about configuring the maximum amount of tx retries for
+vhost-user-client interfaces see `vhost-user-client tx retries config`_.
+
.. note::
Maximum vhost tx batch size is defined by NETDEV_MAX_BURST, and is currently
typedef uint16_t dpdk_port_t;
#define DPDK_PORT_ID_FMT "%"PRIu16
-#define VHOST_ENQ_RETRY_NUM 8
+/* Minimum amount of vhost tx retries, effectively a disable. */
+#define VHOST_ENQ_RETRY_MIN 0
+/* Maximum amount of vhost tx retries. */
+#define VHOST_ENQ_RETRY_MAX 32
+/* Legacy default value for vhost tx retries. */
+#define VHOST_ENQ_RETRY_DEF 8
+
#define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)
static const struct rte_eth_conf port_conf = {
/* True if vHost device is 'up' and has been reconfigured at least once */
bool vhost_reconfigured;
- /* 3 pad bytes here. */
+
+ atomic_uint8_t vhost_tx_retries_max;
+ /* 2 pad bytes here. */
);
PADDED_MEMBERS(CACHE_LINE_SIZE,
return ENOMEM;
}
+ atomic_init(&dev->vhost_tx_retries_max, VHOST_ENQ_RETRY_DEF);
+
return common_construct(netdev, DPDK_ETH_PORT_ID_INVALID,
DPDK_DEV_VHOST, socket_id);
}
{
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
const char *path;
+ int max_tx_retries, cur_max_tx_retries;
ovs_mutex_lock(&dev->mutex);
if (!(dev->vhost_driver_flags & RTE_VHOST_USER_CLIENT)) {
netdev_request_reconfigure(netdev);
}
}
+
+ max_tx_retries = smap_get_int(args, "tx-retries-max",
+ VHOST_ENQ_RETRY_DEF);
+ if (max_tx_retries < VHOST_ENQ_RETRY_MIN
+ || max_tx_retries > VHOST_ENQ_RETRY_MAX) {
+ max_tx_retries = VHOST_ENQ_RETRY_DEF;
+ }
+ atomic_read_relaxed(&dev->vhost_tx_retries_max, &cur_max_tx_retries);
+ if (max_tx_retries != cur_max_tx_retries) {
+ atomic_store_relaxed(&dev->vhost_tx_retries_max, max_tx_retries);
+ VLOG_INFO("Max Tx retries for vhost device '%s' set to %d",
+ netdev_get_name(netdev), max_tx_retries);
+ }
ovs_mutex_unlock(&dev->mutex);
return 0;
unsigned int total_pkts = cnt;
unsigned int dropped = 0;
int i, retries = 0;
+ int max_retries = VHOST_ENQ_RETRY_MIN;
int vid = netdev_dpdk_get_vid(dev);
qid = dev->tx_q[qid % netdev->n_txq].map;
cnt -= tx_pkts;
/* Prepare for possible retry.*/
cur_pkts = &cur_pkts[tx_pkts];
+ if (OVS_UNLIKELY(cnt && !retries)) {
+ /*
+ * Read max retries as there are packets not sent
+ * and no retries have already occurred.
+ */
+ atomic_read_relaxed(&dev->vhost_tx_retries_max, &max_retries);
+ }
} else {
/* No packets sent - do not retry.*/
break;
}
- } while (cnt && (retries++ < VHOST_ENQ_RETRY_NUM));
+ } while (cnt && (retries++ < max_retries));
rte_spinlock_unlock(&dev->tx_q[qid].tx_lock);
rte_spinlock_lock(&dev->stats_lock);
netdev_dpdk_vhost_update_tx_counters(&dev->stats, pkts, total_pkts,
cnt + dropped);
- dev->tx_retries += MIN(retries, VHOST_ENQ_RETRY_NUM);
+ dev->tx_retries += MIN(retries, max_retries);
rte_spinlock_unlock(&dev->stats_lock);
out: