ethdev: add VLAN and MPLS actions to flow API
[dpdk.git] / app / test-pmd / cmdline_flow.c
index 976fde7..4239602 100644 (file)
@@ -69,6 +69,7 @@ enum index {
        PRIORITY,
        INGRESS,
        EGRESS,
+       TRANSFER,
 
        /* Validate/create pattern. */
        PATTERN,
@@ -86,8 +87,10 @@ enum index {
        ITEM_PF,
        ITEM_VF,
        ITEM_VF_ID,
-       ITEM_PORT,
-       ITEM_PORT_INDEX,
+       ITEM_PHY_PORT,
+       ITEM_PHY_PORT_INDEX,
+       ITEM_PORT_ID,
+       ITEM_PORT_ID_ID,
        ITEM_RAW,
        ITEM_RAW_RELATIVE,
        ITEM_RAW_SEARCH,
@@ -99,11 +102,11 @@ enum index {
        ITEM_ETH_SRC,
        ITEM_ETH_TYPE,
        ITEM_VLAN,
-       ITEM_VLAN_TPID,
        ITEM_VLAN_TCI,
        ITEM_VLAN_PCP,
        ITEM_VLAN_DEI,
        ITEM_VLAN_VID,
+       ITEM_VLAN_INNER_TYPE,
        ITEM_IPV4,
        ITEM_IPV4_TOS,
        ITEM_IPV4_TTL,
@@ -151,6 +154,28 @@ enum index {
        ITEM_GENEVE,
        ITEM_GENEVE_VNI,
        ITEM_GENEVE_PROTO,
+       ITEM_VXLAN_GPE,
+       ITEM_VXLAN_GPE_VNI,
+       ITEM_ARP_ETH_IPV4,
+       ITEM_ARP_ETH_IPV4_SHA,
+       ITEM_ARP_ETH_IPV4_SPA,
+       ITEM_ARP_ETH_IPV4_THA,
+       ITEM_ARP_ETH_IPV4_TPA,
+       ITEM_IPV6_EXT,
+       ITEM_IPV6_EXT_NEXT_HDR,
+       ITEM_ICMP6,
+       ITEM_ICMP6_TYPE,
+       ITEM_ICMP6_CODE,
+       ITEM_ICMP6_ND_NS,
+       ITEM_ICMP6_ND_NS_TARGET_ADDR,
+       ITEM_ICMP6_ND_NA,
+       ITEM_ICMP6_ND_NA_TARGET_ADDR,
+       ITEM_ICMP6_ND_OPT,
+       ITEM_ICMP6_ND_OPT_TYPE,
+       ITEM_ICMP6_ND_OPT_SLA_ETH,
+       ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
+       ITEM_ICMP6_ND_OPT_TLA_ETH,
+       ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
 
        /* Validate/create actions. */
        ACTIONS,
@@ -181,8 +206,33 @@ enum index {
        ACTION_VF,
        ACTION_VF_ORIGINAL,
        ACTION_VF_ID,
+       ACTION_PHY_PORT,
+       ACTION_PHY_PORT_ORIGINAL,
+       ACTION_PHY_PORT_INDEX,
+       ACTION_PORT_ID,
+       ACTION_PORT_ID_ORIGINAL,
+       ACTION_PORT_ID_ID,
        ACTION_METER,
        ACTION_METER_ID,
+       ACTION_OF_SET_MPLS_TTL,
+       ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
+       ACTION_OF_DEC_MPLS_TTL,
+       ACTION_OF_SET_NW_TTL,
+       ACTION_OF_SET_NW_TTL_NW_TTL,
+       ACTION_OF_DEC_NW_TTL,
+       ACTION_OF_COPY_TTL_OUT,
+       ACTION_OF_COPY_TTL_IN,
+       ACTION_OF_POP_VLAN,
+       ACTION_OF_PUSH_VLAN,
+       ACTION_OF_PUSH_VLAN_ETHERTYPE,
+       ACTION_OF_SET_VLAN_VID,
+       ACTION_OF_SET_VLAN_VID_VLAN_VID,
+       ACTION_OF_SET_VLAN_PCP,
+       ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
+       ACTION_OF_POP_MPLS,
+       ACTION_OF_POP_MPLS_ETHERTYPE,
+       ACTION_OF_PUSH_MPLS,
+       ACTION_OF_PUSH_MPLS_ETHERTYPE,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -407,6 +457,7 @@ static const enum index next_vc_attr[] = {
        PRIORITY,
        INGRESS,
        EGRESS,
+       TRANSFER,
        PATTERN,
        ZERO,
 };
@@ -439,7 +490,8 @@ static const enum index next_item[] = {
        ITEM_ANY,
        ITEM_PF,
        ITEM_VF,
-       ITEM_PORT,
+       ITEM_PHY_PORT,
+       ITEM_PORT_ID,
        ITEM_RAW,
        ITEM_ETH,
        ITEM_VLAN,
@@ -459,6 +511,15 @@ static const enum index next_item[] = {
        ITEM_GTPC,
        ITEM_GTPU,
        ITEM_GENEVE,
+       ITEM_VXLAN_GPE,
+       ITEM_ARP_ETH_IPV4,
+       ITEM_IPV6_EXT,
+       ITEM_ICMP6,
+       ITEM_ICMP6_ND_NS,
+       ITEM_ICMP6_ND_NA,
+       ITEM_ICMP6_ND_OPT,
+       ITEM_ICMP6_ND_OPT_SLA_ETH,
+       ITEM_ICMP6_ND_OPT_TLA_ETH,
        ZERO,
 };
 
@@ -480,8 +541,14 @@ static const enum index item_vf[] = {
        ZERO,
 };
 
-static const enum index item_port[] = {
-       ITEM_PORT_INDEX,
+static const enum index item_phy_port[] = {
+       ITEM_PHY_PORT_INDEX,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_port_id[] = {
+       ITEM_PORT_ID_ID,
        ITEM_NEXT,
        ZERO,
 };
@@ -505,11 +572,11 @@ static const enum index item_eth[] = {
 };
 
 static const enum index item_vlan[] = {
-       ITEM_VLAN_TPID,
        ITEM_VLAN_TCI,
        ITEM_VLAN_PCP,
        ITEM_VLAN_DEI,
        ITEM_VLAN_VID,
+       ITEM_VLAN_INNER_TYPE,
        ITEM_NEXT,
        ZERO,
 };
@@ -609,6 +676,64 @@ static const enum index item_geneve[] = {
        ZERO,
 };
 
+static const enum index item_vxlan_gpe[] = {
+       ITEM_VXLAN_GPE_VNI,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_arp_eth_ipv4[] = {
+       ITEM_ARP_ETH_IPV4_SHA,
+       ITEM_ARP_ETH_IPV4_SPA,
+       ITEM_ARP_ETH_IPV4_THA,
+       ITEM_ARP_ETH_IPV4_TPA,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_ipv6_ext[] = {
+       ITEM_IPV6_EXT_NEXT_HDR,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_icmp6[] = {
+       ITEM_ICMP6_TYPE,
+       ITEM_ICMP6_CODE,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_icmp6_nd_ns[] = {
+       ITEM_ICMP6_ND_NS_TARGET_ADDR,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_icmp6_nd_na[] = {
+       ITEM_ICMP6_ND_NA_TARGET_ADDR,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_icmp6_nd_opt[] = {
+       ITEM_ICMP6_ND_OPT_TYPE,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_icmp6_nd_opt_sla_eth[] = {
+       ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
+       ITEM_NEXT,
+       ZERO,
+};
+
+static const enum index item_icmp6_nd_opt_tla_eth[] = {
+       ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
+       ITEM_NEXT,
+       ZERO,
+};
+
 static const enum index next_action[] = {
        ACTION_END,
        ACTION_VOID,
@@ -621,7 +746,21 @@ static const enum index next_action[] = {
        ACTION_RSS,
        ACTION_PF,
        ACTION_VF,
+       ACTION_PHY_PORT,
+       ACTION_PORT_ID,
        ACTION_METER,
+       ACTION_OF_SET_MPLS_TTL,
+       ACTION_OF_DEC_MPLS_TTL,
+       ACTION_OF_SET_NW_TTL,
+       ACTION_OF_DEC_NW_TTL,
+       ACTION_OF_COPY_TTL_OUT,
+       ACTION_OF_COPY_TTL_IN,
+       ACTION_OF_POP_VLAN,
+       ACTION_OF_PUSH_VLAN,
+       ACTION_OF_SET_VLAN_VID,
+       ACTION_OF_SET_VLAN_PCP,
+       ACTION_OF_POP_MPLS,
+       ACTION_OF_PUSH_MPLS,
        ZERO,
 };
 
@@ -655,12 +794,68 @@ static const enum index action_vf[] = {
        ZERO,
 };
 
+static const enum index action_phy_port[] = {
+       ACTION_PHY_PORT_ORIGINAL,
+       ACTION_PHY_PORT_INDEX,
+       ACTION_NEXT,
+       ZERO,
+};
+
+static const enum index action_port_id[] = {
+       ACTION_PORT_ID_ORIGINAL,
+       ACTION_PORT_ID_ID,
+       ACTION_NEXT,
+       ZERO,
+};
+
 static const enum index action_meter[] = {
        ACTION_METER_ID,
        ACTION_NEXT,
        ZERO,
 };
 
+static const enum index action_of_set_mpls_ttl[] = {
+       ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
+       ACTION_NEXT,
+       ZERO,
+};
+
+static const enum index action_of_set_nw_ttl[] = {
+       ACTION_OF_SET_NW_TTL_NW_TTL,
+       ACTION_NEXT,
+       ZERO,
+};
+
+static const enum index action_of_push_vlan[] = {
+       ACTION_OF_PUSH_VLAN_ETHERTYPE,
+       ACTION_NEXT,
+       ZERO,
+};
+
+static const enum index action_of_set_vlan_vid[] = {
+       ACTION_OF_SET_VLAN_VID_VLAN_VID,
+       ACTION_NEXT,
+       ZERO,
+};
+
+static const enum index action_of_set_vlan_pcp[] = {
+       ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
+       ACTION_NEXT,
+       ZERO,
+};
+
+static const enum index action_of_pop_mpls[] = {
+       ACTION_OF_POP_MPLS_ETHERTYPE,
+       ACTION_NEXT,
+       ZERO,
+};
+
+static const enum index action_of_push_mpls[] = {
+       ACTION_OF_PUSH_MPLS_ETHERTYPE,
+       ACTION_NEXT,
+       ZERO,
+};
+
 static int parse_init(struct context *, const struct token *,
                      const char *, unsigned int,
                      void *, unsigned int);
@@ -960,6 +1155,12 @@ static const struct token token_list[] = {
                .next = NEXT(next_vc_attr),
                .call = parse_vc,
        },
+       [TRANSFER] = {
+               .name = "transfer",
+               .help = "apply rule directly to endpoints found in pattern",
+               .next = NEXT(next_vc_attr),
+               .call = parse_vc,
+       },
        /* Validate/create pattern. */
        [PATTERN] = {
                .name = "pattern",
@@ -1033,36 +1234,51 @@ static const struct token token_list[] = {
        },
        [ITEM_PF] = {
                .name = "pf",
-               .help = "match packets addressed to the physical function",
+               .help = "match traffic from/to the physical function",
                .priv = PRIV_ITEM(PF, 0),
                .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
                .call = parse_vc,
        },
        [ITEM_VF] = {
                .name = "vf",
-               .help = "match packets addressed to a virtual function ID",
+               .help = "match traffic from/to a virtual function ID",
                .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
                .next = NEXT(item_vf),
                .call = parse_vc,
        },
        [ITEM_VF_ID] = {
                .name = "id",
-               .help = "destination VF ID",
+               .help = "VF ID",
                .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
        },
-       [ITEM_PORT] = {
-               .name = "port",
-               .help = "device-specific physical port index to use",
-               .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)),
-               .next = NEXT(item_port),
+       [ITEM_PHY_PORT] = {
+               .name = "phy_port",
+               .help = "match traffic from/to a specific physical port",
+               .priv = PRIV_ITEM(PHY_PORT,
+                                 sizeof(struct rte_flow_item_phy_port)),
+               .next = NEXT(item_phy_port),
                .call = parse_vc,
        },
-       [ITEM_PORT_INDEX] = {
+       [ITEM_PHY_PORT_INDEX] = {
                .name = "index",
                .help = "physical port index",
-               .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param),
-               .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)),
+               .next = NEXT(item_phy_port, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_item_phy_port, index)),
+       },
+       [ITEM_PORT_ID] = {
+               .name = "port_id",
+               .help = "match traffic from/to a given DPDK port ID",
+               .priv = PRIV_ITEM(PORT_ID,
+                                 sizeof(struct rte_flow_item_port_id)),
+               .next = NEXT(item_port_id),
+               .call = parse_vc,
+       },
+       [ITEM_PORT_ID_ID] = {
+               .name = "id",
+               .help = "DPDK port ID",
+               .next = NEXT(item_port_id, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port_id, id)),
        },
        [ITEM_RAW] = {
                .name = "raw",
@@ -1142,12 +1358,6 @@ static const struct token token_list[] = {
                .next = NEXT(item_vlan),
                .call = parse_vc,
        },
-       [ITEM_VLAN_TPID] = {
-               .name = "tpid",
-               .help = "tag protocol identifier",
-               .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
-               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)),
-       },
        [ITEM_VLAN_TCI] = {
                .name = "tci",
                .help = "tag control information",
@@ -1175,6 +1385,13 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
                                                  tci, "\x0f\xff")),
        },
+       [ITEM_VLAN_INNER_TYPE] = {
+               .name = "inner_type",
+               .help = "inner EtherType",
+               .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan,
+                                            inner_type)),
+       },
        [ITEM_IPV4] = {
                .name = "ipv4",
                .help = "match IPv4 header",
@@ -1505,6 +1722,182 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
                                             protocol)),
        },
+       [ITEM_VXLAN_GPE] = {
+               .name = "vxlan-gpe",
+               .help = "match VXLAN-GPE header",
+               .priv = PRIV_ITEM(VXLAN_GPE,
+                                 sizeof(struct rte_flow_item_vxlan_gpe)),
+               .next = NEXT(item_vxlan_gpe),
+               .call = parse_vc,
+       },
+       [ITEM_VXLAN_GPE_VNI] = {
+               .name = "vni",
+               .help = "VXLAN-GPE identifier",
+               .next = NEXT(item_vxlan_gpe, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan_gpe,
+                                            vni)),
+       },
+       [ITEM_ARP_ETH_IPV4] = {
+               .name = "arp_eth_ipv4",
+               .help = "match ARP header for Ethernet/IPv4",
+               .priv = PRIV_ITEM(ARP_ETH_IPV4,
+                                 sizeof(struct rte_flow_item_arp_eth_ipv4)),
+               .next = NEXT(item_arp_eth_ipv4),
+               .call = parse_vc,
+       },
+       [ITEM_ARP_ETH_IPV4_SHA] = {
+               .name = "sha",
+               .help = "sender hardware address",
+               .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+                                            sha)),
+       },
+       [ITEM_ARP_ETH_IPV4_SPA] = {
+               .name = "spa",
+               .help = "sender IPv4 address",
+               .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+                                            spa)),
+       },
+       [ITEM_ARP_ETH_IPV4_THA] = {
+               .name = "tha",
+               .help = "target hardware address",
+               .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+                                            tha)),
+       },
+       [ITEM_ARP_ETH_IPV4_TPA] = {
+               .name = "tpa",
+               .help = "target IPv4 address",
+               .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
+                                            tpa)),
+       },
+       [ITEM_IPV6_EXT] = {
+               .name = "ipv6_ext",
+               .help = "match presence of any IPv6 extension header",
+               .priv = PRIV_ITEM(IPV6_EXT,
+                                 sizeof(struct rte_flow_item_ipv6_ext)),
+               .next = NEXT(item_ipv6_ext),
+               .call = parse_vc,
+       },
+       [ITEM_IPV6_EXT_NEXT_HDR] = {
+               .name = "next_hdr",
+               .help = "next header",
+               .next = NEXT(item_ipv6_ext, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext,
+                                            next_hdr)),
+       },
+       [ITEM_ICMP6] = {
+               .name = "icmp6",
+               .help = "match any ICMPv6 header",
+               .priv = PRIV_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)),
+               .next = NEXT(item_icmp6),
+               .call = parse_vc,
+       },
+       [ITEM_ICMP6_TYPE] = {
+               .name = "type",
+               .help = "ICMPv6 type",
+               .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
+                                            type)),
+       },
+       [ITEM_ICMP6_CODE] = {
+               .name = "code",
+               .help = "ICMPv6 code",
+               .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
+                                            code)),
+       },
+       [ITEM_ICMP6_ND_NS] = {
+               .name = "icmp6_nd_ns",
+               .help = "match ICMPv6 neighbor discovery solicitation",
+               .priv = PRIV_ITEM(ICMP6_ND_NS,
+                                 sizeof(struct rte_flow_item_icmp6_nd_ns)),
+               .next = NEXT(item_icmp6_nd_ns),
+               .call = parse_vc,
+       },
+       [ITEM_ICMP6_ND_NS_TARGET_ADDR] = {
+               .name = "target_addr",
+               .help = "target address",
+               .next = NEXT(item_icmp6_nd_ns, NEXT_ENTRY(IPV6_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_ns,
+                                            target_addr)),
+       },
+       [ITEM_ICMP6_ND_NA] = {
+               .name = "icmp6_nd_na",
+               .help = "match ICMPv6 neighbor discovery advertisement",
+               .priv = PRIV_ITEM(ICMP6_ND_NA,
+                                 sizeof(struct rte_flow_item_icmp6_nd_na)),
+               .next = NEXT(item_icmp6_nd_na),
+               .call = parse_vc,
+       },
+       [ITEM_ICMP6_ND_NA_TARGET_ADDR] = {
+               .name = "target_addr",
+               .help = "target address",
+               .next = NEXT(item_icmp6_nd_na, NEXT_ENTRY(IPV6_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_na,
+                                            target_addr)),
+       },
+       [ITEM_ICMP6_ND_OPT] = {
+               .name = "icmp6_nd_opt",
+               .help = "match presence of any ICMPv6 neighbor discovery"
+                       " option",
+               .priv = PRIV_ITEM(ICMP6_ND_OPT,
+                                 sizeof(struct rte_flow_item_icmp6_nd_opt)),
+               .next = NEXT(item_icmp6_nd_opt),
+               .call = parse_vc,
+       },
+       [ITEM_ICMP6_ND_OPT_TYPE] = {
+               .name = "type",
+               .help = "ND option type",
+               .next = NEXT(item_icmp6_nd_opt, NEXT_ENTRY(UNSIGNED),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_opt,
+                                            type)),
+       },
+       [ITEM_ICMP6_ND_OPT_SLA_ETH] = {
+               .name = "icmp6_nd_opt_sla_eth",
+               .help = "match ICMPv6 neighbor discovery source Ethernet"
+                       " link-layer address option",
+               .priv = PRIV_ITEM
+                       (ICMP6_ND_OPT_SLA_ETH,
+                        sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),
+               .next = NEXT(item_icmp6_nd_opt_sla_eth),
+               .call = parse_vc,
+       },
+       [ITEM_ICMP6_ND_OPT_SLA_ETH_SLA] = {
+               .name = "sla",
+               .help = "source Ethernet LLA",
+               .next = NEXT(item_icmp6_nd_opt_sla_eth, NEXT_ENTRY(MAC_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON
+                            (struct rte_flow_item_icmp6_nd_opt_sla_eth, sla)),
+       },
+       [ITEM_ICMP6_ND_OPT_TLA_ETH] = {
+               .name = "icmp6_nd_opt_tla_eth",
+               .help = "match ICMPv6 neighbor discovery target Ethernet"
+                       " link-layer address option",
+               .priv = PRIV_ITEM
+                       (ICMP6_ND_OPT_TLA_ETH,
+                        sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),
+               .next = NEXT(item_icmp6_nd_opt_tla_eth),
+               .call = parse_vc,
+       },
+       [ITEM_ICMP6_ND_OPT_TLA_ETH_TLA] = {
+               .name = "tla",
+               .help = "target Ethernet LLA",
+               .next = NEXT(item_icmp6_nd_opt_tla_eth, NEXT_ENTRY(MAC_ADDR),
+                            item_param),
+               .args = ARGS(ARGS_ENTRY_HTON
+                            (struct rte_flow_item_icmp6_nd_opt_tla_eth, tla)),
+       },
 
        /* Validate/create actions. */
        [ACTIONS] = {
@@ -1677,14 +2070,14 @@ static const struct token token_list[] = {
        },
        [ACTION_PF] = {
                .name = "pf",
-               .help = "redirect packets to physical device function",
+               .help = "direct traffic to physical function",
                .priv = PRIV_ACTION(PF, 0),
                .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
                .call = parse_vc,
        },
        [ACTION_VF] = {
                .name = "vf",
-               .help = "redirect packets to virtual device function",
+               .help = "direct traffic to a virtual function ID",
                .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
                .next = NEXT(action_vf),
                .call = parse_vc,
@@ -1699,11 +2092,58 @@ static const struct token token_list[] = {
        },
        [ACTION_VF_ID] = {
                .name = "id",
-               .help = "VF ID to redirect packets to",
+               .help = "VF ID",
                .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
                .call = parse_vc_conf,
        },
+       [ACTION_PHY_PORT] = {
+               .name = "phy_port",
+               .help = "direct packets to physical port index",
+               .priv = PRIV_ACTION(PHY_PORT,
+                                   sizeof(struct rte_flow_action_phy_port)),
+               .next = NEXT(action_phy_port),
+               .call = parse_vc,
+       },
+       [ACTION_PHY_PORT_ORIGINAL] = {
+               .name = "original",
+               .help = "use original port index if possible",
+               .next = NEXT(action_phy_port, NEXT_ENTRY(BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_phy_port,
+                                          original, 1)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_PHY_PORT_INDEX] = {
+               .name = "index",
+               .help = "physical port index",
+               .next = NEXT(action_phy_port, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_action_phy_port,
+                                       index)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_PORT_ID] = {
+               .name = "port_id",
+               .help = "direct matching traffic to a given DPDK port ID",
+               .priv = PRIV_ACTION(PORT_ID,
+                                   sizeof(struct rte_flow_action_port_id)),
+               .next = NEXT(action_port_id),
+               .call = parse_vc,
+       },
+       [ACTION_PORT_ID_ORIGINAL] = {
+               .name = "original",
+               .help = "use original DPDK port ID if possible",
+               .next = NEXT(action_port_id, NEXT_ENTRY(BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_port_id,
+                                          original, 1)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_PORT_ID_ID] = {
+               .name = "id",
+               .help = "DPDK port ID",
+               .next = NEXT(action_port_id, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_action_port_id, id)),
+               .call = parse_vc_conf,
+       },
        [ACTION_METER] = {
                .name = "meter",
                .help = "meter the directed packets at given id",
@@ -1719,6 +2159,164 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
                .call = parse_vc_conf,
        },
+       [ACTION_OF_SET_MPLS_TTL] = {
+               .name = "of_set_mpls_ttl",
+               .help = "OpenFlow's OFPAT_SET_MPLS_TTL",
+               .priv = PRIV_ACTION
+                       (OF_SET_MPLS_TTL,
+                        sizeof(struct rte_flow_action_of_set_mpls_ttl)),
+               .next = NEXT(action_of_set_mpls_ttl),
+               .call = parse_vc,
+       },
+       [ACTION_OF_SET_MPLS_TTL_MPLS_TTL] = {
+               .name = "mpls_ttl",
+               .help = "MPLS TTL",
+               .next = NEXT(action_of_set_mpls_ttl, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_mpls_ttl,
+                                       mpls_ttl)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_OF_DEC_MPLS_TTL] = {
+               .name = "of_dec_mpls_ttl",
+               .help = "OpenFlow's OFPAT_DEC_MPLS_TTL",
+               .priv = PRIV_ACTION(OF_DEC_MPLS_TTL, 0),
+               .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+               .call = parse_vc,
+       },
+       [ACTION_OF_SET_NW_TTL] = {
+               .name = "of_set_nw_ttl",
+               .help = "OpenFlow's OFPAT_SET_NW_TTL",
+               .priv = PRIV_ACTION
+                       (OF_SET_NW_TTL,
+                        sizeof(struct rte_flow_action_of_set_nw_ttl)),
+               .next = NEXT(action_of_set_nw_ttl),
+               .call = parse_vc,
+       },
+       [ACTION_OF_SET_NW_TTL_NW_TTL] = {
+               .name = "nw_ttl",
+               .help = "IP TTL",
+               .next = NEXT(action_of_set_nw_ttl, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_nw_ttl,
+                                       nw_ttl)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_OF_DEC_NW_TTL] = {
+               .name = "of_dec_nw_ttl",
+               .help = "OpenFlow's OFPAT_DEC_NW_TTL",
+               .priv = PRIV_ACTION(OF_DEC_NW_TTL, 0),
+               .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+               .call = parse_vc,
+       },
+       [ACTION_OF_COPY_TTL_OUT] = {
+               .name = "of_copy_ttl_out",
+               .help = "OpenFlow's OFPAT_COPY_TTL_OUT",
+               .priv = PRIV_ACTION(OF_COPY_TTL_OUT, 0),
+               .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+               .call = parse_vc,
+       },
+       [ACTION_OF_COPY_TTL_IN] = {
+               .name = "of_copy_ttl_in",
+               .help = "OpenFlow's OFPAT_COPY_TTL_IN",
+               .priv = PRIV_ACTION(OF_COPY_TTL_IN, 0),
+               .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+               .call = parse_vc,
+       },
+       [ACTION_OF_POP_VLAN] = {
+               .name = "of_pop_vlan",
+               .help = "OpenFlow's OFPAT_POP_VLAN",
+               .priv = PRIV_ACTION(OF_POP_VLAN, 0),
+               .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+               .call = parse_vc,
+       },
+       [ACTION_OF_PUSH_VLAN] = {
+               .name = "of_push_vlan",
+               .help = "OpenFlow's OFPAT_PUSH_VLAN",
+               .priv = PRIV_ACTION
+                       (OF_PUSH_VLAN,
+                        sizeof(struct rte_flow_action_of_push_vlan)),
+               .next = NEXT(action_of_push_vlan),
+               .call = parse_vc,
+       },
+       [ACTION_OF_PUSH_VLAN_ETHERTYPE] = {
+               .name = "ethertype",
+               .help = "EtherType",
+               .next = NEXT(action_of_push_vlan, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_HTON
+                            (struct rte_flow_action_of_push_vlan,
+                             ethertype)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_OF_SET_VLAN_VID] = {
+               .name = "of_set_vlan_vid",
+               .help = "OpenFlow's OFPAT_SET_VLAN_VID",
+               .priv = PRIV_ACTION
+                       (OF_SET_VLAN_VID,
+                        sizeof(struct rte_flow_action_of_set_vlan_vid)),
+               .next = NEXT(action_of_set_vlan_vid),
+               .call = parse_vc,
+       },
+       [ACTION_OF_SET_VLAN_VID_VLAN_VID] = {
+               .name = "vlan_vid",
+               .help = "VLAN id",
+               .next = NEXT(action_of_set_vlan_vid, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_HTON
+                            (struct rte_flow_action_of_set_vlan_vid,
+                             vlan_vid)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_OF_SET_VLAN_PCP] = {
+               .name = "of_set_vlan_pcp",
+               .help = "OpenFlow's OFPAT_SET_VLAN_PCP",
+               .priv = PRIV_ACTION
+                       (OF_SET_VLAN_PCP,
+                        sizeof(struct rte_flow_action_of_set_vlan_pcp)),
+               .next = NEXT(action_of_set_vlan_pcp),
+               .call = parse_vc,
+       },
+       [ACTION_OF_SET_VLAN_PCP_VLAN_PCP] = {
+               .name = "vlan_pcp",
+               .help = "VLAN priority",
+               .next = NEXT(action_of_set_vlan_pcp, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_HTON
+                            (struct rte_flow_action_of_set_vlan_pcp,
+                             vlan_pcp)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_OF_POP_MPLS] = {
+               .name = "of_pop_mpls",
+               .help = "OpenFlow's OFPAT_POP_MPLS",
+               .priv = PRIV_ACTION(OF_POP_MPLS,
+                                   sizeof(struct rte_flow_action_of_pop_mpls)),
+               .next = NEXT(action_of_pop_mpls),
+               .call = parse_vc,
+       },
+       [ACTION_OF_POP_MPLS_ETHERTYPE] = {
+               .name = "ethertype",
+               .help = "EtherType",
+               .next = NEXT(action_of_pop_mpls, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_HTON
+                            (struct rte_flow_action_of_pop_mpls,
+                             ethertype)),
+               .call = parse_vc_conf,
+       },
+       [ACTION_OF_PUSH_MPLS] = {
+               .name = "of_push_mpls",
+               .help = "OpenFlow's OFPAT_PUSH_MPLS",
+               .priv = PRIV_ACTION
+                       (OF_PUSH_MPLS,
+                        sizeof(struct rte_flow_action_of_push_mpls)),
+               .next = NEXT(action_of_push_mpls),
+               .call = parse_vc,
+       },
+       [ACTION_OF_PUSH_MPLS_ETHERTYPE] = {
+               .name = "ethertype",
+               .help = "EtherType",
+               .next = NEXT(action_of_push_mpls, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_HTON
+                            (struct rte_flow_action_of_push_mpls,
+                             ethertype)),
+               .call = parse_vc_conf,
+       },
 };
 
 /** Remove and return last entry from argument stack. */
@@ -1944,6 +2542,9 @@ parse_vc(struct context *ctx, const struct token *token,
        case EGRESS:
                out->args.vc.attr.egress = 1;
                return len;
+       case TRANSFER:
+               out->args.vc.attr.transfer = 1;
+               return len;
        case PATTERN:
                out->args.vc.pattern =
                        (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),