This approach not only ensures a relatively balanced distribution of traffic across the transmission queues of the port but also maintains high transmission performance.
Signed-off-by: wangyan4 <[email protected]> --- lib/dpif-netdev-private-thread.h | 1 + lib/dpif-netdev.c | 82 +++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/lib/dpif-netdev-private-thread.h b/lib/dpif-netdev-private-thread.h index 8715b3837..fea78c617 100644 --- a/lib/dpif-netdev-private-thread.h +++ b/lib/dpif-netdev-private-thread.h @@ -229,6 +229,7 @@ struct dp_netdev_pmd_thread { /* Next time when PMD should try RCU quiescing. */ long long next_rcu_quiesce; + uint32_t pmd_id; /* pmd id of this pmd thread. */ }; #ifdef __cplusplus diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 2a529f272..1d5788331 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -463,12 +463,14 @@ struct dp_netdev_rxq { enum txq_req_mode { TXQ_REQ_MODE_THREAD, TXQ_REQ_MODE_HASH, + TXQ_REQ_MODE_HASH_PER_THREAD }; enum txq_mode { TXQ_MODE_STATIC, TXQ_MODE_XPS, TXQ_MODE_XPS_HASH, + TXQ_MODE_XPS_HASH_PER_THREAD }; /* A port in a netdev-based datapath. */ @@ -5410,6 +5412,8 @@ dpif_netdev_port_set_config(struct dpif *dpif, odp_port_t port_no, if (nullable_string_is_equal(tx_steering_mode, "hash")) { txq_mode = TXQ_REQ_MODE_HASH; + } else if (nullable_string_is_equal(tx_steering_mode, "hash-per-thread")) { + txq_mode = TXQ_REQ_MODE_HASH_PER_THREAD; } else { txq_mode = TXQ_REQ_MODE_THREAD; } @@ -5541,7 +5545,43 @@ dp_netdev_pmd_flush_output_on_port(struct dp_netdev_pmd_thread *pmd, output_cnt = dp_packet_batch_size(&p->output_pkts); ovs_assert(output_cnt > 0); - if (p->port->txq_mode == TXQ_MODE_XPS_HASH) { + int pmd_cnt = cmap_count(&pmd->dp->poll_threads); + if (p->port->txq_mode == TXQ_MODE_XPS_HASH_PER_THREAD) { + int n_txq = netdev_n_txq(p->port->netdev); + /* for example 6 txq, ovs has 4 pmd + * pmd0 alloc txq 0,4 pmdid=0 + * pmd1 alloc txq 1,5 pmdid=1 + * pmd2 alloc txq 2 pmdid=2 + * pmd3 alloc txq 3 pmdid=3*/ + int ntxq_this_thread = n_txq / pmd_cnt + (pmd->pmd_id < + (n_txq % pmd_cnt) ? 1 : 0); + + /* Re-batch per txq based on packet hash. */ + struct dp_packet *packet; + DP_PACKET_BATCH_FOR_EACH (j, packet, &p->output_pkts) { + uint32_t hash; + + if (OVS_LIKELY(dp_packet_rss_valid(packet))) { + hash = dp_packet_get_rss_hash(packet); + } else { + struct flow flow; + + flow_extract(packet, &flow); + hash = flow_hash_5tuple(&flow, 0); + } + dp_packet_batch_add(&p->txq_pkts[hash % ntxq_this_thread], packet); + } + + /* Flush batches of each Tx queues. */ + for (i = 0; i < ntxq_this_thread; i++) { + if (dp_packet_batch_is_empty(&p->txq_pkts[i])) { + continue; + } + tx_qid = i * pmd_cnt + pmd->pmd_id; + netdev_send(p->port->netdev, tx_qid, &p->txq_pkts[i], true); + dp_packet_batch_init(&p->txq_pkts[i]); + } + } else if (p->port->txq_mode == TXQ_MODE_XPS_HASH) { int n_txq = netdev_n_txq(p->port->netdev); /* Re-batch per txq based on packet hash. */ @@ -6661,6 +6701,7 @@ reconfigure_pmd_threads(struct dp_netdev *dp) } /* Check for required new pmd threads */ + uint32_t pmd_index = 0; FOR_EACH_CORE_ON_DUMP(core, pmd_cores) { pmd = dp_netdev_get_pmd(dp, core->core_id); if (!pmd) { @@ -6668,7 +6709,7 @@ reconfigure_pmd_threads(struct dp_netdev *dp) pmd = xzalloc(sizeof *pmd); dp_netdev_configure_pmd(pmd, dp, core->core_id, core->numa_id); - + pmd->pmd_id = pmd_index; ds_put_format(&name, "pmd-c%02d/id:", core->core_id); pmd->thread = ovs_thread_create(ds_cstr(&name), pmd_thread_main, pmd); @@ -6724,6 +6765,24 @@ pmd_remove_stale_ports(struct dp_netdev *dp, ovs_mutex_unlock(&pmd->port_mutex); } +static enum txq_mode get_current_txq_mode(struct dp_netdev_port *port, + int wanted_txqs) +{ + /* With a single queue, there is no point in using hash mode. */ + if (port->txq_requested_mode == TXQ_REQ_MODE_HASH && + netdev_n_txq(port->netdev) > 1) { + return TXQ_MODE_XPS_HASH; + } else if (port->txq_requested_mode == TXQ_REQ_MODE_HASH_PER_THREAD && + netdev_n_txq(port->netdev) >= wanted_txqs) { + return TXQ_MODE_XPS_HASH_PER_THREAD; + } + else if (netdev_n_txq(port->netdev) < wanted_txqs) { + return TXQ_MODE_XPS; + } else { + return TXQ_MODE_STATIC; + } +} + /* Must be called each time a port is added/removed or the cmask changes. * This creates and destroys pmd threads, reconfigures ports, opens their * rxqs and assigns all rxqs/txqs to pmd threads. */ @@ -6764,11 +6823,7 @@ reconfigure_datapath(struct dp_netdev *dp) * unnecessary. */ HMAP_FOR_EACH (port, node, &dp->ports) { if (netdev_is_reconf_required(port->netdev) - || ((port->txq_mode == TXQ_MODE_XPS) - != (netdev_n_txq(port->netdev) < wanted_txqs)) - || ((port->txq_mode == TXQ_MODE_XPS_HASH) - != (port->txq_requested_mode == TXQ_REQ_MODE_HASH - && netdev_n_txq(port->netdev) > 1))) { + || port->txq_mode != get_current_txq_mode(port, wanted_txqs)) { port->need_reconfigure = true; } } @@ -6802,15 +6857,7 @@ reconfigure_datapath(struct dp_netdev *dp) seq_change(dp->port_seq); port_destroy(port); } else { - /* With a single queue, there is no point in using hash mode. */ - if (port->txq_requested_mode == TXQ_REQ_MODE_HASH && - netdev_n_txq(port->netdev) > 1) { - port->txq_mode = TXQ_MODE_XPS_HASH; - } else if (netdev_n_txq(port->netdev) < wanted_txqs) { - port->txq_mode = TXQ_MODE_XPS; - } else { - port->txq_mode = TXQ_MODE_STATIC; - } + port->txq_mode = get_current_txq_mode(port, wanted_txqs); } } @@ -8066,7 +8113,8 @@ dp_netdev_add_port_tx_to_pmd(struct dp_netdev_pmd_thread *pmd, tx->flush_time = 0LL; dp_packet_batch_init(&tx->output_pkts); - if (tx->port->txq_mode == TXQ_MODE_XPS_HASH) { + if (tx->port->txq_mode == TXQ_MODE_XPS_HASH || + tx->port->txq_mode == TXQ_MODE_XPS_HASH_PER_THREAD) { int i, n_txq = netdev_n_txq(tx->port->netdev); tx->txq_pkts = xzalloc(n_txq * sizeof *tx->txq_pkts); -- 2.39.2 (Apple Git-143) _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
