app/testpmd: add qinq stripping and insertion
authorHelin Zhang <helin.zhang@intel.com>
Thu, 11 Jun 2015 07:03:58 +0000 (15:03 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Tue, 7 Jul 2015 14:42:11 +0000 (16:42 +0200)
If double vlan is detected, its stripped flag and vlan tags can be
printed on rxonly mode. Test command of 'tx_vlan set' is expanded
to set both single and double vlan tags on TX side for each packets
to be sent out.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
app/test-pmd/cmdline.c
app/test-pmd/config.c
app/test-pmd/flowgen.c
app/test-pmd/macfwd.c
app/test-pmd/macswap.c
app/test-pmd/rxonly.c
app/test-pmd/testpmd.h
app/test-pmd/txonly.c
doc/guides/testpmd_app_ug/testpmd_funcs.rst

index 8142910..95a8f95 100644 (file)
@@ -304,9 +304,9 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "rx_vxlan_port rm (udp_port) (port_id)\n"
                        "    Remove an UDP port for VXLAN packet filter on a port\n\n"
 
-                       "tx_vlan set vlan_id (port_id)\n"
-                       "    Set hardware insertion of VLAN ID in packets sent"
-                       " on a port.\n\n"
+                       "tx_vlan set (port_id) vlan_id[, vlan_id_outer]\n"
+                       "    Set hardware insertion of VLAN IDs (single or double VLAN "
+                       "depends on the number of VLAN IDs) in packets sent on a port.\n\n"
 
                        "tx_vlan set pvid port_id vlan_id (on|off)\n"
                        "    Set port based TX VLAN insertion.\n\n"
@@ -2799,8 +2799,8 @@ cmdline_parse_inst_t cmd_rx_vlan_filter = {
 struct cmd_tx_vlan_set_result {
        cmdline_fixed_string_t tx_vlan;
        cmdline_fixed_string_t set;
-       uint16_t vlan_id;
        uint8_t port_id;
+       uint16_t vlan_id;
 };
 
 static void
@@ -2809,6 +2809,13 @@ cmd_tx_vlan_set_parsed(void *parsed_result,
                       __attribute__((unused)) void *data)
 {
        struct cmd_tx_vlan_set_result *res = parsed_result;
+       int vlan_offload = rte_eth_dev_get_vlan_offload(res->port_id);
+
+       if (vlan_offload & ETH_VLAN_EXTEND_OFFLOAD) {
+               printf("Error, as QinQ has been enabled.\n");
+               return;
+       }
+
        tx_vlan_set(res->port_id, res->vlan_id);
 }
 
@@ -2828,13 +2835,69 @@ cmdline_parse_token_num_t cmd_tx_vlan_set_portid =
 cmdline_parse_inst_t cmd_tx_vlan_set = {
        .f = cmd_tx_vlan_set_parsed,
        .data = NULL,
-       .help_str = "enable hardware insertion of a VLAN header with a given "
-       "TAG Identifier in packets sent on a port",
+       .help_str = "enable hardware insertion of a single VLAN header "
+               "with a given TAG Identifier in packets sent on a port",
        .tokens = {
                (void *)&cmd_tx_vlan_set_tx_vlan,
                (void *)&cmd_tx_vlan_set_set,
-               (void *)&cmd_tx_vlan_set_vlanid,
                (void *)&cmd_tx_vlan_set_portid,
+               (void *)&cmd_tx_vlan_set_vlanid,
+               NULL,
+       },
+};
+
+/* *** ENABLE HARDWARE INSERTION OF Double VLAN HEADER IN TX PACKETS *** */
+struct cmd_tx_vlan_set_qinq_result {
+       cmdline_fixed_string_t tx_vlan;
+       cmdline_fixed_string_t set;
+       uint8_t port_id;
+       uint16_t vlan_id;
+       uint16_t vlan_id_outer;
+};
+
+static void
+cmd_tx_vlan_set_qinq_parsed(void *parsed_result,
+                           __attribute__((unused)) struct cmdline *cl,
+                           __attribute__((unused)) void *data)
+{
+       struct cmd_tx_vlan_set_qinq_result *res = parsed_result;
+       int vlan_offload = rte_eth_dev_get_vlan_offload(res->port_id);
+
+       if (!(vlan_offload & ETH_VLAN_EXTEND_OFFLOAD)) {
+               printf("Error, as QinQ hasn't been enabled.\n");
+               return;
+       }
+
+       tx_qinq_set(res->port_id, res->vlan_id, res->vlan_id_outer);
+}
+
+cmdline_parse_token_string_t cmd_tx_vlan_set_qinq_tx_vlan =
+       TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+               tx_vlan, "tx_vlan");
+cmdline_parse_token_string_t cmd_tx_vlan_set_qinq_set =
+       TOKEN_STRING_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+               set, "set");
+cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_portid =
+       TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+               port_id, UINT8);
+cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_vlanid =
+       TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+               vlan_id, UINT16);
+cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_vlanid_outer =
+       TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+               vlan_id_outer, UINT16);
+
+cmdline_parse_inst_t cmd_tx_vlan_set_qinq = {
+       .f = cmd_tx_vlan_set_qinq_parsed,
+       .data = NULL,
+       .help_str = "enable hardware insertion of double VLAN header "
+               "with given TAG Identifiers in packets sent on a port",
+       .tokens = {
+               (void *)&cmd_tx_vlan_set_qinq_tx_vlan,
+               (void *)&cmd_tx_vlan_set_qinq_set,
+               (void *)&cmd_tx_vlan_set_qinq_portid,
+               (void *)&cmd_tx_vlan_set_qinq_vlanid,
+               (void *)&cmd_tx_vlan_set_qinq_vlanid_outer,
                NULL,
        },
 };
@@ -8834,6 +8897,7 @@ cmdline_parse_ctx_t main_ctx[] = {
        (cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
        (cmdline_parse_inst_t *)&cmd_rx_vlan_filter,
        (cmdline_parse_inst_t *)&cmd_tx_vlan_set,
+       (cmdline_parse_inst_t *)&cmd_tx_vlan_set_qinq,
        (cmdline_parse_inst_t *)&cmd_tx_vlan_reset,
        (cmdline_parse_inst_t *)&cmd_tx_vlan_set_pvid,
        (cmdline_parse_inst_t *)&cmd_csum_set,
index 52917c7..24c8637 100644 (file)
@@ -1732,16 +1732,35 @@ tx_vlan_set(portid_t port_id, uint16_t vlan_id)
                return;
        if (vlan_id_is_invalid(vlan_id))
                return;
+       tx_vlan_reset(port_id);
        ports[port_id].tx_ol_flags |= TESTPMD_TX_OFFLOAD_INSERT_VLAN;
        ports[port_id].tx_vlan_id = vlan_id;
 }
 
+void
+tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer)
+{
+       if (port_id_is_invalid(port_id, ENABLED_WARN))
+               return;
+       if (vlan_id_is_invalid(vlan_id))
+               return;
+       if (vlan_id_is_invalid(vlan_id_outer))
+               return;
+       tx_vlan_reset(port_id);
+       ports[port_id].tx_ol_flags |= TESTPMD_TX_OFFLOAD_INSERT_QINQ;
+       ports[port_id].tx_vlan_id = vlan_id;
+       ports[port_id].tx_vlan_id_outer = vlan_id_outer;
+}
+
 void
 tx_vlan_reset(portid_t port_id)
 {
        if (port_id_is_invalid(port_id, ENABLED_WARN))
                return;
-       ports[port_id].tx_ol_flags &= ~TESTPMD_TX_OFFLOAD_INSERT_VLAN;
+       ports[port_id].tx_ol_flags &= ~(TESTPMD_TX_OFFLOAD_INSERT_VLAN |
+                               TESTPMD_TX_OFFLOAD_INSERT_QINQ);
+       ports[port_id].tx_vlan_id = 0;
+       ports[port_id].tx_vlan_id_outer = 0;
 }
 
 void
index 174c003..e3620f5 100644 (file)
@@ -136,7 +136,7 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
        struct ether_hdr *eth_hdr;
        struct ipv4_hdr *ip_hdr;
        struct udp_hdr *udp_hdr;
-       uint16_t vlan_tci;
+       uint16_t vlan_tci, vlan_tci_outer;
        uint16_t ol_flags;
        uint16_t nb_rx;
        uint16_t nb_tx;
@@ -163,6 +163,7 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
 
        mbp = current_fwd_lcore()->mbp;
        vlan_tci = ports[fs->tx_port].tx_vlan_id;
+       vlan_tci_outer = ports[fs->tx_port].tx_vlan_id_outer;
        ol_flags = ports[fs->tx_port].tx_ol_flags;
 
        for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
@@ -208,6 +209,7 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
                pkt->pkt_len            = pkt_size;
                pkt->ol_flags           = ol_flags;
                pkt->vlan_tci           = vlan_tci;
+               pkt->vlan_tci_outer     = vlan_tci_outer;
                pkt->l2_len             = sizeof(struct ether_hdr);
                pkt->l3_len             = sizeof(struct ipv4_hdr);
                pkts_burst[nb_pkt]      = pkt;
index 035e5eb..3b7fffb 100644 (file)
@@ -110,6 +110,8 @@ pkt_burst_mac_forward(struct fwd_stream *fs)
        txp = &ports[fs->tx_port];
        if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_VLAN)
                ol_flags = PKT_TX_VLAN_PKT;
+       if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_QINQ)
+               ol_flags |= PKT_TX_QINQ_PKT;
        for (i = 0; i < nb_rx; i++) {
                mb = pkts_burst[i];
                eth_hdr = rte_pktmbuf_mtod(mb, struct ether_hdr *);
@@ -121,6 +123,7 @@ pkt_burst_mac_forward(struct fwd_stream *fs)
                mb->l2_len = sizeof(struct ether_hdr);
                mb->l3_len = sizeof(struct ipv4_hdr);
                mb->vlan_tci = txp->tx_vlan_id;
+               mb->vlan_tci_outer = txp->tx_vlan_id_outer;
        }
        nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
        fs->tx_packets += nb_tx;
index 6729849..154889d 100644 (file)
@@ -110,6 +110,8 @@ pkt_burst_mac_swap(struct fwd_stream *fs)
        txp = &ports[fs->tx_port];
        if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_VLAN)
                ol_flags = PKT_TX_VLAN_PKT;
+       if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_QINQ)
+               ol_flags |= PKT_TX_QINQ_PKT;
        for (i = 0; i < nb_rx; i++) {
                mb = pkts_burst[i];
                eth_hdr = rte_pktmbuf_mtod(mb, struct ether_hdr *);
@@ -123,6 +125,7 @@ pkt_burst_mac_swap(struct fwd_stream *fs)
                mb->l2_len = sizeof(struct ether_hdr);
                mb->l3_len = sizeof(struct ipv4_hdr);
                mb->vlan_tci = txp->tx_vlan_id;
+               mb->vlan_tci_outer = txp->tx_vlan_id_outer;
        }
        nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
        fs->tx_packets += nb_tx;
index b8e35ab..4a9f86e 100644 (file)
@@ -160,6 +160,9 @@ pkt_burst_receive(struct fwd_stream *fs)
                }
                if (ol_flags & PKT_RX_VLAN_PKT)
                        printf(" - VLAN tci=0x%x", mb->vlan_tci);
+               if (ol_flags & PKT_RX_QINQ_PKT)
+                       printf(" - QinQ VLAN tci=0x%x, VLAN tci outer=0x%x",
+                                       mb->vlan_tci, mb->vlan_tci_outer);
                if (is_encapsulation) {
                        struct ipv4_hdr *ipv4_hdr;
                        struct ipv6_hdr *ipv6_hdr;
index f2c84d9..e91e077 100644 (file)
@@ -133,6 +133,8 @@ struct fwd_stream {
 #define TESTPMD_TX_OFFLOAD_PARSE_TUNNEL      0x0020
 /** Insert VLAN header in forward engine */
 #define TESTPMD_TX_OFFLOAD_INSERT_VLAN       0x0040
+/** Insert double VLAN header in forward engine */
+#define TESTPMD_TX_OFFLOAD_INSERT_QINQ       0x0080
 
 /**
  * The data structure associated with each port.
@@ -149,7 +151,8 @@ struct rte_port {
        unsigned int            socket_id;  /**< For NUMA support */
        uint16_t                tx_ol_flags;/**< TX Offload Flags (TESTPMD_TX_OFFLOAD...). */
        uint16_t                tso_segsz;  /**< MSS for segmentation offload. */
-       uint16_t                tx_vlan_id; /**< Tag Id. in TX VLAN packets. */
+       uint16_t                tx_vlan_id;/**< The tag ID */
+       uint16_t                tx_vlan_id_outer;/**< The outer tag ID */
        void                    *fwd_ctx;   /**< Forwarding mode context */
        uint64_t                rx_bad_ip_csum; /**< rx pkts with bad ip checksum  */
        uint64_t                rx_bad_l4_csum; /**< rx pkts with bad l4 checksum */
@@ -515,6 +518,7 @@ int rx_vft_set(portid_t port_id, uint16_t vlan_id, int on);
 void vlan_extend_set(portid_t port_id, int on);
 void vlan_tpid_set(portid_t port_id, uint16_t tp_id);
 void tx_vlan_set(portid_t port_id, uint16_t vlan_id);
+void tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer);
 void tx_vlan_reset(portid_t port_id);
 void tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on);
 
index f8027f1..db8f37a 100644 (file)
@@ -202,7 +202,7 @@ pkt_burst_transmit(struct fwd_stream *fs)
        struct ether_hdr eth_hdr;
        uint16_t nb_tx;
        uint16_t nb_pkt;
-       uint16_t vlan_tci;
+       uint16_t vlan_tci, vlan_tci_outer;
        uint64_t ol_flags = 0;
        uint8_t  i;
 #ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
@@ -218,8 +218,11 @@ pkt_burst_transmit(struct fwd_stream *fs)
        mbp = current_fwd_lcore()->mbp;
        txp = &ports[fs->tx_port];
        vlan_tci = txp->tx_vlan_id;
+       vlan_tci_outer = txp->tx_vlan_id_outer;
        if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_VLAN)
                ol_flags = PKT_TX_VLAN_PKT;
+       if (txp->tx_ol_flags & TESTPMD_TX_OFFLOAD_INSERT_QINQ)
+               ol_flags |= PKT_TX_QINQ_PKT;
        for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
                pkt = tx_mbuf_alloc(mbp);
                if (pkt == NULL) {
@@ -266,7 +269,8 @@ pkt_burst_transmit(struct fwd_stream *fs)
                pkt->nb_segs = tx_pkt_nb_segs;
                pkt->pkt_len = tx_pkt_length;
                pkt->ol_flags = ol_flags;
-               pkt->vlan_tci  = vlan_tci;
+               pkt->vlan_tci = vlan_tci;
+               pkt->vlan_tci_outer = vlan_tci_outer;
                pkt->l2_len = sizeof(struct ether_hdr);
                pkt->l3_len = sizeof(struct ipv4_hdr);
                pkts_burst[nb_pkt] = pkt;
index 761172e..f1fa523 100644 (file)
@@ -503,9 +503,19 @@ rx_vxlan_port rm (udp_port) (port_id)
 tx_vlan set
 ~~~~~~~~~~~
 
-Set hardware insertion of VLAN ID in packets sent on a port:
+Set hardware insertion of VLAN IDs in packets sent on a port:
 
-tx_vlan set (vlan_id) (port_id)
+tx_vlan set (port_id) vlan_id[, vlan_id_outer]
+
+.. code-block:: console
+
+    Set a single VLAN ID (5) insertion on port 0.
+
+    tx_vlan set 0 5
+
+    Set double VLAN ID (inner: 2, outer: 3) insertion on port 1.
+
+    tx_vlan set 1 2 3
 
 tx_vlan set pvid
 ~~~~~~~~~~~~~~~~