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_common.h>
17 #include <rte_eth_ctrl.h>
18 #include <rte_ethdev.h>
19 #include <rte_byteorder.h>
20 #include <cmdline_parse.h>
21 #include <cmdline_parse_etheraddr.h>
26 /** Parser token indices. */
46 /* Top-level command. */
49 /* Sub-level commands. */
58 /* Destroy arguments. */
61 /* Query arguments. */
67 /* Validate/create arguments. */
74 /* Validate/create pattern. */
111 ITEM_VLAN_INNER_TYPE,
143 ITEM_E_TAG_GRP_ECID_B,
162 ITEM_ARP_ETH_IPV4_SHA,
163 ITEM_ARP_ETH_IPV4_SPA,
164 ITEM_ARP_ETH_IPV4_THA,
165 ITEM_ARP_ETH_IPV4_TPA,
167 ITEM_IPV6_EXT_NEXT_HDR,
172 ITEM_ICMP6_ND_NS_TARGET_ADDR,
174 ITEM_ICMP6_ND_NA_TARGET_ADDR,
176 ITEM_ICMP6_ND_OPT_TYPE,
177 ITEM_ICMP6_ND_OPT_SLA_ETH,
178 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
179 ITEM_ICMP6_ND_OPT_TLA_ETH,
180 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
182 /* Validate/create actions. */
202 ACTION_RSS_FUNC_DEFAULT,
203 ACTION_RSS_FUNC_TOEPLITZ,
204 ACTION_RSS_FUNC_SIMPLE_XOR,
216 ACTION_PHY_PORT_ORIGINAL,
217 ACTION_PHY_PORT_INDEX,
219 ACTION_PORT_ID_ORIGINAL,
223 ACTION_OF_SET_MPLS_TTL,
224 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
225 ACTION_OF_DEC_MPLS_TTL,
226 ACTION_OF_SET_NW_TTL,
227 ACTION_OF_SET_NW_TTL_NW_TTL,
228 ACTION_OF_DEC_NW_TTL,
229 ACTION_OF_COPY_TTL_OUT,
230 ACTION_OF_COPY_TTL_IN,
233 ACTION_OF_PUSH_VLAN_ETHERTYPE,
234 ACTION_OF_SET_VLAN_VID,
235 ACTION_OF_SET_VLAN_VID_VLAN_VID,
236 ACTION_OF_SET_VLAN_PCP,
237 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
239 ACTION_OF_POP_MPLS_ETHERTYPE,
241 ACTION_OF_PUSH_MPLS_ETHERTYPE,
246 /** Maximum size for pattern in struct rte_flow_item_raw. */
247 #define ITEM_RAW_PATTERN_SIZE 40
249 /** Storage size for struct rte_flow_item_raw including pattern. */
250 #define ITEM_RAW_SIZE \
251 (sizeof(struct rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE)
253 /** Maximum number of queue indices in struct rte_flow_action_rss. */
254 #define ACTION_RSS_QUEUE_NUM 32
256 /** Storage for struct rte_flow_action_rss including external data. */
257 struct action_rss_data {
258 struct rte_flow_action_rss conf;
259 uint8_t key[RSS_HASH_KEY_LENGTH];
260 uint16_t queue[ACTION_RSS_QUEUE_NUM];
263 /** Maximum number of items in struct rte_flow_action_vxlan_encap. */
264 #define ACTION_VXLAN_ENCAP_ITEMS_NUM 6
266 /** Storage for struct rte_flow_action_vxlan_encap including external data. */
267 struct action_vxlan_encap_data {
268 struct rte_flow_action_vxlan_encap conf;
269 struct rte_flow_item items[ACTION_VXLAN_ENCAP_ITEMS_NUM];
270 struct rte_flow_item_eth item_eth;
271 struct rte_flow_item_vlan item_vlan;
273 struct rte_flow_item_ipv4 item_ipv4;
274 struct rte_flow_item_ipv6 item_ipv6;
276 struct rte_flow_item_udp item_udp;
277 struct rte_flow_item_vxlan item_vxlan;
280 /** Maximum number of subsequent tokens and arguments on the stack. */
281 #define CTX_STACK_SIZE 16
283 /** Parser context. */
285 /** Stack of subsequent token lists to process. */
286 const enum index *next[CTX_STACK_SIZE];
287 /** Arguments for stacked tokens. */
288 const void *args[CTX_STACK_SIZE];
289 enum index curr; /**< Current token index. */
290 enum index prev; /**< Index of the last token seen. */
291 int next_num; /**< Number of entries in next[]. */
292 int args_num; /**< Number of entries in args[]. */
293 uint32_t eol:1; /**< EOL has been detected. */
294 uint32_t last:1; /**< No more arguments. */
295 portid_t port; /**< Current port ID (for completions). */
296 uint32_t objdata; /**< Object-specific data. */
297 void *object; /**< Address of current object for relative offsets. */
298 void *objmask; /**< Object a full mask must be written to. */
301 /** Token argument. */
303 uint32_t hton:1; /**< Use network byte ordering. */
304 uint32_t sign:1; /**< Value is signed. */
305 uint32_t bounded:1; /**< Value is bounded. */
306 uintmax_t min; /**< Minimum value if bounded. */
307 uintmax_t max; /**< Maximum value if bounded. */
308 uint32_t offset; /**< Relative offset from ctx->object. */
309 uint32_t size; /**< Field size. */
310 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
313 /** Parser token definition. */
315 /** Type displayed during completion (defaults to "TOKEN"). */
317 /** Help displayed during completion (defaults to token name). */
319 /** Private data used by parser functions. */
322 * Lists of subsequent tokens to push on the stack. Each call to the
323 * parser consumes the last entry of that stack.
325 const enum index *const *next;
326 /** Arguments stack for subsequent tokens that need them. */
327 const struct arg *const *args;
329 * Token-processing callback, returns -1 in case of error, the
330 * length of the matched string otherwise. If NULL, attempts to
331 * match the token name.
333 * If buf is not NULL, the result should be stored in it according
334 * to context. An error is returned if not large enough.
336 int (*call)(struct context *ctx, const struct token *token,
337 const char *str, unsigned int len,
338 void *buf, unsigned int size);
340 * Callback that provides possible values for this token, used for
341 * completion. Returns -1 in case of error, the number of possible
342 * values otherwise. If NULL, the token name is used.
344 * If buf is not NULL, entry index ent is written to buf and the
345 * full length of the entry is returned (same behavior as
348 int (*comp)(struct context *ctx, const struct token *token,
349 unsigned int ent, char *buf, unsigned int size);
350 /** Mandatory token name, no default value. */
354 /** Static initializer for the next field. */
355 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
357 /** Static initializer for a NEXT() entry. */
358 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
360 /** Static initializer for the args field. */
361 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
363 /** Static initializer for ARGS() to target a field. */
364 #define ARGS_ENTRY(s, f) \
365 (&(const struct arg){ \
366 .offset = offsetof(s, f), \
367 .size = sizeof(((s *)0)->f), \
370 /** Static initializer for ARGS() to target a bit-field. */
371 #define ARGS_ENTRY_BF(s, f, b) \
372 (&(const struct arg){ \
374 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
377 /** Static initializer for ARGS() to target an arbitrary bit-mask. */
378 #define ARGS_ENTRY_MASK(s, f, m) \
379 (&(const struct arg){ \
380 .offset = offsetof(s, f), \
381 .size = sizeof(((s *)0)->f), \
382 .mask = (const void *)(m), \
385 /** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */
386 #define ARGS_ENTRY_MASK_HTON(s, f, m) \
387 (&(const struct arg){ \
389 .offset = offsetof(s, f), \
390 .size = sizeof(((s *)0)->f), \
391 .mask = (const void *)(m), \
394 /** Static initializer for ARGS() to target a pointer. */
395 #define ARGS_ENTRY_PTR(s, f) \
396 (&(const struct arg){ \
397 .size = sizeof(*((s *)0)->f), \
400 /** Static initializer for ARGS() with arbitrary offset and size. */
401 #define ARGS_ENTRY_ARB(o, s) \
402 (&(const struct arg){ \
407 /** Same as ARGS_ENTRY_ARB() with bounded values. */
408 #define ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
409 (&(const struct arg){ \
417 /** Same as ARGS_ENTRY() using network byte ordering. */
418 #define ARGS_ENTRY_HTON(s, f) \
419 (&(const struct arg){ \
421 .offset = offsetof(s, f), \
422 .size = sizeof(((s *)0)->f), \
425 /** Parser output buffer layout expected by cmd_flow_parsed(). */
427 enum index command; /**< Flow command. */
428 portid_t port; /**< Affected port ID. */
431 struct rte_flow_attr attr;
432 struct rte_flow_item *pattern;
433 struct rte_flow_action *actions;
437 } vc; /**< Validate/create arguments. */
441 } destroy; /**< Destroy arguments. */
444 struct rte_flow_action action;
445 } query; /**< Query arguments. */
449 } list; /**< List arguments. */
452 } isolate; /**< Isolated mode arguments. */
453 } args; /**< Command arguments. */
456 /** Private data for pattern items. */
457 struct parse_item_priv {
458 enum rte_flow_item_type type; /**< Item type. */
459 uint32_t size; /**< Size of item specification structure. */
462 #define PRIV_ITEM(t, s) \
463 (&(const struct parse_item_priv){ \
464 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
468 /** Private data for actions. */
469 struct parse_action_priv {
470 enum rte_flow_action_type type; /**< Action type. */
471 uint32_t size; /**< Size of action configuration structure. */
474 #define PRIV_ACTION(t, s) \
475 (&(const struct parse_action_priv){ \
476 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
480 static const enum index next_vc_attr[] = {
490 static const enum index next_destroy_attr[] = {
496 static const enum index next_list_attr[] = {
502 static const enum index item_param[] = {
511 static const enum index next_item[] = {
547 ITEM_ICMP6_ND_OPT_SLA_ETH,
548 ITEM_ICMP6_ND_OPT_TLA_ETH,
552 static const enum index item_fuzzy[] = {
558 static const enum index item_any[] = {
564 static const enum index item_vf[] = {
570 static const enum index item_phy_port[] = {
576 static const enum index item_port_id[] = {
582 static const enum index item_mark[] = {
588 static const enum index item_raw[] = {
598 static const enum index item_eth[] = {
606 static const enum index item_vlan[] = {
611 ITEM_VLAN_INNER_TYPE,
616 static const enum index item_ipv4[] = {
626 static const enum index item_ipv6[] = {
637 static const enum index item_icmp[] = {
644 static const enum index item_udp[] = {
651 static const enum index item_tcp[] = {
659 static const enum index item_sctp[] = {
668 static const enum index item_vxlan[] = {
674 static const enum index item_e_tag[] = {
675 ITEM_E_TAG_GRP_ECID_B,
680 static const enum index item_nvgre[] = {
686 static const enum index item_mpls[] = {
692 static const enum index item_gre[] = {
698 static const enum index item_gtp[] = {
704 static const enum index item_geneve[] = {
711 static const enum index item_vxlan_gpe[] = {
717 static const enum index item_arp_eth_ipv4[] = {
718 ITEM_ARP_ETH_IPV4_SHA,
719 ITEM_ARP_ETH_IPV4_SPA,
720 ITEM_ARP_ETH_IPV4_THA,
721 ITEM_ARP_ETH_IPV4_TPA,
726 static const enum index item_ipv6_ext[] = {
727 ITEM_IPV6_EXT_NEXT_HDR,
732 static const enum index item_icmp6[] = {
739 static const enum index item_icmp6_nd_ns[] = {
740 ITEM_ICMP6_ND_NS_TARGET_ADDR,
745 static const enum index item_icmp6_nd_na[] = {
746 ITEM_ICMP6_ND_NA_TARGET_ADDR,
751 static const enum index item_icmp6_nd_opt[] = {
752 ITEM_ICMP6_ND_OPT_TYPE,
757 static const enum index item_icmp6_nd_opt_sla_eth[] = {
758 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
763 static const enum index item_icmp6_nd_opt_tla_eth[] = {
764 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
769 static const enum index next_action[] = {
785 ACTION_OF_SET_MPLS_TTL,
786 ACTION_OF_DEC_MPLS_TTL,
787 ACTION_OF_SET_NW_TTL,
788 ACTION_OF_DEC_NW_TTL,
789 ACTION_OF_COPY_TTL_OUT,
790 ACTION_OF_COPY_TTL_IN,
793 ACTION_OF_SET_VLAN_VID,
794 ACTION_OF_SET_VLAN_PCP,
802 static const enum index action_mark[] = {
808 static const enum index action_queue[] = {
814 static const enum index action_count[] = {
821 static const enum index action_rss[] = {
832 static const enum index action_vf[] = {
839 static const enum index action_phy_port[] = {
840 ACTION_PHY_PORT_ORIGINAL,
841 ACTION_PHY_PORT_INDEX,
846 static const enum index action_port_id[] = {
847 ACTION_PORT_ID_ORIGINAL,
853 static const enum index action_meter[] = {
859 static const enum index action_of_set_mpls_ttl[] = {
860 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
865 static const enum index action_of_set_nw_ttl[] = {
866 ACTION_OF_SET_NW_TTL_NW_TTL,
871 static const enum index action_of_push_vlan[] = {
872 ACTION_OF_PUSH_VLAN_ETHERTYPE,
877 static const enum index action_of_set_vlan_vid[] = {
878 ACTION_OF_SET_VLAN_VID_VLAN_VID,
883 static const enum index action_of_set_vlan_pcp[] = {
884 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
889 static const enum index action_of_pop_mpls[] = {
890 ACTION_OF_POP_MPLS_ETHERTYPE,
895 static const enum index action_of_push_mpls[] = {
896 ACTION_OF_PUSH_MPLS_ETHERTYPE,
901 static const enum index action_jump[] = {
907 static int parse_init(struct context *, const struct token *,
908 const char *, unsigned int,
909 void *, unsigned int);
910 static int parse_vc(struct context *, const struct token *,
911 const char *, unsigned int,
912 void *, unsigned int);
913 static int parse_vc_spec(struct context *, const struct token *,
914 const char *, unsigned int, void *, unsigned int);
915 static int parse_vc_conf(struct context *, const struct token *,
916 const char *, unsigned int, void *, unsigned int);
917 static int parse_vc_action_rss(struct context *, const struct token *,
918 const char *, unsigned int, void *,
920 static int parse_vc_action_rss_func(struct context *, const struct token *,
921 const char *, unsigned int, void *,
923 static int parse_vc_action_rss_type(struct context *, const struct token *,
924 const char *, unsigned int, void *,
926 static int parse_vc_action_rss_queue(struct context *, const struct token *,
927 const char *, unsigned int, void *,
929 static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
930 const char *, unsigned int, void *,
932 static int parse_destroy(struct context *, const struct token *,
933 const char *, unsigned int,
934 void *, unsigned int);
935 static int parse_flush(struct context *, const struct token *,
936 const char *, unsigned int,
937 void *, unsigned int);
938 static int parse_query(struct context *, const struct token *,
939 const char *, unsigned int,
940 void *, unsigned int);
941 static int parse_action(struct context *, const struct token *,
942 const char *, unsigned int,
943 void *, unsigned int);
944 static int parse_list(struct context *, const struct token *,
945 const char *, unsigned int,
946 void *, unsigned int);
947 static int parse_isolate(struct context *, const struct token *,
948 const char *, unsigned int,
949 void *, unsigned int);
950 static int parse_int(struct context *, const struct token *,
951 const char *, unsigned int,
952 void *, unsigned int);
953 static int parse_prefix(struct context *, const struct token *,
954 const char *, unsigned int,
955 void *, unsigned int);
956 static int parse_boolean(struct context *, const struct token *,
957 const char *, unsigned int,
958 void *, unsigned int);
959 static int parse_string(struct context *, const struct token *,
960 const char *, unsigned int,
961 void *, unsigned int);
962 static int parse_mac_addr(struct context *, const struct token *,
963 const char *, unsigned int,
964 void *, unsigned int);
965 static int parse_ipv4_addr(struct context *, const struct token *,
966 const char *, unsigned int,
967 void *, unsigned int);
968 static int parse_ipv6_addr(struct context *, const struct token *,
969 const char *, unsigned int,
970 void *, unsigned int);
971 static int parse_port(struct context *, const struct token *,
972 const char *, unsigned int,
973 void *, unsigned int);
974 static int comp_none(struct context *, const struct token *,
975 unsigned int, char *, unsigned int);
976 static int comp_boolean(struct context *, const struct token *,
977 unsigned int, char *, unsigned int);
978 static int comp_action(struct context *, const struct token *,
979 unsigned int, char *, unsigned int);
980 static int comp_port(struct context *, const struct token *,
981 unsigned int, char *, unsigned int);
982 static int comp_rule_id(struct context *, const struct token *,
983 unsigned int, char *, unsigned int);
984 static int comp_vc_action_rss_type(struct context *, const struct token *,
985 unsigned int, char *, unsigned int);
986 static int comp_vc_action_rss_queue(struct context *, const struct token *,
987 unsigned int, char *, unsigned int);
989 /** Token definitions. */
990 static const struct token token_list[] = {
991 /* Special tokens. */
994 .help = "null entry, abused as the entry point",
995 .next = NEXT(NEXT_ENTRY(FLOW)),
1000 .help = "command may end here",
1002 /* Common tokens. */
1006 .help = "integer value",
1011 .name = "{unsigned}",
1013 .help = "unsigned integer value",
1020 .help = "prefix length for bit-mask",
1021 .call = parse_prefix,
1025 .name = "{boolean}",
1027 .help = "any boolean value",
1028 .call = parse_boolean,
1029 .comp = comp_boolean,
1034 .help = "fixed string",
1035 .call = parse_string,
1039 .name = "{MAC address}",
1041 .help = "standard MAC address notation",
1042 .call = parse_mac_addr,
1046 .name = "{IPv4 address}",
1047 .type = "IPV4 ADDRESS",
1048 .help = "standard IPv4 address notation",
1049 .call = parse_ipv4_addr,
1053 .name = "{IPv6 address}",
1054 .type = "IPV6 ADDRESS",
1055 .help = "standard IPv6 address notation",
1056 .call = parse_ipv6_addr,
1060 .name = "{rule id}",
1062 .help = "rule identifier",
1064 .comp = comp_rule_id,
1067 .name = "{port_id}",
1069 .help = "port identifier",
1074 .name = "{group_id}",
1076 .help = "group identifier",
1080 [PRIORITY_LEVEL] = {
1083 .help = "priority level",
1087 /* Top-level command. */
1090 .type = "{command} {port_id} [{arg} [...]]",
1091 .help = "manage ingress/egress flow rules",
1092 .next = NEXT(NEXT_ENTRY
1102 /* Sub-level commands. */
1105 .help = "check whether a flow rule can be created",
1106 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1107 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1112 .help = "create a flow rule",
1113 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1114 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1119 .help = "destroy specific flow rules",
1120 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
1121 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1122 .call = parse_destroy,
1126 .help = "destroy all flow rules",
1127 .next = NEXT(NEXT_ENTRY(PORT_ID)),
1128 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1129 .call = parse_flush,
1133 .help = "query an existing flow rule",
1134 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
1135 NEXT_ENTRY(RULE_ID),
1136 NEXT_ENTRY(PORT_ID)),
1137 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action.type),
1138 ARGS_ENTRY(struct buffer, args.query.rule),
1139 ARGS_ENTRY(struct buffer, port)),
1140 .call = parse_query,
1144 .help = "list existing flow rules",
1145 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
1146 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1151 .help = "restrict ingress traffic to the defined flow rules",
1152 .next = NEXT(NEXT_ENTRY(BOOLEAN),
1153 NEXT_ENTRY(PORT_ID)),
1154 .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
1155 ARGS_ENTRY(struct buffer, port)),
1156 .call = parse_isolate,
1158 /* Destroy arguments. */
1161 .help = "specify a rule identifier",
1162 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
1163 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
1164 .call = parse_destroy,
1166 /* Query arguments. */
1170 .help = "action to query, must be part of the rule",
1171 .call = parse_action,
1172 .comp = comp_action,
1174 /* List arguments. */
1177 .help = "specify a group",
1178 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
1179 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
1182 /* Validate/create attributes. */
1185 .help = "specify a group",
1186 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
1187 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
1192 .help = "specify a priority level",
1193 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
1194 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
1199 .help = "affect rule to ingress",
1200 .next = NEXT(next_vc_attr),
1205 .help = "affect rule to egress",
1206 .next = NEXT(next_vc_attr),
1211 .help = "apply rule directly to endpoints found in pattern",
1212 .next = NEXT(next_vc_attr),
1215 /* Validate/create pattern. */
1218 .help = "submit a list of pattern items",
1219 .next = NEXT(next_item),
1224 .help = "match value perfectly (with full bit-mask)",
1225 .call = parse_vc_spec,
1227 [ITEM_PARAM_SPEC] = {
1229 .help = "match value according to configured bit-mask",
1230 .call = parse_vc_spec,
1232 [ITEM_PARAM_LAST] = {
1234 .help = "specify upper bound to establish a range",
1235 .call = parse_vc_spec,
1237 [ITEM_PARAM_MASK] = {
1239 .help = "specify bit-mask with relevant bits set to one",
1240 .call = parse_vc_spec,
1242 [ITEM_PARAM_PREFIX] = {
1244 .help = "generate bit-mask from a prefix length",
1245 .call = parse_vc_spec,
1249 .help = "specify next pattern item",
1250 .next = NEXT(next_item),
1254 .help = "end list of pattern items",
1255 .priv = PRIV_ITEM(END, 0),
1256 .next = NEXT(NEXT_ENTRY(ACTIONS)),
1261 .help = "no-op pattern item",
1262 .priv = PRIV_ITEM(VOID, 0),
1263 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1268 .help = "perform actions when pattern does not match",
1269 .priv = PRIV_ITEM(INVERT, 0),
1270 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1275 .help = "match any protocol for the current layer",
1276 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
1277 .next = NEXT(item_any),
1282 .help = "number of layers covered",
1283 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
1284 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
1288 .help = "match traffic from/to the physical function",
1289 .priv = PRIV_ITEM(PF, 0),
1290 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1295 .help = "match traffic from/to a virtual function ID",
1296 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
1297 .next = NEXT(item_vf),
1303 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
1304 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
1308 .help = "match traffic from/to a specific physical port",
1309 .priv = PRIV_ITEM(PHY_PORT,
1310 sizeof(struct rte_flow_item_phy_port)),
1311 .next = NEXT(item_phy_port),
1314 [ITEM_PHY_PORT_INDEX] = {
1316 .help = "physical port index",
1317 .next = NEXT(item_phy_port, NEXT_ENTRY(UNSIGNED), item_param),
1318 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_phy_port, index)),
1322 .help = "match traffic from/to a given DPDK port ID",
1323 .priv = PRIV_ITEM(PORT_ID,
1324 sizeof(struct rte_flow_item_port_id)),
1325 .next = NEXT(item_port_id),
1328 [ITEM_PORT_ID_ID] = {
1330 .help = "DPDK port ID",
1331 .next = NEXT(item_port_id, NEXT_ENTRY(UNSIGNED), item_param),
1332 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port_id, id)),
1336 .help = "match traffic against value set in previously matched rule",
1337 .priv = PRIV_ITEM(MARK, sizeof(struct rte_flow_item_mark)),
1338 .next = NEXT(item_mark),
1343 .help = "Integer value to match against",
1344 .next = NEXT(item_mark, NEXT_ENTRY(UNSIGNED), item_param),
1345 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_mark, id)),
1349 .help = "match an arbitrary byte string",
1350 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
1351 .next = NEXT(item_raw),
1354 [ITEM_RAW_RELATIVE] = {
1356 .help = "look for pattern after the previous item",
1357 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1358 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1361 [ITEM_RAW_SEARCH] = {
1363 .help = "search pattern from offset (see also limit)",
1364 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1365 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1368 [ITEM_RAW_OFFSET] = {
1370 .help = "absolute or relative offset for pattern",
1371 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
1372 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
1374 [ITEM_RAW_LIMIT] = {
1376 .help = "search area limit for start of pattern",
1377 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
1378 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
1380 [ITEM_RAW_PATTERN] = {
1382 .help = "byte string to look for",
1383 .next = NEXT(item_raw,
1385 NEXT_ENTRY(ITEM_PARAM_IS,
1388 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, pattern),
1389 ARGS_ENTRY(struct rte_flow_item_raw, length),
1390 ARGS_ENTRY_ARB(sizeof(struct rte_flow_item_raw),
1391 ITEM_RAW_PATTERN_SIZE)),
1395 .help = "match Ethernet header",
1396 .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
1397 .next = NEXT(item_eth),
1402 .help = "destination MAC",
1403 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1404 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, dst)),
1408 .help = "source MAC",
1409 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1410 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, src)),
1414 .help = "EtherType",
1415 .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
1416 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)),
1420 .help = "match 802.1Q/ad VLAN tag",
1421 .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
1422 .next = NEXT(item_vlan),
1427 .help = "tag control information",
1428 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1429 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
1433 .help = "priority code point",
1434 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1435 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1440 .help = "drop eligible indicator",
1441 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1442 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1447 .help = "VLAN identifier",
1448 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1449 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1452 [ITEM_VLAN_INNER_TYPE] = {
1453 .name = "inner_type",
1454 .help = "inner EtherType",
1455 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1456 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan,
1461 .help = "match IPv4 header",
1462 .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
1463 .next = NEXT(item_ipv4),
1468 .help = "type of service",
1469 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1470 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1471 hdr.type_of_service)),
1475 .help = "time to live",
1476 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1477 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1480 [ITEM_IPV4_PROTO] = {
1482 .help = "next protocol ID",
1483 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1484 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1485 hdr.next_proto_id)),
1489 .help = "source address",
1490 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1491 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1496 .help = "destination address",
1497 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1498 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1503 .help = "match IPv6 header",
1504 .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
1505 .next = NEXT(item_ipv6),
1510 .help = "traffic class",
1511 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1512 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1514 "\x0f\xf0\x00\x00")),
1516 [ITEM_IPV6_FLOW] = {
1518 .help = "flow label",
1519 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1520 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1522 "\x00\x0f\xff\xff")),
1524 [ITEM_IPV6_PROTO] = {
1526 .help = "protocol (next header)",
1527 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1528 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1533 .help = "hop limit",
1534 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1535 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1540 .help = "source address",
1541 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1542 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1547 .help = "destination address",
1548 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1549 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1554 .help = "match ICMP header",
1555 .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
1556 .next = NEXT(item_icmp),
1559 [ITEM_ICMP_TYPE] = {
1561 .help = "ICMP packet type",
1562 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1563 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1566 [ITEM_ICMP_CODE] = {
1568 .help = "ICMP packet code",
1569 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1570 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1575 .help = "match UDP header",
1576 .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
1577 .next = NEXT(item_udp),
1582 .help = "UDP source port",
1583 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1584 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1589 .help = "UDP destination port",
1590 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1591 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1596 .help = "match TCP header",
1597 .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
1598 .next = NEXT(item_tcp),
1603 .help = "TCP source port",
1604 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1605 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1610 .help = "TCP destination port",
1611 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1612 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1615 [ITEM_TCP_FLAGS] = {
1617 .help = "TCP flags",
1618 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1619 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1624 .help = "match SCTP header",
1625 .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
1626 .next = NEXT(item_sctp),
1631 .help = "SCTP source port",
1632 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1633 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1638 .help = "SCTP destination port",
1639 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1640 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1645 .help = "validation tag",
1646 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1647 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1650 [ITEM_SCTP_CKSUM] = {
1653 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1654 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1659 .help = "match VXLAN header",
1660 .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
1661 .next = NEXT(item_vxlan),
1664 [ITEM_VXLAN_VNI] = {
1666 .help = "VXLAN identifier",
1667 .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
1668 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)),
1672 .help = "match E-Tag header",
1673 .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
1674 .next = NEXT(item_e_tag),
1677 [ITEM_E_TAG_GRP_ECID_B] = {
1678 .name = "grp_ecid_b",
1679 .help = "GRP and E-CID base",
1680 .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param),
1681 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag,
1687 .help = "match NVGRE header",
1688 .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
1689 .next = NEXT(item_nvgre),
1692 [ITEM_NVGRE_TNI] = {
1694 .help = "virtual subnet ID",
1695 .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param),
1696 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)),
1700 .help = "match MPLS header",
1701 .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
1702 .next = NEXT(item_mpls),
1705 [ITEM_MPLS_LABEL] = {
1707 .help = "MPLS label",
1708 .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
1709 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
1715 .help = "match GRE header",
1716 .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
1717 .next = NEXT(item_gre),
1720 [ITEM_GRE_PROTO] = {
1722 .help = "GRE protocol type",
1723 .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
1724 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
1729 .help = "fuzzy pattern match, expect faster than default",
1730 .priv = PRIV_ITEM(FUZZY,
1731 sizeof(struct rte_flow_item_fuzzy)),
1732 .next = NEXT(item_fuzzy),
1735 [ITEM_FUZZY_THRESH] = {
1737 .help = "match accuracy threshold",
1738 .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param),
1739 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy,
1744 .help = "match GTP header",
1745 .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
1746 .next = NEXT(item_gtp),
1751 .help = "tunnel endpoint identifier",
1752 .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
1753 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)),
1757 .help = "match GTP header",
1758 .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
1759 .next = NEXT(item_gtp),
1764 .help = "match GTP header",
1765 .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
1766 .next = NEXT(item_gtp),
1771 .help = "match GENEVE header",
1772 .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
1773 .next = NEXT(item_geneve),
1776 [ITEM_GENEVE_VNI] = {
1778 .help = "virtual network identifier",
1779 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
1780 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)),
1782 [ITEM_GENEVE_PROTO] = {
1784 .help = "GENEVE protocol type",
1785 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
1786 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
1789 [ITEM_VXLAN_GPE] = {
1790 .name = "vxlan-gpe",
1791 .help = "match VXLAN-GPE header",
1792 .priv = PRIV_ITEM(VXLAN_GPE,
1793 sizeof(struct rte_flow_item_vxlan_gpe)),
1794 .next = NEXT(item_vxlan_gpe),
1797 [ITEM_VXLAN_GPE_VNI] = {
1799 .help = "VXLAN-GPE identifier",
1800 .next = NEXT(item_vxlan_gpe, NEXT_ENTRY(UNSIGNED), item_param),
1801 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan_gpe,
1804 [ITEM_ARP_ETH_IPV4] = {
1805 .name = "arp_eth_ipv4",
1806 .help = "match ARP header for Ethernet/IPv4",
1807 .priv = PRIV_ITEM(ARP_ETH_IPV4,
1808 sizeof(struct rte_flow_item_arp_eth_ipv4)),
1809 .next = NEXT(item_arp_eth_ipv4),
1812 [ITEM_ARP_ETH_IPV4_SHA] = {
1814 .help = "sender hardware address",
1815 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
1817 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1820 [ITEM_ARP_ETH_IPV4_SPA] = {
1822 .help = "sender IPv4 address",
1823 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
1825 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1828 [ITEM_ARP_ETH_IPV4_THA] = {
1830 .help = "target hardware address",
1831 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
1833 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1836 [ITEM_ARP_ETH_IPV4_TPA] = {
1838 .help = "target IPv4 address",
1839 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
1841 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1846 .help = "match presence of any IPv6 extension header",
1847 .priv = PRIV_ITEM(IPV6_EXT,
1848 sizeof(struct rte_flow_item_ipv6_ext)),
1849 .next = NEXT(item_ipv6_ext),
1852 [ITEM_IPV6_EXT_NEXT_HDR] = {
1854 .help = "next header",
1855 .next = NEXT(item_ipv6_ext, NEXT_ENTRY(UNSIGNED), item_param),
1856 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext,
1861 .help = "match any ICMPv6 header",
1862 .priv = PRIV_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)),
1863 .next = NEXT(item_icmp6),
1866 [ITEM_ICMP6_TYPE] = {
1868 .help = "ICMPv6 type",
1869 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
1870 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
1873 [ITEM_ICMP6_CODE] = {
1875 .help = "ICMPv6 code",
1876 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
1877 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
1880 [ITEM_ICMP6_ND_NS] = {
1881 .name = "icmp6_nd_ns",
1882 .help = "match ICMPv6 neighbor discovery solicitation",
1883 .priv = PRIV_ITEM(ICMP6_ND_NS,
1884 sizeof(struct rte_flow_item_icmp6_nd_ns)),
1885 .next = NEXT(item_icmp6_nd_ns),
1888 [ITEM_ICMP6_ND_NS_TARGET_ADDR] = {
1889 .name = "target_addr",
1890 .help = "target address",
1891 .next = NEXT(item_icmp6_nd_ns, NEXT_ENTRY(IPV6_ADDR),
1893 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_ns,
1896 [ITEM_ICMP6_ND_NA] = {
1897 .name = "icmp6_nd_na",
1898 .help = "match ICMPv6 neighbor discovery advertisement",
1899 .priv = PRIV_ITEM(ICMP6_ND_NA,
1900 sizeof(struct rte_flow_item_icmp6_nd_na)),
1901 .next = NEXT(item_icmp6_nd_na),
1904 [ITEM_ICMP6_ND_NA_TARGET_ADDR] = {
1905 .name = "target_addr",
1906 .help = "target address",
1907 .next = NEXT(item_icmp6_nd_na, NEXT_ENTRY(IPV6_ADDR),
1909 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_na,
1912 [ITEM_ICMP6_ND_OPT] = {
1913 .name = "icmp6_nd_opt",
1914 .help = "match presence of any ICMPv6 neighbor discovery"
1916 .priv = PRIV_ITEM(ICMP6_ND_OPT,
1917 sizeof(struct rte_flow_item_icmp6_nd_opt)),
1918 .next = NEXT(item_icmp6_nd_opt),
1921 [ITEM_ICMP6_ND_OPT_TYPE] = {
1923 .help = "ND option type",
1924 .next = NEXT(item_icmp6_nd_opt, NEXT_ENTRY(UNSIGNED),
1926 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_opt,
1929 [ITEM_ICMP6_ND_OPT_SLA_ETH] = {
1930 .name = "icmp6_nd_opt_sla_eth",
1931 .help = "match ICMPv6 neighbor discovery source Ethernet"
1932 " link-layer address option",
1934 (ICMP6_ND_OPT_SLA_ETH,
1935 sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),
1936 .next = NEXT(item_icmp6_nd_opt_sla_eth),
1939 [ITEM_ICMP6_ND_OPT_SLA_ETH_SLA] = {
1941 .help = "source Ethernet LLA",
1942 .next = NEXT(item_icmp6_nd_opt_sla_eth, NEXT_ENTRY(MAC_ADDR),
1944 .args = ARGS(ARGS_ENTRY_HTON
1945 (struct rte_flow_item_icmp6_nd_opt_sla_eth, sla)),
1947 [ITEM_ICMP6_ND_OPT_TLA_ETH] = {
1948 .name = "icmp6_nd_opt_tla_eth",
1949 .help = "match ICMPv6 neighbor discovery target Ethernet"
1950 " link-layer address option",
1952 (ICMP6_ND_OPT_TLA_ETH,
1953 sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),
1954 .next = NEXT(item_icmp6_nd_opt_tla_eth),
1957 [ITEM_ICMP6_ND_OPT_TLA_ETH_TLA] = {
1959 .help = "target Ethernet LLA",
1960 .next = NEXT(item_icmp6_nd_opt_tla_eth, NEXT_ENTRY(MAC_ADDR),
1962 .args = ARGS(ARGS_ENTRY_HTON
1963 (struct rte_flow_item_icmp6_nd_opt_tla_eth, tla)),
1966 /* Validate/create actions. */
1969 .help = "submit a list of associated actions",
1970 .next = NEXT(next_action),
1975 .help = "specify next action",
1976 .next = NEXT(next_action),
1980 .help = "end list of actions",
1981 .priv = PRIV_ACTION(END, 0),
1986 .help = "no-op action",
1987 .priv = PRIV_ACTION(VOID, 0),
1988 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
1991 [ACTION_PASSTHRU] = {
1993 .help = "let subsequent rule process matched packets",
1994 .priv = PRIV_ACTION(PASSTHRU, 0),
1995 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2000 .help = "redirect traffic to a given group",
2001 .priv = PRIV_ACTION(JUMP, sizeof(struct rte_flow_action_jump)),
2002 .next = NEXT(action_jump),
2005 [ACTION_JUMP_GROUP] = {
2007 .help = "group to redirect traffic to",
2008 .next = NEXT(action_jump, NEXT_ENTRY(UNSIGNED)),
2009 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_jump, group)),
2010 .call = parse_vc_conf,
2014 .help = "attach 32 bit value to packets",
2015 .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
2016 .next = NEXT(action_mark),
2019 [ACTION_MARK_ID] = {
2021 .help = "32 bit value to return with packets",
2022 .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
2023 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)),
2024 .call = parse_vc_conf,
2028 .help = "flag packets",
2029 .priv = PRIV_ACTION(FLAG, 0),
2030 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2035 .help = "assign packets to a given queue index",
2036 .priv = PRIV_ACTION(QUEUE,
2037 sizeof(struct rte_flow_action_queue)),
2038 .next = NEXT(action_queue),
2041 [ACTION_QUEUE_INDEX] = {
2043 .help = "queue index to use",
2044 .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
2045 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)),
2046 .call = parse_vc_conf,
2050 .help = "drop packets (note: passthru has priority)",
2051 .priv = PRIV_ACTION(DROP, 0),
2052 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2057 .help = "enable counters for this rule",
2058 .priv = PRIV_ACTION(COUNT,
2059 sizeof(struct rte_flow_action_count)),
2060 .next = NEXT(action_count),
2063 [ACTION_COUNT_ID] = {
2064 .name = "identifier",
2065 .help = "counter identifier to use",
2066 .next = NEXT(action_count, NEXT_ENTRY(UNSIGNED)),
2067 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_count, id)),
2068 .call = parse_vc_conf,
2070 [ACTION_COUNT_SHARED] = {
2072 .help = "shared counter",
2073 .next = NEXT(action_count, NEXT_ENTRY(BOOLEAN)),
2074 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_count,
2076 .call = parse_vc_conf,
2080 .help = "spread packets among several queues",
2081 .priv = PRIV_ACTION(RSS, sizeof(struct action_rss_data)),
2082 .next = NEXT(action_rss),
2083 .call = parse_vc_action_rss,
2085 [ACTION_RSS_FUNC] = {
2087 .help = "RSS hash function to apply",
2088 .next = NEXT(action_rss,
2089 NEXT_ENTRY(ACTION_RSS_FUNC_DEFAULT,
2090 ACTION_RSS_FUNC_TOEPLITZ,
2091 ACTION_RSS_FUNC_SIMPLE_XOR)),
2093 [ACTION_RSS_FUNC_DEFAULT] = {
2095 .help = "default hash function",
2096 .call = parse_vc_action_rss_func,
2098 [ACTION_RSS_FUNC_TOEPLITZ] = {
2100 .help = "Toeplitz hash function",
2101 .call = parse_vc_action_rss_func,
2103 [ACTION_RSS_FUNC_SIMPLE_XOR] = {
2104 .name = "simple_xor",
2105 .help = "simple XOR hash function",
2106 .call = parse_vc_action_rss_func,
2108 [ACTION_RSS_LEVEL] = {
2110 .help = "encapsulation level for \"types\"",
2111 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2112 .args = ARGS(ARGS_ENTRY_ARB
2113 (offsetof(struct action_rss_data, conf) +
2114 offsetof(struct rte_flow_action_rss, level),
2115 sizeof(((struct rte_flow_action_rss *)0)->
2118 [ACTION_RSS_TYPES] = {
2120 .help = "specific RSS hash types",
2121 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_TYPE)),
2123 [ACTION_RSS_TYPE] = {
2125 .help = "RSS hash type",
2126 .call = parse_vc_action_rss_type,
2127 .comp = comp_vc_action_rss_type,
2129 [ACTION_RSS_KEY] = {
2131 .help = "RSS hash key",
2132 .next = NEXT(action_rss, NEXT_ENTRY(STRING)),
2133 .args = ARGS(ARGS_ENTRY_ARB(0, 0),
2135 (offsetof(struct action_rss_data, conf) +
2136 offsetof(struct rte_flow_action_rss, key_len),
2137 sizeof(((struct rte_flow_action_rss *)0)->
2139 ARGS_ENTRY(struct action_rss_data, key)),
2141 [ACTION_RSS_KEY_LEN] = {
2143 .help = "RSS hash key length in bytes",
2144 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2145 .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
2146 (offsetof(struct action_rss_data, conf) +
2147 offsetof(struct rte_flow_action_rss, key_len),
2148 sizeof(((struct rte_flow_action_rss *)0)->
2151 RSS_HASH_KEY_LENGTH)),
2153 [ACTION_RSS_QUEUES] = {
2155 .help = "queue indices to use",
2156 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
2157 .call = parse_vc_conf,
2159 [ACTION_RSS_QUEUE] = {
2161 .help = "queue index",
2162 .call = parse_vc_action_rss_queue,
2163 .comp = comp_vc_action_rss_queue,
2167 .help = "direct traffic to physical function",
2168 .priv = PRIV_ACTION(PF, 0),
2169 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2174 .help = "direct traffic to a virtual function ID",
2175 .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
2176 .next = NEXT(action_vf),
2179 [ACTION_VF_ORIGINAL] = {
2181 .help = "use original VF ID if possible",
2182 .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
2183 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
2185 .call = parse_vc_conf,
2190 .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
2191 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
2192 .call = parse_vc_conf,
2194 [ACTION_PHY_PORT] = {
2196 .help = "direct packets to physical port index",
2197 .priv = PRIV_ACTION(PHY_PORT,
2198 sizeof(struct rte_flow_action_phy_port)),
2199 .next = NEXT(action_phy_port),
2202 [ACTION_PHY_PORT_ORIGINAL] = {
2204 .help = "use original port index if possible",
2205 .next = NEXT(action_phy_port, NEXT_ENTRY(BOOLEAN)),
2206 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_phy_port,
2208 .call = parse_vc_conf,
2210 [ACTION_PHY_PORT_INDEX] = {
2212 .help = "physical port index",
2213 .next = NEXT(action_phy_port, NEXT_ENTRY(UNSIGNED)),
2214 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_phy_port,
2216 .call = parse_vc_conf,
2218 [ACTION_PORT_ID] = {
2220 .help = "direct matching traffic to a given DPDK port ID",
2221 .priv = PRIV_ACTION(PORT_ID,
2222 sizeof(struct rte_flow_action_port_id)),
2223 .next = NEXT(action_port_id),
2226 [ACTION_PORT_ID_ORIGINAL] = {
2228 .help = "use original DPDK port ID if possible",
2229 .next = NEXT(action_port_id, NEXT_ENTRY(BOOLEAN)),
2230 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_port_id,
2232 .call = parse_vc_conf,
2234 [ACTION_PORT_ID_ID] = {
2236 .help = "DPDK port ID",
2237 .next = NEXT(action_port_id, NEXT_ENTRY(UNSIGNED)),
2238 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_port_id, id)),
2239 .call = parse_vc_conf,
2243 .help = "meter the directed packets at given id",
2244 .priv = PRIV_ACTION(METER,
2245 sizeof(struct rte_flow_action_meter)),
2246 .next = NEXT(action_meter),
2249 [ACTION_METER_ID] = {
2251 .help = "meter id to use",
2252 .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
2253 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
2254 .call = parse_vc_conf,
2256 [ACTION_OF_SET_MPLS_TTL] = {
2257 .name = "of_set_mpls_ttl",
2258 .help = "OpenFlow's OFPAT_SET_MPLS_TTL",
2261 sizeof(struct rte_flow_action_of_set_mpls_ttl)),
2262 .next = NEXT(action_of_set_mpls_ttl),
2265 [ACTION_OF_SET_MPLS_TTL_MPLS_TTL] = {
2268 .next = NEXT(action_of_set_mpls_ttl, NEXT_ENTRY(UNSIGNED)),
2269 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_mpls_ttl,
2271 .call = parse_vc_conf,
2273 [ACTION_OF_DEC_MPLS_TTL] = {
2274 .name = "of_dec_mpls_ttl",
2275 .help = "OpenFlow's OFPAT_DEC_MPLS_TTL",
2276 .priv = PRIV_ACTION(OF_DEC_MPLS_TTL, 0),
2277 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2280 [ACTION_OF_SET_NW_TTL] = {
2281 .name = "of_set_nw_ttl",
2282 .help = "OpenFlow's OFPAT_SET_NW_TTL",
2285 sizeof(struct rte_flow_action_of_set_nw_ttl)),
2286 .next = NEXT(action_of_set_nw_ttl),
2289 [ACTION_OF_SET_NW_TTL_NW_TTL] = {
2292 .next = NEXT(action_of_set_nw_ttl, NEXT_ENTRY(UNSIGNED)),
2293 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_nw_ttl,
2295 .call = parse_vc_conf,
2297 [ACTION_OF_DEC_NW_TTL] = {
2298 .name = "of_dec_nw_ttl",
2299 .help = "OpenFlow's OFPAT_DEC_NW_TTL",
2300 .priv = PRIV_ACTION(OF_DEC_NW_TTL, 0),
2301 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2304 [ACTION_OF_COPY_TTL_OUT] = {
2305 .name = "of_copy_ttl_out",
2306 .help = "OpenFlow's OFPAT_COPY_TTL_OUT",
2307 .priv = PRIV_ACTION(OF_COPY_TTL_OUT, 0),
2308 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2311 [ACTION_OF_COPY_TTL_IN] = {
2312 .name = "of_copy_ttl_in",
2313 .help = "OpenFlow's OFPAT_COPY_TTL_IN",
2314 .priv = PRIV_ACTION(OF_COPY_TTL_IN, 0),
2315 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2318 [ACTION_OF_POP_VLAN] = {
2319 .name = "of_pop_vlan",
2320 .help = "OpenFlow's OFPAT_POP_VLAN",
2321 .priv = PRIV_ACTION(OF_POP_VLAN, 0),
2322 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2325 [ACTION_OF_PUSH_VLAN] = {
2326 .name = "of_push_vlan",
2327 .help = "OpenFlow's OFPAT_PUSH_VLAN",
2330 sizeof(struct rte_flow_action_of_push_vlan)),
2331 .next = NEXT(action_of_push_vlan),
2334 [ACTION_OF_PUSH_VLAN_ETHERTYPE] = {
2335 .name = "ethertype",
2336 .help = "EtherType",
2337 .next = NEXT(action_of_push_vlan, NEXT_ENTRY(UNSIGNED)),
2338 .args = ARGS(ARGS_ENTRY_HTON
2339 (struct rte_flow_action_of_push_vlan,
2341 .call = parse_vc_conf,
2343 [ACTION_OF_SET_VLAN_VID] = {
2344 .name = "of_set_vlan_vid",
2345 .help = "OpenFlow's OFPAT_SET_VLAN_VID",
2348 sizeof(struct rte_flow_action_of_set_vlan_vid)),
2349 .next = NEXT(action_of_set_vlan_vid),
2352 [ACTION_OF_SET_VLAN_VID_VLAN_VID] = {
2355 .next = NEXT(action_of_set_vlan_vid, NEXT_ENTRY(UNSIGNED)),
2356 .args = ARGS(ARGS_ENTRY_HTON
2357 (struct rte_flow_action_of_set_vlan_vid,
2359 .call = parse_vc_conf,
2361 [ACTION_OF_SET_VLAN_PCP] = {
2362 .name = "of_set_vlan_pcp",
2363 .help = "OpenFlow's OFPAT_SET_VLAN_PCP",
2366 sizeof(struct rte_flow_action_of_set_vlan_pcp)),
2367 .next = NEXT(action_of_set_vlan_pcp),
2370 [ACTION_OF_SET_VLAN_PCP_VLAN_PCP] = {
2372 .help = "VLAN priority",
2373 .next = NEXT(action_of_set_vlan_pcp, NEXT_ENTRY(UNSIGNED)),
2374 .args = ARGS(ARGS_ENTRY_HTON
2375 (struct rte_flow_action_of_set_vlan_pcp,
2377 .call = parse_vc_conf,
2379 [ACTION_OF_POP_MPLS] = {
2380 .name = "of_pop_mpls",
2381 .help = "OpenFlow's OFPAT_POP_MPLS",
2382 .priv = PRIV_ACTION(OF_POP_MPLS,
2383 sizeof(struct rte_flow_action_of_pop_mpls)),
2384 .next = NEXT(action_of_pop_mpls),
2387 [ACTION_OF_POP_MPLS_ETHERTYPE] = {
2388 .name = "ethertype",
2389 .help = "EtherType",
2390 .next = NEXT(action_of_pop_mpls, NEXT_ENTRY(UNSIGNED)),
2391 .args = ARGS(ARGS_ENTRY_HTON
2392 (struct rte_flow_action_of_pop_mpls,
2394 .call = parse_vc_conf,
2396 [ACTION_OF_PUSH_MPLS] = {
2397 .name = "of_push_mpls",
2398 .help = "OpenFlow's OFPAT_PUSH_MPLS",
2401 sizeof(struct rte_flow_action_of_push_mpls)),
2402 .next = NEXT(action_of_push_mpls),
2405 [ACTION_OF_PUSH_MPLS_ETHERTYPE] = {
2406 .name = "ethertype",
2407 .help = "EtherType",
2408 .next = NEXT(action_of_push_mpls, NEXT_ENTRY(UNSIGNED)),
2409 .args = ARGS(ARGS_ENTRY_HTON
2410 (struct rte_flow_action_of_push_mpls,
2412 .call = parse_vc_conf,
2414 [ACTION_VXLAN_ENCAP] = {
2415 .name = "vxlan_encap",
2416 .help = "VXLAN encapsulation, uses configuration set by \"set"
2418 .priv = PRIV_ACTION(VXLAN_ENCAP,
2419 sizeof(struct action_vxlan_encap_data)),
2420 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2421 .call = parse_vc_action_vxlan_encap,
2423 [ACTION_VXLAN_DECAP] = {
2424 .name = "vxlan_decap",
2425 .help = "Performs a decapsulation action by stripping all"
2426 " headers of the VXLAN tunnel network overlay from the"
2428 .priv = PRIV_ACTION(VXLAN_DECAP, 0),
2429 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2434 /** Remove and return last entry from argument stack. */
2435 static const struct arg *
2436 pop_args(struct context *ctx)
2438 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
2441 /** Add entry on top of the argument stack. */
2443 push_args(struct context *ctx, const struct arg *arg)
2445 if (ctx->args_num == CTX_STACK_SIZE)
2447 ctx->args[ctx->args_num++] = arg;
2451 /** Spread value into buffer according to bit-mask. */
2453 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
2455 uint32_t i = arg->size;
2463 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
2472 unsigned int shift = 0;
2473 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
2475 for (shift = 0; arg->mask[i] >> shift; ++shift) {
2476 if (!(arg->mask[i] & (1 << shift)))
2481 *buf &= ~(1 << shift);
2482 *buf |= (val & 1) << shift;
2490 /** Compare a string with a partial one of a given length. */
2492 strcmp_partial(const char *full, const char *partial, size_t partial_len)
2494 int r = strncmp(full, partial, partial_len);
2498 if (strlen(full) <= partial_len)
2500 return full[partial_len];
2504 * Parse a prefix length and generate a bit-mask.
2506 * Last argument (ctx->args) is retrieved to determine mask size, storage
2507 * location and whether the result must use network byte ordering.
2510 parse_prefix(struct context *ctx, const struct token *token,
2511 const char *str, unsigned int len,
2512 void *buf, unsigned int size)
2514 const struct arg *arg = pop_args(ctx);
2515 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
2522 /* Argument is expected. */
2526 u = strtoumax(str, &end, 0);
2527 if (errno || (size_t)(end - str) != len)
2532 extra = arg_entry_bf_fill(NULL, 0, arg);
2541 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
2542 !arg_entry_bf_fill(ctx->objmask, -1, arg))
2549 if (bytes > size || bytes + !!extra > size)
2553 buf = (uint8_t *)ctx->object + arg->offset;
2554 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
2556 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
2557 memset(buf, 0x00, size - bytes);
2559 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
2563 memset(buf, 0xff, bytes);
2564 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
2566 ((uint8_t *)buf)[bytes] = conv[extra];
2569 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
2572 push_args(ctx, arg);
2576 /** Default parsing function for token name matching. */
2578 parse_default(struct context *ctx, const struct token *token,
2579 const char *str, unsigned int len,
2580 void *buf, unsigned int size)
2585 if (strcmp_partial(token->name, str, len))
2590 /** Parse flow command, initialize output buffer for subsequent tokens. */
2592 parse_init(struct context *ctx, const struct token *token,
2593 const char *str, unsigned int len,
2594 void *buf, unsigned int size)
2596 struct buffer *out = buf;
2598 /* Token name must match. */
2599 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2601 /* Nothing else to do if there is no buffer. */
2604 /* Make sure buffer is large enough. */
2605 if (size < sizeof(*out))
2607 /* Initialize buffer. */
2608 memset(out, 0x00, sizeof(*out));
2609 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
2612 ctx->objmask = NULL;
2616 /** Parse tokens for validate/create commands. */
2618 parse_vc(struct context *ctx, const struct token *token,
2619 const char *str, unsigned int len,
2620 void *buf, unsigned int size)
2622 struct buffer *out = buf;
2626 /* Token name must match. */
2627 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2629 /* Nothing else to do if there is no buffer. */
2632 if (!out->command) {
2633 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
2635 if (sizeof(*out) > size)
2637 out->command = ctx->curr;
2640 ctx->objmask = NULL;
2641 out->args.vc.data = (uint8_t *)out + size;
2645 ctx->object = &out->args.vc.attr;
2646 ctx->objmask = NULL;
2647 switch (ctx->curr) {
2652 out->args.vc.attr.ingress = 1;
2655 out->args.vc.attr.egress = 1;
2658 out->args.vc.attr.transfer = 1;
2661 out->args.vc.pattern =
2662 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
2664 ctx->object = out->args.vc.pattern;
2665 ctx->objmask = NULL;
2668 out->args.vc.actions =
2669 (void *)RTE_ALIGN_CEIL((uintptr_t)
2670 (out->args.vc.pattern +
2671 out->args.vc.pattern_n),
2673 ctx->object = out->args.vc.actions;
2674 ctx->objmask = NULL;
2681 if (!out->args.vc.actions) {
2682 const struct parse_item_priv *priv = token->priv;
2683 struct rte_flow_item *item =
2684 out->args.vc.pattern + out->args.vc.pattern_n;
2686 data_size = priv->size * 3; /* spec, last, mask */
2687 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
2688 (out->args.vc.data - data_size),
2690 if ((uint8_t *)item + sizeof(*item) > data)
2692 *item = (struct rte_flow_item){
2695 ++out->args.vc.pattern_n;
2697 ctx->objmask = NULL;
2699 const struct parse_action_priv *priv = token->priv;
2700 struct rte_flow_action *action =
2701 out->args.vc.actions + out->args.vc.actions_n;
2703 data_size = priv->size; /* configuration */
2704 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
2705 (out->args.vc.data - data_size),
2707 if ((uint8_t *)action + sizeof(*action) > data)
2709 *action = (struct rte_flow_action){
2711 .conf = data_size ? data : NULL,
2713 ++out->args.vc.actions_n;
2714 ctx->object = action;
2715 ctx->objmask = NULL;
2717 memset(data, 0, data_size);
2718 out->args.vc.data = data;
2719 ctx->objdata = data_size;
2723 /** Parse pattern item parameter type. */
2725 parse_vc_spec(struct context *ctx, const struct token *token,
2726 const char *str, unsigned int len,
2727 void *buf, unsigned int size)
2729 struct buffer *out = buf;
2730 struct rte_flow_item *item;
2736 /* Token name must match. */
2737 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2739 /* Parse parameter types. */
2740 switch (ctx->curr) {
2741 static const enum index prefix[] = NEXT_ENTRY(PREFIX);
2747 case ITEM_PARAM_SPEC:
2750 case ITEM_PARAM_LAST:
2753 case ITEM_PARAM_PREFIX:
2754 /* Modify next token to expect a prefix. */
2755 if (ctx->next_num < 2)
2757 ctx->next[ctx->next_num - 2] = prefix;
2759 case ITEM_PARAM_MASK:
2765 /* Nothing else to do if there is no buffer. */
2768 if (!out->args.vc.pattern_n)
2770 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
2771 data_size = ctx->objdata / 3; /* spec, last, mask */
2772 /* Point to selected object. */
2773 ctx->object = out->args.vc.data + (data_size * index);
2775 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
2776 item->mask = ctx->objmask;
2778 ctx->objmask = NULL;
2779 /* Update relevant item pointer. */
2780 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
2785 /** Parse action configuration field. */
2787 parse_vc_conf(struct context *ctx, const struct token *token,
2788 const char *str, unsigned int len,
2789 void *buf, unsigned int size)
2791 struct buffer *out = buf;
2794 /* Token name must match. */
2795 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2797 /* Nothing else to do if there is no buffer. */
2800 /* Point to selected object. */
2801 ctx->object = out->args.vc.data;
2802 ctx->objmask = NULL;
2806 /** Parse RSS action. */
2808 parse_vc_action_rss(struct context *ctx, const struct token *token,
2809 const char *str, unsigned int len,
2810 void *buf, unsigned int size)
2812 struct buffer *out = buf;
2813 struct rte_flow_action *action;
2814 struct action_rss_data *action_rss_data;
2818 ret = parse_vc(ctx, token, str, len, buf, size);
2821 /* Nothing else to do if there is no buffer. */
2824 if (!out->args.vc.actions_n)
2826 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
2827 /* Point to selected object. */
2828 ctx->object = out->args.vc.data;
2829 ctx->objmask = NULL;
2830 /* Set up default configuration. */
2831 action_rss_data = ctx->object;
2832 *action_rss_data = (struct action_rss_data){
2833 .conf = (struct rte_flow_action_rss){
2834 .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
2837 .key_len = sizeof(action_rss_data->key),
2838 .queue_num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
2839 .key = action_rss_data->key,
2840 .queue = action_rss_data->queue,
2842 .key = "testpmd's default RSS hash key, "
2843 "override it for better balancing",
2846 for (i = 0; i < action_rss_data->conf.queue_num; ++i)
2847 action_rss_data->queue[i] = i;
2848 if (!port_id_is_invalid(ctx->port, DISABLED_WARN) &&
2849 ctx->port != (portid_t)RTE_PORT_ALL) {
2850 struct rte_eth_dev_info info;
2852 rte_eth_dev_info_get(ctx->port, &info);
2853 action_rss_data->conf.key_len =
2854 RTE_MIN(sizeof(action_rss_data->key),
2855 info.hash_key_size);
2857 action->conf = &action_rss_data->conf;
2862 * Parse func field for RSS action.
2864 * The RTE_ETH_HASH_FUNCTION_* value to assign is derived from the
2865 * ACTION_RSS_FUNC_* index that called this function.
2868 parse_vc_action_rss_func(struct context *ctx, const struct token *token,
2869 const char *str, unsigned int len,
2870 void *buf, unsigned int size)
2872 struct action_rss_data *action_rss_data;
2873 enum rte_eth_hash_function func;
2877 /* Token name must match. */
2878 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2880 switch (ctx->curr) {
2881 case ACTION_RSS_FUNC_DEFAULT:
2882 func = RTE_ETH_HASH_FUNCTION_DEFAULT;
2884 case ACTION_RSS_FUNC_TOEPLITZ:
2885 func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
2887 case ACTION_RSS_FUNC_SIMPLE_XOR:
2888 func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
2895 action_rss_data = ctx->object;
2896 action_rss_data->conf.func = func;
2901 * Parse type field for RSS action.
2903 * Valid tokens are type field names and the "end" token.
2906 parse_vc_action_rss_type(struct context *ctx, const struct token *token,
2907 const char *str, unsigned int len,
2908 void *buf, unsigned int size)
2910 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_TYPE);
2911 struct action_rss_data *action_rss_data;
2917 if (ctx->curr != ACTION_RSS_TYPE)
2919 if (!(ctx->objdata >> 16) && ctx->object) {
2920 action_rss_data = ctx->object;
2921 action_rss_data->conf.types = 0;
2923 if (!strcmp_partial("end", str, len)) {
2924 ctx->objdata &= 0xffff;
2927 for (i = 0; rss_type_table[i].str; ++i)
2928 if (!strcmp_partial(rss_type_table[i].str, str, len))
2930 if (!rss_type_table[i].str)
2932 ctx->objdata = 1 << 16 | (ctx->objdata & 0xffff);
2934 if (ctx->next_num == RTE_DIM(ctx->next))
2936 ctx->next[ctx->next_num++] = next;
2939 action_rss_data = ctx->object;
2940 action_rss_data->conf.types |= rss_type_table[i].rss_type;
2945 * Parse queue field for RSS action.
2947 * Valid tokens are queue indices and the "end" token.
2950 parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
2951 const char *str, unsigned int len,
2952 void *buf, unsigned int size)
2954 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
2955 struct action_rss_data *action_rss_data;
2962 if (ctx->curr != ACTION_RSS_QUEUE)
2964 i = ctx->objdata >> 16;
2965 if (!strcmp_partial("end", str, len)) {
2966 ctx->objdata &= 0xffff;
2969 if (i >= ACTION_RSS_QUEUE_NUM)
2972 ARGS_ENTRY_ARB(offsetof(struct action_rss_data, queue) +
2973 i * sizeof(action_rss_data->queue[i]),
2974 sizeof(action_rss_data->queue[i]))))
2976 ret = parse_int(ctx, token, str, len, NULL, 0);
2982 ctx->objdata = i << 16 | (ctx->objdata & 0xffff);
2984 if (ctx->next_num == RTE_DIM(ctx->next))
2986 ctx->next[ctx->next_num++] = next;
2990 action_rss_data = ctx->object;
2991 action_rss_data->conf.queue_num = i;
2992 action_rss_data->conf.queue = i ? action_rss_data->queue : NULL;
2996 /** Parse VXLAN encap action. */
2998 parse_vc_action_vxlan_encap(struct context *ctx, const struct token *token,
2999 const char *str, unsigned int len,
3000 void *buf, unsigned int size)
3002 struct buffer *out = buf;
3003 struct rte_flow_action *action;
3004 struct action_vxlan_encap_data *action_vxlan_encap_data;
3007 ret = parse_vc(ctx, token, str, len, buf, size);
3010 /* Nothing else to do if there is no buffer. */
3013 if (!out->args.vc.actions_n)
3015 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3016 /* Point to selected object. */
3017 ctx->object = out->args.vc.data;
3018 ctx->objmask = NULL;
3019 /* Set up default configuration. */
3020 action_vxlan_encap_data = ctx->object;
3021 *action_vxlan_encap_data = (struct action_vxlan_encap_data){
3022 .conf = (struct rte_flow_action_vxlan_encap){
3023 .definition = action_vxlan_encap_data->items,
3027 .type = RTE_FLOW_ITEM_TYPE_ETH,
3028 .spec = &action_vxlan_encap_data->item_eth,
3029 .mask = &rte_flow_item_eth_mask,
3032 .type = RTE_FLOW_ITEM_TYPE_VLAN,
3033 .spec = &action_vxlan_encap_data->item_vlan,
3034 .mask = &rte_flow_item_vlan_mask,
3037 .type = RTE_FLOW_ITEM_TYPE_IPV4,
3038 .spec = &action_vxlan_encap_data->item_ipv4,
3039 .mask = &rte_flow_item_ipv4_mask,
3042 .type = RTE_FLOW_ITEM_TYPE_UDP,
3043 .spec = &action_vxlan_encap_data->item_udp,
3044 .mask = &rte_flow_item_udp_mask,
3047 .type = RTE_FLOW_ITEM_TYPE_VXLAN,
3048 .spec = &action_vxlan_encap_data->item_vxlan,
3049 .mask = &rte_flow_item_vxlan_mask,
3052 .type = RTE_FLOW_ITEM_TYPE_END,
3057 .tci = vxlan_encap_conf.vlan_tci,
3061 .src_addr = vxlan_encap_conf.ipv4_src,
3062 .dst_addr = vxlan_encap_conf.ipv4_dst,
3065 .src_port = vxlan_encap_conf.udp_src,
3066 .dst_port = vxlan_encap_conf.udp_dst,
3068 .item_vxlan.flags = 0,
3070 memcpy(action_vxlan_encap_data->item_eth.dst.addr_bytes,
3071 vxlan_encap_conf.eth_dst, ETHER_ADDR_LEN);
3072 memcpy(action_vxlan_encap_data->item_eth.src.addr_bytes,
3073 vxlan_encap_conf.eth_src, ETHER_ADDR_LEN);
3074 if (!vxlan_encap_conf.select_ipv4) {
3075 memcpy(&action_vxlan_encap_data->item_ipv6.hdr.src_addr,
3076 &vxlan_encap_conf.ipv6_src,
3077 sizeof(vxlan_encap_conf.ipv6_src));
3078 memcpy(&action_vxlan_encap_data->item_ipv6.hdr.dst_addr,
3079 &vxlan_encap_conf.ipv6_dst,
3080 sizeof(vxlan_encap_conf.ipv6_dst));
3081 action_vxlan_encap_data->items[2] = (struct rte_flow_item){
3082 .type = RTE_FLOW_ITEM_TYPE_IPV6,
3083 .spec = &action_vxlan_encap_data->item_ipv6,
3084 .mask = &rte_flow_item_ipv6_mask,
3087 if (!vxlan_encap_conf.select_vlan)
3088 action_vxlan_encap_data->items[1].type =
3089 RTE_FLOW_ITEM_TYPE_VOID;
3090 memcpy(action_vxlan_encap_data->item_vxlan.vni, vxlan_encap_conf.vni,
3091 RTE_DIM(vxlan_encap_conf.vni));
3092 action->conf = &action_vxlan_encap_data->conf;
3096 /** Parse tokens for destroy command. */
3098 parse_destroy(struct context *ctx, const struct token *token,
3099 const char *str, unsigned int len,
3100 void *buf, unsigned int size)
3102 struct buffer *out = buf;
3104 /* Token name must match. */
3105 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3107 /* Nothing else to do if there is no buffer. */
3110 if (!out->command) {
3111 if (ctx->curr != DESTROY)
3113 if (sizeof(*out) > size)
3115 out->command = ctx->curr;
3118 ctx->objmask = NULL;
3119 out->args.destroy.rule =
3120 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
3124 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
3125 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
3128 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
3129 ctx->objmask = NULL;
3133 /** Parse tokens for flush command. */
3135 parse_flush(struct context *ctx, const struct token *token,
3136 const char *str, unsigned int len,
3137 void *buf, unsigned int size)
3139 struct buffer *out = buf;
3141 /* Token name must match. */
3142 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3144 /* Nothing else to do if there is no buffer. */
3147 if (!out->command) {
3148 if (ctx->curr != FLUSH)
3150 if (sizeof(*out) > size)
3152 out->command = ctx->curr;
3155 ctx->objmask = NULL;
3160 /** Parse tokens for query command. */
3162 parse_query(struct context *ctx, const struct token *token,
3163 const char *str, unsigned int len,
3164 void *buf, unsigned int size)
3166 struct buffer *out = buf;
3168 /* Token name must match. */
3169 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3171 /* Nothing else to do if there is no buffer. */
3174 if (!out->command) {
3175 if (ctx->curr != QUERY)
3177 if (sizeof(*out) > size)
3179 out->command = ctx->curr;
3182 ctx->objmask = NULL;
3187 /** Parse action names. */
3189 parse_action(struct context *ctx, const struct token *token,
3190 const char *str, unsigned int len,
3191 void *buf, unsigned int size)
3193 struct buffer *out = buf;
3194 const struct arg *arg = pop_args(ctx);
3198 /* Argument is expected. */
3201 /* Parse action name. */
3202 for (i = 0; next_action[i]; ++i) {
3203 const struct parse_action_priv *priv;
3205 token = &token_list[next_action[i]];
3206 if (strcmp_partial(token->name, str, len))
3212 memcpy((uint8_t *)ctx->object + arg->offset,
3218 push_args(ctx, arg);
3222 /** Parse tokens for list command. */
3224 parse_list(struct context *ctx, const struct token *token,
3225 const char *str, unsigned int len,
3226 void *buf, unsigned int size)
3228 struct buffer *out = buf;
3230 /* Token name must match. */
3231 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3233 /* Nothing else to do if there is no buffer. */
3236 if (!out->command) {
3237 if (ctx->curr != LIST)
3239 if (sizeof(*out) > size)
3241 out->command = ctx->curr;
3244 ctx->objmask = NULL;
3245 out->args.list.group =
3246 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
3250 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
3251 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
3254 ctx->object = out->args.list.group + out->args.list.group_n++;
3255 ctx->objmask = NULL;
3259 /** Parse tokens for isolate command. */
3261 parse_isolate(struct context *ctx, const struct token *token,
3262 const char *str, unsigned int len,
3263 void *buf, unsigned int size)
3265 struct buffer *out = buf;
3267 /* Token name must match. */
3268 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3270 /* Nothing else to do if there is no buffer. */
3273 if (!out->command) {
3274 if (ctx->curr != ISOLATE)
3276 if (sizeof(*out) > size)
3278 out->command = ctx->curr;
3281 ctx->objmask = NULL;
3287 * Parse signed/unsigned integers 8 to 64-bit long.
3289 * Last argument (ctx->args) is retrieved to determine integer type and
3293 parse_int(struct context *ctx, const struct token *token,
3294 const char *str, unsigned int len,
3295 void *buf, unsigned int size)
3297 const struct arg *arg = pop_args(ctx);
3302 /* Argument is expected. */
3307 (uintmax_t)strtoimax(str, &end, 0) :
3308 strtoumax(str, &end, 0);
3309 if (errno || (size_t)(end - str) != len)
3312 ((arg->sign && ((intmax_t)u < (intmax_t)arg->min ||
3313 (intmax_t)u > (intmax_t)arg->max)) ||
3314 (!arg->sign && (u < arg->min || u > arg->max))))
3319 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
3320 !arg_entry_bf_fill(ctx->objmask, -1, arg))
3324 buf = (uint8_t *)ctx->object + arg->offset;
3328 case sizeof(uint8_t):
3329 *(uint8_t *)buf = u;
3331 case sizeof(uint16_t):
3332 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
3334 case sizeof(uint8_t [3]):
3335 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
3337 ((uint8_t *)buf)[0] = u;
3338 ((uint8_t *)buf)[1] = u >> 8;
3339 ((uint8_t *)buf)[2] = u >> 16;
3343 ((uint8_t *)buf)[0] = u >> 16;
3344 ((uint8_t *)buf)[1] = u >> 8;
3345 ((uint8_t *)buf)[2] = u;
3347 case sizeof(uint32_t):
3348 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
3350 case sizeof(uint64_t):
3351 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
3356 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
3358 buf = (uint8_t *)ctx->objmask + arg->offset;
3363 push_args(ctx, arg);
3370 * Three arguments (ctx->args) are retrieved from the stack to store data,
3371 * its actual length and address (in that order).
3374 parse_string(struct context *ctx, const struct token *token,
3375 const char *str, unsigned int len,
3376 void *buf, unsigned int size)
3378 const struct arg *arg_data = pop_args(ctx);
3379 const struct arg *arg_len = pop_args(ctx);
3380 const struct arg *arg_addr = pop_args(ctx);
3381 char tmp[16]; /* Ought to be enough. */
3384 /* Arguments are expected. */
3388 push_args(ctx, arg_data);
3392 push_args(ctx, arg_len);
3393 push_args(ctx, arg_data);
3396 size = arg_data->size;
3397 /* Bit-mask fill is not supported. */
3398 if (arg_data->mask || size < len)
3402 /* Let parse_int() fill length information first. */
3403 ret = snprintf(tmp, sizeof(tmp), "%u", len);
3406 push_args(ctx, arg_len);
3407 ret = parse_int(ctx, token, tmp, ret, NULL, 0);
3412 buf = (uint8_t *)ctx->object + arg_data->offset;
3413 /* Output buffer is not necessarily NUL-terminated. */
3414 memcpy(buf, str, len);
3415 memset((uint8_t *)buf + len, 0x00, size - len);
3417 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
3418 /* Save address if requested. */
3419 if (arg_addr->size) {
3420 memcpy((uint8_t *)ctx->object + arg_addr->offset,
3422 (uint8_t *)ctx->object + arg_data->offset
3426 memcpy((uint8_t *)ctx->objmask + arg_addr->offset,
3428 (uint8_t *)ctx->objmask + arg_data->offset
3434 push_args(ctx, arg_addr);
3435 push_args(ctx, arg_len);
3436 push_args(ctx, arg_data);
3441 * Parse a MAC address.
3443 * Last argument (ctx->args) is retrieved to determine storage size and
3447 parse_mac_addr(struct context *ctx, const struct token *token,
3448 const char *str, unsigned int len,
3449 void *buf, unsigned int size)
3451 const struct arg *arg = pop_args(ctx);
3452 struct ether_addr tmp;
3456 /* Argument is expected. */
3460 /* Bit-mask fill is not supported. */
3461 if (arg->mask || size != sizeof(tmp))
3463 /* Only network endian is supported. */
3466 ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
3467 if (ret < 0 || (unsigned int)ret != len)
3471 buf = (uint8_t *)ctx->object + arg->offset;
3472 memcpy(buf, &tmp, size);
3474 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
3477 push_args(ctx, arg);
3482 * Parse an IPv4 address.
3484 * Last argument (ctx->args) is retrieved to determine storage size and
3488 parse_ipv4_addr(struct context *ctx, const struct token *token,
3489 const char *str, unsigned int len,
3490 void *buf, unsigned int size)
3492 const struct arg *arg = pop_args(ctx);
3497 /* Argument is expected. */
3501 /* Bit-mask fill is not supported. */
3502 if (arg->mask || size != sizeof(tmp))
3504 /* Only network endian is supported. */
3507 memcpy(str2, str, len);
3509 ret = inet_pton(AF_INET, str2, &tmp);
3511 /* Attempt integer parsing. */
3512 push_args(ctx, arg);
3513 return parse_int(ctx, token, str, len, buf, size);
3517 buf = (uint8_t *)ctx->object + arg->offset;
3518 memcpy(buf, &tmp, size);
3520 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
3523 push_args(ctx, arg);
3528 * Parse an IPv6 address.
3530 * Last argument (ctx->args) is retrieved to determine storage size and
3534 parse_ipv6_addr(struct context *ctx, const struct token *token,
3535 const char *str, unsigned int len,
3536 void *buf, unsigned int size)
3538 const struct arg *arg = pop_args(ctx);
3540 struct in6_addr tmp;
3544 /* Argument is expected. */
3548 /* Bit-mask fill is not supported. */
3549 if (arg->mask || size != sizeof(tmp))
3551 /* Only network endian is supported. */
3554 memcpy(str2, str, len);
3556 ret = inet_pton(AF_INET6, str2, &tmp);
3561 buf = (uint8_t *)ctx->object + arg->offset;
3562 memcpy(buf, &tmp, size);
3564 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
3567 push_args(ctx, arg);
3571 /** Boolean values (even indices stand for false). */
3572 static const char *const boolean_name[] = {
3582 * Parse a boolean value.
3584 * Last argument (ctx->args) is retrieved to determine storage size and
3588 parse_boolean(struct context *ctx, const struct token *token,
3589 const char *str, unsigned int len,
3590 void *buf, unsigned int size)
3592 const struct arg *arg = pop_args(ctx);
3596 /* Argument is expected. */
3599 for (i = 0; boolean_name[i]; ++i)
3600 if (!strcmp_partial(boolean_name[i], str, len))
3602 /* Process token as integer. */
3603 if (boolean_name[i])
3604 str = i & 1 ? "1" : "0";
3605 push_args(ctx, arg);
3606 ret = parse_int(ctx, token, str, strlen(str), buf, size);
3607 return ret > 0 ? (int)len : ret;
3610 /** Parse port and update context. */
3612 parse_port(struct context *ctx, const struct token *token,
3613 const char *str, unsigned int len,
3614 void *buf, unsigned int size)
3616 struct buffer *out = &(struct buffer){ .port = 0 };
3624 ctx->objmask = NULL;
3625 size = sizeof(*out);
3627 ret = parse_int(ctx, token, str, len, out, size);
3629 ctx->port = out->port;
3635 /** No completion. */
3637 comp_none(struct context *ctx, const struct token *token,
3638 unsigned int ent, char *buf, unsigned int size)
3648 /** Complete boolean values. */
3650 comp_boolean(struct context *ctx, const struct token *token,
3651 unsigned int ent, char *buf, unsigned int size)
3657 for (i = 0; boolean_name[i]; ++i)
3658 if (buf && i == ent)
3659 return snprintf(buf, size, "%s", boolean_name[i]);
3665 /** Complete action names. */
3667 comp_action(struct context *ctx, const struct token *token,
3668 unsigned int ent, char *buf, unsigned int size)
3674 for (i = 0; next_action[i]; ++i)
3675 if (buf && i == ent)
3676 return snprintf(buf, size, "%s",
3677 token_list[next_action[i]].name);
3683 /** Complete available ports. */
3685 comp_port(struct context *ctx, const struct token *token,
3686 unsigned int ent, char *buf, unsigned int size)
3693 RTE_ETH_FOREACH_DEV(p) {
3694 if (buf && i == ent)
3695 return snprintf(buf, size, "%u", p);
3703 /** Complete available rule IDs. */
3705 comp_rule_id(struct context *ctx, const struct token *token,
3706 unsigned int ent, char *buf, unsigned int size)
3709 struct rte_port *port;
3710 struct port_flow *pf;
3713 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
3714 ctx->port == (portid_t)RTE_PORT_ALL)
3716 port = &ports[ctx->port];
3717 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
3718 if (buf && i == ent)
3719 return snprintf(buf, size, "%u", pf->id);
3727 /** Complete type field for RSS action. */
3729 comp_vc_action_rss_type(struct context *ctx, const struct token *token,
3730 unsigned int ent, char *buf, unsigned int size)
3736 for (i = 0; rss_type_table[i].str; ++i)
3741 return snprintf(buf, size, "%s", rss_type_table[ent].str);
3743 return snprintf(buf, size, "end");
3747 /** Complete queue field for RSS action. */
3749 comp_vc_action_rss_queue(struct context *ctx, const struct token *token,
3750 unsigned int ent, char *buf, unsigned int size)
3757 return snprintf(buf, size, "%u", ent);
3759 return snprintf(buf, size, "end");
3763 /** Internal context. */
3764 static struct context cmd_flow_context;
3766 /** Global parser instance (cmdline API). */
3767 cmdline_parse_inst_t cmd_flow;
3769 /** Initialize context. */
3771 cmd_flow_context_init(struct context *ctx)
3773 /* A full memset() is not necessary. */
3783 ctx->objmask = NULL;
3786 /** Parse a token (cmdline API). */
3788 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
3791 struct context *ctx = &cmd_flow_context;
3792 const struct token *token;
3793 const enum index *list;
3798 token = &token_list[ctx->curr];
3799 /* Check argument length. */
3802 for (len = 0; src[len]; ++len)
3803 if (src[len] == '#' || isspace(src[len]))
3807 /* Last argument and EOL detection. */
3808 for (i = len; src[i]; ++i)
3809 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
3811 else if (!isspace(src[i])) {
3816 if (src[i] == '\r' || src[i] == '\n') {
3820 /* Initialize context if necessary. */
3821 if (!ctx->next_num) {
3824 ctx->next[ctx->next_num++] = token->next[0];
3826 /* Process argument through candidates. */
3827 ctx->prev = ctx->curr;
3828 list = ctx->next[ctx->next_num - 1];
3829 for (i = 0; list[i]; ++i) {
3830 const struct token *next = &token_list[list[i]];
3833 ctx->curr = list[i];
3835 tmp = next->call(ctx, next, src, len, result, size);
3837 tmp = parse_default(ctx, next, src, len, result, size);
3838 if (tmp == -1 || tmp != len)
3846 /* Push subsequent tokens if any. */
3848 for (i = 0; token->next[i]; ++i) {
3849 if (ctx->next_num == RTE_DIM(ctx->next))
3851 ctx->next[ctx->next_num++] = token->next[i];
3853 /* Push arguments if any. */
3855 for (i = 0; token->args[i]; ++i) {
3856 if (ctx->args_num == RTE_DIM(ctx->args))
3858 ctx->args[ctx->args_num++] = token->args[i];
3863 /** Return number of completion entries (cmdline API). */
3865 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
3867 struct context *ctx = &cmd_flow_context;
3868 const struct token *token = &token_list[ctx->curr];
3869 const enum index *list;
3873 /* Count number of tokens in current list. */
3875 list = ctx->next[ctx->next_num - 1];
3877 list = token->next[0];
3878 for (i = 0; list[i]; ++i)
3883 * If there is a single token, use its completion callback, otherwise
3884 * return the number of entries.
3886 token = &token_list[list[0]];
3887 if (i == 1 && token->comp) {
3888 /* Save index for cmd_flow_get_help(). */
3889 ctx->prev = list[0];
3890 return token->comp(ctx, token, 0, NULL, 0);
3895 /** Return a completion entry (cmdline API). */
3897 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
3898 char *dst, unsigned int size)
3900 struct context *ctx = &cmd_flow_context;
3901 const struct token *token = &token_list[ctx->curr];
3902 const enum index *list;
3906 /* Count number of tokens in current list. */
3908 list = ctx->next[ctx->next_num - 1];
3910 list = token->next[0];
3911 for (i = 0; list[i]; ++i)
3915 /* If there is a single token, use its completion callback. */
3916 token = &token_list[list[0]];
3917 if (i == 1 && token->comp) {
3918 /* Save index for cmd_flow_get_help(). */
3919 ctx->prev = list[0];
3920 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
3922 /* Otherwise make sure the index is valid and use defaults. */
3925 token = &token_list[list[index]];
3926 snprintf(dst, size, "%s", token->name);
3927 /* Save index for cmd_flow_get_help(). */
3928 ctx->prev = list[index];
3932 /** Populate help strings for current token (cmdline API). */
3934 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
3936 struct context *ctx = &cmd_flow_context;
3937 const struct token *token = &token_list[ctx->prev];
3942 /* Set token type and update global help with details. */
3943 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
3945 cmd_flow.help_str = token->help;
3947 cmd_flow.help_str = token->name;
3951 /** Token definition template (cmdline API). */
3952 static struct cmdline_token_hdr cmd_flow_token_hdr = {
3953 .ops = &(struct cmdline_token_ops){
3954 .parse = cmd_flow_parse,
3955 .complete_get_nb = cmd_flow_complete_get_nb,
3956 .complete_get_elt = cmd_flow_complete_get_elt,
3957 .get_help = cmd_flow_get_help,
3962 /** Populate the next dynamic token. */
3964 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
3965 cmdline_parse_token_hdr_t **hdr_inst)
3967 struct context *ctx = &cmd_flow_context;
3969 /* Always reinitialize context before requesting the first token. */
3970 if (!(hdr_inst - cmd_flow.tokens))
3971 cmd_flow_context_init(ctx);
3972 /* Return NULL when no more tokens are expected. */
3973 if (!ctx->next_num && ctx->curr) {
3977 /* Determine if command should end here. */
3978 if (ctx->eol && ctx->last && ctx->next_num) {
3979 const enum index *list = ctx->next[ctx->next_num - 1];
3982 for (i = 0; list[i]; ++i) {
3989 *hdr = &cmd_flow_token_hdr;
3992 /** Dispatch parsed buffer to function calls. */
3994 cmd_flow_parsed(const struct buffer *in)
3996 switch (in->command) {
3998 port_flow_validate(in->port, &in->args.vc.attr,
3999 in->args.vc.pattern, in->args.vc.actions);
4002 port_flow_create(in->port, &in->args.vc.attr,
4003 in->args.vc.pattern, in->args.vc.actions);
4006 port_flow_destroy(in->port, in->args.destroy.rule_n,
4007 in->args.destroy.rule);
4010 port_flow_flush(in->port);
4013 port_flow_query(in->port, in->args.query.rule,
4014 &in->args.query.action);
4017 port_flow_list(in->port, in->args.list.group_n,
4018 in->args.list.group);
4021 port_flow_isolate(in->port, in->args.isolate.set);
4028 /** Token generator and output processing callback (cmdline API). */
4030 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
4033 cmd_flow_tok(arg0, arg2);
4035 cmd_flow_parsed(arg0);
4038 /** Global parser instance (cmdline API). */
4039 cmdline_parse_inst_t cmd_flow = {
4041 .data = NULL, /**< Unused. */
4042 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
4045 }, /**< Tokens are returned by cmd_flow_tok(). */