@@ -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_id0[, vlan_id1]\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_id0;
+ uint16_t vlan_id1;
+};
+
+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_id0, res->vlan_id1);
+}
+
+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_vlanid0 =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+ vlan_id0, UINT16);
+cmdline_parse_token_num_t cmd_tx_vlan_set_qinq_vlanid1 =
+ TOKEN_NUM_INITIALIZER(struct cmd_tx_vlan_set_qinq_result,
+ vlan_id1, 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 a double VLAN header "
+ "with a given TAG Identifier 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_vlanid0,
+ (void *)&cmd_tx_vlan_set_qinq_vlanid1,
NULL,
},
};
@@ -8782,6 +8845,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,
@@ -1732,8 +1732,24 @@ 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;
+ ports[port_id].tx_vlan_id0 = vlan_id;
+}
+
+void
+tx_qinq_set(portid_t port_id, uint16_t vlan_id0, uint16_t vlan_id1)
+{
+ if (port_id_is_invalid(port_id, ENABLED_WARN))
+ return;
+ if (vlan_id_is_invalid(vlan_id0))
+ return;
+ if (vlan_id_is_invalid(vlan_id1))
+ return;
+ tx_vlan_reset(port_id);
+ ports[port_id].tx_ol_flags |= TESTPMD_TX_OFFLOAD_INSERT_QINQ;
+ ports[port_id].tx_vlan_id0 = vlan_id0;
+ ports[port_id].tx_vlan_id1 = vlan_id1;
}
void
@@ -1741,7 +1757,10 @@ 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_id0 = 0;
+ ports[port_id].tx_vlan_id1 = 0;
}
void
@@ -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_tci0, vlan_tci1;
uint16_t ol_flags;
uint16_t nb_rx;
uint16_t nb_tx;
@@ -162,7 +162,8 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
rte_pktmbuf_free(pkts_burst[i]);
mbp = current_fwd_lcore()->mbp;
- vlan_tci = ports[fs->tx_port].tx_vlan_id;
+ vlan_tci0 = ports[fs->tx_port].tx_vlan_id0;
+ vlan_tci1 = ports[fs->tx_port].tx_vlan_id1;
ol_flags = ports[fs->tx_port].tx_ol_flags;
for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
@@ -207,7 +208,8 @@ pkt_burst_flow_gen(struct fwd_stream *fs)
pkt->nb_segs = 1;
pkt->pkt_len = pkt_size;
pkt->ol_flags = ol_flags;
- pkt->vlan_tci0 = vlan_tci;
+ pkt->vlan_tci0 = vlan_tci0;
+ pkt->vlan_tci0 = vlan_tci1;
pkt->l2_len = sizeof(struct ether_hdr);
pkt->l3_len = sizeof(struct ipv4_hdr);
pkts_burst[nb_pkt] = pkt;
@@ -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 *);
@@ -120,7 +122,8 @@ pkt_burst_mac_forward(struct fwd_stream *fs)
mb->ol_flags = ol_flags;
mb->l2_len = sizeof(struct ether_hdr);
mb->l3_len = sizeof(struct ipv4_hdr);
- mb->vlan_tci0 = txp->tx_vlan_id;
+ mb->vlan_tci0 = txp->tx_vlan_id0;
+ mb->vlan_tci1 = txp->tx_vlan_id1;
}
nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
fs->tx_packets += nb_tx;
@@ -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 *);
@@ -122,7 +124,8 @@ pkt_burst_mac_swap(struct fwd_stream *fs)
mb->ol_flags = ol_flags;
mb->l2_len = sizeof(struct ether_hdr);
mb->l3_len = sizeof(struct ipv4_hdr);
- mb->vlan_tci0 = txp->tx_vlan_id;
+ mb->vlan_tci0 = txp->tx_vlan_id0;
+ mb->vlan_tci1 = txp->tx_vlan_id1;
}
nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue, pkts_burst, nb_rx);
fs->tx_packets += nb_tx;
@@ -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_tci0);
+ if (ol_flags & PKT_RX_QINQ_PKT)
+ printf(" - QinQ VLAN tci0=0x%x, VLAN tci1=0x%x",
+ mb->vlan_tci0, mb->vlan_tci1);
if (is_encapsulation) {
struct ipv4_hdr *ipv4_hdr;
struct ipv6_hdr *ipv6_hdr;
@@ -132,6 +132,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.
@@ -148,7 +150,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_id0;/**< The (outer) tag ID */
+ uint16_t tx_vlan_id1;/**< The inner 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 */
@@ -512,6 +515,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_id0, uint16_t vlan_id1);
void tx_vlan_reset(portid_t port_id);
void tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on);
@@ -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_tci0, vlan_tci1;
uint64_t ol_flags = 0;
uint8_t i;
#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
@@ -217,9 +217,12 @@ pkt_burst_transmit(struct fwd_stream *fs)
mbp = current_fwd_lcore()->mbp;
txp = &ports[fs->tx_port];
- vlan_tci = txp->tx_vlan_id;
+ vlan_tci0 = txp->tx_vlan_id0;
+ vlan_tci1 = txp->tx_vlan_id1;
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_tci0 = vlan_tci;
+ pkt->vlan_tci0 = vlan_tci0;
+ pkt->vlan_tci1 = vlan_tci1;
pkt->l2_len = sizeof(struct ether_hdr);
pkt->l3_len = sizeof(struct ipv4_hdr);
pkts_burst[nb_pkt] = pkt;