1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 6WIND S.A.
3 * Copyright 2016 Mellanox Technologies, Ltd
13 #include <arpa/inet.h>
14 #include <sys/socket.h>
16 #include <rte_string_fns.h>
17 #include <rte_common.h>
18 #include <rte_eth_ctrl.h>
19 #include <rte_ethdev.h>
20 #include <rte_byteorder.h>
21 #include <cmdline_parse.h>
22 #include <cmdline_parse_etheraddr.h>
27 /** Parser token indices. */
47 /* Top-level command. */
50 /* Sub-level commands. */
59 /* Destroy arguments. */
62 /* Query arguments. */
68 /* Validate/create arguments. */
75 /* Validate/create pattern. */
112 ITEM_VLAN_INNER_TYPE,
144 ITEM_E_TAG_GRP_ECID_B,
163 ITEM_ARP_ETH_IPV4_SHA,
164 ITEM_ARP_ETH_IPV4_SPA,
165 ITEM_ARP_ETH_IPV4_THA,
166 ITEM_ARP_ETH_IPV4_TPA,
168 ITEM_IPV6_EXT_NEXT_HDR,
173 ITEM_ICMP6_ND_NS_TARGET_ADDR,
175 ITEM_ICMP6_ND_NA_TARGET_ADDR,
177 ITEM_ICMP6_ND_OPT_TYPE,
178 ITEM_ICMP6_ND_OPT_SLA_ETH,
179 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
180 ITEM_ICMP6_ND_OPT_TLA_ETH,
181 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
185 /* Validate/create actions. */
205 ACTION_RSS_FUNC_DEFAULT,
206 ACTION_RSS_FUNC_TOEPLITZ,
207 ACTION_RSS_FUNC_SIMPLE_XOR,
219 ACTION_PHY_PORT_ORIGINAL,
220 ACTION_PHY_PORT_INDEX,
222 ACTION_PORT_ID_ORIGINAL,
226 ACTION_OF_SET_MPLS_TTL,
227 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
228 ACTION_OF_DEC_MPLS_TTL,
229 ACTION_OF_SET_NW_TTL,
230 ACTION_OF_SET_NW_TTL_NW_TTL,
231 ACTION_OF_DEC_NW_TTL,
232 ACTION_OF_COPY_TTL_OUT,
233 ACTION_OF_COPY_TTL_IN,
236 ACTION_OF_PUSH_VLAN_ETHERTYPE,
237 ACTION_OF_SET_VLAN_VID,
238 ACTION_OF_SET_VLAN_VID_VLAN_VID,
239 ACTION_OF_SET_VLAN_PCP,
240 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
242 ACTION_OF_POP_MPLS_ETHERTYPE,
244 ACTION_OF_PUSH_MPLS_ETHERTYPE,
251 ACTION_MPLSOGRE_ENCAP,
252 ACTION_MPLSOGRE_DECAP,
253 ACTION_MPLSOUDP_ENCAP,
254 ACTION_MPLSOUDP_DECAP,
256 ACTION_SET_IPV4_SRC_IPV4_SRC,
258 ACTION_SET_IPV4_DST_IPV4_DST,
260 ACTION_SET_IPV6_SRC_IPV6_SRC,
262 ACTION_SET_IPV6_DST_IPV6_DST,
264 ACTION_SET_TP_SRC_TP_SRC,
266 ACTION_SET_TP_DST_TP_DST,
272 ACTION_SET_MAC_SRC_MAC_SRC,
274 ACTION_SET_MAC_DST_MAC_DST,
277 /** Maximum size for pattern in struct rte_flow_item_raw. */
278 #define ITEM_RAW_PATTERN_SIZE 40
280 /** Storage size for struct rte_flow_item_raw including pattern. */
281 #define ITEM_RAW_SIZE \
282 (sizeof(struct rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE)
284 /** Maximum number of queue indices in struct rte_flow_action_rss. */
285 #define ACTION_RSS_QUEUE_NUM 32
287 /** Storage for struct rte_flow_action_rss including external data. */
288 struct action_rss_data {
289 struct rte_flow_action_rss conf;
290 uint8_t key[RSS_HASH_KEY_LENGTH];
291 uint16_t queue[ACTION_RSS_QUEUE_NUM];
294 /** Maximum number of items in struct rte_flow_action_vxlan_encap. */
295 #define ACTION_VXLAN_ENCAP_ITEMS_NUM 6
297 /** Storage for struct rte_flow_action_vxlan_encap including external data. */
298 struct action_vxlan_encap_data {
299 struct rte_flow_action_vxlan_encap conf;
300 struct rte_flow_item items[ACTION_VXLAN_ENCAP_ITEMS_NUM];
301 struct rte_flow_item_eth item_eth;
302 struct rte_flow_item_vlan item_vlan;
304 struct rte_flow_item_ipv4 item_ipv4;
305 struct rte_flow_item_ipv6 item_ipv6;
307 struct rte_flow_item_udp item_udp;
308 struct rte_flow_item_vxlan item_vxlan;
311 /** Maximum number of items in struct rte_flow_action_nvgre_encap. */
312 #define ACTION_NVGRE_ENCAP_ITEMS_NUM 5
314 /** Storage for struct rte_flow_action_nvgre_encap including external data. */
315 struct action_nvgre_encap_data {
316 struct rte_flow_action_nvgre_encap conf;
317 struct rte_flow_item items[ACTION_NVGRE_ENCAP_ITEMS_NUM];
318 struct rte_flow_item_eth item_eth;
319 struct rte_flow_item_vlan item_vlan;
321 struct rte_flow_item_ipv4 item_ipv4;
322 struct rte_flow_item_ipv6 item_ipv6;
324 struct rte_flow_item_nvgre item_nvgre;
327 /** Maximum data size in struct rte_flow_action_raw_encap. */
328 #define ACTION_RAW_ENCAP_MAX_DATA 128
330 /** Storage for struct rte_flow_action_raw_encap including external data. */
331 struct action_raw_encap_data {
332 struct rte_flow_action_raw_encap conf;
333 uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
334 uint8_t preserve[ACTION_RAW_ENCAP_MAX_DATA];
337 /** Storage for struct rte_flow_action_raw_decap including external data. */
338 struct action_raw_decap_data {
339 struct rte_flow_action_raw_decap conf;
340 uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
343 /** Maximum number of subsequent tokens and arguments on the stack. */
344 #define CTX_STACK_SIZE 16
346 /** Parser context. */
348 /** Stack of subsequent token lists to process. */
349 const enum index *next[CTX_STACK_SIZE];
350 /** Arguments for stacked tokens. */
351 const void *args[CTX_STACK_SIZE];
352 enum index curr; /**< Current token index. */
353 enum index prev; /**< Index of the last token seen. */
354 int next_num; /**< Number of entries in next[]. */
355 int args_num; /**< Number of entries in args[]. */
356 uint32_t eol:1; /**< EOL has been detected. */
357 uint32_t last:1; /**< No more arguments. */
358 portid_t port; /**< Current port ID (for completions). */
359 uint32_t objdata; /**< Object-specific data. */
360 void *object; /**< Address of current object for relative offsets. */
361 void *objmask; /**< Object a full mask must be written to. */
364 /** Token argument. */
366 uint32_t hton:1; /**< Use network byte ordering. */
367 uint32_t sign:1; /**< Value is signed. */
368 uint32_t bounded:1; /**< Value is bounded. */
369 uintmax_t min; /**< Minimum value if bounded. */
370 uintmax_t max; /**< Maximum value if bounded. */
371 uint32_t offset; /**< Relative offset from ctx->object. */
372 uint32_t size; /**< Field size. */
373 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
376 /** Parser token definition. */
378 /** Type displayed during completion (defaults to "TOKEN"). */
380 /** Help displayed during completion (defaults to token name). */
382 /** Private data used by parser functions. */
385 * Lists of subsequent tokens to push on the stack. Each call to the
386 * parser consumes the last entry of that stack.
388 const enum index *const *next;
389 /** Arguments stack for subsequent tokens that need them. */
390 const struct arg *const *args;
392 * Token-processing callback, returns -1 in case of error, the
393 * length of the matched string otherwise. If NULL, attempts to
394 * match the token name.
396 * If buf is not NULL, the result should be stored in it according
397 * to context. An error is returned if not large enough.
399 int (*call)(struct context *ctx, const struct token *token,
400 const char *str, unsigned int len,
401 void *buf, unsigned int size);
403 * Callback that provides possible values for this token, used for
404 * completion. Returns -1 in case of error, the number of possible
405 * values otherwise. If NULL, the token name is used.
407 * If buf is not NULL, entry index ent is written to buf and the
408 * full length of the entry is returned (same behavior as
411 int (*comp)(struct context *ctx, const struct token *token,
412 unsigned int ent, char *buf, unsigned int size);
413 /** Mandatory token name, no default value. */
417 /** Static initializer for the next field. */
418 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
420 /** Static initializer for a NEXT() entry. */
421 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
423 /** Static initializer for the args field. */
424 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
426 /** Static initializer for ARGS() to target a field. */
427 #define ARGS_ENTRY(s, f) \
428 (&(const struct arg){ \
429 .offset = offsetof(s, f), \
430 .size = sizeof(((s *)0)->f), \
433 /** Static initializer for ARGS() to target a bit-field. */
434 #define ARGS_ENTRY_BF(s, f, b) \
435 (&(const struct arg){ \
437 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
440 /** Static initializer for ARGS() to target an arbitrary bit-mask. */
441 #define ARGS_ENTRY_MASK(s, f, m) \
442 (&(const struct arg){ \
443 .offset = offsetof(s, f), \
444 .size = sizeof(((s *)0)->f), \
445 .mask = (const void *)(m), \
448 /** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */
449 #define ARGS_ENTRY_MASK_HTON(s, f, m) \
450 (&(const struct arg){ \
452 .offset = offsetof(s, f), \
453 .size = sizeof(((s *)0)->f), \
454 .mask = (const void *)(m), \
457 /** Static initializer for ARGS() to target a pointer. */
458 #define ARGS_ENTRY_PTR(s, f) \
459 (&(const struct arg){ \
460 .size = sizeof(*((s *)0)->f), \
463 /** Static initializer for ARGS() with arbitrary offset and size. */
464 #define ARGS_ENTRY_ARB(o, s) \
465 (&(const struct arg){ \
470 /** Same as ARGS_ENTRY_ARB() with bounded values. */
471 #define ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
472 (&(const struct arg){ \
480 /** Same as ARGS_ENTRY() using network byte ordering. */
481 #define ARGS_ENTRY_HTON(s, f) \
482 (&(const struct arg){ \
484 .offset = offsetof(s, f), \
485 .size = sizeof(((s *)0)->f), \
488 /** Parser output buffer layout expected by cmd_flow_parsed(). */
490 enum index command; /**< Flow command. */
491 portid_t port; /**< Affected port ID. */
494 struct rte_flow_attr attr;
495 struct rte_flow_item *pattern;
496 struct rte_flow_action *actions;
500 } vc; /**< Validate/create arguments. */
504 } destroy; /**< Destroy arguments. */
507 struct rte_flow_action action;
508 } query; /**< Query arguments. */
512 } list; /**< List arguments. */
515 } isolate; /**< Isolated mode arguments. */
516 } args; /**< Command arguments. */
519 /** Private data for pattern items. */
520 struct parse_item_priv {
521 enum rte_flow_item_type type; /**< Item type. */
522 uint32_t size; /**< Size of item specification structure. */
525 #define PRIV_ITEM(t, s) \
526 (&(const struct parse_item_priv){ \
527 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
531 /** Private data for actions. */
532 struct parse_action_priv {
533 enum rte_flow_action_type type; /**< Action type. */
534 uint32_t size; /**< Size of action configuration structure. */
537 #define PRIV_ACTION(t, s) \
538 (&(const struct parse_action_priv){ \
539 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
543 static const enum index next_vc_attr[] = {
553 static const enum index next_destroy_attr[] = {
559 static const enum index next_list_attr[] = {
565 static const enum index item_param[] = {
574 static const enum index next_item[] = {
610 ITEM_ICMP6_ND_OPT_SLA_ETH,
611 ITEM_ICMP6_ND_OPT_TLA_ETH,
616 static const enum index item_fuzzy[] = {
622 static const enum index item_any[] = {
628 static const enum index item_vf[] = {
634 static const enum index item_phy_port[] = {
640 static const enum index item_port_id[] = {
646 static const enum index item_mark[] = {
652 static const enum index item_raw[] = {
662 static const enum index item_eth[] = {
670 static const enum index item_vlan[] = {
675 ITEM_VLAN_INNER_TYPE,
680 static const enum index item_ipv4[] = {
690 static const enum index item_ipv6[] = {
701 static const enum index item_icmp[] = {
708 static const enum index item_udp[] = {
715 static const enum index item_tcp[] = {
723 static const enum index item_sctp[] = {
732 static const enum index item_vxlan[] = {
738 static const enum index item_e_tag[] = {
739 ITEM_E_TAG_GRP_ECID_B,
744 static const enum index item_nvgre[] = {
750 static const enum index item_mpls[] = {
756 static const enum index item_gre[] = {
762 static const enum index item_gtp[] = {
768 static const enum index item_geneve[] = {
775 static const enum index item_vxlan_gpe[] = {
781 static const enum index item_arp_eth_ipv4[] = {
782 ITEM_ARP_ETH_IPV4_SHA,
783 ITEM_ARP_ETH_IPV4_SPA,
784 ITEM_ARP_ETH_IPV4_THA,
785 ITEM_ARP_ETH_IPV4_TPA,
790 static const enum index item_ipv6_ext[] = {
791 ITEM_IPV6_EXT_NEXT_HDR,
796 static const enum index item_icmp6[] = {
803 static const enum index item_icmp6_nd_ns[] = {
804 ITEM_ICMP6_ND_NS_TARGET_ADDR,
809 static const enum index item_icmp6_nd_na[] = {
810 ITEM_ICMP6_ND_NA_TARGET_ADDR,
815 static const enum index item_icmp6_nd_opt[] = {
816 ITEM_ICMP6_ND_OPT_TYPE,
821 static const enum index item_icmp6_nd_opt_sla_eth[] = {
822 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
827 static const enum index item_icmp6_nd_opt_tla_eth[] = {
828 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
833 static const enum index item_meta[] = {
839 static const enum index next_action[] = {
855 ACTION_OF_SET_MPLS_TTL,
856 ACTION_OF_DEC_MPLS_TTL,
857 ACTION_OF_SET_NW_TTL,
858 ACTION_OF_DEC_NW_TTL,
859 ACTION_OF_COPY_TTL_OUT,
860 ACTION_OF_COPY_TTL_IN,
863 ACTION_OF_SET_VLAN_VID,
864 ACTION_OF_SET_VLAN_PCP,
873 ACTION_MPLSOGRE_ENCAP,
874 ACTION_MPLSOGRE_DECAP,
875 ACTION_MPLSOUDP_ENCAP,
876 ACTION_MPLSOUDP_DECAP,
891 static const enum index action_mark[] = {
897 static const enum index action_queue[] = {
903 static const enum index action_count[] = {
910 static const enum index action_rss[] = {
921 static const enum index action_vf[] = {
928 static const enum index action_phy_port[] = {
929 ACTION_PHY_PORT_ORIGINAL,
930 ACTION_PHY_PORT_INDEX,
935 static const enum index action_port_id[] = {
936 ACTION_PORT_ID_ORIGINAL,
942 static const enum index action_meter[] = {
948 static const enum index action_of_set_mpls_ttl[] = {
949 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
954 static const enum index action_of_set_nw_ttl[] = {
955 ACTION_OF_SET_NW_TTL_NW_TTL,
960 static const enum index action_of_push_vlan[] = {
961 ACTION_OF_PUSH_VLAN_ETHERTYPE,
966 static const enum index action_of_set_vlan_vid[] = {
967 ACTION_OF_SET_VLAN_VID_VLAN_VID,
972 static const enum index action_of_set_vlan_pcp[] = {
973 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
978 static const enum index action_of_pop_mpls[] = {
979 ACTION_OF_POP_MPLS_ETHERTYPE,
984 static const enum index action_of_push_mpls[] = {
985 ACTION_OF_PUSH_MPLS_ETHERTYPE,
990 static const enum index action_set_ipv4_src[] = {
991 ACTION_SET_IPV4_SRC_IPV4_SRC,
996 static const enum index action_set_mac_src[] = {
997 ACTION_SET_MAC_SRC_MAC_SRC,
1002 static const enum index action_set_ipv4_dst[] = {
1003 ACTION_SET_IPV4_DST_IPV4_DST,
1008 static const enum index action_set_ipv6_src[] = {
1009 ACTION_SET_IPV6_SRC_IPV6_SRC,
1014 static const enum index action_set_ipv6_dst[] = {
1015 ACTION_SET_IPV6_DST_IPV6_DST,
1020 static const enum index action_set_tp_src[] = {
1021 ACTION_SET_TP_SRC_TP_SRC,
1026 static const enum index action_set_tp_dst[] = {
1027 ACTION_SET_TP_DST_TP_DST,
1032 static const enum index action_set_ttl[] = {
1038 static const enum index action_jump[] = {
1044 static const enum index action_set_mac_dst[] = {
1045 ACTION_SET_MAC_DST_MAC_DST,
1050 static int parse_init(struct context *, const struct token *,
1051 const char *, unsigned int,
1052 void *, unsigned int);
1053 static int parse_vc(struct context *, const struct token *,
1054 const char *, unsigned int,
1055 void *, unsigned int);
1056 static int parse_vc_spec(struct context *, const struct token *,
1057 const char *, unsigned int, void *, unsigned int);
1058 static int parse_vc_conf(struct context *, const struct token *,
1059 const char *, unsigned int, void *, unsigned int);
1060 static int parse_vc_action_rss(struct context *, const struct token *,
1061 const char *, unsigned int, void *,
1063 static int parse_vc_action_rss_func(struct context *, const struct token *,
1064 const char *, unsigned int, void *,
1066 static int parse_vc_action_rss_type(struct context *, const struct token *,
1067 const char *, unsigned int, void *,
1069 static int parse_vc_action_rss_queue(struct context *, const struct token *,
1070 const char *, unsigned int, void *,
1072 static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
1073 const char *, unsigned int, void *,
1075 static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
1076 const char *, unsigned int, void *,
1078 static int parse_vc_action_l2_encap(struct context *, const struct token *,
1079 const char *, unsigned int, void *,
1081 static int parse_vc_action_l2_decap(struct context *, const struct token *,
1082 const char *, unsigned int, void *,
1084 static int parse_vc_action_mplsogre_encap(struct context *,
1085 const struct token *, const char *,
1086 unsigned int, void *, unsigned int);
1087 static int parse_vc_action_mplsogre_decap(struct context *,
1088 const struct token *, const char *,
1089 unsigned int, void *, unsigned int);
1090 static int parse_vc_action_mplsoudp_encap(struct context *,
1091 const struct token *, const char *,
1092 unsigned int, void *, unsigned int);
1093 static int parse_vc_action_mplsoudp_decap(struct context *,
1094 const struct token *, const char *,
1095 unsigned int, void *, unsigned int);
1096 static int parse_destroy(struct context *, const struct token *,
1097 const char *, unsigned int,
1098 void *, unsigned int);
1099 static int parse_flush(struct context *, const struct token *,
1100 const char *, unsigned int,
1101 void *, unsigned int);
1102 static int parse_query(struct context *, const struct token *,
1103 const char *, unsigned int,
1104 void *, unsigned int);
1105 static int parse_action(struct context *, const struct token *,
1106 const char *, unsigned int,
1107 void *, unsigned int);
1108 static int parse_list(struct context *, const struct token *,
1109 const char *, unsigned int,
1110 void *, unsigned int);
1111 static int parse_isolate(struct context *, const struct token *,
1112 const char *, unsigned int,
1113 void *, unsigned int);
1114 static int parse_int(struct context *, const struct token *,
1115 const char *, unsigned int,
1116 void *, unsigned int);
1117 static int parse_prefix(struct context *, const struct token *,
1118 const char *, unsigned int,
1119 void *, unsigned int);
1120 static int parse_boolean(struct context *, const struct token *,
1121 const char *, unsigned int,
1122 void *, unsigned int);
1123 static int parse_string(struct context *, const struct token *,
1124 const char *, unsigned int,
1125 void *, unsigned int);
1126 static int parse_mac_addr(struct context *, const struct token *,
1127 const char *, unsigned int,
1128 void *, unsigned int);
1129 static int parse_ipv4_addr(struct context *, const struct token *,
1130 const char *, unsigned int,
1131 void *, unsigned int);
1132 static int parse_ipv6_addr(struct context *, const struct token *,
1133 const char *, unsigned int,
1134 void *, unsigned int);
1135 static int parse_port(struct context *, const struct token *,
1136 const char *, unsigned int,
1137 void *, unsigned int);
1138 static int comp_none(struct context *, const struct token *,
1139 unsigned int, char *, unsigned int);
1140 static int comp_boolean(struct context *, const struct token *,
1141 unsigned int, char *, unsigned int);
1142 static int comp_action(struct context *, const struct token *,
1143 unsigned int, char *, unsigned int);
1144 static int comp_port(struct context *, const struct token *,
1145 unsigned int, char *, unsigned int);
1146 static int comp_rule_id(struct context *, const struct token *,
1147 unsigned int, char *, unsigned int);
1148 static int comp_vc_action_rss_type(struct context *, const struct token *,
1149 unsigned int, char *, unsigned int);
1150 static int comp_vc_action_rss_queue(struct context *, const struct token *,
1151 unsigned int, char *, unsigned int);
1153 /** Token definitions. */
1154 static const struct token token_list[] = {
1155 /* Special tokens. */
1158 .help = "null entry, abused as the entry point",
1159 .next = NEXT(NEXT_ENTRY(FLOW)),
1164 .help = "command may end here",
1166 /* Common tokens. */
1170 .help = "integer value",
1175 .name = "{unsigned}",
1177 .help = "unsigned integer value",
1184 .help = "prefix length for bit-mask",
1185 .call = parse_prefix,
1189 .name = "{boolean}",
1191 .help = "any boolean value",
1192 .call = parse_boolean,
1193 .comp = comp_boolean,
1198 .help = "fixed string",
1199 .call = parse_string,
1203 .name = "{MAC address}",
1205 .help = "standard MAC address notation",
1206 .call = parse_mac_addr,
1210 .name = "{IPv4 address}",
1211 .type = "IPV4 ADDRESS",
1212 .help = "standard IPv4 address notation",
1213 .call = parse_ipv4_addr,
1217 .name = "{IPv6 address}",
1218 .type = "IPV6 ADDRESS",
1219 .help = "standard IPv6 address notation",
1220 .call = parse_ipv6_addr,
1224 .name = "{rule id}",
1226 .help = "rule identifier",
1228 .comp = comp_rule_id,
1231 .name = "{port_id}",
1233 .help = "port identifier",
1238 .name = "{group_id}",
1240 .help = "group identifier",
1244 [PRIORITY_LEVEL] = {
1247 .help = "priority level",
1251 /* Top-level command. */
1254 .type = "{command} {port_id} [{arg} [...]]",
1255 .help = "manage ingress/egress flow rules",
1256 .next = NEXT(NEXT_ENTRY
1266 /* Sub-level commands. */
1269 .help = "check whether a flow rule can be created",
1270 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1271 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1276 .help = "create a flow rule",
1277 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1278 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1283 .help = "destroy specific flow rules",
1284 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
1285 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1286 .call = parse_destroy,
1290 .help = "destroy all flow rules",
1291 .next = NEXT(NEXT_ENTRY(PORT_ID)),
1292 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1293 .call = parse_flush,
1297 .help = "query an existing flow rule",
1298 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
1299 NEXT_ENTRY(RULE_ID),
1300 NEXT_ENTRY(PORT_ID)),
1301 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action.type),
1302 ARGS_ENTRY(struct buffer, args.query.rule),
1303 ARGS_ENTRY(struct buffer, port)),
1304 .call = parse_query,
1308 .help = "list existing flow rules",
1309 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
1310 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1315 .help = "restrict ingress traffic to the defined flow rules",
1316 .next = NEXT(NEXT_ENTRY(BOOLEAN),
1317 NEXT_ENTRY(PORT_ID)),
1318 .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
1319 ARGS_ENTRY(struct buffer, port)),
1320 .call = parse_isolate,
1322 /* Destroy arguments. */
1325 .help = "specify a rule identifier",
1326 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
1327 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
1328 .call = parse_destroy,
1330 /* Query arguments. */
1334 .help = "action to query, must be part of the rule",
1335 .call = parse_action,
1336 .comp = comp_action,
1338 /* List arguments. */
1341 .help = "specify a group",
1342 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
1343 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
1346 /* Validate/create attributes. */
1349 .help = "specify a group",
1350 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
1351 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
1356 .help = "specify a priority level",
1357 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
1358 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
1363 .help = "affect rule to ingress",
1364 .next = NEXT(next_vc_attr),
1369 .help = "affect rule to egress",
1370 .next = NEXT(next_vc_attr),
1375 .help = "apply rule directly to endpoints found in pattern",
1376 .next = NEXT(next_vc_attr),
1379 /* Validate/create pattern. */
1382 .help = "submit a list of pattern items",
1383 .next = NEXT(next_item),
1388 .help = "match value perfectly (with full bit-mask)",
1389 .call = parse_vc_spec,
1391 [ITEM_PARAM_SPEC] = {
1393 .help = "match value according to configured bit-mask",
1394 .call = parse_vc_spec,
1396 [ITEM_PARAM_LAST] = {
1398 .help = "specify upper bound to establish a range",
1399 .call = parse_vc_spec,
1401 [ITEM_PARAM_MASK] = {
1403 .help = "specify bit-mask with relevant bits set to one",
1404 .call = parse_vc_spec,
1406 [ITEM_PARAM_PREFIX] = {
1408 .help = "generate bit-mask from a prefix length",
1409 .call = parse_vc_spec,
1413 .help = "specify next pattern item",
1414 .next = NEXT(next_item),
1418 .help = "end list of pattern items",
1419 .priv = PRIV_ITEM(END, 0),
1420 .next = NEXT(NEXT_ENTRY(ACTIONS)),
1425 .help = "no-op pattern item",
1426 .priv = PRIV_ITEM(VOID, 0),
1427 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1432 .help = "perform actions when pattern does not match",
1433 .priv = PRIV_ITEM(INVERT, 0),
1434 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1439 .help = "match any protocol for the current layer",
1440 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
1441 .next = NEXT(item_any),
1446 .help = "number of layers covered",
1447 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
1448 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
1452 .help = "match traffic from/to the physical function",
1453 .priv = PRIV_ITEM(PF, 0),
1454 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1459 .help = "match traffic from/to a virtual function ID",
1460 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
1461 .next = NEXT(item_vf),
1467 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
1468 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
1472 .help = "match traffic from/to a specific physical port",
1473 .priv = PRIV_ITEM(PHY_PORT,
1474 sizeof(struct rte_flow_item_phy_port)),
1475 .next = NEXT(item_phy_port),
1478 [ITEM_PHY_PORT_INDEX] = {
1480 .help = "physical port index",
1481 .next = NEXT(item_phy_port, NEXT_ENTRY(UNSIGNED), item_param),
1482 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_phy_port, index)),
1486 .help = "match traffic from/to a given DPDK port ID",
1487 .priv = PRIV_ITEM(PORT_ID,
1488 sizeof(struct rte_flow_item_port_id)),
1489 .next = NEXT(item_port_id),
1492 [ITEM_PORT_ID_ID] = {
1494 .help = "DPDK port ID",
1495 .next = NEXT(item_port_id, NEXT_ENTRY(UNSIGNED), item_param),
1496 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port_id, id)),
1500 .help = "match traffic against value set in previously matched rule",
1501 .priv = PRIV_ITEM(MARK, sizeof(struct rte_flow_item_mark)),
1502 .next = NEXT(item_mark),
1507 .help = "Integer value to match against",
1508 .next = NEXT(item_mark, NEXT_ENTRY(UNSIGNED), item_param),
1509 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_mark, id)),
1513 .help = "match an arbitrary byte string",
1514 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
1515 .next = NEXT(item_raw),
1518 [ITEM_RAW_RELATIVE] = {
1520 .help = "look for pattern after the previous item",
1521 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1522 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1525 [ITEM_RAW_SEARCH] = {
1527 .help = "search pattern from offset (see also limit)",
1528 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1529 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1532 [ITEM_RAW_OFFSET] = {
1534 .help = "absolute or relative offset for pattern",
1535 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
1536 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
1538 [ITEM_RAW_LIMIT] = {
1540 .help = "search area limit for start of pattern",
1541 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
1542 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
1544 [ITEM_RAW_PATTERN] = {
1546 .help = "byte string to look for",
1547 .next = NEXT(item_raw,
1549 NEXT_ENTRY(ITEM_PARAM_IS,
1552 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, pattern),
1553 ARGS_ENTRY(struct rte_flow_item_raw, length),
1554 ARGS_ENTRY_ARB(sizeof(struct rte_flow_item_raw),
1555 ITEM_RAW_PATTERN_SIZE)),
1559 .help = "match Ethernet header",
1560 .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
1561 .next = NEXT(item_eth),
1566 .help = "destination MAC",
1567 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1568 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, dst)),
1572 .help = "source MAC",
1573 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1574 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, src)),
1578 .help = "EtherType",
1579 .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
1580 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)),
1584 .help = "match 802.1Q/ad VLAN tag",
1585 .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
1586 .next = NEXT(item_vlan),
1591 .help = "tag control information",
1592 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1593 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
1597 .help = "priority code point",
1598 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1599 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1604 .help = "drop eligible indicator",
1605 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1606 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1611 .help = "VLAN identifier",
1612 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1613 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1616 [ITEM_VLAN_INNER_TYPE] = {
1617 .name = "inner_type",
1618 .help = "inner EtherType",
1619 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1620 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan,
1625 .help = "match IPv4 header",
1626 .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
1627 .next = NEXT(item_ipv4),
1632 .help = "type of service",
1633 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1634 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1635 hdr.type_of_service)),
1639 .help = "time to live",
1640 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1641 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1644 [ITEM_IPV4_PROTO] = {
1646 .help = "next protocol ID",
1647 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1648 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1649 hdr.next_proto_id)),
1653 .help = "source address",
1654 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1655 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1660 .help = "destination address",
1661 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1662 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1667 .help = "match IPv6 header",
1668 .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
1669 .next = NEXT(item_ipv6),
1674 .help = "traffic class",
1675 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1676 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1678 "\x0f\xf0\x00\x00")),
1680 [ITEM_IPV6_FLOW] = {
1682 .help = "flow label",
1683 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1684 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1686 "\x00\x0f\xff\xff")),
1688 [ITEM_IPV6_PROTO] = {
1690 .help = "protocol (next header)",
1691 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1692 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1697 .help = "hop limit",
1698 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1699 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1704 .help = "source address",
1705 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1706 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1711 .help = "destination address",
1712 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1713 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1718 .help = "match ICMP header",
1719 .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
1720 .next = NEXT(item_icmp),
1723 [ITEM_ICMP_TYPE] = {
1725 .help = "ICMP packet type",
1726 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1727 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1730 [ITEM_ICMP_CODE] = {
1732 .help = "ICMP packet code",
1733 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1734 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1739 .help = "match UDP header",
1740 .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
1741 .next = NEXT(item_udp),
1746 .help = "UDP source port",
1747 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1748 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1753 .help = "UDP destination port",
1754 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1755 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1760 .help = "match TCP header",
1761 .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
1762 .next = NEXT(item_tcp),
1767 .help = "TCP source port",
1768 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1769 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1774 .help = "TCP destination port",
1775 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1776 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1779 [ITEM_TCP_FLAGS] = {
1781 .help = "TCP flags",
1782 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1783 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1788 .help = "match SCTP header",
1789 .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
1790 .next = NEXT(item_sctp),
1795 .help = "SCTP source port",
1796 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1797 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1802 .help = "SCTP destination port",
1803 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1804 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1809 .help = "validation tag",
1810 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1811 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1814 [ITEM_SCTP_CKSUM] = {
1817 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1818 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1823 .help = "match VXLAN header",
1824 .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
1825 .next = NEXT(item_vxlan),
1828 [ITEM_VXLAN_VNI] = {
1830 .help = "VXLAN identifier",
1831 .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
1832 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)),
1836 .help = "match E-Tag header",
1837 .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
1838 .next = NEXT(item_e_tag),
1841 [ITEM_E_TAG_GRP_ECID_B] = {
1842 .name = "grp_ecid_b",
1843 .help = "GRP and E-CID base",
1844 .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param),
1845 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag,
1851 .help = "match NVGRE header",
1852 .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
1853 .next = NEXT(item_nvgre),
1856 [ITEM_NVGRE_TNI] = {
1858 .help = "virtual subnet ID",
1859 .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param),
1860 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)),
1864 .help = "match MPLS header",
1865 .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
1866 .next = NEXT(item_mpls),
1869 [ITEM_MPLS_LABEL] = {
1871 .help = "MPLS label",
1872 .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
1873 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
1879 .help = "match GRE header",
1880 .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
1881 .next = NEXT(item_gre),
1884 [ITEM_GRE_PROTO] = {
1886 .help = "GRE protocol type",
1887 .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
1888 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
1893 .help = "fuzzy pattern match, expect faster than default",
1894 .priv = PRIV_ITEM(FUZZY,
1895 sizeof(struct rte_flow_item_fuzzy)),
1896 .next = NEXT(item_fuzzy),
1899 [ITEM_FUZZY_THRESH] = {
1901 .help = "match accuracy threshold",
1902 .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param),
1903 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy,
1908 .help = "match GTP header",
1909 .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
1910 .next = NEXT(item_gtp),
1915 .help = "tunnel endpoint identifier",
1916 .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
1917 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)),
1921 .help = "match GTP header",
1922 .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
1923 .next = NEXT(item_gtp),
1928 .help = "match GTP header",
1929 .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
1930 .next = NEXT(item_gtp),
1935 .help = "match GENEVE header",
1936 .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
1937 .next = NEXT(item_geneve),
1940 [ITEM_GENEVE_VNI] = {
1942 .help = "virtual network identifier",
1943 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
1944 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)),
1946 [ITEM_GENEVE_PROTO] = {
1948 .help = "GENEVE protocol type",
1949 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
1950 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
1953 [ITEM_VXLAN_GPE] = {
1954 .name = "vxlan-gpe",
1955 .help = "match VXLAN-GPE header",
1956 .priv = PRIV_ITEM(VXLAN_GPE,
1957 sizeof(struct rte_flow_item_vxlan_gpe)),
1958 .next = NEXT(item_vxlan_gpe),
1961 [ITEM_VXLAN_GPE_VNI] = {
1963 .help = "VXLAN-GPE identifier",
1964 .next = NEXT(item_vxlan_gpe, NEXT_ENTRY(UNSIGNED), item_param),
1965 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan_gpe,
1968 [ITEM_ARP_ETH_IPV4] = {
1969 .name = "arp_eth_ipv4",
1970 .help = "match ARP header for Ethernet/IPv4",
1971 .priv = PRIV_ITEM(ARP_ETH_IPV4,
1972 sizeof(struct rte_flow_item_arp_eth_ipv4)),
1973 .next = NEXT(item_arp_eth_ipv4),
1976 [ITEM_ARP_ETH_IPV4_SHA] = {
1978 .help = "sender hardware address",
1979 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
1981 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1984 [ITEM_ARP_ETH_IPV4_SPA] = {
1986 .help = "sender IPv4 address",
1987 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
1989 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1992 [ITEM_ARP_ETH_IPV4_THA] = {
1994 .help = "target hardware address",
1995 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
1997 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
2000 [ITEM_ARP_ETH_IPV4_TPA] = {
2002 .help = "target IPv4 address",
2003 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
2005 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
2010 .help = "match presence of any IPv6 extension header",
2011 .priv = PRIV_ITEM(IPV6_EXT,
2012 sizeof(struct rte_flow_item_ipv6_ext)),
2013 .next = NEXT(item_ipv6_ext),
2016 [ITEM_IPV6_EXT_NEXT_HDR] = {
2018 .help = "next header",
2019 .next = NEXT(item_ipv6_ext, NEXT_ENTRY(UNSIGNED), item_param),
2020 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext,
2025 .help = "match any ICMPv6 header",
2026 .priv = PRIV_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)),
2027 .next = NEXT(item_icmp6),
2030 [ITEM_ICMP6_TYPE] = {
2032 .help = "ICMPv6 type",
2033 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
2034 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
2037 [ITEM_ICMP6_CODE] = {
2039 .help = "ICMPv6 code",
2040 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
2041 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
2044 [ITEM_ICMP6_ND_NS] = {
2045 .name = "icmp6_nd_ns",
2046 .help = "match ICMPv6 neighbor discovery solicitation",
2047 .priv = PRIV_ITEM(ICMP6_ND_NS,
2048 sizeof(struct rte_flow_item_icmp6_nd_ns)),
2049 .next = NEXT(item_icmp6_nd_ns),
2052 [ITEM_ICMP6_ND_NS_TARGET_ADDR] = {
2053 .name = "target_addr",
2054 .help = "target address",
2055 .next = NEXT(item_icmp6_nd_ns, NEXT_ENTRY(IPV6_ADDR),
2057 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_ns,
2060 [ITEM_ICMP6_ND_NA] = {
2061 .name = "icmp6_nd_na",
2062 .help = "match ICMPv6 neighbor discovery advertisement",
2063 .priv = PRIV_ITEM(ICMP6_ND_NA,
2064 sizeof(struct rte_flow_item_icmp6_nd_na)),
2065 .next = NEXT(item_icmp6_nd_na),
2068 [ITEM_ICMP6_ND_NA_TARGET_ADDR] = {
2069 .name = "target_addr",
2070 .help = "target address",
2071 .next = NEXT(item_icmp6_nd_na, NEXT_ENTRY(IPV6_ADDR),
2073 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_na,
2076 [ITEM_ICMP6_ND_OPT] = {
2077 .name = "icmp6_nd_opt",
2078 .help = "match presence of any ICMPv6 neighbor discovery"
2080 .priv = PRIV_ITEM(ICMP6_ND_OPT,
2081 sizeof(struct rte_flow_item_icmp6_nd_opt)),
2082 .next = NEXT(item_icmp6_nd_opt),
2085 [ITEM_ICMP6_ND_OPT_TYPE] = {
2087 .help = "ND option type",
2088 .next = NEXT(item_icmp6_nd_opt, NEXT_ENTRY(UNSIGNED),
2090 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_opt,
2093 [ITEM_ICMP6_ND_OPT_SLA_ETH] = {
2094 .name = "icmp6_nd_opt_sla_eth",
2095 .help = "match ICMPv6 neighbor discovery source Ethernet"
2096 " link-layer address option",
2098 (ICMP6_ND_OPT_SLA_ETH,
2099 sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),
2100 .next = NEXT(item_icmp6_nd_opt_sla_eth),
2103 [ITEM_ICMP6_ND_OPT_SLA_ETH_SLA] = {
2105 .help = "source Ethernet LLA",
2106 .next = NEXT(item_icmp6_nd_opt_sla_eth, NEXT_ENTRY(MAC_ADDR),
2108 .args = ARGS(ARGS_ENTRY_HTON
2109 (struct rte_flow_item_icmp6_nd_opt_sla_eth, sla)),
2111 [ITEM_ICMP6_ND_OPT_TLA_ETH] = {
2112 .name = "icmp6_nd_opt_tla_eth",
2113 .help = "match ICMPv6 neighbor discovery target Ethernet"
2114 " link-layer address option",
2116 (ICMP6_ND_OPT_TLA_ETH,
2117 sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),
2118 .next = NEXT(item_icmp6_nd_opt_tla_eth),
2121 [ITEM_ICMP6_ND_OPT_TLA_ETH_TLA] = {
2123 .help = "target Ethernet LLA",
2124 .next = NEXT(item_icmp6_nd_opt_tla_eth, NEXT_ENTRY(MAC_ADDR),
2126 .args = ARGS(ARGS_ENTRY_HTON
2127 (struct rte_flow_item_icmp6_nd_opt_tla_eth, tla)),
2131 .help = "match metadata header",
2132 .priv = PRIV_ITEM(META, sizeof(struct rte_flow_item_meta)),
2133 .next = NEXT(item_meta),
2136 [ITEM_META_DATA] = {
2138 .help = "metadata value",
2139 .next = NEXT(item_meta, NEXT_ENTRY(UNSIGNED), item_param),
2140 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_meta,
2141 data, "\xff\xff\xff\xff")),
2144 /* Validate/create actions. */
2147 .help = "submit a list of associated actions",
2148 .next = NEXT(next_action),
2153 .help = "specify next action",
2154 .next = NEXT(next_action),
2158 .help = "end list of actions",
2159 .priv = PRIV_ACTION(END, 0),
2164 .help = "no-op action",
2165 .priv = PRIV_ACTION(VOID, 0),
2166 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2169 [ACTION_PASSTHRU] = {
2171 .help = "let subsequent rule process matched packets",
2172 .priv = PRIV_ACTION(PASSTHRU, 0),
2173 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2178 .help = "redirect traffic to a given group",
2179 .priv = PRIV_ACTION(JUMP, sizeof(struct rte_flow_action_jump)),
2180 .next = NEXT(action_jump),
2183 [ACTION_JUMP_GROUP] = {
2185 .help = "group to redirect traffic to",
2186 .next = NEXT(action_jump, NEXT_ENTRY(UNSIGNED)),
2187 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_jump, group)),
2188 .call = parse_vc_conf,
2192 .help = "attach 32 bit value to packets",
2193 .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
2194 .next = NEXT(action_mark),
2197 [ACTION_MARK_ID] = {
2199 .help = "32 bit value to return with packets",
2200 .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
2201 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)),
2202 .call = parse_vc_conf,
2206 .help = "flag packets",
2207 .priv = PRIV_ACTION(FLAG, 0),
2208 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2213 .help = "assign packets to a given queue index",
2214 .priv = PRIV_ACTION(QUEUE,
2215 sizeof(struct rte_flow_action_queue)),
2216 .next = NEXT(action_queue),
2219 [ACTION_QUEUE_INDEX] = {
2221 .help = "queue index to use",
2222 .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
2223 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)),
2224 .call = parse_vc_conf,
2228 .help = "drop packets (note: passthru has priority)",
2229 .priv = PRIV_ACTION(DROP, 0),
2230 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2235 .help = "enable counters for this rule",
2236 .priv = PRIV_ACTION(COUNT,
2237 sizeof(struct rte_flow_action_count)),
2238 .next = NEXT(action_count),
2241 [ACTION_COUNT_ID] = {
2242 .name = "identifier",
2243 .help = "counter identifier to use",
2244 .next = NEXT(action_count, NEXT_ENTRY(UNSIGNED)),
2245 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_count, id)),
2246 .call = parse_vc_conf,
2248 [ACTION_COUNT_SHARED] = {
2250 .help = "shared counter",
2251 .next = NEXT(action_count, NEXT_ENTRY(BOOLEAN)),
2252 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_count,
2254 .call = parse_vc_conf,
2258 .help = "spread packets among several queues",
2259 .priv = PRIV_ACTION(RSS, sizeof(struct action_rss_data)),
2260 .next = NEXT(action_rss),
2261 .call = parse_vc_action_rss,
2263 [ACTION_RSS_FUNC] = {
2265 .help = "RSS hash function to apply",
2266 .next = NEXT(action_rss,
2267 NEXT_ENTRY(ACTION_RSS_FUNC_DEFAULT,
2268 ACTION_RSS_FUNC_TOEPLITZ,
2269 ACTION_RSS_FUNC_SIMPLE_XOR)),
2271 [ACTION_RSS_FUNC_DEFAULT] = {
2273 .help = "default hash function",
2274 .call = parse_vc_action_rss_func,
2276 [ACTION_RSS_FUNC_TOEPLITZ] = {
2278 .help = "Toeplitz hash function",
2279 .call = parse_vc_action_rss_func,
2281 [ACTION_RSS_FUNC_SIMPLE_XOR] = {
2282 .name = "simple_xor",
2283 .help = "simple XOR hash function",
2284 .call = parse_vc_action_rss_func,
2286 [ACTION_RSS_LEVEL] = {
2288 .help = "encapsulation level for \"types\"",
2289 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2290 .args = ARGS(ARGS_ENTRY_ARB
2291 (offsetof(struct action_rss_data, conf) +
2292 offsetof(struct rte_flow_action_rss, level),
2293 sizeof(((struct rte_flow_action_rss *)0)->
2296 [ACTION_RSS_TYPES] = {
2298 .help = "specific RSS hash types",
2299 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_TYPE)),
2301 [ACTION_RSS_TYPE] = {
2303 .help = "RSS hash type",
2304 .call = parse_vc_action_rss_type,
2305 .comp = comp_vc_action_rss_type,
2307 [ACTION_RSS_KEY] = {
2309 .help = "RSS hash key",
2310 .next = NEXT(action_rss, NEXT_ENTRY(STRING)),
2311 .args = ARGS(ARGS_ENTRY_ARB(0, 0),
2313 (offsetof(struct action_rss_data, conf) +
2314 offsetof(struct rte_flow_action_rss, key_len),
2315 sizeof(((struct rte_flow_action_rss *)0)->
2317 ARGS_ENTRY(struct action_rss_data, key)),
2319 [ACTION_RSS_KEY_LEN] = {
2321 .help = "RSS hash key length in bytes",
2322 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2323 .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
2324 (offsetof(struct action_rss_data, conf) +
2325 offsetof(struct rte_flow_action_rss, key_len),
2326 sizeof(((struct rte_flow_action_rss *)0)->
2329 RSS_HASH_KEY_LENGTH)),
2331 [ACTION_RSS_QUEUES] = {
2333 .help = "queue indices to use",
2334 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
2335 .call = parse_vc_conf,
2337 [ACTION_RSS_QUEUE] = {
2339 .help = "queue index",
2340 .call = parse_vc_action_rss_queue,
2341 .comp = comp_vc_action_rss_queue,
2345 .help = "direct traffic to physical function",
2346 .priv = PRIV_ACTION(PF, 0),
2347 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2352 .help = "direct traffic to a virtual function ID",
2353 .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
2354 .next = NEXT(action_vf),
2357 [ACTION_VF_ORIGINAL] = {
2359 .help = "use original VF ID if possible",
2360 .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
2361 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
2363 .call = parse_vc_conf,
2368 .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
2369 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
2370 .call = parse_vc_conf,
2372 [ACTION_PHY_PORT] = {
2374 .help = "direct packets to physical port index",
2375 .priv = PRIV_ACTION(PHY_PORT,
2376 sizeof(struct rte_flow_action_phy_port)),
2377 .next = NEXT(action_phy_port),
2380 [ACTION_PHY_PORT_ORIGINAL] = {
2382 .help = "use original port index if possible",
2383 .next = NEXT(action_phy_port, NEXT_ENTRY(BOOLEAN)),
2384 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_phy_port,
2386 .call = parse_vc_conf,
2388 [ACTION_PHY_PORT_INDEX] = {
2390 .help = "physical port index",
2391 .next = NEXT(action_phy_port, NEXT_ENTRY(UNSIGNED)),
2392 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_phy_port,
2394 .call = parse_vc_conf,
2396 [ACTION_PORT_ID] = {
2398 .help = "direct matching traffic to a given DPDK port ID",
2399 .priv = PRIV_ACTION(PORT_ID,
2400 sizeof(struct rte_flow_action_port_id)),
2401 .next = NEXT(action_port_id),
2404 [ACTION_PORT_ID_ORIGINAL] = {
2406 .help = "use original DPDK port ID if possible",
2407 .next = NEXT(action_port_id, NEXT_ENTRY(BOOLEAN)),
2408 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_port_id,
2410 .call = parse_vc_conf,
2412 [ACTION_PORT_ID_ID] = {
2414 .help = "DPDK port ID",
2415 .next = NEXT(action_port_id, NEXT_ENTRY(UNSIGNED)),
2416 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_port_id, id)),
2417 .call = parse_vc_conf,
2421 .help = "meter the directed packets at given id",
2422 .priv = PRIV_ACTION(METER,
2423 sizeof(struct rte_flow_action_meter)),
2424 .next = NEXT(action_meter),
2427 [ACTION_METER_ID] = {
2429 .help = "meter id to use",
2430 .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
2431 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
2432 .call = parse_vc_conf,
2434 [ACTION_OF_SET_MPLS_TTL] = {
2435 .name = "of_set_mpls_ttl",
2436 .help = "OpenFlow's OFPAT_SET_MPLS_TTL",
2439 sizeof(struct rte_flow_action_of_set_mpls_ttl)),
2440 .next = NEXT(action_of_set_mpls_ttl),
2443 [ACTION_OF_SET_MPLS_TTL_MPLS_TTL] = {
2446 .next = NEXT(action_of_set_mpls_ttl, NEXT_ENTRY(UNSIGNED)),
2447 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_mpls_ttl,
2449 .call = parse_vc_conf,
2451 [ACTION_OF_DEC_MPLS_TTL] = {
2452 .name = "of_dec_mpls_ttl",
2453 .help = "OpenFlow's OFPAT_DEC_MPLS_TTL",
2454 .priv = PRIV_ACTION(OF_DEC_MPLS_TTL, 0),
2455 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2458 [ACTION_OF_SET_NW_TTL] = {
2459 .name = "of_set_nw_ttl",
2460 .help = "OpenFlow's OFPAT_SET_NW_TTL",
2463 sizeof(struct rte_flow_action_of_set_nw_ttl)),
2464 .next = NEXT(action_of_set_nw_ttl),
2467 [ACTION_OF_SET_NW_TTL_NW_TTL] = {
2470 .next = NEXT(action_of_set_nw_ttl, NEXT_ENTRY(UNSIGNED)),
2471 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_nw_ttl,
2473 .call = parse_vc_conf,
2475 [ACTION_OF_DEC_NW_TTL] = {
2476 .name = "of_dec_nw_ttl",
2477 .help = "OpenFlow's OFPAT_DEC_NW_TTL",
2478 .priv = PRIV_ACTION(OF_DEC_NW_TTL, 0),
2479 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2482 [ACTION_OF_COPY_TTL_OUT] = {
2483 .name = "of_copy_ttl_out",
2484 .help = "OpenFlow's OFPAT_COPY_TTL_OUT",
2485 .priv = PRIV_ACTION(OF_COPY_TTL_OUT, 0),
2486 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2489 [ACTION_OF_COPY_TTL_IN] = {
2490 .name = "of_copy_ttl_in",
2491 .help = "OpenFlow's OFPAT_COPY_TTL_IN",
2492 .priv = PRIV_ACTION(OF_COPY_TTL_IN, 0),
2493 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2496 [ACTION_OF_POP_VLAN] = {
2497 .name = "of_pop_vlan",
2498 .help = "OpenFlow's OFPAT_POP_VLAN",
2499 .priv = PRIV_ACTION(OF_POP_VLAN, 0),
2500 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2503 [ACTION_OF_PUSH_VLAN] = {
2504 .name = "of_push_vlan",
2505 .help = "OpenFlow's OFPAT_PUSH_VLAN",
2508 sizeof(struct rte_flow_action_of_push_vlan)),
2509 .next = NEXT(action_of_push_vlan),
2512 [ACTION_OF_PUSH_VLAN_ETHERTYPE] = {
2513 .name = "ethertype",
2514 .help = "EtherType",
2515 .next = NEXT(action_of_push_vlan, NEXT_ENTRY(UNSIGNED)),
2516 .args = ARGS(ARGS_ENTRY_HTON
2517 (struct rte_flow_action_of_push_vlan,
2519 .call = parse_vc_conf,
2521 [ACTION_OF_SET_VLAN_VID] = {
2522 .name = "of_set_vlan_vid",
2523 .help = "OpenFlow's OFPAT_SET_VLAN_VID",
2526 sizeof(struct rte_flow_action_of_set_vlan_vid)),
2527 .next = NEXT(action_of_set_vlan_vid),
2530 [ACTION_OF_SET_VLAN_VID_VLAN_VID] = {
2533 .next = NEXT(action_of_set_vlan_vid, NEXT_ENTRY(UNSIGNED)),
2534 .args = ARGS(ARGS_ENTRY_HTON
2535 (struct rte_flow_action_of_set_vlan_vid,
2537 .call = parse_vc_conf,
2539 [ACTION_OF_SET_VLAN_PCP] = {
2540 .name = "of_set_vlan_pcp",
2541 .help = "OpenFlow's OFPAT_SET_VLAN_PCP",
2544 sizeof(struct rte_flow_action_of_set_vlan_pcp)),
2545 .next = NEXT(action_of_set_vlan_pcp),
2548 [ACTION_OF_SET_VLAN_PCP_VLAN_PCP] = {
2550 .help = "VLAN priority",
2551 .next = NEXT(action_of_set_vlan_pcp, NEXT_ENTRY(UNSIGNED)),
2552 .args = ARGS(ARGS_ENTRY_HTON
2553 (struct rte_flow_action_of_set_vlan_pcp,
2555 .call = parse_vc_conf,
2557 [ACTION_OF_POP_MPLS] = {
2558 .name = "of_pop_mpls",
2559 .help = "OpenFlow's OFPAT_POP_MPLS",
2560 .priv = PRIV_ACTION(OF_POP_MPLS,
2561 sizeof(struct rte_flow_action_of_pop_mpls)),
2562 .next = NEXT(action_of_pop_mpls),
2565 [ACTION_OF_POP_MPLS_ETHERTYPE] = {
2566 .name = "ethertype",
2567 .help = "EtherType",
2568 .next = NEXT(action_of_pop_mpls, NEXT_ENTRY(UNSIGNED)),
2569 .args = ARGS(ARGS_ENTRY_HTON
2570 (struct rte_flow_action_of_pop_mpls,
2572 .call = parse_vc_conf,
2574 [ACTION_OF_PUSH_MPLS] = {
2575 .name = "of_push_mpls",
2576 .help = "OpenFlow's OFPAT_PUSH_MPLS",
2579 sizeof(struct rte_flow_action_of_push_mpls)),
2580 .next = NEXT(action_of_push_mpls),
2583 [ACTION_OF_PUSH_MPLS_ETHERTYPE] = {
2584 .name = "ethertype",
2585 .help = "EtherType",
2586 .next = NEXT(action_of_push_mpls, NEXT_ENTRY(UNSIGNED)),
2587 .args = ARGS(ARGS_ENTRY_HTON
2588 (struct rte_flow_action_of_push_mpls,
2590 .call = parse_vc_conf,
2592 [ACTION_VXLAN_ENCAP] = {
2593 .name = "vxlan_encap",
2594 .help = "VXLAN encapsulation, uses configuration set by \"set"
2596 .priv = PRIV_ACTION(VXLAN_ENCAP,
2597 sizeof(struct action_vxlan_encap_data)),
2598 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2599 .call = parse_vc_action_vxlan_encap,
2601 [ACTION_VXLAN_DECAP] = {
2602 .name = "vxlan_decap",
2603 .help = "Performs a decapsulation action by stripping all"
2604 " headers of the VXLAN tunnel network overlay from the"
2606 .priv = PRIV_ACTION(VXLAN_DECAP, 0),
2607 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2610 [ACTION_NVGRE_ENCAP] = {
2611 .name = "nvgre_encap",
2612 .help = "NVGRE encapsulation, uses configuration set by \"set"
2614 .priv = PRIV_ACTION(NVGRE_ENCAP,
2615 sizeof(struct action_nvgre_encap_data)),
2616 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2617 .call = parse_vc_action_nvgre_encap,
2619 [ACTION_NVGRE_DECAP] = {
2620 .name = "nvgre_decap",
2621 .help = "Performs a decapsulation action by stripping all"
2622 " headers of the NVGRE tunnel network overlay from the"
2624 .priv = PRIV_ACTION(NVGRE_DECAP, 0),
2625 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2628 [ACTION_L2_ENCAP] = {
2630 .help = "l2 encap, uses configuration set by"
2631 " \"set l2_encap\"",
2632 .priv = PRIV_ACTION(RAW_ENCAP,
2633 sizeof(struct action_raw_encap_data)),
2634 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2635 .call = parse_vc_action_l2_encap,
2637 [ACTION_L2_DECAP] = {
2639 .help = "l2 decap, uses configuration set by"
2640 " \"set l2_decap\"",
2641 .priv = PRIV_ACTION(RAW_DECAP,
2642 sizeof(struct action_raw_decap_data)),
2643 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2644 .call = parse_vc_action_l2_decap,
2646 [ACTION_MPLSOGRE_ENCAP] = {
2647 .name = "mplsogre_encap",
2648 .help = "mplsogre encapsulation, uses configuration set by"
2649 " \"set mplsogre_encap\"",
2650 .priv = PRIV_ACTION(RAW_ENCAP,
2651 sizeof(struct action_raw_encap_data)),
2652 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2653 .call = parse_vc_action_mplsogre_encap,
2655 [ACTION_MPLSOGRE_DECAP] = {
2656 .name = "mplsogre_decap",
2657 .help = "mplsogre decapsulation, uses configuration set by"
2658 " \"set mplsogre_decap\"",
2659 .priv = PRIV_ACTION(RAW_DECAP,
2660 sizeof(struct action_raw_decap_data)),
2661 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2662 .call = parse_vc_action_mplsogre_decap,
2664 [ACTION_MPLSOUDP_ENCAP] = {
2665 .name = "mplsoudp_encap",
2666 .help = "mplsoudp encapsulation, uses configuration set by"
2667 " \"set mplsoudp_encap\"",
2668 .priv = PRIV_ACTION(RAW_ENCAP,
2669 sizeof(struct action_raw_encap_data)),
2670 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2671 .call = parse_vc_action_mplsoudp_encap,
2673 [ACTION_MPLSOUDP_DECAP] = {
2674 .name = "mplsoudp_decap",
2675 .help = "mplsoudp decapsulation, uses configuration set by"
2676 " \"set mplsoudp_decap\"",
2677 .priv = PRIV_ACTION(RAW_DECAP,
2678 sizeof(struct action_raw_decap_data)),
2679 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2680 .call = parse_vc_action_mplsoudp_decap,
2682 [ACTION_SET_IPV4_SRC] = {
2683 .name = "set_ipv4_src",
2684 .help = "Set a new IPv4 source address in the outermost"
2686 .priv = PRIV_ACTION(SET_IPV4_SRC,
2687 sizeof(struct rte_flow_action_set_ipv4)),
2688 .next = NEXT(action_set_ipv4_src),
2691 [ACTION_SET_IPV4_SRC_IPV4_SRC] = {
2692 .name = "ipv4_addr",
2693 .help = "new IPv4 source address to set",
2694 .next = NEXT(action_set_ipv4_src, NEXT_ENTRY(IPV4_ADDR)),
2695 .args = ARGS(ARGS_ENTRY_HTON
2696 (struct rte_flow_action_set_ipv4, ipv4_addr)),
2697 .call = parse_vc_conf,
2699 [ACTION_SET_IPV4_DST] = {
2700 .name = "set_ipv4_dst",
2701 .help = "Set a new IPv4 destination address in the outermost"
2703 .priv = PRIV_ACTION(SET_IPV4_DST,
2704 sizeof(struct rte_flow_action_set_ipv4)),
2705 .next = NEXT(action_set_ipv4_dst),
2708 [ACTION_SET_IPV4_DST_IPV4_DST] = {
2709 .name = "ipv4_addr",
2710 .help = "new IPv4 destination address to set",
2711 .next = NEXT(action_set_ipv4_dst, NEXT_ENTRY(IPV4_ADDR)),
2712 .args = ARGS(ARGS_ENTRY_HTON
2713 (struct rte_flow_action_set_ipv4, ipv4_addr)),
2714 .call = parse_vc_conf,
2716 [ACTION_SET_IPV6_SRC] = {
2717 .name = "set_ipv6_src",
2718 .help = "Set a new IPv6 source address in the outermost"
2720 .priv = PRIV_ACTION(SET_IPV6_SRC,
2721 sizeof(struct rte_flow_action_set_ipv6)),
2722 .next = NEXT(action_set_ipv6_src),
2725 [ACTION_SET_IPV6_SRC_IPV6_SRC] = {
2726 .name = "ipv6_addr",
2727 .help = "new IPv6 source address to set",
2728 .next = NEXT(action_set_ipv6_src, NEXT_ENTRY(IPV6_ADDR)),
2729 .args = ARGS(ARGS_ENTRY_HTON
2730 (struct rte_flow_action_set_ipv6, ipv6_addr)),
2731 .call = parse_vc_conf,
2733 [ACTION_SET_IPV6_DST] = {
2734 .name = "set_ipv6_dst",
2735 .help = "Set a new IPv6 destination address in the outermost"
2737 .priv = PRIV_ACTION(SET_IPV6_DST,
2738 sizeof(struct rte_flow_action_set_ipv6)),
2739 .next = NEXT(action_set_ipv6_dst),
2742 [ACTION_SET_IPV6_DST_IPV6_DST] = {
2743 .name = "ipv6_addr",
2744 .help = "new IPv6 destination address to set",
2745 .next = NEXT(action_set_ipv6_dst, NEXT_ENTRY(IPV6_ADDR)),
2746 .args = ARGS(ARGS_ENTRY_HTON
2747 (struct rte_flow_action_set_ipv6, ipv6_addr)),
2748 .call = parse_vc_conf,
2750 [ACTION_SET_TP_SRC] = {
2751 .name = "set_tp_src",
2752 .help = "set a new source port number in the outermost"
2754 .priv = PRIV_ACTION(SET_TP_SRC,
2755 sizeof(struct rte_flow_action_set_tp)),
2756 .next = NEXT(action_set_tp_src),
2759 [ACTION_SET_TP_SRC_TP_SRC] = {
2761 .help = "new source port number to set",
2762 .next = NEXT(action_set_tp_src, NEXT_ENTRY(UNSIGNED)),
2763 .args = ARGS(ARGS_ENTRY_HTON
2764 (struct rte_flow_action_set_tp, port)),
2765 .call = parse_vc_conf,
2767 [ACTION_SET_TP_DST] = {
2768 .name = "set_tp_dst",
2769 .help = "set a new destination port number in the outermost"
2771 .priv = PRIV_ACTION(SET_TP_DST,
2772 sizeof(struct rte_flow_action_set_tp)),
2773 .next = NEXT(action_set_tp_dst),
2776 [ACTION_SET_TP_DST_TP_DST] = {
2778 .help = "new destination port number to set",
2779 .next = NEXT(action_set_tp_dst, NEXT_ENTRY(UNSIGNED)),
2780 .args = ARGS(ARGS_ENTRY_HTON
2781 (struct rte_flow_action_set_tp, port)),
2782 .call = parse_vc_conf,
2784 [ACTION_MAC_SWAP] = {
2786 .help = "Swap the source and destination MAC addresses"
2787 " in the outermost Ethernet header",
2788 .priv = PRIV_ACTION(MAC_SWAP, 0),
2789 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2792 [ACTION_DEC_TTL] = {
2794 .help = "decrease network TTL if available",
2795 .priv = PRIV_ACTION(DEC_TTL, 0),
2796 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2799 [ACTION_SET_TTL] = {
2801 .help = "set ttl value",
2802 .priv = PRIV_ACTION(SET_TTL,
2803 sizeof(struct rte_flow_action_set_ttl)),
2804 .next = NEXT(action_set_ttl),
2807 [ACTION_SET_TTL_TTL] = {
2808 .name = "ttl_value",
2809 .help = "new ttl value to set",
2810 .next = NEXT(action_set_ttl, NEXT_ENTRY(UNSIGNED)),
2811 .args = ARGS(ARGS_ENTRY_HTON
2812 (struct rte_flow_action_set_ttl, ttl_value)),
2813 .call = parse_vc_conf,
2815 [ACTION_SET_MAC_SRC] = {
2816 .name = "set_mac_src",
2817 .help = "set source mac address",
2818 .priv = PRIV_ACTION(SET_MAC_SRC,
2819 sizeof(struct rte_flow_action_set_mac)),
2820 .next = NEXT(action_set_mac_src),
2823 [ACTION_SET_MAC_SRC_MAC_SRC] = {
2825 .help = "new source mac address",
2826 .next = NEXT(action_set_mac_src, NEXT_ENTRY(MAC_ADDR)),
2827 .args = ARGS(ARGS_ENTRY_HTON
2828 (struct rte_flow_action_set_mac, mac_addr)),
2829 .call = parse_vc_conf,
2831 [ACTION_SET_MAC_DST] = {
2832 .name = "set_mac_dst",
2833 .help = "set destination mac address",
2834 .priv = PRIV_ACTION(SET_MAC_DST,
2835 sizeof(struct rte_flow_action_set_mac)),
2836 .next = NEXT(action_set_mac_dst),
2839 [ACTION_SET_MAC_DST_MAC_DST] = {
2841 .help = "new destination mac address to set",
2842 .next = NEXT(action_set_mac_dst, NEXT_ENTRY(MAC_ADDR)),
2843 .args = ARGS(ARGS_ENTRY_HTON
2844 (struct rte_flow_action_set_mac, mac_addr)),
2845 .call = parse_vc_conf,
2849 /** Remove and return last entry from argument stack. */
2850 static const struct arg *
2851 pop_args(struct context *ctx)
2853 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
2856 /** Add entry on top of the argument stack. */
2858 push_args(struct context *ctx, const struct arg *arg)
2860 if (ctx->args_num == CTX_STACK_SIZE)
2862 ctx->args[ctx->args_num++] = arg;
2866 /** Spread value into buffer according to bit-mask. */
2868 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
2870 uint32_t i = arg->size;
2878 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
2887 unsigned int shift = 0;
2888 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
2890 for (shift = 0; arg->mask[i] >> shift; ++shift) {
2891 if (!(arg->mask[i] & (1 << shift)))
2896 *buf &= ~(1 << shift);
2897 *buf |= (val & 1) << shift;
2905 /** Compare a string with a partial one of a given length. */
2907 strcmp_partial(const char *full, const char *partial, size_t partial_len)
2909 int r = strncmp(full, partial, partial_len);
2913 if (strlen(full) <= partial_len)
2915 return full[partial_len];
2919 * Parse a prefix length and generate a bit-mask.
2921 * Last argument (ctx->args) is retrieved to determine mask size, storage
2922 * location and whether the result must use network byte ordering.
2925 parse_prefix(struct context *ctx, const struct token *token,
2926 const char *str, unsigned int len,
2927 void *buf, unsigned int size)
2929 const struct arg *arg = pop_args(ctx);
2930 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
2937 /* Argument is expected. */
2941 u = strtoumax(str, &end, 0);
2942 if (errno || (size_t)(end - str) != len)
2947 extra = arg_entry_bf_fill(NULL, 0, arg);
2956 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
2957 !arg_entry_bf_fill(ctx->objmask, -1, arg))
2964 if (bytes > size || bytes + !!extra > size)
2968 buf = (uint8_t *)ctx->object + arg->offset;
2969 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
2971 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
2972 memset(buf, 0x00, size - bytes);
2974 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
2978 memset(buf, 0xff, bytes);
2979 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
2981 ((uint8_t *)buf)[bytes] = conv[extra];
2984 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
2987 push_args(ctx, arg);
2991 /** Default parsing function for token name matching. */
2993 parse_default(struct context *ctx, const struct token *token,
2994 const char *str, unsigned int len,
2995 void *buf, unsigned int size)
3000 if (strcmp_partial(token->name, str, len))
3005 /** Parse flow command, initialize output buffer for subsequent tokens. */
3007 parse_init(struct context *ctx, const struct token *token,
3008 const char *str, unsigned int len,
3009 void *buf, unsigned int size)
3011 struct buffer *out = buf;
3013 /* Token name must match. */
3014 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3016 /* Nothing else to do if there is no buffer. */
3019 /* Make sure buffer is large enough. */
3020 if (size < sizeof(*out))
3022 /* Initialize buffer. */
3023 memset(out, 0x00, sizeof(*out));
3024 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
3027 ctx->objmask = NULL;
3031 /** Parse tokens for validate/create commands. */
3033 parse_vc(struct context *ctx, const struct token *token,
3034 const char *str, unsigned int len,
3035 void *buf, unsigned int size)
3037 struct buffer *out = buf;
3041 /* Token name must match. */
3042 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3044 /* Nothing else to do if there is no buffer. */
3047 if (!out->command) {
3048 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
3050 if (sizeof(*out) > size)
3052 out->command = ctx->curr;
3055 ctx->objmask = NULL;
3056 out->args.vc.data = (uint8_t *)out + size;
3060 ctx->object = &out->args.vc.attr;
3061 ctx->objmask = NULL;
3062 switch (ctx->curr) {
3067 out->args.vc.attr.ingress = 1;
3070 out->args.vc.attr.egress = 1;
3073 out->args.vc.attr.transfer = 1;
3076 out->args.vc.pattern =
3077 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
3079 ctx->object = out->args.vc.pattern;
3080 ctx->objmask = NULL;
3083 out->args.vc.actions =
3084 (void *)RTE_ALIGN_CEIL((uintptr_t)
3085 (out->args.vc.pattern +
3086 out->args.vc.pattern_n),
3088 ctx->object = out->args.vc.actions;
3089 ctx->objmask = NULL;
3096 if (!out->args.vc.actions) {
3097 const struct parse_item_priv *priv = token->priv;
3098 struct rte_flow_item *item =
3099 out->args.vc.pattern + out->args.vc.pattern_n;
3101 data_size = priv->size * 3; /* spec, last, mask */
3102 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
3103 (out->args.vc.data - data_size),
3105 if ((uint8_t *)item + sizeof(*item) > data)
3107 *item = (struct rte_flow_item){
3110 ++out->args.vc.pattern_n;
3112 ctx->objmask = NULL;
3114 const struct parse_action_priv *priv = token->priv;
3115 struct rte_flow_action *action =
3116 out->args.vc.actions + out->args.vc.actions_n;
3118 data_size = priv->size; /* configuration */
3119 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
3120 (out->args.vc.data - data_size),
3122 if ((uint8_t *)action + sizeof(*action) > data)
3124 *action = (struct rte_flow_action){
3126 .conf = data_size ? data : NULL,
3128 ++out->args.vc.actions_n;
3129 ctx->object = action;
3130 ctx->objmask = NULL;
3132 memset(data, 0, data_size);
3133 out->args.vc.data = data;
3134 ctx->objdata = data_size;
3138 /** Parse pattern item parameter type. */
3140 parse_vc_spec(struct context *ctx, const struct token *token,
3141 const char *str, unsigned int len,
3142 void *buf, unsigned int size)
3144 struct buffer *out = buf;
3145 struct rte_flow_item *item;
3151 /* Token name must match. */
3152 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3154 /* Parse parameter types. */
3155 switch (ctx->curr) {
3156 static const enum index prefix[] = NEXT_ENTRY(PREFIX);
3162 case ITEM_PARAM_SPEC:
3165 case ITEM_PARAM_LAST:
3168 case ITEM_PARAM_PREFIX:
3169 /* Modify next token to expect a prefix. */
3170 if (ctx->next_num < 2)
3172 ctx->next[ctx->next_num - 2] = prefix;
3174 case ITEM_PARAM_MASK:
3180 /* Nothing else to do if there is no buffer. */
3183 if (!out->args.vc.pattern_n)
3185 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
3186 data_size = ctx->objdata / 3; /* spec, last, mask */
3187 /* Point to selected object. */
3188 ctx->object = out->args.vc.data + (data_size * index);
3190 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
3191 item->mask = ctx->objmask;
3193 ctx->objmask = NULL;
3194 /* Update relevant item pointer. */
3195 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
3200 /** Parse action configuration field. */
3202 parse_vc_conf(struct context *ctx, const struct token *token,
3203 const char *str, unsigned int len,
3204 void *buf, unsigned int size)
3206 struct buffer *out = buf;
3209 /* Token name must match. */
3210 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3212 /* Nothing else to do if there is no buffer. */
3215 /* Point to selected object. */
3216 ctx->object = out->args.vc.data;
3217 ctx->objmask = NULL;
3221 /** Parse RSS action. */
3223 parse_vc_action_rss(struct context *ctx, const struct token *token,
3224 const char *str, unsigned int len,
3225 void *buf, unsigned int size)
3227 struct buffer *out = buf;
3228 struct rte_flow_action *action;
3229 struct action_rss_data *action_rss_data;
3233 ret = parse_vc(ctx, token, str, len, buf, size);
3236 /* Nothing else to do if there is no buffer. */
3239 if (!out->args.vc.actions_n)
3241 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3242 /* Point to selected object. */
3243 ctx->object = out->args.vc.data;
3244 ctx->objmask = NULL;
3245 /* Set up default configuration. */
3246 action_rss_data = ctx->object;
3247 *action_rss_data = (struct action_rss_data){
3248 .conf = (struct rte_flow_action_rss){
3249 .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
3252 .key_len = sizeof(action_rss_data->key),
3253 .queue_num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
3254 .key = action_rss_data->key,
3255 .queue = action_rss_data->queue,
3257 .key = "testpmd's default RSS hash key, "
3258 "override it for better balancing",
3261 for (i = 0; i < action_rss_data->conf.queue_num; ++i)
3262 action_rss_data->queue[i] = i;
3263 if (!port_id_is_invalid(ctx->port, DISABLED_WARN) &&
3264 ctx->port != (portid_t)RTE_PORT_ALL) {
3265 struct rte_eth_dev_info info;
3267 rte_eth_dev_info_get(ctx->port, &info);
3268 action_rss_data->conf.key_len =
3269 RTE_MIN(sizeof(action_rss_data->key),
3270 info.hash_key_size);
3272 action->conf = &action_rss_data->conf;
3277 * Parse func field for RSS action.
3279 * The RTE_ETH_HASH_FUNCTION_* value to assign is derived from the
3280 * ACTION_RSS_FUNC_* index that called this function.
3283 parse_vc_action_rss_func(struct context *ctx, const struct token *token,
3284 const char *str, unsigned int len,
3285 void *buf, unsigned int size)
3287 struct action_rss_data *action_rss_data;
3288 enum rte_eth_hash_function func;
3292 /* Token name must match. */
3293 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3295 switch (ctx->curr) {
3296 case ACTION_RSS_FUNC_DEFAULT:
3297 func = RTE_ETH_HASH_FUNCTION_DEFAULT;
3299 case ACTION_RSS_FUNC_TOEPLITZ:
3300 func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
3302 case ACTION_RSS_FUNC_SIMPLE_XOR:
3303 func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
3310 action_rss_data = ctx->object;
3311 action_rss_data->conf.func = func;
3316 * Parse type field for RSS action.
3318 * Valid tokens are type field names and the "end" token.
3321 parse_vc_action_rss_type(struct context *ctx, const struct token *token,
3322 const char *str, unsigned int len,
3323 void *buf, unsigned int size)
3325 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_TYPE);
3326 struct action_rss_data *action_rss_data;
3332 if (ctx->curr != ACTION_RSS_TYPE)
3334 if (!(ctx->objdata >> 16) && ctx->object) {
3335 action_rss_data = ctx->object;
3336 action_rss_data->conf.types = 0;
3338 if (!strcmp_partial("end", str, len)) {
3339 ctx->objdata &= 0xffff;
3342 for (i = 0; rss_type_table[i].str; ++i)
3343 if (!strcmp_partial(rss_type_table[i].str, str, len))
3345 if (!rss_type_table[i].str)
3347 ctx->objdata = 1 << 16 | (ctx->objdata & 0xffff);
3349 if (ctx->next_num == RTE_DIM(ctx->next))
3351 ctx->next[ctx->next_num++] = next;
3354 action_rss_data = ctx->object;
3355 action_rss_data->conf.types |= rss_type_table[i].rss_type;
3360 * Parse queue field for RSS action.
3362 * Valid tokens are queue indices and the "end" token.
3365 parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
3366 const char *str, unsigned int len,
3367 void *buf, unsigned int size)
3369 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
3370 struct action_rss_data *action_rss_data;
3377 if (ctx->curr != ACTION_RSS_QUEUE)
3379 i = ctx->objdata >> 16;
3380 if (!strcmp_partial("end", str, len)) {
3381 ctx->objdata &= 0xffff;
3384 if (i >= ACTION_RSS_QUEUE_NUM)
3387 ARGS_ENTRY_ARB(offsetof(struct action_rss_data, queue) +
3388 i * sizeof(action_rss_data->queue[i]),
3389 sizeof(action_rss_data->queue[i]))))
3391 ret = parse_int(ctx, token, str, len, NULL, 0);
3397 ctx->objdata = i << 16 | (ctx->objdata & 0xffff);
3399 if (ctx->next_num == RTE_DIM(ctx->next))
3401 ctx->next[ctx->next_num++] = next;
3405 action_rss_data = ctx->object;
3406 action_rss_data->conf.queue_num = i;
3407 action_rss_data->conf.queue = i ? action_rss_data->queue : NULL;
3411 /** Parse VXLAN encap action. */
3413 parse_vc_action_vxlan_encap(struct context *ctx, const struct token *token,
3414 const char *str, unsigned int len,
3415 void *buf, unsigned int size)
3417 struct buffer *out = buf;
3418 struct rte_flow_action *action;
3419 struct action_vxlan_encap_data *action_vxlan_encap_data;
3422 ret = parse_vc(ctx, token, str, len, buf, size);
3425 /* Nothing else to do if there is no buffer. */
3428 if (!out->args.vc.actions_n)
3430 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3431 /* Point to selected object. */
3432 ctx->object = out->args.vc.data;
3433 ctx->objmask = NULL;
3434 /* Set up default configuration. */
3435 action_vxlan_encap_data = ctx->object;
3436 *action_vxlan_encap_data = (struct action_vxlan_encap_data){
3437 .conf = (struct rte_flow_action_vxlan_encap){
3438 .definition = action_vxlan_encap_data->items,
3442 .type = RTE_FLOW_ITEM_TYPE_ETH,
3443 .spec = &action_vxlan_encap_data->item_eth,
3444 .mask = &rte_flow_item_eth_mask,
3447 .type = RTE_FLOW_ITEM_TYPE_VLAN,
3448 .spec = &action_vxlan_encap_data->item_vlan,
3449 .mask = &rte_flow_item_vlan_mask,
3452 .type = RTE_FLOW_ITEM_TYPE_IPV4,
3453 .spec = &action_vxlan_encap_data->item_ipv4,
3454 .mask = &rte_flow_item_ipv4_mask,
3457 .type = RTE_FLOW_ITEM_TYPE_UDP,
3458 .spec = &action_vxlan_encap_data->item_udp,
3459 .mask = &rte_flow_item_udp_mask,
3462 .type = RTE_FLOW_ITEM_TYPE_VXLAN,
3463 .spec = &action_vxlan_encap_data->item_vxlan,
3464 .mask = &rte_flow_item_vxlan_mask,
3467 .type = RTE_FLOW_ITEM_TYPE_END,
3472 .tci = vxlan_encap_conf.vlan_tci,
3476 .src_addr = vxlan_encap_conf.ipv4_src,
3477 .dst_addr = vxlan_encap_conf.ipv4_dst,
3480 .src_port = vxlan_encap_conf.udp_src,
3481 .dst_port = vxlan_encap_conf.udp_dst,
3483 .item_vxlan.flags = 0,
3485 memcpy(action_vxlan_encap_data->item_eth.dst.addr_bytes,
3486 vxlan_encap_conf.eth_dst, ETHER_ADDR_LEN);
3487 memcpy(action_vxlan_encap_data->item_eth.src.addr_bytes,
3488 vxlan_encap_conf.eth_src, ETHER_ADDR_LEN);
3489 if (!vxlan_encap_conf.select_ipv4) {
3490 memcpy(&action_vxlan_encap_data->item_ipv6.hdr.src_addr,
3491 &vxlan_encap_conf.ipv6_src,
3492 sizeof(vxlan_encap_conf.ipv6_src));
3493 memcpy(&action_vxlan_encap_data->item_ipv6.hdr.dst_addr,
3494 &vxlan_encap_conf.ipv6_dst,
3495 sizeof(vxlan_encap_conf.ipv6_dst));
3496 action_vxlan_encap_data->items[2] = (struct rte_flow_item){
3497 .type = RTE_FLOW_ITEM_TYPE_IPV6,
3498 .spec = &action_vxlan_encap_data->item_ipv6,
3499 .mask = &rte_flow_item_ipv6_mask,
3502 if (!vxlan_encap_conf.select_vlan)
3503 action_vxlan_encap_data->items[1].type =
3504 RTE_FLOW_ITEM_TYPE_VOID;
3505 if (vxlan_encap_conf.select_tos_ttl) {
3506 if (vxlan_encap_conf.select_ipv4) {
3507 static struct rte_flow_item_ipv4 ipv4_mask_tos;
3509 memcpy(&ipv4_mask_tos, &rte_flow_item_ipv4_mask,
3510 sizeof(ipv4_mask_tos));
3511 ipv4_mask_tos.hdr.type_of_service = 0xff;
3512 ipv4_mask_tos.hdr.time_to_live = 0xff;
3513 action_vxlan_encap_data->item_ipv4.hdr.type_of_service =
3514 vxlan_encap_conf.ip_tos;
3515 action_vxlan_encap_data->item_ipv4.hdr.time_to_live =
3516 vxlan_encap_conf.ip_ttl;
3517 action_vxlan_encap_data->items[2].mask =
3520 static struct rte_flow_item_ipv6 ipv6_mask_tos;
3522 memcpy(&ipv6_mask_tos, &rte_flow_item_ipv6_mask,
3523 sizeof(ipv6_mask_tos));
3524 ipv6_mask_tos.hdr.vtc_flow |=
3525 RTE_BE32(0xfful << IPV6_HDR_TC_SHIFT);
3526 ipv6_mask_tos.hdr.hop_limits = 0xff;
3527 action_vxlan_encap_data->item_ipv6.hdr.vtc_flow |=
3529 ((uint32_t)vxlan_encap_conf.ip_tos <<
3531 action_vxlan_encap_data->item_ipv6.hdr.hop_limits =
3532 vxlan_encap_conf.ip_ttl;
3533 action_vxlan_encap_data->items[2].mask =
3537 memcpy(action_vxlan_encap_data->item_vxlan.vni, vxlan_encap_conf.vni,
3538 RTE_DIM(vxlan_encap_conf.vni));
3539 action->conf = &action_vxlan_encap_data->conf;
3543 /** Parse NVGRE encap action. */
3545 parse_vc_action_nvgre_encap(struct context *ctx, const struct token *token,
3546 const char *str, unsigned int len,
3547 void *buf, unsigned int size)
3549 struct buffer *out = buf;
3550 struct rte_flow_action *action;
3551 struct action_nvgre_encap_data *action_nvgre_encap_data;
3554 ret = parse_vc(ctx, token, str, len, buf, size);
3557 /* Nothing else to do if there is no buffer. */
3560 if (!out->args.vc.actions_n)
3562 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3563 /* Point to selected object. */
3564 ctx->object = out->args.vc.data;
3565 ctx->objmask = NULL;
3566 /* Set up default configuration. */
3567 action_nvgre_encap_data = ctx->object;
3568 *action_nvgre_encap_data = (struct action_nvgre_encap_data){
3569 .conf = (struct rte_flow_action_nvgre_encap){
3570 .definition = action_nvgre_encap_data->items,
3574 .type = RTE_FLOW_ITEM_TYPE_ETH,
3575 .spec = &action_nvgre_encap_data->item_eth,
3576 .mask = &rte_flow_item_eth_mask,
3579 .type = RTE_FLOW_ITEM_TYPE_VLAN,
3580 .spec = &action_nvgre_encap_data->item_vlan,
3581 .mask = &rte_flow_item_vlan_mask,
3584 .type = RTE_FLOW_ITEM_TYPE_IPV4,
3585 .spec = &action_nvgre_encap_data->item_ipv4,
3586 .mask = &rte_flow_item_ipv4_mask,
3589 .type = RTE_FLOW_ITEM_TYPE_NVGRE,
3590 .spec = &action_nvgre_encap_data->item_nvgre,
3591 .mask = &rte_flow_item_nvgre_mask,
3594 .type = RTE_FLOW_ITEM_TYPE_END,
3599 .tci = nvgre_encap_conf.vlan_tci,
3603 .src_addr = nvgre_encap_conf.ipv4_src,
3604 .dst_addr = nvgre_encap_conf.ipv4_dst,
3606 .item_nvgre.flow_id = 0,
3608 memcpy(action_nvgre_encap_data->item_eth.dst.addr_bytes,
3609 nvgre_encap_conf.eth_dst, ETHER_ADDR_LEN);
3610 memcpy(action_nvgre_encap_data->item_eth.src.addr_bytes,
3611 nvgre_encap_conf.eth_src, ETHER_ADDR_LEN);
3612 if (!nvgre_encap_conf.select_ipv4) {
3613 memcpy(&action_nvgre_encap_data->item_ipv6.hdr.src_addr,
3614 &nvgre_encap_conf.ipv6_src,
3615 sizeof(nvgre_encap_conf.ipv6_src));
3616 memcpy(&action_nvgre_encap_data->item_ipv6.hdr.dst_addr,
3617 &nvgre_encap_conf.ipv6_dst,
3618 sizeof(nvgre_encap_conf.ipv6_dst));
3619 action_nvgre_encap_data->items[2] = (struct rte_flow_item){
3620 .type = RTE_FLOW_ITEM_TYPE_IPV6,
3621 .spec = &action_nvgre_encap_data->item_ipv6,
3622 .mask = &rte_flow_item_ipv6_mask,
3625 if (!nvgre_encap_conf.select_vlan)
3626 action_nvgre_encap_data->items[1].type =
3627 RTE_FLOW_ITEM_TYPE_VOID;
3628 memcpy(action_nvgre_encap_data->item_nvgre.tni, nvgre_encap_conf.tni,
3629 RTE_DIM(nvgre_encap_conf.tni));
3630 action->conf = &action_nvgre_encap_data->conf;
3634 /** Parse l2 encap action. */
3636 parse_vc_action_l2_encap(struct context *ctx, const struct token *token,
3637 const char *str, unsigned int len,
3638 void *buf, unsigned int size)
3640 struct buffer *out = buf;
3641 struct rte_flow_action *action;
3642 struct action_raw_encap_data *action_encap_data;
3643 struct rte_flow_item_eth eth = { .type = 0, };
3644 struct rte_flow_item_vlan vlan = {
3645 .tci = mplsoudp_encap_conf.vlan_tci,
3651 ret = parse_vc(ctx, token, str, len, buf, size);
3654 /* Nothing else to do if there is no buffer. */
3657 if (!out->args.vc.actions_n)
3659 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3660 /* Point to selected object. */
3661 ctx->object = out->args.vc.data;
3662 ctx->objmask = NULL;
3663 /* Copy the headers to the buffer. */
3664 action_encap_data = ctx->object;
3665 *action_encap_data = (struct action_raw_encap_data) {
3666 .conf = (struct rte_flow_action_raw_encap){
3667 .data = action_encap_data->data,
3671 header = action_encap_data->data;
3672 if (l2_encap_conf.select_vlan)
3673 eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
3674 else if (l2_encap_conf.select_ipv4)
3675 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
3677 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
3678 memcpy(eth.dst.addr_bytes,
3679 l2_encap_conf.eth_dst, ETHER_ADDR_LEN);
3680 memcpy(eth.src.addr_bytes,
3681 l2_encap_conf.eth_src, ETHER_ADDR_LEN);
3682 memcpy(header, ð, sizeof(eth));
3683 header += sizeof(eth);
3684 if (l2_encap_conf.select_vlan) {
3685 if (l2_encap_conf.select_ipv4)
3686 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
3688 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
3689 memcpy(header, &vlan, sizeof(vlan));
3690 header += sizeof(vlan);
3692 action_encap_data->conf.size = header -
3693 action_encap_data->data;
3694 action->conf = &action_encap_data->conf;
3698 /** Parse l2 decap action. */
3700 parse_vc_action_l2_decap(struct context *ctx, const struct token *token,
3701 const char *str, unsigned int len,
3702 void *buf, unsigned int size)
3704 struct buffer *out = buf;
3705 struct rte_flow_action *action;
3706 struct action_raw_decap_data *action_decap_data;
3707 struct rte_flow_item_eth eth = { .type = 0, };
3708 struct rte_flow_item_vlan vlan = {
3709 .tci = mplsoudp_encap_conf.vlan_tci,
3715 ret = parse_vc(ctx, token, str, len, buf, size);
3718 /* Nothing else to do if there is no buffer. */
3721 if (!out->args.vc.actions_n)
3723 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3724 /* Point to selected object. */
3725 ctx->object = out->args.vc.data;
3726 ctx->objmask = NULL;
3727 /* Copy the headers to the buffer. */
3728 action_decap_data = ctx->object;
3729 *action_decap_data = (struct action_raw_decap_data) {
3730 .conf = (struct rte_flow_action_raw_decap){
3731 .data = action_decap_data->data,
3735 header = action_decap_data->data;
3736 if (l2_decap_conf.select_vlan)
3737 eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
3738 memcpy(header, ð, sizeof(eth));
3739 header += sizeof(eth);
3740 if (l2_decap_conf.select_vlan) {
3741 memcpy(header, &vlan, sizeof(vlan));
3742 header += sizeof(vlan);
3744 action_decap_data->conf.size = header -
3745 action_decap_data->data;
3746 action->conf = &action_decap_data->conf;
3750 #define ETHER_TYPE_MPLS_UNICAST 0x8847
3752 /** Parse MPLSOGRE encap action. */
3754 parse_vc_action_mplsogre_encap(struct context *ctx, const struct token *token,
3755 const char *str, unsigned int len,
3756 void *buf, unsigned int size)
3758 struct buffer *out = buf;
3759 struct rte_flow_action *action;
3760 struct action_raw_encap_data *action_encap_data;
3761 struct rte_flow_item_eth eth = { .type = 0, };
3762 struct rte_flow_item_vlan vlan = {
3763 .tci = mplsogre_encap_conf.vlan_tci,
3766 struct rte_flow_item_ipv4 ipv4 = {
3768 .src_addr = mplsogre_encap_conf.ipv4_src,
3769 .dst_addr = mplsogre_encap_conf.ipv4_dst,
3770 .next_proto_id = IPPROTO_GRE,
3773 struct rte_flow_item_ipv6 ipv6 = {
3775 .proto = IPPROTO_GRE,
3778 struct rte_flow_item_gre gre = {
3779 .protocol = rte_cpu_to_be_16(ETHER_TYPE_MPLS_UNICAST),
3781 struct rte_flow_item_mpls mpls;
3785 ret = parse_vc(ctx, token, str, len, buf, size);
3788 /* Nothing else to do if there is no buffer. */
3791 if (!out->args.vc.actions_n)
3793 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3794 /* Point to selected object. */
3795 ctx->object = out->args.vc.data;
3796 ctx->objmask = NULL;
3797 /* Copy the headers to the buffer. */
3798 action_encap_data = ctx->object;
3799 *action_encap_data = (struct action_raw_encap_data) {
3800 .conf = (struct rte_flow_action_raw_encap){
3801 .data = action_encap_data->data,
3806 header = action_encap_data->data;
3807 if (mplsogre_encap_conf.select_vlan)
3808 eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
3809 else if (mplsogre_encap_conf.select_ipv4)
3810 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
3812 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
3813 memcpy(eth.dst.addr_bytes,
3814 mplsogre_encap_conf.eth_dst, ETHER_ADDR_LEN);
3815 memcpy(eth.src.addr_bytes,
3816 mplsogre_encap_conf.eth_src, ETHER_ADDR_LEN);
3817 memcpy(header, ð, sizeof(eth));
3818 header += sizeof(eth);
3819 if (mplsogre_encap_conf.select_vlan) {
3820 if (mplsogre_encap_conf.select_ipv4)
3821 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
3823 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
3824 memcpy(header, &vlan, sizeof(vlan));
3825 header += sizeof(vlan);
3827 if (mplsogre_encap_conf.select_ipv4) {
3828 memcpy(header, &ipv4, sizeof(ipv4));
3829 header += sizeof(ipv4);
3831 memcpy(&ipv6.hdr.src_addr,
3832 &mplsogre_encap_conf.ipv6_src,
3833 sizeof(mplsogre_encap_conf.ipv6_src));
3834 memcpy(&ipv6.hdr.dst_addr,
3835 &mplsogre_encap_conf.ipv6_dst,
3836 sizeof(mplsogre_encap_conf.ipv6_dst));
3837 memcpy(header, &ipv6, sizeof(ipv6));
3838 header += sizeof(ipv6);
3840 memcpy(header, &gre, sizeof(gre));
3841 header += sizeof(gre);
3842 memcpy(mpls.label_tc_s, mplsogre_encap_conf.label,
3843 RTE_DIM(mplsogre_encap_conf.label));
3844 mpls.label_tc_s[2] |= 0x1;
3845 memcpy(header, &mpls, sizeof(mpls));
3846 header += sizeof(mpls);
3847 action_encap_data->conf.size = header -
3848 action_encap_data->data;
3849 action->conf = &action_encap_data->conf;
3853 /** Parse MPLSOGRE decap action. */
3855 parse_vc_action_mplsogre_decap(struct context *ctx, const struct token *token,
3856 const char *str, unsigned int len,
3857 void *buf, unsigned int size)
3859 struct buffer *out = buf;
3860 struct rte_flow_action *action;
3861 struct action_raw_decap_data *action_decap_data;
3862 struct rte_flow_item_eth eth = { .type = 0, };
3863 struct rte_flow_item_vlan vlan = {.tci = 0};
3864 struct rte_flow_item_ipv4 ipv4 = {
3866 .next_proto_id = IPPROTO_GRE,
3869 struct rte_flow_item_ipv6 ipv6 = {
3871 .proto = IPPROTO_GRE,
3874 struct rte_flow_item_gre gre = {
3875 .protocol = rte_cpu_to_be_16(ETHER_TYPE_MPLS_UNICAST),
3877 struct rte_flow_item_mpls mpls;
3881 ret = parse_vc(ctx, token, str, len, buf, size);
3884 /* Nothing else to do if there is no buffer. */
3887 if (!out->args.vc.actions_n)
3889 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3890 /* Point to selected object. */
3891 ctx->object = out->args.vc.data;
3892 ctx->objmask = NULL;
3893 /* Copy the headers to the buffer. */
3894 action_decap_data = ctx->object;
3895 *action_decap_data = (struct action_raw_decap_data) {
3896 .conf = (struct rte_flow_action_raw_decap){
3897 .data = action_decap_data->data,
3901 header = action_decap_data->data;
3902 if (mplsogre_decap_conf.select_vlan)
3903 eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
3904 else if (mplsogre_encap_conf.select_ipv4)
3905 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
3907 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
3908 memcpy(eth.dst.addr_bytes,
3909 mplsogre_encap_conf.eth_dst, ETHER_ADDR_LEN);
3910 memcpy(eth.src.addr_bytes,
3911 mplsogre_encap_conf.eth_src, ETHER_ADDR_LEN);
3912 memcpy(header, ð, sizeof(eth));
3913 header += sizeof(eth);
3914 if (mplsogre_encap_conf.select_vlan) {
3915 if (mplsogre_encap_conf.select_ipv4)
3916 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
3918 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
3919 memcpy(header, &vlan, sizeof(vlan));
3920 header += sizeof(vlan);
3922 if (mplsogre_encap_conf.select_ipv4) {
3923 memcpy(header, &ipv4, sizeof(ipv4));
3924 header += sizeof(ipv4);
3926 memcpy(header, &ipv6, sizeof(ipv6));
3927 header += sizeof(ipv6);
3929 memcpy(header, &gre, sizeof(gre));
3930 header += sizeof(gre);
3931 memset(&mpls, 0, sizeof(mpls));
3932 memcpy(header, &mpls, sizeof(mpls));
3933 header += sizeof(mpls);
3934 action_decap_data->conf.size = header -
3935 action_decap_data->data;
3936 action->conf = &action_decap_data->conf;
3940 /** Parse MPLSOUDP encap action. */
3942 parse_vc_action_mplsoudp_encap(struct context *ctx, const struct token *token,
3943 const char *str, unsigned int len,
3944 void *buf, unsigned int size)
3946 struct buffer *out = buf;
3947 struct rte_flow_action *action;
3948 struct action_raw_encap_data *action_encap_data;
3949 struct rte_flow_item_eth eth = { .type = 0, };
3950 struct rte_flow_item_vlan vlan = {
3951 .tci = mplsoudp_encap_conf.vlan_tci,
3954 struct rte_flow_item_ipv4 ipv4 = {
3956 .src_addr = mplsoudp_encap_conf.ipv4_src,
3957 .dst_addr = mplsoudp_encap_conf.ipv4_dst,
3958 .next_proto_id = IPPROTO_UDP,
3961 struct rte_flow_item_ipv6 ipv6 = {
3963 .proto = IPPROTO_UDP,
3966 struct rte_flow_item_udp udp = {
3968 .src_port = mplsoudp_encap_conf.udp_src,
3969 .dst_port = mplsoudp_encap_conf.udp_dst,
3972 struct rte_flow_item_mpls mpls;
3976 ret = parse_vc(ctx, token, str, len, buf, size);
3979 /* Nothing else to do if there is no buffer. */
3982 if (!out->args.vc.actions_n)
3984 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3985 /* Point to selected object. */
3986 ctx->object = out->args.vc.data;
3987 ctx->objmask = NULL;
3988 /* Copy the headers to the buffer. */
3989 action_encap_data = ctx->object;
3990 *action_encap_data = (struct action_raw_encap_data) {
3991 .conf = (struct rte_flow_action_raw_encap){
3992 .data = action_encap_data->data,
3997 header = action_encap_data->data;
3998 if (mplsoudp_encap_conf.select_vlan)
3999 eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
4000 else if (mplsoudp_encap_conf.select_ipv4)
4001 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
4003 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
4004 memcpy(eth.dst.addr_bytes,
4005 mplsoudp_encap_conf.eth_dst, ETHER_ADDR_LEN);
4006 memcpy(eth.src.addr_bytes,
4007 mplsoudp_encap_conf.eth_src, ETHER_ADDR_LEN);
4008 memcpy(header, ð, sizeof(eth));
4009 header += sizeof(eth);
4010 if (mplsoudp_encap_conf.select_vlan) {
4011 if (mplsoudp_encap_conf.select_ipv4)
4012 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
4014 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
4015 memcpy(header, &vlan, sizeof(vlan));
4016 header += sizeof(vlan);
4018 if (mplsoudp_encap_conf.select_ipv4) {
4019 memcpy(header, &ipv4, sizeof(ipv4));
4020 header += sizeof(ipv4);
4022 memcpy(&ipv6.hdr.src_addr,
4023 &mplsoudp_encap_conf.ipv6_src,
4024 sizeof(mplsoudp_encap_conf.ipv6_src));
4025 memcpy(&ipv6.hdr.dst_addr,
4026 &mplsoudp_encap_conf.ipv6_dst,
4027 sizeof(mplsoudp_encap_conf.ipv6_dst));
4028 memcpy(header, &ipv6, sizeof(ipv6));
4029 header += sizeof(ipv6);
4031 memcpy(header, &udp, sizeof(udp));
4032 header += sizeof(udp);
4033 memcpy(mpls.label_tc_s, mplsoudp_encap_conf.label,
4034 RTE_DIM(mplsoudp_encap_conf.label));
4035 mpls.label_tc_s[2] |= 0x1;
4036 memcpy(header, &mpls, sizeof(mpls));
4037 header += sizeof(mpls);
4038 action_encap_data->conf.size = header -
4039 action_encap_data->data;
4040 action->conf = &action_encap_data->conf;
4044 /** Parse MPLSOUDP decap action. */
4046 parse_vc_action_mplsoudp_decap(struct context *ctx, const struct token *token,
4047 const char *str, unsigned int len,
4048 void *buf, unsigned int size)
4050 struct buffer *out = buf;
4051 struct rte_flow_action *action;
4052 struct action_raw_decap_data *action_decap_data;
4053 struct rte_flow_item_eth eth = { .type = 0, };
4054 struct rte_flow_item_vlan vlan = {.tci = 0};
4055 struct rte_flow_item_ipv4 ipv4 = {
4057 .next_proto_id = IPPROTO_UDP,
4060 struct rte_flow_item_ipv6 ipv6 = {
4062 .proto = IPPROTO_UDP,
4065 struct rte_flow_item_udp udp = {
4067 .dst_port = rte_cpu_to_be_16(6635),
4070 struct rte_flow_item_mpls mpls;
4074 ret = parse_vc(ctx, token, str, len, buf, size);
4077 /* Nothing else to do if there is no buffer. */
4080 if (!out->args.vc.actions_n)
4082 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
4083 /* Point to selected object. */
4084 ctx->object = out->args.vc.data;
4085 ctx->objmask = NULL;
4086 /* Copy the headers to the buffer. */
4087 action_decap_data = ctx->object;
4088 *action_decap_data = (struct action_raw_decap_data) {
4089 .conf = (struct rte_flow_action_raw_decap){
4090 .data = action_decap_data->data,
4094 header = action_decap_data->data;
4095 if (mplsoudp_decap_conf.select_vlan)
4096 eth.type = rte_cpu_to_be_16(ETHER_TYPE_VLAN);
4097 else if (mplsoudp_encap_conf.select_ipv4)
4098 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
4100 eth.type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
4101 memcpy(eth.dst.addr_bytes,
4102 mplsoudp_encap_conf.eth_dst, ETHER_ADDR_LEN);
4103 memcpy(eth.src.addr_bytes,
4104 mplsoudp_encap_conf.eth_src, ETHER_ADDR_LEN);
4105 memcpy(header, ð, sizeof(eth));
4106 header += sizeof(eth);
4107 if (mplsoudp_encap_conf.select_vlan) {
4108 if (mplsoudp_encap_conf.select_ipv4)
4109 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
4111 vlan.inner_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
4112 memcpy(header, &vlan, sizeof(vlan));
4113 header += sizeof(vlan);
4115 if (mplsoudp_encap_conf.select_ipv4) {
4116 memcpy(header, &ipv4, sizeof(ipv4));
4117 header += sizeof(ipv4);
4119 memcpy(header, &ipv6, sizeof(ipv6));
4120 header += sizeof(ipv6);
4122 memcpy(header, &udp, sizeof(udp));
4123 header += sizeof(udp);
4124 memset(&mpls, 0, sizeof(mpls));
4125 memcpy(header, &mpls, sizeof(mpls));
4126 header += sizeof(mpls);
4127 action_decap_data->conf.size = header -
4128 action_decap_data->data;
4129 action->conf = &action_decap_data->conf;
4133 /** Parse tokens for destroy command. */
4135 parse_destroy(struct context *ctx, const struct token *token,
4136 const char *str, unsigned int len,
4137 void *buf, unsigned int size)
4139 struct buffer *out = buf;
4141 /* Token name must match. */
4142 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4144 /* Nothing else to do if there is no buffer. */
4147 if (!out->command) {
4148 if (ctx->curr != DESTROY)
4150 if (sizeof(*out) > size)
4152 out->command = ctx->curr;
4155 ctx->objmask = NULL;
4156 out->args.destroy.rule =
4157 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
4161 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
4162 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
4165 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
4166 ctx->objmask = NULL;
4170 /** Parse tokens for flush command. */
4172 parse_flush(struct context *ctx, const struct token *token,
4173 const char *str, unsigned int len,
4174 void *buf, unsigned int size)
4176 struct buffer *out = buf;
4178 /* Token name must match. */
4179 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4181 /* Nothing else to do if there is no buffer. */
4184 if (!out->command) {
4185 if (ctx->curr != FLUSH)
4187 if (sizeof(*out) > size)
4189 out->command = ctx->curr;
4192 ctx->objmask = NULL;
4197 /** Parse tokens for query command. */
4199 parse_query(struct context *ctx, const struct token *token,
4200 const char *str, unsigned int len,
4201 void *buf, unsigned int size)
4203 struct buffer *out = buf;
4205 /* Token name must match. */
4206 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4208 /* Nothing else to do if there is no buffer. */
4211 if (!out->command) {
4212 if (ctx->curr != QUERY)
4214 if (sizeof(*out) > size)
4216 out->command = ctx->curr;
4219 ctx->objmask = NULL;
4224 /** Parse action names. */
4226 parse_action(struct context *ctx, const struct token *token,
4227 const char *str, unsigned int len,
4228 void *buf, unsigned int size)
4230 struct buffer *out = buf;
4231 const struct arg *arg = pop_args(ctx);
4235 /* Argument is expected. */
4238 /* Parse action name. */
4239 for (i = 0; next_action[i]; ++i) {
4240 const struct parse_action_priv *priv;
4242 token = &token_list[next_action[i]];
4243 if (strcmp_partial(token->name, str, len))
4249 memcpy((uint8_t *)ctx->object + arg->offset,
4255 push_args(ctx, arg);
4259 /** Parse tokens for list command. */
4261 parse_list(struct context *ctx, const struct token *token,
4262 const char *str, unsigned int len,
4263 void *buf, unsigned int size)
4265 struct buffer *out = buf;
4267 /* Token name must match. */
4268 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4270 /* Nothing else to do if there is no buffer. */
4273 if (!out->command) {
4274 if (ctx->curr != LIST)
4276 if (sizeof(*out) > size)
4278 out->command = ctx->curr;
4281 ctx->objmask = NULL;
4282 out->args.list.group =
4283 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
4287 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
4288 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
4291 ctx->object = out->args.list.group + out->args.list.group_n++;
4292 ctx->objmask = NULL;
4296 /** Parse tokens for isolate command. */
4298 parse_isolate(struct context *ctx, const struct token *token,
4299 const char *str, unsigned int len,
4300 void *buf, unsigned int size)
4302 struct buffer *out = buf;
4304 /* Token name must match. */
4305 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4307 /* Nothing else to do if there is no buffer. */
4310 if (!out->command) {
4311 if (ctx->curr != ISOLATE)
4313 if (sizeof(*out) > size)
4315 out->command = ctx->curr;
4318 ctx->objmask = NULL;
4324 * Parse signed/unsigned integers 8 to 64-bit long.
4326 * Last argument (ctx->args) is retrieved to determine integer type and
4330 parse_int(struct context *ctx, const struct token *token,
4331 const char *str, unsigned int len,
4332 void *buf, unsigned int size)
4334 const struct arg *arg = pop_args(ctx);
4339 /* Argument is expected. */
4344 (uintmax_t)strtoimax(str, &end, 0) :
4345 strtoumax(str, &end, 0);
4346 if (errno || (size_t)(end - str) != len)
4349 ((arg->sign && ((intmax_t)u < (intmax_t)arg->min ||
4350 (intmax_t)u > (intmax_t)arg->max)) ||
4351 (!arg->sign && (u < arg->min || u > arg->max))))
4356 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
4357 !arg_entry_bf_fill(ctx->objmask, -1, arg))
4361 buf = (uint8_t *)ctx->object + arg->offset;
4363 if (u > RTE_LEN2MASK(size * CHAR_BIT, uint64_t))
4367 case sizeof(uint8_t):
4368 *(uint8_t *)buf = u;
4370 case sizeof(uint16_t):
4371 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
4373 case sizeof(uint8_t [3]):
4374 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
4376 ((uint8_t *)buf)[0] = u;
4377 ((uint8_t *)buf)[1] = u >> 8;
4378 ((uint8_t *)buf)[2] = u >> 16;
4382 ((uint8_t *)buf)[0] = u >> 16;
4383 ((uint8_t *)buf)[1] = u >> 8;
4384 ((uint8_t *)buf)[2] = u;
4386 case sizeof(uint32_t):
4387 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
4389 case sizeof(uint64_t):
4390 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
4395 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
4397 buf = (uint8_t *)ctx->objmask + arg->offset;
4402 push_args(ctx, arg);
4409 * Three arguments (ctx->args) are retrieved from the stack to store data,
4410 * its actual length and address (in that order).
4413 parse_string(struct context *ctx, const struct token *token,
4414 const char *str, unsigned int len,
4415 void *buf, unsigned int size)
4417 const struct arg *arg_data = pop_args(ctx);
4418 const struct arg *arg_len = pop_args(ctx);
4419 const struct arg *arg_addr = pop_args(ctx);
4420 char tmp[16]; /* Ought to be enough. */
4423 /* Arguments are expected. */
4427 push_args(ctx, arg_data);
4431 push_args(ctx, arg_len);
4432 push_args(ctx, arg_data);
4435 size = arg_data->size;
4436 /* Bit-mask fill is not supported. */
4437 if (arg_data->mask || size < len)
4441 /* Let parse_int() fill length information first. */
4442 ret = snprintf(tmp, sizeof(tmp), "%u", len);
4445 push_args(ctx, arg_len);
4446 ret = parse_int(ctx, token, tmp, ret, NULL, 0);
4451 buf = (uint8_t *)ctx->object + arg_data->offset;
4452 /* Output buffer is not necessarily NUL-terminated. */
4453 memcpy(buf, str, len);
4454 memset((uint8_t *)buf + len, 0x00, size - len);
4456 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
4457 /* Save address if requested. */
4458 if (arg_addr->size) {
4459 memcpy((uint8_t *)ctx->object + arg_addr->offset,
4461 (uint8_t *)ctx->object + arg_data->offset
4465 memcpy((uint8_t *)ctx->objmask + arg_addr->offset,
4467 (uint8_t *)ctx->objmask + arg_data->offset
4473 push_args(ctx, arg_addr);
4474 push_args(ctx, arg_len);
4475 push_args(ctx, arg_data);
4480 * Parse a MAC address.
4482 * Last argument (ctx->args) is retrieved to determine storage size and
4486 parse_mac_addr(struct context *ctx, const struct token *token,
4487 const char *str, unsigned int len,
4488 void *buf, unsigned int size)
4490 const struct arg *arg = pop_args(ctx);
4491 struct ether_addr tmp;
4495 /* Argument is expected. */
4499 /* Bit-mask fill is not supported. */
4500 if (arg->mask || size != sizeof(tmp))
4502 /* Only network endian is supported. */
4505 ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
4506 if (ret < 0 || (unsigned int)ret != len)
4510 buf = (uint8_t *)ctx->object + arg->offset;
4511 memcpy(buf, &tmp, size);
4513 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
4516 push_args(ctx, arg);
4521 * Parse an IPv4 address.
4523 * Last argument (ctx->args) is retrieved to determine storage size and
4527 parse_ipv4_addr(struct context *ctx, const struct token *token,
4528 const char *str, unsigned int len,
4529 void *buf, unsigned int size)
4531 const struct arg *arg = pop_args(ctx);
4536 /* Argument is expected. */
4540 /* Bit-mask fill is not supported. */
4541 if (arg->mask || size != sizeof(tmp))
4543 /* Only network endian is supported. */
4546 memcpy(str2, str, len);
4548 ret = inet_pton(AF_INET, str2, &tmp);
4550 /* Attempt integer parsing. */
4551 push_args(ctx, arg);
4552 return parse_int(ctx, token, str, len, buf, size);
4556 buf = (uint8_t *)ctx->object + arg->offset;
4557 memcpy(buf, &tmp, size);
4559 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
4562 push_args(ctx, arg);
4567 * Parse an IPv6 address.
4569 * Last argument (ctx->args) is retrieved to determine storage size and
4573 parse_ipv6_addr(struct context *ctx, const struct token *token,
4574 const char *str, unsigned int len,
4575 void *buf, unsigned int size)
4577 const struct arg *arg = pop_args(ctx);
4579 struct in6_addr tmp;
4583 /* Argument is expected. */
4587 /* Bit-mask fill is not supported. */
4588 if (arg->mask || size != sizeof(tmp))
4590 /* Only network endian is supported. */
4593 memcpy(str2, str, len);
4595 ret = inet_pton(AF_INET6, str2, &tmp);
4600 buf = (uint8_t *)ctx->object + arg->offset;
4601 memcpy(buf, &tmp, size);
4603 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
4606 push_args(ctx, arg);
4610 /** Boolean values (even indices stand for false). */
4611 static const char *const boolean_name[] = {
4621 * Parse a boolean value.
4623 * Last argument (ctx->args) is retrieved to determine storage size and
4627 parse_boolean(struct context *ctx, const struct token *token,
4628 const char *str, unsigned int len,
4629 void *buf, unsigned int size)
4631 const struct arg *arg = pop_args(ctx);
4635 /* Argument is expected. */
4638 for (i = 0; boolean_name[i]; ++i)
4639 if (!strcmp_partial(boolean_name[i], str, len))
4641 /* Process token as integer. */
4642 if (boolean_name[i])
4643 str = i & 1 ? "1" : "0";
4644 push_args(ctx, arg);
4645 ret = parse_int(ctx, token, str, strlen(str), buf, size);
4646 return ret > 0 ? (int)len : ret;
4649 /** Parse port and update context. */
4651 parse_port(struct context *ctx, const struct token *token,
4652 const char *str, unsigned int len,
4653 void *buf, unsigned int size)
4655 struct buffer *out = &(struct buffer){ .port = 0 };
4663 ctx->objmask = NULL;
4664 size = sizeof(*out);
4666 ret = parse_int(ctx, token, str, len, out, size);
4668 ctx->port = out->port;
4674 /** No completion. */
4676 comp_none(struct context *ctx, const struct token *token,
4677 unsigned int ent, char *buf, unsigned int size)
4687 /** Complete boolean values. */
4689 comp_boolean(struct context *ctx, const struct token *token,
4690 unsigned int ent, char *buf, unsigned int size)
4696 for (i = 0; boolean_name[i]; ++i)
4697 if (buf && i == ent)
4698 return strlcpy(buf, boolean_name[i], size);
4704 /** Complete action names. */
4706 comp_action(struct context *ctx, const struct token *token,
4707 unsigned int ent, char *buf, unsigned int size)
4713 for (i = 0; next_action[i]; ++i)
4714 if (buf && i == ent)
4715 return strlcpy(buf, token_list[next_action[i]].name,
4722 /** Complete available ports. */
4724 comp_port(struct context *ctx, const struct token *token,
4725 unsigned int ent, char *buf, unsigned int size)
4732 RTE_ETH_FOREACH_DEV(p) {
4733 if (buf && i == ent)
4734 return snprintf(buf, size, "%u", p);
4742 /** Complete available rule IDs. */
4744 comp_rule_id(struct context *ctx, const struct token *token,
4745 unsigned int ent, char *buf, unsigned int size)
4748 struct rte_port *port;
4749 struct port_flow *pf;
4752 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
4753 ctx->port == (portid_t)RTE_PORT_ALL)
4755 port = &ports[ctx->port];
4756 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
4757 if (buf && i == ent)
4758 return snprintf(buf, size, "%u", pf->id);
4766 /** Complete type field for RSS action. */
4768 comp_vc_action_rss_type(struct context *ctx, const struct token *token,
4769 unsigned int ent, char *buf, unsigned int size)
4775 for (i = 0; rss_type_table[i].str; ++i)
4780 return strlcpy(buf, rss_type_table[ent].str, size);
4782 return snprintf(buf, size, "end");
4786 /** Complete queue field for RSS action. */
4788 comp_vc_action_rss_queue(struct context *ctx, const struct token *token,
4789 unsigned int ent, char *buf, unsigned int size)
4796 return snprintf(buf, size, "%u", ent);
4798 return snprintf(buf, size, "end");
4802 /** Internal context. */
4803 static struct context cmd_flow_context;
4805 /** Global parser instance (cmdline API). */
4806 cmdline_parse_inst_t cmd_flow;
4808 /** Initialize context. */
4810 cmd_flow_context_init(struct context *ctx)
4812 /* A full memset() is not necessary. */
4822 ctx->objmask = NULL;
4825 /** Parse a token (cmdline API). */
4827 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
4830 struct context *ctx = &cmd_flow_context;
4831 const struct token *token;
4832 const enum index *list;
4837 token = &token_list[ctx->curr];
4838 /* Check argument length. */
4841 for (len = 0; src[len]; ++len)
4842 if (src[len] == '#' || isspace(src[len]))
4846 /* Last argument and EOL detection. */
4847 for (i = len; src[i]; ++i)
4848 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
4850 else if (!isspace(src[i])) {
4855 if (src[i] == '\r' || src[i] == '\n') {
4859 /* Initialize context if necessary. */
4860 if (!ctx->next_num) {
4863 ctx->next[ctx->next_num++] = token->next[0];
4865 /* Process argument through candidates. */
4866 ctx->prev = ctx->curr;
4867 list = ctx->next[ctx->next_num - 1];
4868 for (i = 0; list[i]; ++i) {
4869 const struct token *next = &token_list[list[i]];
4872 ctx->curr = list[i];
4874 tmp = next->call(ctx, next, src, len, result, size);
4876 tmp = parse_default(ctx, next, src, len, result, size);
4877 if (tmp == -1 || tmp != len)
4885 /* Push subsequent tokens if any. */
4887 for (i = 0; token->next[i]; ++i) {
4888 if (ctx->next_num == RTE_DIM(ctx->next))
4890 ctx->next[ctx->next_num++] = token->next[i];
4892 /* Push arguments if any. */
4894 for (i = 0; token->args[i]; ++i) {
4895 if (ctx->args_num == RTE_DIM(ctx->args))
4897 ctx->args[ctx->args_num++] = token->args[i];
4902 /** Return number of completion entries (cmdline API). */
4904 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
4906 struct context *ctx = &cmd_flow_context;
4907 const struct token *token = &token_list[ctx->curr];
4908 const enum index *list;
4912 /* Count number of tokens in current list. */
4914 list = ctx->next[ctx->next_num - 1];
4916 list = token->next[0];
4917 for (i = 0; list[i]; ++i)
4922 * If there is a single token, use its completion callback, otherwise
4923 * return the number of entries.
4925 token = &token_list[list[0]];
4926 if (i == 1 && token->comp) {
4927 /* Save index for cmd_flow_get_help(). */
4928 ctx->prev = list[0];
4929 return token->comp(ctx, token, 0, NULL, 0);
4934 /** Return a completion entry (cmdline API). */
4936 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
4937 char *dst, unsigned int size)
4939 struct context *ctx = &cmd_flow_context;
4940 const struct token *token = &token_list[ctx->curr];
4941 const enum index *list;
4945 /* Count number of tokens in current list. */
4947 list = ctx->next[ctx->next_num - 1];
4949 list = token->next[0];
4950 for (i = 0; list[i]; ++i)
4954 /* If there is a single token, use its completion callback. */
4955 token = &token_list[list[0]];
4956 if (i == 1 && token->comp) {
4957 /* Save index for cmd_flow_get_help(). */
4958 ctx->prev = list[0];
4959 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
4961 /* Otherwise make sure the index is valid and use defaults. */
4964 token = &token_list[list[index]];
4965 strlcpy(dst, token->name, size);
4966 /* Save index for cmd_flow_get_help(). */
4967 ctx->prev = list[index];
4971 /** Populate help strings for current token (cmdline API). */
4973 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
4975 struct context *ctx = &cmd_flow_context;
4976 const struct token *token = &token_list[ctx->prev];
4981 /* Set token type and update global help with details. */
4982 strlcpy(dst, (token->type ? token->type : "TOKEN"), size);
4984 cmd_flow.help_str = token->help;
4986 cmd_flow.help_str = token->name;
4990 /** Token definition template (cmdline API). */
4991 static struct cmdline_token_hdr cmd_flow_token_hdr = {
4992 .ops = &(struct cmdline_token_ops){
4993 .parse = cmd_flow_parse,
4994 .complete_get_nb = cmd_flow_complete_get_nb,
4995 .complete_get_elt = cmd_flow_complete_get_elt,
4996 .get_help = cmd_flow_get_help,
5001 /** Populate the next dynamic token. */
5003 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
5004 cmdline_parse_token_hdr_t **hdr_inst)
5006 struct context *ctx = &cmd_flow_context;
5008 /* Always reinitialize context before requesting the first token. */
5009 if (!(hdr_inst - cmd_flow.tokens))
5010 cmd_flow_context_init(ctx);
5011 /* Return NULL when no more tokens are expected. */
5012 if (!ctx->next_num && ctx->curr) {
5016 /* Determine if command should end here. */
5017 if (ctx->eol && ctx->last && ctx->next_num) {
5018 const enum index *list = ctx->next[ctx->next_num - 1];
5021 for (i = 0; list[i]; ++i) {
5028 *hdr = &cmd_flow_token_hdr;
5031 /** Dispatch parsed buffer to function calls. */
5033 cmd_flow_parsed(const struct buffer *in)
5035 switch (in->command) {
5037 port_flow_validate(in->port, &in->args.vc.attr,
5038 in->args.vc.pattern, in->args.vc.actions);
5041 port_flow_create(in->port, &in->args.vc.attr,
5042 in->args.vc.pattern, in->args.vc.actions);
5045 port_flow_destroy(in->port, in->args.destroy.rule_n,
5046 in->args.destroy.rule);
5049 port_flow_flush(in->port);
5052 port_flow_query(in->port, in->args.query.rule,
5053 &in->args.query.action);
5056 port_flow_list(in->port, in->args.list.group_n,
5057 in->args.list.group);
5060 port_flow_isolate(in->port, in->args.isolate.set);
5067 /** Token generator and output processing callback (cmdline API). */
5069 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
5072 cmd_flow_tok(arg0, arg2);
5074 cmd_flow_parsed(arg0);
5077 /** Global parser instance (cmdline API). */
5078 cmdline_parse_inst_t cmd_flow = {
5080 .data = NULL, /**< Unused. */
5081 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
5084 }, /**< Tokens are returned by cmd_flow_tok(). */