@@ -15598,6 +15598,110 @@ static void cmd_set_mplsogre_parsed(void *parsed_result,
},
};
+/** Set decapsulation L3 details */
+struct cmd_set_decap_l3_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t decap_l3;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+ uint16_t tci;
+ struct ether_addr eth_src;
+ struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_decap_l3_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, set, "set");
+cmdline_parse_token_string_t cmd_set_decap_l3_decap_l3 =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, decap_l3,
+ "decap_l3");
+cmdline_parse_token_string_t cmd_set_decap_l3_decap_l3_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, decap_l3,
+ "decap_l3-with-vlan");
+cmdline_parse_token_string_t cmd_set_decap_l3_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+ "ip-version");
+cmdline_parse_token_string_t cmd_set_decap_l3_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, ip_version,
+ "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_decap_l3_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+ "vlan-tci");
+cmdline_parse_token_num_t cmd_set_decap_l3_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_decap_l3_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_decap_l3_eth_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+ "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_decap_l3_eth_src_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_decap_l3_result, eth_src);
+cmdline_parse_token_string_t cmd_set_decap_l3_eth_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_decap_l3_result, pos_token,
+ "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_decap_l3_eth_dst_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_decap_l3_result, eth_dst);
+
+static void cmd_set_decap_l3_parsed(void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_decap_l3_result *res = parsed_result;
+
+ if (strcmp(res->decap_l3, "decap_l3") == 0)
+ decap_l3_conf.select_vlan = 0;
+ else if (strcmp(res->decap_l3, "decap_l3-with-vlan") == 0)
+ decap_l3_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ decap_l3_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ decap_l3_conf.select_ipv4 = 0;
+ else
+ return;
+ if (decap_l3_conf.select_vlan)
+ decap_l3_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+ rte_memcpy(decap_l3_conf.eth_src, res->eth_src.addr_bytes,
+ ETHER_ADDR_LEN);
+ rte_memcpy(decap_l3_conf.eth_dst, res->eth_dst.addr_bytes,
+ ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_decap_l3 = {
+ .f = cmd_set_decap_l3_parsed,
+ .data = NULL,
+ .help_str = "set decap_l3 ip-version ipv4|ipv6 eth-src <eth-src>"
+ " eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_decap_l3_set,
+ (void *)&cmd_set_decap_l3_decap_l3,
+ (void *)&cmd_set_decap_l3_ip_version,
+ (void *)&cmd_set_decap_l3_ip_version_value,
+ (void *)&cmd_set_decap_l3_eth_src,
+ (void *)&cmd_set_decap_l3_eth_src_value,
+ (void *)&cmd_set_decap_l3_eth_dst,
+ (void *)&cmd_set_decap_l3_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_decap_l3_with_vlan = {
+ .f = cmd_set_decap_l3_parsed,
+ .data = NULL,
+ .help_str = "set decap_l3-with-vlan ip-version ipv4|ipv6"
+ " vlan-tci <vlan-tci> eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_decap_l3_set,
+ (void *)&cmd_set_decap_l3_decap_l3_with_vlan,
+ (void *)&cmd_set_decap_l3_ip_version,
+ (void *)&cmd_set_decap_l3_ip_version_value,
+ (void *)&cmd_set_decap_l3_vlan,
+ (void *)&cmd_set_decap_l3_vlan_value,
+ (void *)&cmd_set_decap_l3_eth_src,
+ (void *)&cmd_set_decap_l3_eth_src_value,
+ (void *)&cmd_set_decap_l3_eth_dst,
+ (void *)&cmd_set_decap_l3_eth_dst_value,
+ NULL,
+ },
+};
+
/* Strict link priority scheduling mode setting */
static void
cmd_strict_link_prio_parsed(
@@ -18231,6 +18335,8 @@ struct cmd_config_per_queue_tx_offload_result {
(cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
(cmdline_parse_inst_t *)&cmd_set_mplsogre,
(cmdline_parse_inst_t *)&cmd_set_mplsogre_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_decap_l3,
+ (cmdline_parse_inst_t *)&cmd_set_decap_l3_with_vlan,
(cmdline_parse_inst_t *)&cmd_ddp_add,
(cmdline_parse_inst_t *)&cmd_ddp_del,
(cmdline_parse_inst_t *)&cmd_ddp_get_list,
@@ -245,6 +245,7 @@ enum index {
ACTION_NVGRE_DECAP,
ACTION_MPLSOUDP_ENCAP,
ACTION_MPLSOGRE_ENCAP,
+ ACTION_DECAP_L3,
};
/** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -279,6 +280,16 @@ struct action_tunnel_encap_l3_data {
uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
};
+/** Maximum buffer size for the decap L3 data. */
+#define ACTION_TUNNEL_DECAP_L3_MAX_BUFFER_SIZE \
+ (sizeof(struct rte_flow_item_eth) + sizeof(struct rte_flow_item_vlan))
+
+/** Storage for struct rte_flow_action_tunnel_decap_l3 with external data. */
+struct action_tunnel_decap_l3_data {
+ struct rte_flow_action_tunnel_decap_l3 conf;
+ uint8_t buf[ACTION_TUNNEL_DECAP_L3_MAX_BUFFER_SIZE];
+};
+
/** Maximum number of subsequent tokens and arguments on the stack. */
#define CTX_STACK_SIZE 16
@@ -802,6 +813,7 @@ struct parse_action_priv {
ACTION_NVGRE_DECAP,
ACTION_MPLSOUDP_ENCAP,
ACTION_MPLSOGRE_ENCAP,
+ ACTION_DECAP_L3,
ZERO,
};
@@ -944,6 +956,9 @@ static int parse_vc_action_mplsoudp_encap(struct context *,
static int parse_vc_action_mplsogre_encap(struct context *,
const struct token *, const char *,
unsigned int, void *, unsigned int);
+static int parse_vc_action_decap_l3(struct context *, const struct token *,
+ const char *, unsigned int, void *,
+ unsigned int);
static int parse_destroy(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@@ -2480,6 +2495,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
.call = parse_vc_action_mplsogre_encap,
},
+ [ACTION_DECAP_L3] = {
+ .name = "decap_l3",
+ .help = "decap l3 packet, uses configuration set by"
+ " \"set decap_l3\"",
+ .priv = PRIV_ACTION(TUNNEL_DECAP_L3,
+ sizeof(struct action_tunnel_decap_l3_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_decap_l3,
+ },
};
/** Remove and return last entry from argument stack. */
@@ -3442,6 +3466,63 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
return ret;
}
+/** Parse decap_l3 action. */
+static int
+parse_vc_action_decap_l3(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+ struct rte_flow_action *action;
+ struct action_tunnel_decap_l3_data *action_decap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {
+ .tci = mplsogre_encap_conf.vlan_tci,
+ .inner_type = 0,
+ };
+ uint8_t *header;
+ int ret;
+
+ ret = parse_vc(ctx, token, str, len, buf, size);
+ if (ret < 0)
+ return ret;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return ret;
+ if (!out->args.vc.actions_n)
+ return -1;
+ action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+ /* Point to selected object. */
+ ctx->object = out->args.vc.data;
+ ctx->objmask = NULL;
+ /* Copy the headers to the buffer. */
+ action_decap_data = ctx->object;
+ *action_decap_data = (struct action_tunnel_decap_l3_data) {
+ .conf = (struct rte_flow_action_tunnel_decap_l3){
+ .buf = action_decap_data->buf,
+ },
+ .buf = {},
+ };
+ header = action_decap_data->buf;
+ if (decap_l3_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+ memcpy(eth.dst.addr_bytes, decap_l3_conf.eth_dst, ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes, decap_l3_conf.eth_src, ETHER_ADDR_LEN);
+ memcpy(header, ð, sizeof(eth));
+ header += sizeof(eth);
+ if (decap_l3_conf.select_vlan) {
+ if (decap_l3_conf.select_ipv4)
+ vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+ else
+ vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+ memcpy(header, &vlan, sizeof(vlan));
+ header += sizeof(vlan);
+ }
+ action_decap_data->conf.size = header - action_decap_data->buf;
+ action->conf = &action_decap_data->conf;
+ return ret;
+}
+
/** Parse tokens for destroy command. */
static int
parse_destroy(struct context *ctx, const struct token *token,
@@ -516,6 +516,16 @@ struct mplsogre_encap_conf {
};
struct mplsogre_encap_conf mplsogre_encap_conf;
+/* decap l3 parameters. */
+struct decap_l3_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+ rte_be16_t vlan_tci;
+ uint8_t eth_src[ETHER_ADDR_LEN];
+ uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct decap_l3_conf decap_l3_conf;
+
static inline unsigned int
lcore_num(void)
{
@@ -1602,6 +1602,20 @@ flow rule using the action mplsogre_encap will use the last configuration set.
To have a different encapsulation header, one of those commands must be called
before the flow rule creation.
+Config decapsulation L3
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the layer 2 header value of the inner packet::
+
+ set decap_l3 ip-version (ipv4|ipv6) eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) vlan-tci (vlan-tci) \
+ eth-src (eth-src) eth-dst (eth-dst)
+
+Those command will set an internal configuration inside testpmd, any following
+flow rule using the action decap_l3 will use the last configuration set.
+To have a different decapsulation header, one of those commands must be called
+before the flow rule creation.
+
Port Functions
--------------
@@ -3742,6 +3756,9 @@ This section lists supported actions and their attributes, if any.
- ``mplsogre_encap``: Performs a MPLSoGRE encapsulation, outer layer
configuration is done through `Config MPLSoGRE Encap outer layers`_.
+- ``decap_l3``: Performs a decapsulation of l3 tunnel, L2 configuratin
+ is done through `Config decapsulation L3`_.
+
Destroying flow rules
~~~~~~~~~~~~~~~~~~~~~
@@ -4128,6 +4145,24 @@ IPv6 MPLSoUDP outer header::
eth-dst 22:22:22:22:22:22
testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+Sample decapsulation l3 rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Decapsulation of L3 tunnel has default L2 value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 L2 header::
+
+ testpmd> set decap_l3 ip-version ipv4 eth-src 11:11:11:11:11:11
+ eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 ingress pattern eth / ipv4 / udp / mpls / end actions
+ decap_l3 / end
+
+ testpmd> set decap_l3-with-vlan ip-version ipv4 vlan-tci 34
+ eth-src 11:11:11:11:11:11 eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 ingress pattern eth / ipv4 / udp / mpls / end actions
+ decap_l3 / end
+
BPF Functions
--------------