Add support for test-pmd to parse protocol pattern L2TPv2 and PPP.

Signed-off-by: Wenjun Wu <wenjun1...@intel.com>
Signed-off-by: Jie Wang <jie1x.w...@intel.com>
---
 app/test-pmd/cmdline.c      | 244 ++++++++++++++++++++++
 app/test-pmd/cmdline_flow.c | 396 ++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.h      |  22 ++
 3 files changed, 662 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 36d50fd3c7..bba761ad4b 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -13300,6 +13300,247 @@ cmdline_parse_inst_t cmd_set_nvgre_with_vlan = {
        },
 };
 
+/** Set L2TPV2 encapsulation details */
+struct cmd_set_l2tpv2_result {
+       cmdline_fixed_string_t set;
+       cmdline_fixed_string_t l2tpv2;
+       cmdline_fixed_string_t pos_token;
+       cmdline_fixed_string_t ip_version;
+       uint32_t vlan_present:1;
+       uint16_t flags_version;
+       uint16_t session_id;
+       uint16_t udp_src;
+       uint16_t udp_dst;
+       cmdline_ipaddr_t ip_src;
+       cmdline_ipaddr_t ip_dst;
+       uint16_t tci;
+       uint8_t tos;
+       uint8_t ttl;
+       struct rte_ether_addr eth_src;
+       struct rte_ether_addr eth_dst;
+};
+
+cmdline_parse_token_string_t cmd_set_l2tpv2_set =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, set, "set");
+cmdline_parse_token_string_t cmd_set_l2tpv2_l2tpv2 =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, l2tpv2, 
"l2tpv2");
+cmdline_parse_token_string_t cmd_set_l2tpv2_l2tpv2_tos_ttl =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, l2tpv2,
+                                "l2tpv2-tos-ttl");
+cmdline_parse_token_string_t cmd_set_l2tpv2_l2tpv2_with_vlan =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, l2tpv2,
+                                "l2tpv2-with-vlan");
+cmdline_parse_token_string_t cmd_set_l2tpv2_ip_version =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "ip-version");
+cmdline_parse_token_string_t cmd_set_l2tpv2_ip_version_value =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, ip_version,
+                                "ipv4#ipv6");
+cmdline_parse_token_string_t cmd_set_l2tpv2_flags_version =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "flags_version");
+cmdline_parse_token_num_t cmd_set_l2tpv2_flags_version_value =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_l2tpv2_result, flags_version,
+                             RTE_UINT16);
+cmdline_parse_token_string_t cmd_set_l2tpv2_session_id =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "session_id");
+cmdline_parse_token_num_t cmd_set_l2tpv2_session_id_value =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_l2tpv2_result, session_id,
+                             RTE_UINT16);
+cmdline_parse_token_string_t cmd_set_l2tpv2_udp_src =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "udp-src");
+cmdline_parse_token_num_t cmd_set_l2tpv2_udp_src_value =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_l2tpv2_result, udp_src,
+                             RTE_UINT16);
+cmdline_parse_token_string_t cmd_set_l2tpv2_udp_dst =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "udp-dst");
+cmdline_parse_token_num_t cmd_set_l2tpv2_udp_dst_value =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_l2tpv2_result, udp_dst,
+                             RTE_UINT16);
+cmdline_parse_token_string_t cmd_set_l2tpv2_ip_tos =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "ip-tos");
+cmdline_parse_token_num_t cmd_set_l2tpv2_ip_tos_value =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_l2tpv2_result, tos, RTE_UINT8);
+cmdline_parse_token_string_t cmd_set_l2tpv2_ip_ttl =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "ip-ttl");
+cmdline_parse_token_num_t cmd_set_l2tpv2_ip_ttl_value =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_l2tpv2_result, ttl, RTE_UINT8);
+cmdline_parse_token_string_t cmd_set_l2tpv2_ip_src =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "ip-src");
+cmdline_parse_token_ipaddr_t cmd_set_l2tpv2_ip_src_value =
+       TOKEN_IPADDR_INITIALIZER(struct cmd_set_l2tpv2_result, ip_src);
+cmdline_parse_token_string_t cmd_set_l2tpv2_ip_dst =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "ip-dst");
+cmdline_parse_token_ipaddr_t cmd_set_l2tpv2_ip_dst_value =
+       TOKEN_IPADDR_INITIALIZER(struct cmd_set_l2tpv2_result, ip_dst);
+cmdline_parse_token_string_t cmd_set_l2tpv2_vlan =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "vlan-tci");
+cmdline_parse_token_num_t cmd_set_l2tpv2_vlan_value =
+       TOKEN_NUM_INITIALIZER(struct cmd_set_l2tpv2_result, tci, RTE_UINT16);
+cmdline_parse_token_string_t cmd_set_l2tpv2_eth_src =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "eth-src");
+cmdline_parse_token_etheraddr_t cmd_set_l2tpv2_eth_src_value =
+       TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_l2tpv2_result, eth_src);
+cmdline_parse_token_string_t cmd_set_l2tpv2_eth_dst =
+       TOKEN_STRING_INITIALIZER(struct cmd_set_l2tpv2_result, pos_token,
+                                "eth-dst");
+cmdline_parse_token_etheraddr_t cmd_set_l2tpv2_eth_dst_value =
+       TOKEN_ETHERADDR_INITIALIZER(struct cmd_set_l2tpv2_result, eth_dst);
+
+static void cmd_set_l2tpv2_parsed(void *parsed_result,
+       __rte_unused struct cmdline *cl,
+       __rte_unused void *data)
+{
+       struct cmd_set_l2tpv2_result *res = parsed_result;
+
+       l2tpv2_encap_conf.select_tos_ttl = 0;
+       if (strcmp(res->l2tpv2, "l2tpv2") == 0)
+               l2tpv2_encap_conf.select_vlan = 0;
+       else if (strcmp(res->l2tpv2, "l2tpv2-with-vlan") == 0)
+               l2tpv2_encap_conf.select_vlan = 1;
+       else if (strcmp(res->l2tpv2, "l2tpv2-tos-ttl") == 0) {
+               l2tpv2_encap_conf.select_vlan = 0;
+               l2tpv2_encap_conf.select_tos_ttl = 1;
+       }
+       if (strcmp(res->ip_version, "ipv4") == 0)
+               l2tpv2_encap_conf.select_ipv4 = 1;
+       else if (strcmp(res->ip_version, "ipv6") == 0)
+               l2tpv2_encap_conf.select_ipv4 = 0;
+       else
+               return;
+
+       l2tpv2_encap_conf.flags_version = res->flags_version;
+       l2tpv2_encap_conf.session_id = res->session_id;
+       l2tpv2_encap_conf.udp_src = res->udp_src;
+       l2tpv2_encap_conf.udp_dst = res->udp_dst;
+       l2tpv2_encap_conf.ip_tos = res->tos;
+       l2tpv2_encap_conf.ip_ttl = res->ttl;
+       if (l2tpv2_encap_conf.select_ipv4) {
+               IPV4_ADDR_TO_UINT(res->ip_src, l2tpv2_encap_conf.ipv4_src);
+               IPV4_ADDR_TO_UINT(res->ip_dst, l2tpv2_encap_conf.ipv4_dst);
+       } else {
+               IPV6_ADDR_TO_ARRAY(res->ip_src, l2tpv2_encap_conf.ipv6_src);
+               IPV6_ADDR_TO_ARRAY(res->ip_dst, l2tpv2_encap_conf.ipv6_dst);
+       }
+       if (l2tpv2_encap_conf.select_vlan)
+               l2tpv2_encap_conf.vlan_tci = rte_cpu_to_be_16(res->tci);
+       rte_memcpy(l2tpv2_encap_conf.eth_src, res->eth_src.addr_bytes,
+                  RTE_ETHER_ADDR_LEN);
+       rte_memcpy(l2tpv2_encap_conf.eth_dst, res->eth_dst.addr_bytes,
+                  RTE_ETHER_ADDR_LEN);
+}
+
+cmdline_parse_inst_t cmd_set_l2tpv2 = {
+       .f = cmd_set_l2tpv2_parsed,
+       .data = NULL,
+       .help_str = "set l2tpv2 ip-version ipv4|ipv6 flags_version"
+               " <flags_version> session_id <session_id> 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_l2tpv2_set,
+               (void *)&cmd_set_l2tpv2_l2tpv2,
+               (void *)&cmd_set_l2tpv2_ip_version,
+               (void *)&cmd_set_l2tpv2_ip_version_value,
+               (void *)&cmd_set_l2tpv2_flags_version,
+               (void *)&cmd_set_l2tpv2_flags_version_value,
+               (void *)&cmd_set_l2tpv2_session_id,
+               (void *)&cmd_set_l2tpv2_session_id_value,
+               (void *)&cmd_set_l2tpv2_udp_src,
+               (void *)&cmd_set_l2tpv2_udp_src_value,
+               (void *)&cmd_set_l2tpv2_udp_dst,
+               (void *)&cmd_set_l2tpv2_udp_dst_value,
+               (void *)&cmd_set_l2tpv2_ip_src,
+               (void *)&cmd_set_l2tpv2_ip_src_value,
+               (void *)&cmd_set_l2tpv2_ip_dst,
+               (void *)&cmd_set_l2tpv2_ip_dst_value,
+               (void *)&cmd_set_l2tpv2_eth_src,
+               (void *)&cmd_set_l2tpv2_eth_src_value,
+               (void *)&cmd_set_l2tpv2_eth_dst,
+               (void *)&cmd_set_l2tpv2_eth_dst_value,
+               NULL,
+       },
+};
+
+cmdline_parse_inst_t cmd_set_l2tpv2_tos_ttl = {
+       .f = cmd_set_l2tpv2_parsed,
+       .data = NULL,
+       .help_str = "set l2tpv2-tos-ttl ip-version ipv4|ipv6 flags_version"
+               " <flags_version> session_id <session_id> udp-src <udp-src>"
+               " udp-dst <udp-dst> ip-tos <ip-tos> ip-ttl <ip-ttl> ip-src"
+               " <ip-src> ip-dst <ip-dst> eth-src <eth-src> eth-dst <eth-dst>",
+       .tokens = {
+               (void *)&cmd_set_l2tpv2_set,
+               (void *)&cmd_set_l2tpv2_l2tpv2_tos_ttl,
+               (void *)&cmd_set_l2tpv2_ip_version,
+               (void *)&cmd_set_l2tpv2_ip_version_value,
+               (void *)&cmd_set_l2tpv2_flags_version,
+               (void *)&cmd_set_l2tpv2_flags_version_value,
+               (void *)&cmd_set_l2tpv2_session_id,
+               (void *)&cmd_set_l2tpv2_session_id_value,
+               (void *)&cmd_set_l2tpv2_udp_src,
+               (void *)&cmd_set_l2tpv2_udp_src_value,
+               (void *)&cmd_set_l2tpv2_udp_dst,
+               (void *)&cmd_set_l2tpv2_udp_dst_value,
+               (void *)&cmd_set_l2tpv2_ip_tos,
+               (void *)&cmd_set_l2tpv2_ip_tos_value,
+               (void *)&cmd_set_l2tpv2_ip_ttl,
+               (void *)&cmd_set_l2tpv2_ip_ttl_value,
+               (void *)&cmd_set_l2tpv2_ip_src,
+               (void *)&cmd_set_l2tpv2_ip_src_value,
+               (void *)&cmd_set_l2tpv2_ip_dst,
+               (void *)&cmd_set_l2tpv2_ip_dst_value,
+               (void *)&cmd_set_l2tpv2_eth_src,
+               (void *)&cmd_set_l2tpv2_eth_src_value,
+               (void *)&cmd_set_l2tpv2_eth_dst,
+               (void *)&cmd_set_l2tpv2_eth_dst_value,
+               NULL,
+       },
+};
+
+cmdline_parse_inst_t cmd_set_l2tpv2_with_vlan = {
+       .f = cmd_set_l2tpv2_parsed,
+       .data = NULL,
+       .help_str = "set l2tpv2-with-vlan ip-version ipv4|ipv6 flags_version"
+               " <flags_version> session_id <session_id> 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_l2tpv2_set,
+               (void *)&cmd_set_l2tpv2_l2tpv2_with_vlan,
+               (void *)&cmd_set_l2tpv2_ip_version,
+               (void *)&cmd_set_l2tpv2_ip_version_value,
+               (void *)&cmd_set_l2tpv2_flags_version,
+               (void *)&cmd_set_l2tpv2_flags_version_value,
+               (void *)&cmd_set_l2tpv2_session_id,
+               (void *)&cmd_set_l2tpv2_session_id_value,
+               (void *)&cmd_set_l2tpv2_udp_src,
+               (void *)&cmd_set_l2tpv2_udp_src_value,
+               (void *)&cmd_set_l2tpv2_udp_dst,
+               (void *)&cmd_set_l2tpv2_udp_dst_value,
+               (void *)&cmd_set_l2tpv2_ip_src,
+               (void *)&cmd_set_l2tpv2_ip_src_value,
+               (void *)&cmd_set_l2tpv2_ip_dst,
+               (void *)&cmd_set_l2tpv2_ip_dst_value,
+               (void *)&cmd_set_l2tpv2_vlan,
+               (void *)&cmd_set_l2tpv2_vlan_value,
+               (void *)&cmd_set_l2tpv2_eth_src,
+               (void *)&cmd_set_l2tpv2_eth_src_value,
+               (void *)&cmd_set_l2tpv2_eth_dst,
+               (void *)&cmd_set_l2tpv2_eth_dst_value,
+               NULL,
+       },
+};
+
 /** Set L2 encapsulation details */
 struct cmd_set_l2_encap_result {
        cmdline_fixed_string_t set;
@@ -17774,6 +18015,9 @@ cmdline_parse_ctx_t main_ctx[] = {
        (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_l2tpv2,
+       (cmdline_parse_inst_t *)&cmd_set_l2tpv2_tos_ttl,
+       (cmdline_parse_inst_t *)&cmd_set_l2tpv2_with_vlan,
        (cmdline_parse_inst_t *)&cmd_set_l2_encap,
        (cmdline_parse_inst_t *)&cmd_set_l2_encap_with_vlan,
        (cmdline_parse_inst_t *)&cmd_set_l2_decap,
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 0b5856c7d5..4f73d4f39d 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -306,6 +306,23 @@ enum index {
        ITEM_POL_PORT,
        ITEM_POL_METER,
        ITEM_POL_POLICY,
+       ITEM_L2TPV2,
+       ITEM_L2TPV2_COMMON,
+       ITEM_L2TPV2_COMMON_TYPE,
+       ITEM_L2TPV2_COMMON_TYPE_DATA_L,
+       ITEM_L2TPV2_COMMON_TYPE_CTRL,
+       ITEM_L2TPV2_MSG_DATA_L_LENGTH,
+       ITEM_L2TPV2_MSG_DATA_L_TUNNEL_ID,
+       ITEM_L2TPV2_MSG_DATA_L_SESSION_ID,
+       ITEM_L2TPV2_MSG_CTRL_LENGTH,
+       ITEM_L2TPV2_MSG_CTRL_TUNNEL_ID,
+       ITEM_L2TPV2_MSG_CTRL_SESSION_ID,
+       ITEM_L2TPV2_MSG_CTRL_NS,
+       ITEM_L2TPV2_MSG_CTRL_NR,
+       ITEM_PPP,
+       ITEM_PPP_ADDR,
+       ITEM_PPP_CTRL,
+       ITEM_PPP_PROTO_ID,
 
        /* Validate/create actions. */
        ACTIONS,
@@ -376,6 +393,8 @@ enum index {
        ACTION_VXLAN_DECAP,
        ACTION_NVGRE_ENCAP,
        ACTION_NVGRE_DECAP,
+       ACTION_L2TPV2_ENCAP,
+       ACTION_L2TPV2_DECAP,
        ACTION_L2_ENCAP,
        ACTION_L2_DECAP,
        ACTION_MPLSOGRE_ENCAP,
@@ -581,6 +600,44 @@ struct action_nvgre_encap_data {
        struct rte_flow_item_nvgre item_nvgre;
 };
 
+struct l2tpv2_encap_conf l2tpv2_encap_conf = {
+       .select_ipv4 = 1,
+       .select_vlan = 0,
+       .select_tos_ttl = 0,
+       .flags_version = 0,
+       .session_id = 0,
+       .udp_src = 0,
+       .udp_dst = 1701,
+       .ipv4_src = RTE_IPV4(127, 0, 0, 1),
+       .ipv4_dst = RTE_IPV4(255, 255, 255, 255),
+       .ipv6_src = "\x00\x00\x00\x00\x00\x00\x00\x00"
+               "\x00\x00\x00\x00\x00\x00\x00\x01",
+       .ipv6_dst = "\x00\x00\x00\x00\x00\x00\x00\x00"
+               "\x00\x00\x00\x00\x00\x00\x11\x11",
+       .vlan_tci = 0,
+       .ip_tos = 0,
+       .ip_ttl = 255,
+       .eth_src = "\x00\x00\x00\x00\x00\x00",
+       .eth_dst = "\xff\xff\xff\xff\xff\xff",
+};
+
+/** Maximum number of items in struct rte_flow_action_l2tpv2_encap. */
+#define ACTION_L2TPV2_ENCAP_ITEMS_NUM 6
+
+/** Storage for struct rte_flow_action_l2tpv2_encap including external data. */
+struct action_l2tpv2_encap_data {
+       struct rte_flow_action_l2tpv2_encap conf;
+       struct rte_flow_item items[ACTION_L2TPV2_ENCAP_ITEMS_NUM];
+       struct rte_flow_item_eth item_eth;
+       struct rte_flow_item_vlan item_vlan;
+       union {
+               struct rte_flow_item_ipv4 item_ipv4;
+               struct rte_flow_item_ipv6 item_ipv6;
+       };
+       struct rte_flow_item_udp item_udp;
+       struct rte_flow_item_l2tpv2 item_l2tpv2;
+};
+
 struct l2_encap_conf l2_encap_conf;
 
 struct l2_decap_conf l2_decap_conf;
@@ -614,6 +671,7 @@ struct rte_flow_action_port_id 
sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 struct action_vxlan_encap_data sample_vxlan_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 struct action_nvgre_encap_data sample_nvgre_encap[RAW_SAMPLE_CONFS_MAX_NUM];
+struct action_l2tpv2_encap_data sample_l2tpv2_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 struct action_rss_data sample_rss_data[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_vf sample_vf[RAW_SAMPLE_CONFS_MAX_NUM];
 
@@ -999,6 +1057,8 @@ static const enum index next_item[] = {
        ITEM_GENEVE_OPT,
        ITEM_INTEGRITY,
        ITEM_CONNTRACK,
+       ITEM_L2TPV2,
+       ITEM_PPP,
        END_SET,
        ZERO,
 };
@@ -1367,6 +1427,31 @@ static const enum index item_integrity_lv[] = {
        ZERO,
 };
 
+static const enum index item_l2tpv2[] = {
+       ITEM_L2TPV2_COMMON,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_l2tpv2_common[] = {
+       ITEM_L2TPV2_COMMON_TYPE,
+       ZERO,
+};
+
+static const enum index item_l2tpv2_common_type[] = {
+       ITEM_L2TPV2_COMMON_TYPE_DATA_L,
+       ITEM_L2TPV2_COMMON_TYPE_CTRL,
+       ZERO,
+};
+
+static const enum index item_ppp[] = {
+       ITEM_PPP_ADDR,
+       ITEM_PPP_CTRL,
+       ITEM_PPP_PROTO_ID,
+       ITEM_NEXT,
+       ZERO,
+};
+
 static const enum index next_action[] = {
        ACTION_END,
        ACTION_VOID,
@@ -1400,6 +1485,8 @@ static const enum index next_action[] = {
        ACTION_VXLAN_DECAP,
        ACTION_NVGRE_ENCAP,
        ACTION_NVGRE_DECAP,
+       ACTION_L2TPV2_ENCAP,
+       ACTION_L2TPV2_DECAP,
        ACTION_L2_ENCAP,
        ACTION_L2_DECAP,
        ACTION_MPLSOGRE_ENCAP,
@@ -1687,6 +1774,7 @@ static const enum index next_action_sample[] = {
        ACTION_RAW_ENCAP,
        ACTION_VXLAN_ENCAP,
        ACTION_NVGRE_ENCAP,
+       ACTION_L2TPV2_ENCAP,
        ACTION_NEXT,
        ZERO,
 };
@@ -1757,6 +1845,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_l2tpv2_encap(struct context *, const struct token *,
+                                       const char *, unsigned int, void *,
+                                       unsigned int);
 static int parse_vc_action_l2_encap(struct context *, const struct token *,
                                    const char *, unsigned int, void *,
                                    unsigned int);
@@ -3606,6 +3697,136 @@ static const struct token token_list[] = {
                             item_param),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_item_conntrack, flags)),
        },
+       [ITEM_L2TPV2] = {
+               .name = "l2tpv2",
+               .help = "match l2tpv2 header",
+               .priv = PRIV_ITEM(L2TPV2, sizeof(struct rte_flow_item_l2tpv2)),
+               .next = NEXT(item_l2tpv2),
+               .call = parse_vc,
+       },
+       [ITEM_L2TPV2_COMMON] = {
+               .name = "common",
+               .help = "l2tpv2 common header",
+               .next = NEXT(item_l2tpv2_common),
+       },
+       [ITEM_L2TPV2_COMMON_TYPE] = {
+               .name = "type",
+               .help = "type of common header",
+               .next = NEXT(item_l2tpv2_common_type),
+               .args = ARGS(ARG_ENTRY_HTON(struct rte_flow_item_l2tpv2)),
+       },
+       [ITEM_L2TPV2_COMMON_TYPE_DATA_L] = {
+               .name = "data_l",
+               .help = "Type #6: data message with length option",
+               .next = NEXT(NEXT_ENTRY(ITEM_L2TPV2_MSG_DATA_L_LENGTH,
+                                       ITEM_L2TPV2_MSG_DATA_L_TUNNEL_ID,
+                                       ITEM_L2TPV2_MSG_DATA_L_SESSION_ID,
+                                       ITEM_NEXT)),
+               .call = parse_vc,
+       },
+       [ITEM_L2TPV2_MSG_DATA_L_LENGTH] = {
+               .name = "length",
+               .help = "message length",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type7.tunnel_id)),
+       },
+       [ITEM_L2TPV2_MSG_DATA_L_TUNNEL_ID] = {
+               .name = "tunnel_id",
+               .help = "tunnel identifier",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type7.tunnel_id)),
+       },
+       [ITEM_L2TPV2_MSG_DATA_L_SESSION_ID] = {
+               .name = "session_id",
+               .help = "session identifier",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type7.session_id)),
+       },
+       [ITEM_L2TPV2_COMMON_TYPE_CTRL] = {
+               .name = "control",
+               .help = "Type #3: conrtol message contains length, ns, nr 
options",
+               .next = NEXT(NEXT_ENTRY(ITEM_L2TPV2_MSG_CTRL_LENGTH,
+                                       ITEM_L2TPV2_MSG_CTRL_TUNNEL_ID,
+                                       ITEM_L2TPV2_MSG_CTRL_SESSION_ID,
+                                       ITEM_L2TPV2_MSG_CTRL_NS,
+                                       ITEM_L2TPV2_MSG_CTRL_NR,
+                                       ITEM_NEXT)),
+               .call = parse_vc,
+       },
+       [ITEM_L2TPV2_MSG_CTRL_LENGTH] = {
+               .name = "length",
+               .help = "message length",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type3.length)),
+       },
+       [ITEM_L2TPV2_MSG_CTRL_TUNNEL_ID] = {
+               .name = "tunnel_id",
+               .help = "tunnel identifier",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type3.tunnel_id)),
+       },
+       [ITEM_L2TPV2_MSG_CTRL_SESSION_ID] = {
+               .name = "session_id",
+               .help = "session identifier",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type3.session_id)),
+       },
+       [ITEM_L2TPV2_MSG_CTRL_NS] = {
+               .name = "ns",
+               .help = "sequence number for message",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type3.ns)),
+       },
+       [ITEM_L2TPV2_MSG_CTRL_NR] = {
+               .name = "nr",
+               .help = "sequence number for next receive message",
+               .next = NEXT(item_l2tpv2, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_l2tpv2,
+                                            hdr.type3.nr)),
+       },
+       [ITEM_PPP] = {
+               .name = "ppp",
+               .help = "match ppp header",
+               .priv = PRIV_ITEM(PPP, sizeof(struct rte_flow_item_ppp)),
+               .next = NEXT(item_ppp),
+               .call = parse_vc,
+       },
+       [ITEM_PPP_ADDR] = {
+               .name = "addr",
+               .help = "ppp address",
+               .next = NEXT(item_ppp, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_item_ppp, addr)),
+       },
+       [ITEM_PPP_CTRL] = {
+               .name = "ctrl",
+               .help = "ppp control",
+               .next = NEXT(item_ppp, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_item_ppp, ctrl)),
+       },
+       [ITEM_PPP_PROTO_ID] = {
+               .name = "proto_id",
+               .help = "ppp protocol id",
+               .next = NEXT(item_ppp, NEXT_ENTRY(COMMON_UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_item_ppp, proto_id)),
+       },
        /* Validate/create actions. */
        [ACTIONS] = {
                .name = "actions",
@@ -4125,6 +4346,24 @@ static const struct token token_list[] = {
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
                .call = parse_vc,
        },
+       [ACTION_L2TPV2_ENCAP] = {
+               .name = "l2tpv2_encap",
+               .help = "L2TPV2 encapsulation, uses configuration set by \"set"
+                       " l2tpv2\"",
+               .priv = PRIV_ACTION(L2TPV2_ENCAP,
+                                   sizeof(struct action_l2tpv2_encap_data)),
+               .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+               .call = parse_vc_action_l2tpv2_encap,
+       },
+       [ACTION_L2TPV2_DECAP] = {
+               .name = "l2tpv2_decap",
+               .help = "Performs a decapsulation action by stripping all"
+                       " headers of the L2TPV2 tunnel network overlay from the"
+                       " matched flow.",
+               .priv = PRIV_ACTION(L2TPV2_DECAP, 0),
+               .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+               .call = parse_vc,
+       },
        [ACTION_L2_ENCAP] = {
                .name = "l2_encap",
                .help = "l2 encap, uses configuration set by"
@@ -5907,6 +6146,152 @@ parse_vc_action_nvgre_encap(struct context *ctx, const 
struct token *token,
        return ret;
 }
 
+/** Setup L2TPV2 encap configuration. */
+static int
+parse_setup_l2tpv2_encap_data(struct action_l2tpv2_encap_data 
*action_l2tpv2_encap_data)
+{
+       /* Set up default configuration. */
+       *action_l2tpv2_encap_data = (struct action_l2tpv2_encap_data){
+               .conf = (struct rte_flow_action_l2tpv2_encap){
+                       .definition = action_l2tpv2_encap_data->items,
+               },
+               .items = {
+                       {
+                               .type = RTE_FLOW_ITEM_TYPE_ETH,
+                               .spec = &action_l2tpv2_encap_data->item_eth,
+                               .mask = &rte_flow_item_eth_mask,
+                       },
+                       {
+                               .type = RTE_FLOW_ITEM_TYPE_VLAN,
+                               .spec = &action_l2tpv2_encap_data->item_vlan,
+                               .mask = &rte_flow_item_vlan_mask,
+                       },
+                       {
+                               .type = RTE_FLOW_ITEM_TYPE_IPV4,
+                               .spec = &action_l2tpv2_encap_data->item_ipv4,
+                               .mask = &rte_flow_item_ipv4_mask,
+                       },
+                       {
+                               .type = RTE_FLOW_ITEM_TYPE_UDP,
+                               .spec = &action_l2tpv2_encap_data->item_udp,
+                               .mask = &rte_flow_item_udp_mask,
+                       },
+                       {
+                               .type = RTE_FLOW_ITEM_TYPE_L2TPV2,
+                               .spec = &action_l2tpv2_encap_data->item_l2tpv2,
+                               .mask = &rte_flow_item_l2tpv2_mask,
+                       },
+                       {
+                               .type = RTE_FLOW_ITEM_TYPE_END,
+                       },
+               },
+               .item_eth.type = 0,
+               .item_vlan = {
+                       .tci = l2tpv2_encap_conf.vlan_tci,
+                       .inner_type = 0,
+               },
+               .item_ipv4.hdr = {
+                       .src_addr = l2tpv2_encap_conf.ipv4_src,
+                       .dst_addr = l2tpv2_encap_conf.ipv4_dst,
+               },
+               .item_udp.hdr = {
+                       .src_port = l2tpv2_encap_conf.udp_src,
+                       .dst_port = l2tpv2_encap_conf.udp_dst,
+               },
+       };
+       memcpy(action_l2tpv2_encap_data->item_eth.dst.addr_bytes,
+              l2tpv2_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
+       memcpy(action_l2tpv2_encap_data->item_eth.src.addr_bytes,
+              l2tpv2_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
+       if (!l2tpv2_encap_conf.select_ipv4) {
+               memcpy(&action_l2tpv2_encap_data->item_ipv6.hdr.src_addr,
+                      &l2tpv2_encap_conf.ipv6_src,
+                      sizeof(l2tpv2_encap_conf.ipv6_src));
+               memcpy(&action_l2tpv2_encap_data->item_ipv6.hdr.dst_addr,
+                      &l2tpv2_encap_conf.ipv6_dst,
+                      sizeof(l2tpv2_encap_conf.ipv6_dst));
+               action_l2tpv2_encap_data->items[2] = (struct rte_flow_item){
+                       .type = RTE_FLOW_ITEM_TYPE_IPV6,
+                       .spec = &action_l2tpv2_encap_data->item_ipv6,
+                       .mask = &rte_flow_item_ipv6_mask,
+               };
+       }
+       if (!l2tpv2_encap_conf.select_vlan)
+               action_l2tpv2_encap_data->items[1].type =
+                       RTE_FLOW_ITEM_TYPE_VOID;
+       if (l2tpv2_encap_conf.select_tos_ttl) {
+               if (l2tpv2_encap_conf.select_ipv4) {
+                       static struct rte_flow_item_ipv4 ipv4_mask_tos;
+
+                       memcpy(&ipv4_mask_tos, &rte_flow_item_ipv4_mask,
+                              sizeof(ipv4_mask_tos));
+                       ipv4_mask_tos.hdr.type_of_service = 0xff;
+                       ipv4_mask_tos.hdr.time_to_live = 0xff;
+                       action_l2tpv2_encap_data->item_ipv4.hdr.type_of_service 
=
+                                       l2tpv2_encap_conf.ip_tos;
+                       action_l2tpv2_encap_data->item_ipv4.hdr.time_to_live =
+                                       l2tpv2_encap_conf.ip_ttl;
+                       action_l2tpv2_encap_data->items[2].mask =
+                                                       &ipv4_mask_tos;
+               } else {
+                       static struct rte_flow_item_ipv6 ipv6_mask_tos;
+
+                       memcpy(&ipv6_mask_tos, &rte_flow_item_ipv6_mask,
+                              sizeof(ipv6_mask_tos));
+                       ipv6_mask_tos.hdr.vtc_flow |=
+                               RTE_BE32(0xfful << RTE_IPV6_HDR_TC_SHIFT);
+                       ipv6_mask_tos.hdr.hop_limits = 0xff;
+                       action_l2tpv2_encap_data->item_ipv6.hdr.vtc_flow |=
+                               rte_cpu_to_be_32
+                                       ((uint32_t)l2tpv2_encap_conf.ip_tos <<
+                                        RTE_IPV6_HDR_TC_SHIFT);
+                       action_l2tpv2_encap_data->item_ipv6.hdr.hop_limits =
+                                       l2tpv2_encap_conf.ip_ttl;
+                       action_l2tpv2_encap_data->items[2].mask =
+                                                       &ipv6_mask_tos;
+               }
+       }
+
+       if (0xc800 == (l2tpv2_encap_conf.flags_version & 0xcb00)) {
+               action_l2tpv2_encap_data->item_l2tpv2.hdr.type3.session_id =
+                       l2tpv2_encap_conf.session_id;
+       } else if (0x4000 == (l2tpv2_encap_conf.flags_version & 0xcb00)) {
+               action_l2tpv2_encap_data->item_l2tpv2.hdr.type6.session_id =
+                       l2tpv2_encap_conf.session_id;
+       }
+
+       return 0;
+}
+
+/** Parse l2tpv2 encap action. */
+static int
+parse_vc_action_l2tpv2_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_l2tpv2_encap_data *action_l2tpv2_encap_data;
+       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;
+       action_l2tpv2_encap_data = ctx->object;
+       parse_setup_l2tpv2_encap_data(action_l2tpv2_encap_data);
+       action->conf = &action_l2tpv2_encap_data->conf;
+       return ret;
+}
+
 /** Parse l2 encap action. */
 static int
 parse_vc_action_l2_encap(struct context *ctx, const struct token *token,
@@ -8333,6 +8718,12 @@ flow_item_default_mask(const struct rte_flow_item *item)
        case RTE_FLOW_ITEM_TYPE_PFCP:
                mask = &rte_flow_item_pfcp_mask;
                break;
+       case RTE_FLOW_ITEM_TYPE_L2TPV2:
+               mask = &rte_flow_item_l2tpv2_mask;
+               break;
+       case RTE_FLOW_ITEM_TYPE_PPP:
+               mask = &rte_flow_item_ppp_mask;
+               break;
        default:
                break;
        }
@@ -8432,6 +8823,11 @@ cmd_set_raw_parsed_sample(const struct buffer *in)
                        parse_setup_nvgre_encap_data(&sample_nvgre_encap[idx]);
                        action->conf = &sample_nvgre_encap[idx];
                        break;
+               case RTE_FLOW_ACTION_TYPE_L2TPV2_ENCAP:
+                       size = sizeof(struct rte_flow_action_l2tpv2_encap);
+                       
parse_setup_l2tpv2_encap_data(&sample_l2tpv2_encap[idx]);
+                       action->conf = &sample_l2tpv2_encap[idx];
+                       break;
                default:
                        fprintf(stderr, "Error - Not supported action\n");
                        return;
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index e9d9db06ce..c744799b46 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -567,6 +567,28 @@ struct nvgre_encap_conf {
 
 extern struct nvgre_encap_conf nvgre_encap_conf;
 
+/* L2TPV2 encap/decap parameters. */
+struct l2tpv2_encap_conf {
+       uint32_t select_ipv4:1;
+       uint32_t select_vlan:1;
+       uint32_t select_tos_ttl:1;
+       rte_be16_t flags_version;
+       rte_be16_t session_id;
+       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 ip_tos;
+       uint8_t ip_ttl;
+       uint8_t eth_src[RTE_ETHER_ADDR_LEN];
+       uint8_t eth_dst[RTE_ETHER_ADDR_LEN];
+};
+
+extern struct l2tpv2_encap_conf l2tpv2_encap_conf;
+
 /* L2 encap parameters. */
 struct l2_encap_conf {
        uint32_t select_ipv4:1;
-- 
2.25.1

Reply via email to