@@ -15274,6 +15274,179 @@ static void cmd_set_nvgre_parsed(void *parsed_result,
},
};
+/** Set MPLSoUDP encapsulation details */
+struct cmd_set_mplsoudp_result {
+ cmdline_fixed_string_t set;
+ cmdline_fixed_string_t mplsoudp;
+ cmdline_fixed_string_t pos_token;
+ cmdline_fixed_string_t ip_version;
+ uint32_t vlan_present:1;
+ uint32_t label;
+ uint16_t udp_src;
+ uint16_t udp_dst;
+ cmdline_ipaddr_t ip_src;
+ cmdline_ipaddr_t ip_dst;
+ uint16_t tci;
+ struct ether_addr eth_src;
+ struct ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_mplsoudp_set =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, set, "set");
+cmdline_parse_token_string_t cmd_set_mplsoudp_mplsoudp =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, mplsoudp, "mplsoudp");
+cmdline_parse_token_string_t cmd_set_mplsoudp_mplsoudp_with_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, mplsoudp,
+ "mplsoudp-with-vlan");
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_version =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "ip-version");
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_version_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, ip_version,
+ "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_mplsoudp_label =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "label");
+cmdline_parse_token_num_t cmd_set_mplsoudp_label_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, label, UINT32);
+cmdline_parse_token_string_t cmd_set_mplsoudp_udp_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "udp-src");
+cmdline_parse_token_num_t cmd_set_mplsoudp_udp_src_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, udp_src, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_udp_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "udp-dst");
+cmdline_parse_token_num_t cmd_set_mplsoudp_udp_dst_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, udp_dst, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_ip_src_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_result, ip_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_ip_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_mplsoudp_ip_dst_value =
+ TOKEN_IPADDR_INITIALIZER(struct cmd_set_mplsoudp_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_mplsoudp_vlan =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "vlan-tci");
+cmdline_parse_token_num_t cmd_set_mplsoudp_vlan_value =
+ TOKEN_NUM_INITIALIZER(struct cmd_set_mplsoudp_result, tci, UINT16);
+cmdline_parse_token_string_t cmd_set_mplsoudp_eth_src =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_eth_src_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_result, eth_src);
+cmdline_parse_token_string_t cmd_set_mplsoudp_eth_dst =
+ TOKEN_STRING_INITIALIZER(struct cmd_set_mplsoudp_result, pos_token,
+ "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_mplsoudp_eth_dst_value =
+ TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_mplsoudp_result, eth_dst);
+
+static void cmd_set_mplsoudp_parsed(void *parsed_result,
+ __attribute__((unused)) struct cmdline *cl,
+ __attribute__((unused)) void *data)
+{
+ struct cmd_set_mplsoudp_result *res = parsed_result;
+ union {
+ uint32_t mplsoudp_label;
+ uint8_t label[3];
+ } id = {
+ .mplsoudp_label =
+ rte_cpu_to_be_32(res->label) & RTE_BE32(0x00ffffff),
+ };
+
+ if (strcmp(res->mplsoudp, "mplsoudp") == 0)
+ mplsoudp_encap_conf.select_vlan = 0;
+ else if (strcmp(res->mplsoudp, "mplsoudp-with-vlan") == 0)
+ mplsoudp_encap_conf.select_vlan = 1;
+ if (strcmp(res->ip_version, "ipv4") == 0)
+ mplsoudp_encap_conf.select_ipv4 = 1;
+ else if (strcmp(res->ip_version, "ipv6") == 0)
+ mplsoudp_encap_conf.select_ipv4 = 0;
+ else
+ return;
+ rte_memcpy(mplsoudp_encap_conf.label, &id.label[1], 3);
+ mplsoudp_encap_conf.udp_src = rte_cpu_to_be_16(res->udp_src);
+ mplsoudp_encap_conf.udp_dst = rte_cpu_to_be_16(res->udp_dst);
+ if (mplsoudp_encap_conf.select_ipv4) {
+ IPV4_ADDR_TO_UINT(res->ip_src, mplsoudp_encap_conf.ipv4_src);
+ IPV4_ADDR_TO_UINT(res->ip_dst, mplsoudp_encap_conf.ipv4_dst);
+ } else {
+ IPV6_ADDR_TO_ARRAY(res->ip_src, mplsoudp_encap_conf.ipv6_src);
+ IPV6_ADDR_TO_ARRAY(res->ip_dst, mplsoudp_encap_conf.ipv6_dst);
+ }
+ if (mplsoudp_encap_conf.select_vlan)
+ mplsoudp_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+ rte_memcpy(mplsoudp_encap_conf.eth_src, res->eth_src.addr_bytes,
+ ETHER_ADDR_LEN);
+ rte_memcpy(mplsoudp_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+ ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_mplsoudp = {
+ .f = cmd_set_mplsoudp_parsed,
+ .data = NULL,
+ .help_str = "set mplsoudp ip-version ipv4|ipv6 label <label> udp-src"
+ " <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst <ip-dst>"
+ " eth-src <eth-src> eth-dst <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_mplsoudp_set,
+ (void *)&cmd_set_mplsoudp_mplsoudp,
+ (void *)&cmd_set_mplsoudp_ip_version,
+ (void *)&cmd_set_mplsoudp_ip_version_value,
+ (void *)&cmd_set_mplsoudp_label,
+ (void *)&cmd_set_mplsoudp_label_value,
+ (void *)&cmd_set_mplsoudp_udp_src,
+ (void *)&cmd_set_mplsoudp_udp_src_value,
+ (void *)&cmd_set_mplsoudp_udp_dst,
+ (void *)&cmd_set_mplsoudp_udp_dst_value,
+ (void *)&cmd_set_mplsoudp_ip_src,
+ (void *)&cmd_set_mplsoudp_ip_src_value,
+ (void *)&cmd_set_mplsoudp_ip_dst,
+ (void *)&cmd_set_mplsoudp_ip_dst_value,
+ (void *)&cmd_set_mplsoudp_eth_src,
+ (void *)&cmd_set_mplsoudp_eth_src_value,
+ (void *)&cmd_set_mplsoudp_eth_dst,
+ (void *)&cmd_set_mplsoudp_eth_dst_value,
+ NULL,
+ },
+};
+
+cmdline_parse_inst_t cmd_set_mplsoudp_with_vlan = {
+ .f = cmd_set_mplsoudp_parsed,
+ .data = NULL,
+ .help_str = "set mplsoudp-with-vlan ip-version ipv4|ipv6 label <label>"
+ " udp-src <udp-src> udp-dst <udp-dst> ip-src <ip-src> ip-dst"
+ " <ip-dst> vlan-tci <vlan-tci> eth-src <eth-src> eth-dst"
+ " <eth-dst>",
+ .tokens = {
+ (void *)&cmd_set_mplsoudp_set,
+ (void *)&cmd_set_mplsoudp_mplsoudp_with_vlan,
+ (void *)&cmd_set_mplsoudp_ip_version,
+ (void *)&cmd_set_mplsoudp_ip_version_value,
+ (void *)&cmd_set_mplsoudp_label,
+ (void *)&cmd_set_mplsoudp_label_value,
+ (void *)&cmd_set_mplsoudp_udp_src,
+ (void *)&cmd_set_mplsoudp_udp_src_value,
+ (void *)&cmd_set_mplsoudp_udp_dst,
+ (void *)&cmd_set_mplsoudp_udp_dst_value,
+ (void *)&cmd_set_mplsoudp_ip_src,
+ (void *)&cmd_set_mplsoudp_ip_src_value,
+ (void *)&cmd_set_mplsoudp_ip_dst,
+ (void *)&cmd_set_mplsoudp_ip_dst_value,
+ (void *)&cmd_set_mplsoudp_vlan,
+ (void *)&cmd_set_mplsoudp_vlan_value,
+ (void *)&cmd_set_mplsoudp_eth_src,
+ (void *)&cmd_set_mplsoudp_eth_src_value,
+ (void *)&cmd_set_mplsoudp_eth_dst,
+ (void *)&cmd_set_mplsoudp_eth_dst_value,
+ NULL,
+ },
+};
+
/* Strict link priority scheduling mode setting */
static void
cmd_strict_link_prio_parsed(
@@ -17903,6 +18076,8 @@ struct cmd_config_per_queue_tx_offload_result {
(cmdline_parse_inst_t *)&cmd_set_vxlan_with_vlan,
(cmdline_parse_inst_t *)&cmd_set_nvgre,
(cmdline_parse_inst_t *)&cmd_set_nvgre_with_vlan,
+ (cmdline_parse_inst_t *)&cmd_set_mplsoudp,
+ (cmdline_parse_inst_t *)&cmd_set_mplsoudp_with_vlan,
(cmdline_parse_inst_t *)&cmd_ddp_add,
(cmdline_parse_inst_t *)&cmd_ddp_del,
(cmdline_parse_inst_t *)&cmd_ddp_get_list,
@@ -243,6 +243,7 @@ enum index {
ACTION_VXLAN_DECAP,
ACTION_NVGRE_ENCAP,
ACTION_NVGRE_DECAP,
+ ACTION_MPLSOUDP_ENCAP,
};
/** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -271,6 +272,12 @@ struct action_tunnel_encap_data {
uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
};
+/** Storage for struct rte_flow_action_tunnel_encap including external data. */
+struct action_tunnel_encap_l3_data {
+ struct rte_flow_action_tunnel_encap_l3 conf;
+ uint8_t buf[ACTION_TUNNEL_ENCAP_MAX_BUFFER_SIZE];
+};
+
/** Maximum number of subsequent tokens and arguments on the stack. */
#define CTX_STACK_SIZE 16
@@ -792,6 +799,7 @@ struct parse_action_priv {
ACTION_VXLAN_DECAP,
ACTION_NVGRE_ENCAP,
ACTION_NVGRE_DECAP,
+ ACTION_MPLSOUDP_ENCAP,
ZERO,
};
@@ -928,6 +936,9 @@ static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
const char *, unsigned int, void *,
unsigned int);
+static int parse_vc_action_mplsoudp_encap(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);
@@ -2446,6 +2457,15 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
.call = parse_vc,
},
+ [ACTION_MPLSOUDP_ENCAP] = {
+ .name = "mplsoudp_encap",
+ .help = "mplsoudp encapsulation, uses configuration set by"
+ " \"set vxlan\"",
+ .priv = PRIV_ACTION(TUNNEL_ENCAP_L3,
+ sizeof(struct action_tunnel_encap_l3_data)),
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_mplsoudp_encap,
+ },
};
/** Remove and return last entry from argument stack. */
@@ -3207,6 +3227,108 @@ static int comp_vc_action_rss_queue(struct context *, const struct token *,
return ret;
}
+/** Parse MPLSOUDP encap action. */
+static int
+parse_vc_action_mplsoudp_encap(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_encap_data *action_encap_data;
+ struct rte_flow_item_eth eth = { .type = 0, };
+ struct rte_flow_item_vlan vlan = {
+ .tci = mplsoudp_encap_conf.vlan_tci,
+ .inner_type = 0,
+ };
+ struct rte_flow_item_ipv4 ipv4 = {
+ .hdr = {
+ .src_addr = mplsoudp_encap_conf.ipv4_src,
+ .dst_addr = mplsoudp_encap_conf.ipv4_dst,
+ .next_proto_id = IP_PROTO_UDP,
+ },
+ };
+ struct rte_flow_item_ipv6 ipv6 = {
+ .hdr = {
+ .proto = IP_PROTO_UDP,
+ },
+ };
+ struct rte_flow_item_udp udp = {
+ .hdr = {
+ .src_port = mplsoudp_encap_conf.udp_src,
+ .dst_port = mplsoudp_encap_conf.udp_dst,
+ },
+ };
+ struct rte_flow_item_mpls mpls;
+ 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_encap_data = ctx->object;
+ *action_encap_data = (struct action_tunnel_encap_data) {
+ .conf = (struct rte_flow_action_tunnel_encap){
+ .buf = action_encap_data->buf,
+ },
+ .buf = {},
+ };
+ header = action_encap_data->buf;
+ if (mplsoudp_encap_conf.select_vlan)
+ eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
+ else if (mplsoudp_encap_conf.select_ipv4)
+ eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+ else
+ eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
+ memcpy(eth.dst.addr_bytes,
+ mplsoudp_encap_conf.eth_dst, ETHER_ADDR_LEN);
+ memcpy(eth.src.addr_bytes,
+ mplsoudp_encap_conf.eth_src, ETHER_ADDR_LEN);
+ memcpy(header, ð, sizeof(eth));
+ header += sizeof(eth);
+ if (mplsoudp_encap_conf.select_vlan) {
+ if (mplsoudp_encap_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);
+ }
+ if (mplsoudp_encap_conf.select_ipv4) {
+ memcpy(header, &ipv4, sizeof(ipv4));
+ header += sizeof(ipv4);
+ } else {
+ memcpy(&ipv6.hdr.src_addr,
+ &mplsoudp_encap_conf.ipv6_src,
+ sizeof(mplsoudp_encap_conf.ipv6_src));
+ memcpy(&ipv6.hdr.dst_addr,
+ &mplsoudp_encap_conf.ipv6_dst,
+ sizeof(mplsoudp_encap_conf.ipv6_dst));
+ memcpy(header, &ipv6, sizeof(ipv6));
+ header += sizeof(ipv6);
+ }
+ memcpy(header, &udp, sizeof(udp));
+ header += sizeof(udp);
+ memcpy(mpls.label_tc_s, mplsoudp_encap_conf.label,
+ RTE_DIM(mplsoudp_encap_conf.label));
+ memcpy(header, &mpls, sizeof(mpls));
+ header += sizeof(mpls);
+ action_encap_data->conf.size = header -
+ action_encap_data->buf;
+ action->conf = &action_encap_data->conf;
+ return ret;
+}
+
/** Parse tokens for destroy command. */
static int
parse_destroy(struct context *ctx, const struct token *token,
@@ -484,6 +484,23 @@ struct nvgre_encap_conf {
};
struct nvgre_encap_conf nvgre_encap_conf;
+/* MPLSoUDP encap parameters. */
+struct mplsoudp_encap_conf {
+ uint32_t select_ipv4:1;
+ uint32_t select_vlan:1;
+ uint8_t label[3];
+ rte_be16_t udp_src;
+ rte_be16_t udp_dst;
+ rte_be32_t ipv4_src;
+ rte_be32_t ipv4_dst;
+ uint8_t ipv6_src[16];
+ uint8_t ipv6_dst[16];
+ rte_be16_t vlan_tci;
+ uint8_t eth_src[ETHER_ADDR_LEN];
+ uint8_t eth_dst[ETHER_ADDR_LEN];
+};
+struct mplsoudp_encap_conf mplsoudp_encap_conf;
+
static inline unsigned int
lcore_num(void)
{
@@ -1570,6 +1570,23 @@ flow rule using the action nvgre_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 MPLSoUDP Encap outer layers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure the outer layer to encapsulate a packet inside a MPLSoUDP tunnel::
+
+ set mplsoudp ip-version (ipv4|ipv6) label (label) udp-src (udp-src) \
+ udp-dst (udp-dst) ip-src (ip-src) ip-dst (ip-dst) \
+ eth-src (eth-src) eth-dst (eth-dst)
+ set mplsoudp-with-vlan ip-version (ipv4|ipv6) label (label) udp-src (udp-src)
+ udp-dst (udp-dst) ip-src (ip-src) ip-dst (ip-dst) 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 mplsoudp_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.
+
Port Functions
--------------
@@ -3704,6 +3721,9 @@ This section lists supported actions and their attributes, if any.
- ``nvgre_decap``: Performs a decapsulation action by stripping all headers of
the NVGRE tunnel network overlay from the matched flow.
+- ``mplsoudp_encap``: Performs a MPLSoUDP encapsulation, outer layer
+ configuration is done through `Config MPLSoUDP Encap outer layers`_.
+
Destroying flow rules
~~~~~~~~~~~~~~~~~~~~~
@@ -4032,6 +4052,36 @@ IPv6 NVGRE outer header::
testpmd> flow create 0 ingress pattern end actions nvgre_encap /
queue index 0 / end
+Sample MPLSoUDP encapsulation rule
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+MPLSoUDP encapsulation outer layer has default value pre-configured in testpmd
+source code, those can be changed by using the following commands
+
+IPv4 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv4 label 4 udp-src 5 udp-dst 10
+ ip-src 127.0.0.1 ip-dst 128.0.0.1 eth-src 11:11:11:11:11:11
+ eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv4 label 4 udp-src 5 udp-dst 10
+ ip-src 127.0.0.1 ip-dst 128.0.0.1 vlan-tci 34 eth-src 11:11:11:11:11:11
+ eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+IPv6 MPLSoUDP outer header::
+
+ testpmd> set mplsoudp ip-version ipv6 mask 4 udp-src 5 udp-dst 10
+ ip-src ::1 ip-dst ::2222 eth-src 11:11:11:11:11:11
+ eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
+ testpmd> set mplsoudp-with-vlan ip-version ipv6 mask 4 udp-src 5 udp-dst 10
+ ip-src ::1 ip-dst ::2222 vlan-tci 34 eth-src 11:11:11:11:11:11
+ eth-dst 22:22:22:22:22:22
+ testpmd> flow create 0 egress pattern end actions mplsoudp_encap / end
+
BPF Functions
--------------