+ /* Do split & copy for the packet. */
+ if (tx_pkt_split != TX_PKT_SPLIT_OFF) {
+ p = pkt_copy_split(m);
+ if (p != NULL) {
+ rte_pktmbuf_free(m);
+ m = p;
+ pkts_burst[i] = m;
+ }
+ }
+
+ /* if verbose mode is enabled, dump debug info */
+ if (verbose_level > 0) {
+ char buf[256];
+
+ printf("-----------------\n");
+ printf("port=%u, mbuf=%p, pkt_len=%u, nb_segs=%u:\n",
+ fs->rx_port, m, m->pkt_len, m->nb_segs);
+ /* dump rx parsed packet info */
+ rte_get_rx_ol_flag_list(rx_ol_flags, buf, sizeof(buf));
+ printf("rx: l2_len=%d ethertype=%x l3_len=%d "
+ "l4_proto=%d l4_len=%d flags=%s\n",
+ info.l2_len, rte_be_to_cpu_16(info.ethertype),
+ info.l3_len, info.l4_proto, info.l4_len, buf);
+ if (rx_ol_flags & PKT_RX_LRO)
+ printf("rx: m->lro_segsz=%u\n", m->tso_segsz);
+ if (info.is_tunnel == 1)
+ printf("rx: outer_l2_len=%d outer_ethertype=%x "
+ "outer_l3_len=%d\n", info.outer_l2_len,
+ rte_be_to_cpu_16(info.outer_ethertype),
+ info.outer_l3_len);
+ /* dump tx packet info */
+ if ((tx_offloads & (DEV_TX_OFFLOAD_IPV4_CKSUM |
+ DEV_TX_OFFLOAD_UDP_CKSUM |
+ DEV_TX_OFFLOAD_TCP_CKSUM |
+ DEV_TX_OFFLOAD_SCTP_CKSUM)) ||
+ info.tso_segsz != 0)
+ printf("tx: m->l2_len=%d m->l3_len=%d "
+ "m->l4_len=%d\n",
+ m->l2_len, m->l3_len, m->l4_len);
+ if (info.is_tunnel == 1) {
+ if ((tx_offloads &
+ DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM) ||
+ (tx_offloads &
+ DEV_TX_OFFLOAD_OUTER_UDP_CKSUM) ||
+ (tx_ol_flags & PKT_TX_OUTER_IPV6))
+ printf("tx: m->outer_l2_len=%d "
+ "m->outer_l3_len=%d\n",
+ m->outer_l2_len,
+ m->outer_l3_len);
+ if (info.tunnel_tso_segsz != 0 &&
+ (m->ol_flags & PKT_TX_TCP_SEG))
+ printf("tx: m->tso_segsz=%d\n",
+ m->tso_segsz);
+ } else if (info.tso_segsz != 0 &&
+ (m->ol_flags & PKT_TX_TCP_SEG))
+ printf("tx: m->tso_segsz=%d\n", m->tso_segsz);
+ rte_get_tx_ol_flag_list(m->ol_flags, buf, sizeof(buf));
+ printf("tx: flags=%s", buf);
+ printf("\n");
+ }
+ }
+
+ if (unlikely(gro_enable)) {
+ if (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) {
+ nb_rx = rte_gro_reassemble_burst(pkts_burst, nb_rx,
+ &(gro_ports[fs->rx_port].param));
+ } else {
+ gro_ctx = current_fwd_lcore()->gro_ctx;
+ nb_rx = rte_gro_reassemble(pkts_burst, nb_rx, gro_ctx);
+
+ if (++fs->gro_times >= gro_flush_cycles) {
+ gro_pkts_num = rte_gro_get_pkt_count(gro_ctx);
+ if (gro_pkts_num > MAX_PKT_BURST - nb_rx)
+ gro_pkts_num = MAX_PKT_BURST - nb_rx;
+
+ nb_rx += rte_gro_timeout_flush(gro_ctx, 0,
+ RTE_GRO_TCP_IPV4,
+ &pkts_burst[nb_rx],
+ gro_pkts_num);
+ fs->gro_times = 0;
+ }
+ }
+ }
+
+ if (gso_ports[fs->tx_port].enable == 0)
+ tx_pkts_burst = pkts_burst;
+ else {
+ gso_ctx = &(current_fwd_lcore()->gso_ctx);
+ gso_ctx->gso_size = gso_max_segment_size;
+ for (i = 0; i < nb_rx; i++) {
+ ret = rte_gso_segment(pkts_burst[i], gso_ctx,
+ &gso_segments[nb_segments],
+ GSO_MAX_PKT_BURST - nb_segments);
+ if (ret >= 0)
+ nb_segments += ret;
+ else {
+ TESTPMD_LOG(DEBUG, "Unable to segment packet");
+ rte_pktmbuf_free(pkts_burst[i]);
+ }
+ }
+
+ tx_pkts_burst = gso_segments;
+ nb_rx = nb_segments;
+ }
+
+ nb_prep = rte_eth_tx_prepare(fs->tx_port, fs->tx_queue,
+ tx_pkts_burst, nb_rx);
+ if (nb_prep != nb_rx)
+ printf("Preparing packet burst to transmit failed: %s\n",
+ rte_strerror(rte_errno));
+
+ nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, tx_pkts_burst,
+ nb_prep);
+
+ /*
+ * Retry if necessary
+ */
+ if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+ retry = 0;
+ while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+ rte_delay_us(burst_tx_delay_time);
+ nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+ &tx_pkts_burst[nb_tx], nb_rx - nb_tx);
+ }