Add simple Tx xmit functions (zxdh_xmit_pkts_simple) for single-segment packet xmit.
Signed-off-by: Junlong Wang <[email protected]> --- drivers/net/zxdh/zxdh_ethdev.c | 11 +- drivers/net/zxdh/zxdh_rxtx.c | 341 +++++++++++++++++++++++++-------- drivers/net/zxdh/zxdh_rxtx.h | 11 +- 3 files changed, 271 insertions(+), 92 deletions(-) diff --git a/drivers/net/zxdh/zxdh_ethdev.c b/drivers/net/zxdh/zxdh_ethdev.c index 0ab137189b..54d43b54d9 100644 --- a/drivers/net/zxdh/zxdh_ethdev.c +++ b/drivers/net/zxdh/zxdh_ethdev.c @@ -490,7 +490,7 @@ zxdh_dev_free_mbufs(struct rte_eth_dev *dev) if (!vq) continue; while ((buf = zxdh_queue_detach_unused(vq)) != NULL) - rte_pktmbuf_free(buf); + rte_pktmbuf_free_seg(buf); PMD_DRV_LOG(DEBUG, "freeing %s[%d] used and unused buf", "rxq", i * 2); } @@ -499,7 +499,7 @@ zxdh_dev_free_mbufs(struct rte_eth_dev *dev) if (!vq) continue; while ((buf = zxdh_queue_detach_unused(vq)) != NULL) - rte_pktmbuf_free(buf); + rte_pktmbuf_free_seg(buf); PMD_DRV_LOG(DEBUG, "freeing %s[%d] used and unused buf", "txq", i * 2 + 1); } @@ -1291,10 +1291,15 @@ static int zxdh_scattered_rx(struct rte_eth_dev *eth_dev) static int32_t zxdh_set_rxtx_funcs(struct rte_eth_dev *eth_dev) { + uint64_t tx_offloads = eth_dev->data->dev_conf.txmode.offloads; + eth_dev->tx_pkt_prepare = zxdh_xmit_pkts_prepare; eth_dev->data->scattered_rx = zxdh_scattered_rx(eth_dev); - eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed; + if (!(tx_offloads & RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) + eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_simple; + else + eth_dev->tx_pkt_burst = &zxdh_xmit_pkts_packed; if (eth_dev->data->scattered_rx) eth_dev->rx_pkt_burst = &zxdh_recv_pkts_packed; diff --git a/drivers/net/zxdh/zxdh_rxtx.c b/drivers/net/zxdh/zxdh_rxtx.c index 4723d4b1d2..e8f1cd65b0 100644 --- a/drivers/net/zxdh/zxdh_rxtx.c +++ b/drivers/net/zxdh/zxdh_rxtx.c @@ -114,6 +114,22 @@ RTE_MBUF_F_TX_SEC_OFFLOAD | \ RTE_MBUF_F_TX_UDP_SEG) +#if RTE_CACHE_LINE_SIZE == 128 +#define NEXT_CACHELINE_OFF_16B 8 +#define NEXT_CACHELINE_OFF_8B 16 +#elif RTE_CACHE_LINE_SIZE == 64 +#define NEXT_CACHELINE_OFF_16B 4 +#define NEXT_CACHELINE_OFF_8B 8 +#else +#define NEXT_CACHELINE_OFF_16B (RTE_CACHE_LINE_SIZE / 16) +#define NEXT_CACHELINE_OFF_8B (RTE_CACHE_LINE_SIZE / 8) +#endif +#define N_PER_LOOP NEXT_CACHELINE_OFF_8B +#define N_PER_LOOP_MASK (N_PER_LOOP - 1) + +#define rxq_get_vq(q) ((q)->vq) +#define txq_get_vq(q) ((q)->vq) + uint32_t zxdh_outer_l2_type[16] = { 0, RTE_PTYPE_L2_ETHER, @@ -201,43 +217,6 @@ uint32_t zxdh_inner_l4_type[16] = { 0, }; -static void -zxdh_xmit_cleanup_inorder_packed(struct zxdh_virtqueue *vq, int32_t num) -{ - uint16_t used_idx = 0; - uint16_t id = 0; - uint16_t curr_id = 0; - uint16_t free_cnt = 0; - uint16_t size = vq->vq_nentries; - struct zxdh_vring_packed_desc *desc = vq->vq_packed.ring.desc; - struct zxdh_vq_desc_extra *dxp = NULL; - - used_idx = vq->vq_used_cons_idx; - /* desc_is_used has a load-acquire or rte_io_rmb inside - * and wait for used desc in virtqueue. - */ - while (num > 0 && desc_is_used(&desc[used_idx], vq)) { - id = desc[used_idx].id; - do { - curr_id = used_idx; - dxp = &vq->vq_descx[used_idx]; - used_idx += dxp->ndescs; - free_cnt += dxp->ndescs; - num -= dxp->ndescs; - if (used_idx >= size) { - used_idx -= size; - vq->used_wrap_counter ^= 1; - } - if (dxp->cookie != NULL) { - rte_pktmbuf_free(dxp->cookie); - dxp->cookie = NULL; - } - } while (curr_id != id); - } - vq->vq_used_cons_idx = used_idx; - vq->vq_free_cnt += free_cnt; -} - static inline uint16_t zxdh_get_mtu(struct zxdh_virtqueue *vq) { @@ -334,7 +313,7 @@ zxdh_xmit_fill_net_hdr(struct zxdh_virtqueue *vq, struct rte_mbuf *cookie, } static inline void -zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq, +zxdh_xmit_enqueue_push(struct zxdh_virtnet_tx *txvq, struct rte_mbuf *cookie) { struct zxdh_virtqueue *vq = txvq->vq; @@ -345,7 +324,6 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq, uint8_t hdr_len = vq->hw->dl_net_hdr_len; struct zxdh_vring_packed_desc *dp = &vq->vq_packed.ring.desc[id]; - dxp->ndescs = 1; dxp->cookie = cookie; hdr = rte_pktmbuf_mtod_offset(cookie, struct zxdh_net_hdr_dl *, -hdr_len); zxdh_xmit_fill_net_hdr(vq, cookie, hdr); @@ -362,52 +340,57 @@ zxdh_enqueue_xmit_packed_fast(struct zxdh_virtnet_tx *txvq, } static inline void -zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq, +zxdh_xmit_enqueue_append(struct zxdh_virtnet_tx *txvq, struct rte_mbuf *cookie, uint16_t needed) { struct zxdh_tx_region *txr = txvq->zxdh_net_hdr_mz->addr; struct zxdh_virtqueue *vq = txvq->vq; - uint16_t id = vq->vq_avail_idx; - struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id]; + struct zxdh_vq_desc_extra *dep = &vq->vq_descx[0]; uint16_t head_idx = vq->vq_avail_idx; uint16_t idx = head_idx; struct zxdh_vring_packed_desc *start_dp = vq->vq_packed.ring.desc; struct zxdh_vring_packed_desc *head_dp = &vq->vq_packed.ring.desc[idx]; struct zxdh_net_hdr_dl *hdr = NULL; - - uint16_t head_flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0; + uint16_t id = vq->vq_avail_idx; + struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id]; uint8_t hdr_len = vq->hw->dl_net_hdr_len; + uint16_t head_flags = 0; - dxp->ndescs = needed; - dxp->cookie = cookie; - head_flags |= vq->cached_flags; + /* + * IMPORTANT: For multi-seg packets, we set the head descriptor's cookie to NULL + * and store each segment's mbuf in its corresponding vq_descx[idx].cookie. + * This is required for the per-descriptor mbuf free in zxdh_xmit_fast_flush() + * which uses rte_pktmbuf_free_seg() to free individual segments. + * Any code path that attempts to read vq_descx[head_id].cookie will see NULL + * and must handle this case appropriately. + */ + dxp->cookie = NULL; + /* setup first tx ring slot to point to header stored in reserved region. */ start_dp[idx].addr = txvq->zxdh_net_hdr_mem + RTE_PTR_DIFF(&txr[idx].tx_hdr, txr); start_dp[idx].len = hdr_len; - head_flags |= ZXDH_VRING_DESC_F_NEXT; + start_dp[idx].id = idx; + head_flags |= vq->cached_flags | ZXDH_VRING_DESC_F_NEXT; hdr = (void *)&txr[idx].tx_hdr; - rte_prefetch1(hdr); + zxdh_xmit_fill_net_hdr(vq, cookie, hdr); + idx++; if (idx >= vq->vq_nentries) { idx -= vq->vq_nentries; vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED; } - zxdh_xmit_fill_net_hdr(vq, cookie, hdr); - do { start_dp[idx].addr = rte_pktmbuf_iova(cookie); start_dp[idx].len = cookie->data_len; - start_dp[idx].id = id; - if (likely(idx != head_idx)) { - uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0; - - flags |= vq->cached_flags; - start_dp[idx].flags = flags; - } + start_dp[idx].id = idx; + dep[idx].cookie = cookie; + uint16_t flags = cookie->next ? ZXDH_VRING_DESC_F_NEXT : 0; + flags |= vq->cached_flags; + start_dp[idx].flags = flags; idx++; if (idx >= vq->vq_nentries) { idx -= vq->vq_nentries; @@ -417,7 +400,6 @@ zxdh_enqueue_xmit_packed(struct zxdh_virtnet_tx *txvq, vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed); vq->vq_avail_idx = idx; - zxdh_queue_store_flags_packed(head_dp, head_flags); } @@ -456,7 +438,7 @@ zxdh_update_packet_stats(struct zxdh_virtnet_stats *stats, struct rte_mbuf *mbuf } static void -zxdh_xmit_flush(struct zxdh_virtqueue *vq) +zxdh_xmit_fast_flush(struct zxdh_virtqueue *vq) { uint16_t id = 0; uint16_t curr_id = 0; @@ -472,20 +454,22 @@ zxdh_xmit_flush(struct zxdh_virtqueue *vq) * for a used descriptor in the virtqueue. */ while (desc_is_used(&desc[used_idx], vq)) { + rte_prefetch0(&desc[used_idx + NEXT_CACHELINE_OFF_16B]); id = desc[used_idx].id; do { + desc[used_idx].id = used_idx; curr_id = used_idx; dxp = &vq->vq_descx[used_idx]; - used_idx += dxp->ndescs; - free_cnt += dxp->ndescs; - if (used_idx >= size) { - used_idx -= size; - vq->used_wrap_counter ^= 1; - } if (dxp->cookie != NULL) { - rte_pktmbuf_free(dxp->cookie); + rte_pktmbuf_free_seg(dxp->cookie); dxp->cookie = NULL; } + used_idx += 1; + free_cnt += 1; + if (unlikely(used_idx == size)) { + used_idx = 0; + vq->used_wrap_counter ^= 1; + } } while (curr_id != id); } vq->vq_used_cons_idx = used_idx; @@ -499,13 +483,12 @@ zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt struct zxdh_virtqueue *vq = txvq->vq; uint16_t nb_tx = 0; - zxdh_xmit_flush(vq); + zxdh_xmit_fast_flush(vq); for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { struct rte_mbuf *txm = tx_pkts[nb_tx]; int32_t can_push = 0; int32_t slots = 0; - int32_t need = 0; rte_prefetch0(txm); /* optimize ring usage */ @@ -522,26 +505,15 @@ zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkt * default => number of segments + 1 **/ slots = txm->nb_segs + !can_push; - need = slots - vq->vq_free_cnt; /* Positive value indicates it need free vring descriptors */ - if (unlikely(need > 0)) { - zxdh_xmit_cleanup_inorder_packed(vq, need); - need = slots - vq->vq_free_cnt; - if (unlikely(need > 0)) { - PMD_TX_LOG(ERR, - " No enough %d free tx descriptors to transmit." - "freecnt %d", - need, - vq->vq_free_cnt); - break; - } - } + if (unlikely(slots > vq->vq_free_cnt)) + break; /* Enqueue Packet buffers */ if (can_push) - zxdh_enqueue_xmit_packed_fast(txvq, txm); + zxdh_xmit_enqueue_push(txvq, txm); else - zxdh_enqueue_xmit_packed(txvq, txm, slots); + zxdh_xmit_enqueue_append(txvq, txm, slots); zxdh_update_packet_stats(&txvq->stats, txm); } txvq->stats.packets += nb_tx; @@ -1083,3 +1055,204 @@ uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint1 } return nb_rx; } + +static inline void pkt_padding(struct rte_mbuf *cookie, struct zxdh_hw *hw) +{ + uint16_t mtu_or_mss = 0; + uint16_t pkt_flag_lw16 = ZXDH_NO_IPID_UPDATE; + uint16_t l3_offset; + uint8_t pcode = ZXDH_PCODE_NO_IP_PKT_TYPE; + uint8_t l3_ptype = ZXDH_PI_L3TYPE_NOIP; + struct zxdh_pi_hdr *pi_hdr; + struct zxdh_pd_hdr_dl *pd_hdr; + struct zxdh_net_hdr_dl *net_hdr_dl = hw->net_hdr_dl; + uint8_t hdr_len = hw->dl_net_hdr_len; + uint16_t ol_flag = 0; + struct zxdh_net_hdr_dl *hdr; + + hdr = (struct zxdh_net_hdr_dl *)rte_pktmbuf_prepend(cookie, hdr_len); + rte_memcpy(hdr, net_hdr_dl, hdr_len); + + if (hw->has_tx_offload) { + pi_hdr = &hdr->pipd_hdr_dl.pi_hdr; + pd_hdr = &hdr->pipd_hdr_dl.pd_hdr; + + pcode = ZXDH_PCODE_IP_PKT_TYPE; + if (cookie->ol_flags & RTE_MBUF_F_TX_IPV6) + l3_ptype = ZXDH_PI_L3TYPE_IPV6; + else if (cookie->ol_flags & RTE_MBUF_F_TX_IPV4) + l3_ptype = ZXDH_PI_L3TYPE_IP; + else + pcode = ZXDH_PCODE_NO_IP_PKT_TYPE; + + if (cookie->ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + mtu_or_mss = (cookie->tso_segsz >= ZXDH_MIN_MSS) ? + cookie->tso_segsz : ZXDH_MIN_MSS; + pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL; + pkt_flag_lw16 |= ZXDH_NO_IP_FRAGMENT | ZXDH_TX_IP_CKSUM_CAL; + pcode = ZXDH_PCODE_TCP_PKT_TYPE; + } else if (cookie->ol_flags & RTE_MBUF_F_TX_UDP_SEG) { + mtu_or_mss = hw->eth_dev->data->mtu; + mtu_or_mss = (mtu_or_mss >= ZXDH_MIN_MSS) ? mtu_or_mss : ZXDH_MIN_MSS; + pkt_flag_lw16 |= ZXDH_TX_IP_CKSUM_CAL; + pi_hdr->pkt_flag_hi8 |= ZXDH_NO_TCP_FRAGMENT | ZXDH_TX_TCPUDP_CKSUM_CAL; + pcode = ZXDH_PCODE_UDP_PKT_TYPE; + } else { + pkt_flag_lw16 |= ZXDH_NO_IP_FRAGMENT; + pi_hdr->pkt_flag_hi8 |= ZXDH_NO_TCP_FRAGMENT; + } + + if (cookie->ol_flags & RTE_MBUF_F_TX_IP_CKSUM) + pkt_flag_lw16 |= ZXDH_TX_IP_CKSUM_CAL; + + if ((cookie->ol_flags & RTE_MBUF_F_TX_UDP_CKSUM) == RTE_MBUF_F_TX_UDP_CKSUM) { + pcode = ZXDH_PCODE_UDP_PKT_TYPE; + pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL; + } else if ((cookie->ol_flags & RTE_MBUF_F_TX_TCP_CKSUM) == + RTE_MBUF_F_TX_TCP_CKSUM) { + pcode = ZXDH_PCODE_TCP_PKT_TYPE; + pi_hdr->pkt_flag_hi8 |= ZXDH_TX_TCPUDP_CKSUM_CAL; + } + pkt_flag_lw16 |= (mtu_or_mss >> ZXDH_MTU_MSS_UNIT_SHIFTBIT) & ZXDH_MTU_MSS_MASK; + pi_hdr->pkt_flag_lw16 = rte_be_to_cpu_16(pkt_flag_lw16); + pi_hdr->pkt_type = l3_ptype | ZXDH_PKT_FORM_CPU | pcode; + + l3_offset = hdr_len + cookie->l2_len; + l3_offset += (cookie->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) ? + cookie->outer_l2_len + cookie->outer_l3_len : 0; + pi_hdr->l3_offset = rte_be_to_cpu_16(l3_offset); + pi_hdr->l4_offset = rte_be_to_cpu_16(l3_offset + cookie->l3_len); + if (cookie->ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM) + ol_flag |= ZXDH_PD_OFFLOAD_OUTER_IPCSUM; + } else { + pd_hdr = &hdr->pd_hdr; + } + + pd_hdr->dst_vfid = rte_be_to_cpu_16(cookie->port); + + if (cookie->ol_flags & (RTE_MBUF_F_TX_VLAN | RTE_MBUF_F_TX_QINQ)) { + ol_flag |= ZXDH_PD_OFFLOAD_CVLAN_INSERT; + pd_hdr->cvlan_insert = rte_be_to_cpu_16(cookie->vlan_tci); + if (cookie->ol_flags & RTE_MBUF_F_TX_QINQ) { + ol_flag |= ZXDH_PD_OFFLOAD_SVLAN_INSERT; + pd_hdr->svlan_insert = rte_be_to_cpu_16(cookie->vlan_tci_outer); + } + } + + pd_hdr->ol_flag = rte_be_to_cpu_16(ol_flag); +} + +/* + * Populate N_PER_LOOP descriptors with data from N_PER_LOOP single-segment mbufs. + * Note: The simple transmit path (zxdh_xmit_pkts_simple) is selected only when + * RTE_ETH_TX_OFFLOAD_MULTI_SEGS is disabled, so all packets handled here are + * guaranteed to be single-segment. + */ +static inline void +tx_bunch(struct zxdh_virtqueue *vq, volatile struct zxdh_vring_packed_desc *txdp, + struct rte_mbuf **pkts, uint16_t start_id) +{ + uint16_t flags = vq->cached_flags; + int i; + for (i = 0; i < N_PER_LOOP; ++i, ++txdp, ++pkts) { + /* write data to descriptor */ + txdp->addr = rte_mbuf_data_iova(*pkts); + txdp->len = (*pkts)->data_len; + txdp->id = start_id + i; + txdp->flags = flags; + } +} + +/* Populate 1 descriptor with data from 1 single-segment mbuf */ +static inline void +tx1(struct zxdh_virtqueue *vq, volatile struct zxdh_vring_packed_desc *txdp, + struct rte_mbuf *pkts, uint16_t id) +{ + uint16_t flags = vq->cached_flags; + txdp->addr = rte_mbuf_data_iova(pkts); + txdp->len = pkts->data_len; + txdp->id = id; + txdp->flags = flags; +} + +static void submit_to_backend_simple(struct zxdh_virtqueue *vq, + struct rte_mbuf **tx_pkts, uint16_t nb_pkts) +{ + struct zxdh_hw *hw = vq->hw; + struct rte_mbuf *m = NULL; + uint16_t id = vq->vq_avail_idx; + struct zxdh_vring_packed_desc *txdp = &vq->vq_packed.ring.desc[id]; + struct zxdh_vq_desc_extra *dxp = &vq->vq_descx[id]; + int mainpart, leftover; + int i, j; + + /* + * Process most of the packets in chunks of N pkts. Any + * leftover packets will get processed one at a time. + */ + mainpart = (nb_pkts & ~N_PER_LOOP_MASK); + leftover = (nb_pkts & N_PER_LOOP_MASK); + + for (i = 0; i < mainpart; i += N_PER_LOOP) { + rte_prefetch0(dxp + i); + rte_prefetch0(tx_pkts + i); + for (j = 0; j < N_PER_LOOP; ++j) { + m = *(tx_pkts + i + j); + pkt_padding(m, hw); + (dxp + i + j)->cookie = (void *)m; + } + /* write data to descriptor */ + tx_bunch(vq, txdp + i, tx_pkts + i, id + i); + } + + if (leftover > 0) { + rte_prefetch0(dxp + mainpart); + rte_prefetch0(tx_pkts + mainpart); + + for (i = 0; i < leftover; ++i) { + m = *(tx_pkts + mainpart + i); + pkt_padding(m, hw); + (dxp + mainpart + i)->cookie = m; + tx1(vq, txdp + mainpart + i, *(tx_pkts + mainpart + i), id + mainpart + i); + } + } +} + +uint16_t zxdh_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) +{ + struct zxdh_virtnet_tx *txvq = tx_queue; + struct zxdh_virtqueue *vq = txq_get_vq(txvq); + uint16_t nb_tx = 0, nb_tx_left; + + zxdh_xmit_fast_flush(vq); + + nb_pkts = (uint16_t)RTE_MIN(nb_pkts, vq->vq_free_cnt); + if (unlikely(nb_pkts == 0)) { + txvq->stats.idle++; + return 0; + } + + nb_tx_left = nb_pkts; + if ((vq->vq_avail_idx + nb_pkts) >= vq->vq_nentries) { + nb_tx = vq->vq_nentries - vq->vq_avail_idx; + nb_tx_left = nb_pkts - nb_tx; + submit_to_backend_simple(vq, tx_pkts, nb_tx); + vq->vq_avail_idx = 0; + vq->cached_flags ^= ZXDH_VRING_PACKED_DESC_F_AVAIL_USED; + + vq->vq_free_cnt -= nb_tx; + tx_pkts += nb_tx; + } + if (nb_tx_left) { + submit_to_backend_simple(vq, tx_pkts, nb_tx_left); + vq->vq_avail_idx += nb_tx_left; + vq->vq_free_cnt -= nb_tx_left; + } + + zxdh_queue_notify(vq); + txvq->stats.packets += nb_pkts; + for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) + zxdh_update_packet_stats(&txvq->stats, tx_pkts[nb_tx]); + + return nb_pkts; +} diff --git a/drivers/net/zxdh/zxdh_rxtx.h b/drivers/net/zxdh/zxdh_rxtx.h index dba9567414..783fb456de 100644 --- a/drivers/net/zxdh/zxdh_rxtx.h +++ b/drivers/net/zxdh/zxdh_rxtx.h @@ -56,18 +56,19 @@ struct __rte_cache_aligned zxdh_virtnet_rx { struct __rte_cache_aligned zxdh_virtnet_tx { struct zxdh_virtqueue *vq; - - rte_iova_t zxdh_net_hdr_mem; /* hdr for each xmit packet */ - uint16_t queue_id; /* DPDK queue index. */ - uint16_t port_id; /* Device port identifier. */ + const struct rte_memzone *zxdh_net_hdr_mz; /* memzone to populate hdr. */ + rte_iova_t zxdh_net_hdr_mem; /* hdr for each xmit packet */ struct zxdh_virtnet_stats stats; const struct rte_memzone *mz; /* mem zone to populate TX ring. */ - const struct rte_memzone *zxdh_net_hdr_mz; /* memzone to populate hdr. */ + uint64_t offloads; + uint16_t queue_id; /* DPDK queue index. */ + uint16_t port_id; /* Device port identifier. */ }; uint16_t zxdh_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); uint16_t zxdh_xmit_pkts_prepare(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); uint16_t zxdh_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts); uint16_t zxdh_recv_single_pkts(void *rx_queue, struct rte_mbuf **rcv_pkts, uint16_t nb_pkts); +uint16_t zxdh_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); #endif /* ZXDH_RXTX_H */ -- 2.27.0

