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. */
200 ACTION_RSS_FUNC_DEFAULT,
201 ACTION_RSS_FUNC_TOEPLITZ,
202 ACTION_RSS_FUNC_SIMPLE_XOR,
214 ACTION_PHY_PORT_ORIGINAL,
215 ACTION_PHY_PORT_INDEX,
217 ACTION_PORT_ID_ORIGINAL,
221 ACTION_OF_SET_MPLS_TTL,
222 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
223 ACTION_OF_DEC_MPLS_TTL,
224 ACTION_OF_SET_NW_TTL,
225 ACTION_OF_SET_NW_TTL_NW_TTL,
226 ACTION_OF_DEC_NW_TTL,
227 ACTION_OF_COPY_TTL_OUT,
228 ACTION_OF_COPY_TTL_IN,
231 ACTION_OF_PUSH_VLAN_ETHERTYPE,
232 ACTION_OF_SET_VLAN_VID,
233 ACTION_OF_SET_VLAN_VID_VLAN_VID,
234 ACTION_OF_SET_VLAN_PCP,
235 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
237 ACTION_OF_POP_MPLS_ETHERTYPE,
239 ACTION_OF_PUSH_MPLS_ETHERTYPE,
242 /** Maximum size for pattern in struct rte_flow_item_raw. */
243 #define ITEM_RAW_PATTERN_SIZE 40
245 /** Storage size for struct rte_flow_item_raw including pattern. */
246 #define ITEM_RAW_SIZE \
247 (sizeof(struct rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE)
249 /** Maximum number of queue indices in struct rte_flow_action_rss. */
250 #define ACTION_RSS_QUEUE_NUM 32
252 /** Storage for struct rte_flow_action_rss including external data. */
253 struct action_rss_data {
254 struct rte_flow_action_rss conf;
255 uint8_t key[RSS_HASH_KEY_LENGTH];
256 uint16_t queue[ACTION_RSS_QUEUE_NUM];
259 /** Maximum number of subsequent tokens and arguments on the stack. */
260 #define CTX_STACK_SIZE 16
262 /** Parser context. */
264 /** Stack of subsequent token lists to process. */
265 const enum index *next[CTX_STACK_SIZE];
266 /** Arguments for stacked tokens. */
267 const void *args[CTX_STACK_SIZE];
268 enum index curr; /**< Current token index. */
269 enum index prev; /**< Index of the last token seen. */
270 int next_num; /**< Number of entries in next[]. */
271 int args_num; /**< Number of entries in args[]. */
272 uint32_t eol:1; /**< EOL has been detected. */
273 uint32_t last:1; /**< No more arguments. */
274 portid_t port; /**< Current port ID (for completions). */
275 uint32_t objdata; /**< Object-specific data. */
276 void *object; /**< Address of current object for relative offsets. */
277 void *objmask; /**< Object a full mask must be written to. */
280 /** Token argument. */
282 uint32_t hton:1; /**< Use network byte ordering. */
283 uint32_t sign:1; /**< Value is signed. */
284 uint32_t bounded:1; /**< Value is bounded. */
285 uintmax_t min; /**< Minimum value if bounded. */
286 uintmax_t max; /**< Maximum value if bounded. */
287 uint32_t offset; /**< Relative offset from ctx->object. */
288 uint32_t size; /**< Field size. */
289 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
292 /** Parser token definition. */
294 /** Type displayed during completion (defaults to "TOKEN"). */
296 /** Help displayed during completion (defaults to token name). */
298 /** Private data used by parser functions. */
301 * Lists of subsequent tokens to push on the stack. Each call to the
302 * parser consumes the last entry of that stack.
304 const enum index *const *next;
305 /** Arguments stack for subsequent tokens that need them. */
306 const struct arg *const *args;
308 * Token-processing callback, returns -1 in case of error, the
309 * length of the matched string otherwise. If NULL, attempts to
310 * match the token name.
312 * If buf is not NULL, the result should be stored in it according
313 * to context. An error is returned if not large enough.
315 int (*call)(struct context *ctx, const struct token *token,
316 const char *str, unsigned int len,
317 void *buf, unsigned int size);
319 * Callback that provides possible values for this token, used for
320 * completion. Returns -1 in case of error, the number of possible
321 * values otherwise. If NULL, the token name is used.
323 * If buf is not NULL, entry index ent is written to buf and the
324 * full length of the entry is returned (same behavior as
327 int (*comp)(struct context *ctx, const struct token *token,
328 unsigned int ent, char *buf, unsigned int size);
329 /** Mandatory token name, no default value. */
333 /** Static initializer for the next field. */
334 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
336 /** Static initializer for a NEXT() entry. */
337 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
339 /** Static initializer for the args field. */
340 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
342 /** Static initializer for ARGS() to target a field. */
343 #define ARGS_ENTRY(s, f) \
344 (&(const struct arg){ \
345 .offset = offsetof(s, f), \
346 .size = sizeof(((s *)0)->f), \
349 /** Static initializer for ARGS() to target a bit-field. */
350 #define ARGS_ENTRY_BF(s, f, b) \
351 (&(const struct arg){ \
353 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
356 /** Static initializer for ARGS() to target an arbitrary bit-mask. */
357 #define ARGS_ENTRY_MASK(s, f, m) \
358 (&(const struct arg){ \
359 .offset = offsetof(s, f), \
360 .size = sizeof(((s *)0)->f), \
361 .mask = (const void *)(m), \
364 /** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */
365 #define ARGS_ENTRY_MASK_HTON(s, f, m) \
366 (&(const struct arg){ \
368 .offset = offsetof(s, f), \
369 .size = sizeof(((s *)0)->f), \
370 .mask = (const void *)(m), \
373 /** Static initializer for ARGS() to target a pointer. */
374 #define ARGS_ENTRY_PTR(s, f) \
375 (&(const struct arg){ \
376 .size = sizeof(*((s *)0)->f), \
379 /** Static initializer for ARGS() with arbitrary offset and size. */
380 #define ARGS_ENTRY_ARB(o, s) \
381 (&(const struct arg){ \
386 /** Same as ARGS_ENTRY_ARB() with bounded values. */
387 #define ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
388 (&(const struct arg){ \
396 /** Same as ARGS_ENTRY() using network byte ordering. */
397 #define ARGS_ENTRY_HTON(s, f) \
398 (&(const struct arg){ \
400 .offset = offsetof(s, f), \
401 .size = sizeof(((s *)0)->f), \
404 /** Parser output buffer layout expected by cmd_flow_parsed(). */
406 enum index command; /**< Flow command. */
407 portid_t port; /**< Affected port ID. */
410 struct rte_flow_attr attr;
411 struct rte_flow_item *pattern;
412 struct rte_flow_action *actions;
416 } vc; /**< Validate/create arguments. */
420 } destroy; /**< Destroy arguments. */
423 struct rte_flow_action action;
424 } query; /**< Query arguments. */
428 } list; /**< List arguments. */
431 } isolate; /**< Isolated mode arguments. */
432 } args; /**< Command arguments. */
435 /** Private data for pattern items. */
436 struct parse_item_priv {
437 enum rte_flow_item_type type; /**< Item type. */
438 uint32_t size; /**< Size of item specification structure. */
441 #define PRIV_ITEM(t, s) \
442 (&(const struct parse_item_priv){ \
443 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
447 /** Private data for actions. */
448 struct parse_action_priv {
449 enum rte_flow_action_type type; /**< Action type. */
450 uint32_t size; /**< Size of action configuration structure. */
453 #define PRIV_ACTION(t, s) \
454 (&(const struct parse_action_priv){ \
455 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
459 static const enum index next_vc_attr[] = {
469 static const enum index next_destroy_attr[] = {
475 static const enum index next_list_attr[] = {
481 static const enum index item_param[] = {
490 static const enum index next_item[] = {
526 ITEM_ICMP6_ND_OPT_SLA_ETH,
527 ITEM_ICMP6_ND_OPT_TLA_ETH,
531 static const enum index item_fuzzy[] = {
537 static const enum index item_any[] = {
543 static const enum index item_vf[] = {
549 static const enum index item_phy_port[] = {
555 static const enum index item_port_id[] = {
561 static const enum index item_mark[] = {
567 static const enum index item_raw[] = {
577 static const enum index item_eth[] = {
585 static const enum index item_vlan[] = {
590 ITEM_VLAN_INNER_TYPE,
595 static const enum index item_ipv4[] = {
605 static const enum index item_ipv6[] = {
616 static const enum index item_icmp[] = {
623 static const enum index item_udp[] = {
630 static const enum index item_tcp[] = {
638 static const enum index item_sctp[] = {
647 static const enum index item_vxlan[] = {
653 static const enum index item_e_tag[] = {
654 ITEM_E_TAG_GRP_ECID_B,
659 static const enum index item_nvgre[] = {
665 static const enum index item_mpls[] = {
671 static const enum index item_gre[] = {
677 static const enum index item_gtp[] = {
683 static const enum index item_geneve[] = {
690 static const enum index item_vxlan_gpe[] = {
696 static const enum index item_arp_eth_ipv4[] = {
697 ITEM_ARP_ETH_IPV4_SHA,
698 ITEM_ARP_ETH_IPV4_SPA,
699 ITEM_ARP_ETH_IPV4_THA,
700 ITEM_ARP_ETH_IPV4_TPA,
705 static const enum index item_ipv6_ext[] = {
706 ITEM_IPV6_EXT_NEXT_HDR,
711 static const enum index item_icmp6[] = {
718 static const enum index item_icmp6_nd_ns[] = {
719 ITEM_ICMP6_ND_NS_TARGET_ADDR,
724 static const enum index item_icmp6_nd_na[] = {
725 ITEM_ICMP6_ND_NA_TARGET_ADDR,
730 static const enum index item_icmp6_nd_opt[] = {
731 ITEM_ICMP6_ND_OPT_TYPE,
736 static const enum index item_icmp6_nd_opt_sla_eth[] = {
737 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
742 static const enum index item_icmp6_nd_opt_tla_eth[] = {
743 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
748 static const enum index next_action[] = {
764 ACTION_OF_SET_MPLS_TTL,
765 ACTION_OF_DEC_MPLS_TTL,
766 ACTION_OF_SET_NW_TTL,
767 ACTION_OF_DEC_NW_TTL,
768 ACTION_OF_COPY_TTL_OUT,
769 ACTION_OF_COPY_TTL_IN,
772 ACTION_OF_SET_VLAN_VID,
773 ACTION_OF_SET_VLAN_PCP,
779 static const enum index action_mark[] = {
785 static const enum index action_queue[] = {
791 static const enum index action_rss[] = {
802 static const enum index action_vf[] = {
809 static const enum index action_phy_port[] = {
810 ACTION_PHY_PORT_ORIGINAL,
811 ACTION_PHY_PORT_INDEX,
816 static const enum index action_port_id[] = {
817 ACTION_PORT_ID_ORIGINAL,
823 static const enum index action_meter[] = {
829 static const enum index action_of_set_mpls_ttl[] = {
830 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
835 static const enum index action_of_set_nw_ttl[] = {
836 ACTION_OF_SET_NW_TTL_NW_TTL,
841 static const enum index action_of_push_vlan[] = {
842 ACTION_OF_PUSH_VLAN_ETHERTYPE,
847 static const enum index action_of_set_vlan_vid[] = {
848 ACTION_OF_SET_VLAN_VID_VLAN_VID,
853 static const enum index action_of_set_vlan_pcp[] = {
854 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
859 static const enum index action_of_pop_mpls[] = {
860 ACTION_OF_POP_MPLS_ETHERTYPE,
865 static const enum index action_of_push_mpls[] = {
866 ACTION_OF_PUSH_MPLS_ETHERTYPE,
871 static const enum index action_jump[] = {
877 static int parse_init(struct context *, const struct token *,
878 const char *, unsigned int,
879 void *, unsigned int);
880 static int parse_vc(struct context *, const struct token *,
881 const char *, unsigned int,
882 void *, unsigned int);
883 static int parse_vc_spec(struct context *, const struct token *,
884 const char *, unsigned int, void *, unsigned int);
885 static int parse_vc_conf(struct context *, const struct token *,
886 const char *, unsigned int, void *, unsigned int);
887 static int parse_vc_action_rss(struct context *, const struct token *,
888 const char *, unsigned int, void *,
890 static int parse_vc_action_rss_func(struct context *, const struct token *,
891 const char *, unsigned int, void *,
893 static int parse_vc_action_rss_type(struct context *, const struct token *,
894 const char *, unsigned int, void *,
896 static int parse_vc_action_rss_queue(struct context *, const struct token *,
897 const char *, unsigned int, void *,
899 static int parse_destroy(struct context *, const struct token *,
900 const char *, unsigned int,
901 void *, unsigned int);
902 static int parse_flush(struct context *, const struct token *,
903 const char *, unsigned int,
904 void *, unsigned int);
905 static int parse_query(struct context *, const struct token *,
906 const char *, unsigned int,
907 void *, unsigned int);
908 static int parse_action(struct context *, const struct token *,
909 const char *, unsigned int,
910 void *, unsigned int);
911 static int parse_list(struct context *, const struct token *,
912 const char *, unsigned int,
913 void *, unsigned int);
914 static int parse_isolate(struct context *, const struct token *,
915 const char *, unsigned int,
916 void *, unsigned int);
917 static int parse_int(struct context *, const struct token *,
918 const char *, unsigned int,
919 void *, unsigned int);
920 static int parse_prefix(struct context *, const struct token *,
921 const char *, unsigned int,
922 void *, unsigned int);
923 static int parse_boolean(struct context *, const struct token *,
924 const char *, unsigned int,
925 void *, unsigned int);
926 static int parse_string(struct context *, const struct token *,
927 const char *, unsigned int,
928 void *, unsigned int);
929 static int parse_mac_addr(struct context *, const struct token *,
930 const char *, unsigned int,
931 void *, unsigned int);
932 static int parse_ipv4_addr(struct context *, const struct token *,
933 const char *, unsigned int,
934 void *, unsigned int);
935 static int parse_ipv6_addr(struct context *, const struct token *,
936 const char *, unsigned int,
937 void *, unsigned int);
938 static int parse_port(struct context *, const struct token *,
939 const char *, unsigned int,
940 void *, unsigned int);
941 static int comp_none(struct context *, const struct token *,
942 unsigned int, char *, unsigned int);
943 static int comp_boolean(struct context *, const struct token *,
944 unsigned int, char *, unsigned int);
945 static int comp_action(struct context *, const struct token *,
946 unsigned int, char *, unsigned int);
947 static int comp_port(struct context *, const struct token *,
948 unsigned int, char *, unsigned int);
949 static int comp_rule_id(struct context *, const struct token *,
950 unsigned int, char *, unsigned int);
951 static int comp_vc_action_rss_type(struct context *, const struct token *,
952 unsigned int, char *, unsigned int);
953 static int comp_vc_action_rss_queue(struct context *, const struct token *,
954 unsigned int, char *, unsigned int);
956 /** Token definitions. */
957 static const struct token token_list[] = {
958 /* Special tokens. */
961 .help = "null entry, abused as the entry point",
962 .next = NEXT(NEXT_ENTRY(FLOW)),
967 .help = "command may end here",
973 .help = "integer value",
978 .name = "{unsigned}",
980 .help = "unsigned integer value",
987 .help = "prefix length for bit-mask",
988 .call = parse_prefix,
994 .help = "any boolean value",
995 .call = parse_boolean,
996 .comp = comp_boolean,
1001 .help = "fixed string",
1002 .call = parse_string,
1006 .name = "{MAC address}",
1008 .help = "standard MAC address notation",
1009 .call = parse_mac_addr,
1013 .name = "{IPv4 address}",
1014 .type = "IPV4 ADDRESS",
1015 .help = "standard IPv4 address notation",
1016 .call = parse_ipv4_addr,
1020 .name = "{IPv6 address}",
1021 .type = "IPV6 ADDRESS",
1022 .help = "standard IPv6 address notation",
1023 .call = parse_ipv6_addr,
1027 .name = "{rule id}",
1029 .help = "rule identifier",
1031 .comp = comp_rule_id,
1034 .name = "{port_id}",
1036 .help = "port identifier",
1041 .name = "{group_id}",
1043 .help = "group identifier",
1047 [PRIORITY_LEVEL] = {
1050 .help = "priority level",
1054 /* Top-level command. */
1057 .type = "{command} {port_id} [{arg} [...]]",
1058 .help = "manage ingress/egress flow rules",
1059 .next = NEXT(NEXT_ENTRY
1069 /* Sub-level commands. */
1072 .help = "check whether a flow rule can be created",
1073 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1074 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1079 .help = "create a flow rule",
1080 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1081 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1086 .help = "destroy specific flow rules",
1087 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
1088 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1089 .call = parse_destroy,
1093 .help = "destroy all flow rules",
1094 .next = NEXT(NEXT_ENTRY(PORT_ID)),
1095 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1096 .call = parse_flush,
1100 .help = "query an existing flow rule",
1101 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
1102 NEXT_ENTRY(RULE_ID),
1103 NEXT_ENTRY(PORT_ID)),
1104 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action.type),
1105 ARGS_ENTRY(struct buffer, args.query.rule),
1106 ARGS_ENTRY(struct buffer, port)),
1107 .call = parse_query,
1111 .help = "list existing flow rules",
1112 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
1113 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1118 .help = "restrict ingress traffic to the defined flow rules",
1119 .next = NEXT(NEXT_ENTRY(BOOLEAN),
1120 NEXT_ENTRY(PORT_ID)),
1121 .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
1122 ARGS_ENTRY(struct buffer, port)),
1123 .call = parse_isolate,
1125 /* Destroy arguments. */
1128 .help = "specify a rule identifier",
1129 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
1130 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
1131 .call = parse_destroy,
1133 /* Query arguments. */
1137 .help = "action to query, must be part of the rule",
1138 .call = parse_action,
1139 .comp = comp_action,
1141 /* List arguments. */
1144 .help = "specify a group",
1145 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
1146 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
1149 /* Validate/create attributes. */
1152 .help = "specify a group",
1153 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
1154 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
1159 .help = "specify a priority level",
1160 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
1161 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
1166 .help = "affect rule to ingress",
1167 .next = NEXT(next_vc_attr),
1172 .help = "affect rule to egress",
1173 .next = NEXT(next_vc_attr),
1178 .help = "apply rule directly to endpoints found in pattern",
1179 .next = NEXT(next_vc_attr),
1182 /* Validate/create pattern. */
1185 .help = "submit a list of pattern items",
1186 .next = NEXT(next_item),
1191 .help = "match value perfectly (with full bit-mask)",
1192 .call = parse_vc_spec,
1194 [ITEM_PARAM_SPEC] = {
1196 .help = "match value according to configured bit-mask",
1197 .call = parse_vc_spec,
1199 [ITEM_PARAM_LAST] = {
1201 .help = "specify upper bound to establish a range",
1202 .call = parse_vc_spec,
1204 [ITEM_PARAM_MASK] = {
1206 .help = "specify bit-mask with relevant bits set to one",
1207 .call = parse_vc_spec,
1209 [ITEM_PARAM_PREFIX] = {
1211 .help = "generate bit-mask from a prefix length",
1212 .call = parse_vc_spec,
1216 .help = "specify next pattern item",
1217 .next = NEXT(next_item),
1221 .help = "end list of pattern items",
1222 .priv = PRIV_ITEM(END, 0),
1223 .next = NEXT(NEXT_ENTRY(ACTIONS)),
1228 .help = "no-op pattern item",
1229 .priv = PRIV_ITEM(VOID, 0),
1230 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1235 .help = "perform actions when pattern does not match",
1236 .priv = PRIV_ITEM(INVERT, 0),
1237 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1242 .help = "match any protocol for the current layer",
1243 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
1244 .next = NEXT(item_any),
1249 .help = "number of layers covered",
1250 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
1251 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
1255 .help = "match traffic from/to the physical function",
1256 .priv = PRIV_ITEM(PF, 0),
1257 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1262 .help = "match traffic from/to a virtual function ID",
1263 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
1264 .next = NEXT(item_vf),
1270 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
1271 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
1275 .help = "match traffic from/to a specific physical port",
1276 .priv = PRIV_ITEM(PHY_PORT,
1277 sizeof(struct rte_flow_item_phy_port)),
1278 .next = NEXT(item_phy_port),
1281 [ITEM_PHY_PORT_INDEX] = {
1283 .help = "physical port index",
1284 .next = NEXT(item_phy_port, NEXT_ENTRY(UNSIGNED), item_param),
1285 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_phy_port, index)),
1289 .help = "match traffic from/to a given DPDK port ID",
1290 .priv = PRIV_ITEM(PORT_ID,
1291 sizeof(struct rte_flow_item_port_id)),
1292 .next = NEXT(item_port_id),
1295 [ITEM_PORT_ID_ID] = {
1297 .help = "DPDK port ID",
1298 .next = NEXT(item_port_id, NEXT_ENTRY(UNSIGNED), item_param),
1299 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port_id, id)),
1303 .help = "match traffic against value set in previously matched rule",
1304 .priv = PRIV_ITEM(MARK, sizeof(struct rte_flow_item_mark)),
1305 .next = NEXT(item_mark),
1310 .help = "Integer value to match against",
1311 .next = NEXT(item_mark, NEXT_ENTRY(UNSIGNED), item_param),
1312 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_mark, id)),
1316 .help = "match an arbitrary byte string",
1317 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
1318 .next = NEXT(item_raw),
1321 [ITEM_RAW_RELATIVE] = {
1323 .help = "look for pattern after the previous item",
1324 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1325 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1328 [ITEM_RAW_SEARCH] = {
1330 .help = "search pattern from offset (see also limit)",
1331 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1332 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1335 [ITEM_RAW_OFFSET] = {
1337 .help = "absolute or relative offset for pattern",
1338 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
1339 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
1341 [ITEM_RAW_LIMIT] = {
1343 .help = "search area limit for start of pattern",
1344 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
1345 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
1347 [ITEM_RAW_PATTERN] = {
1349 .help = "byte string to look for",
1350 .next = NEXT(item_raw,
1352 NEXT_ENTRY(ITEM_PARAM_IS,
1355 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, pattern),
1356 ARGS_ENTRY(struct rte_flow_item_raw, length),
1357 ARGS_ENTRY_ARB(sizeof(struct rte_flow_item_raw),
1358 ITEM_RAW_PATTERN_SIZE)),
1362 .help = "match Ethernet header",
1363 .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
1364 .next = NEXT(item_eth),
1369 .help = "destination MAC",
1370 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1371 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, dst)),
1375 .help = "source MAC",
1376 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1377 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, src)),
1381 .help = "EtherType",
1382 .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
1383 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)),
1387 .help = "match 802.1Q/ad VLAN tag",
1388 .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
1389 .next = NEXT(item_vlan),
1394 .help = "tag control information",
1395 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1396 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
1400 .help = "priority code point",
1401 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1402 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1407 .help = "drop eligible indicator",
1408 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1409 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1414 .help = "VLAN identifier",
1415 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1416 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1419 [ITEM_VLAN_INNER_TYPE] = {
1420 .name = "inner_type",
1421 .help = "inner EtherType",
1422 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1423 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan,
1428 .help = "match IPv4 header",
1429 .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
1430 .next = NEXT(item_ipv4),
1435 .help = "type of service",
1436 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1437 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1438 hdr.type_of_service)),
1442 .help = "time to live",
1443 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1444 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1447 [ITEM_IPV4_PROTO] = {
1449 .help = "next protocol ID",
1450 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1451 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1452 hdr.next_proto_id)),
1456 .help = "source address",
1457 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1458 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1463 .help = "destination address",
1464 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1465 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1470 .help = "match IPv6 header",
1471 .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
1472 .next = NEXT(item_ipv6),
1477 .help = "traffic class",
1478 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1479 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1481 "\x0f\xf0\x00\x00")),
1483 [ITEM_IPV6_FLOW] = {
1485 .help = "flow label",
1486 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1487 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1489 "\x00\x0f\xff\xff")),
1491 [ITEM_IPV6_PROTO] = {
1493 .help = "protocol (next header)",
1494 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1495 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1500 .help = "hop limit",
1501 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1502 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1507 .help = "source address",
1508 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1509 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1514 .help = "destination address",
1515 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1516 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1521 .help = "match ICMP header",
1522 .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
1523 .next = NEXT(item_icmp),
1526 [ITEM_ICMP_TYPE] = {
1528 .help = "ICMP packet type",
1529 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1530 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1533 [ITEM_ICMP_CODE] = {
1535 .help = "ICMP packet code",
1536 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1537 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1542 .help = "match UDP header",
1543 .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
1544 .next = NEXT(item_udp),
1549 .help = "UDP source port",
1550 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1551 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1556 .help = "UDP destination port",
1557 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1558 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1563 .help = "match TCP header",
1564 .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
1565 .next = NEXT(item_tcp),
1570 .help = "TCP source port",
1571 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1572 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1577 .help = "TCP destination port",
1578 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1579 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1582 [ITEM_TCP_FLAGS] = {
1584 .help = "TCP flags",
1585 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1586 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1591 .help = "match SCTP header",
1592 .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
1593 .next = NEXT(item_sctp),
1598 .help = "SCTP source port",
1599 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1600 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1605 .help = "SCTP destination port",
1606 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1607 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1612 .help = "validation tag",
1613 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1614 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1617 [ITEM_SCTP_CKSUM] = {
1620 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1621 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1626 .help = "match VXLAN header",
1627 .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
1628 .next = NEXT(item_vxlan),
1631 [ITEM_VXLAN_VNI] = {
1633 .help = "VXLAN identifier",
1634 .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
1635 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)),
1639 .help = "match E-Tag header",
1640 .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
1641 .next = NEXT(item_e_tag),
1644 [ITEM_E_TAG_GRP_ECID_B] = {
1645 .name = "grp_ecid_b",
1646 .help = "GRP and E-CID base",
1647 .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param),
1648 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag,
1654 .help = "match NVGRE header",
1655 .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
1656 .next = NEXT(item_nvgre),
1659 [ITEM_NVGRE_TNI] = {
1661 .help = "virtual subnet ID",
1662 .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param),
1663 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)),
1667 .help = "match MPLS header",
1668 .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
1669 .next = NEXT(item_mpls),
1672 [ITEM_MPLS_LABEL] = {
1674 .help = "MPLS label",
1675 .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
1676 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
1682 .help = "match GRE header",
1683 .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
1684 .next = NEXT(item_gre),
1687 [ITEM_GRE_PROTO] = {
1689 .help = "GRE protocol type",
1690 .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
1691 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
1696 .help = "fuzzy pattern match, expect faster than default",
1697 .priv = PRIV_ITEM(FUZZY,
1698 sizeof(struct rte_flow_item_fuzzy)),
1699 .next = NEXT(item_fuzzy),
1702 [ITEM_FUZZY_THRESH] = {
1704 .help = "match accuracy threshold",
1705 .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param),
1706 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy,
1711 .help = "match GTP header",
1712 .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
1713 .next = NEXT(item_gtp),
1718 .help = "tunnel endpoint identifier",
1719 .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
1720 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)),
1724 .help = "match GTP header",
1725 .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
1726 .next = NEXT(item_gtp),
1731 .help = "match GTP header",
1732 .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
1733 .next = NEXT(item_gtp),
1738 .help = "match GENEVE header",
1739 .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
1740 .next = NEXT(item_geneve),
1743 [ITEM_GENEVE_VNI] = {
1745 .help = "virtual network identifier",
1746 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
1747 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)),
1749 [ITEM_GENEVE_PROTO] = {
1751 .help = "GENEVE protocol type",
1752 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
1753 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
1756 [ITEM_VXLAN_GPE] = {
1757 .name = "vxlan-gpe",
1758 .help = "match VXLAN-GPE header",
1759 .priv = PRIV_ITEM(VXLAN_GPE,
1760 sizeof(struct rte_flow_item_vxlan_gpe)),
1761 .next = NEXT(item_vxlan_gpe),
1764 [ITEM_VXLAN_GPE_VNI] = {
1766 .help = "VXLAN-GPE identifier",
1767 .next = NEXT(item_vxlan_gpe, NEXT_ENTRY(UNSIGNED), item_param),
1768 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan_gpe,
1771 [ITEM_ARP_ETH_IPV4] = {
1772 .name = "arp_eth_ipv4",
1773 .help = "match ARP header for Ethernet/IPv4",
1774 .priv = PRIV_ITEM(ARP_ETH_IPV4,
1775 sizeof(struct rte_flow_item_arp_eth_ipv4)),
1776 .next = NEXT(item_arp_eth_ipv4),
1779 [ITEM_ARP_ETH_IPV4_SHA] = {
1781 .help = "sender hardware address",
1782 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
1784 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1787 [ITEM_ARP_ETH_IPV4_SPA] = {
1789 .help = "sender IPv4 address",
1790 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
1792 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1795 [ITEM_ARP_ETH_IPV4_THA] = {
1797 .help = "target hardware address",
1798 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
1800 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1803 [ITEM_ARP_ETH_IPV4_TPA] = {
1805 .help = "target IPv4 address",
1806 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
1808 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
1813 .help = "match presence of any IPv6 extension header",
1814 .priv = PRIV_ITEM(IPV6_EXT,
1815 sizeof(struct rte_flow_item_ipv6_ext)),
1816 .next = NEXT(item_ipv6_ext),
1819 [ITEM_IPV6_EXT_NEXT_HDR] = {
1821 .help = "next header",
1822 .next = NEXT(item_ipv6_ext, NEXT_ENTRY(UNSIGNED), item_param),
1823 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext,
1828 .help = "match any ICMPv6 header",
1829 .priv = PRIV_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)),
1830 .next = NEXT(item_icmp6),
1833 [ITEM_ICMP6_TYPE] = {
1835 .help = "ICMPv6 type",
1836 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
1837 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
1840 [ITEM_ICMP6_CODE] = {
1842 .help = "ICMPv6 code",
1843 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
1844 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
1847 [ITEM_ICMP6_ND_NS] = {
1848 .name = "icmp6_nd_ns",
1849 .help = "match ICMPv6 neighbor discovery solicitation",
1850 .priv = PRIV_ITEM(ICMP6_ND_NS,
1851 sizeof(struct rte_flow_item_icmp6_nd_ns)),
1852 .next = NEXT(item_icmp6_nd_ns),
1855 [ITEM_ICMP6_ND_NS_TARGET_ADDR] = {
1856 .name = "target_addr",
1857 .help = "target address",
1858 .next = NEXT(item_icmp6_nd_ns, NEXT_ENTRY(IPV6_ADDR),
1860 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_ns,
1863 [ITEM_ICMP6_ND_NA] = {
1864 .name = "icmp6_nd_na",
1865 .help = "match ICMPv6 neighbor discovery advertisement",
1866 .priv = PRIV_ITEM(ICMP6_ND_NA,
1867 sizeof(struct rte_flow_item_icmp6_nd_na)),
1868 .next = NEXT(item_icmp6_nd_na),
1871 [ITEM_ICMP6_ND_NA_TARGET_ADDR] = {
1872 .name = "target_addr",
1873 .help = "target address",
1874 .next = NEXT(item_icmp6_nd_na, NEXT_ENTRY(IPV6_ADDR),
1876 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_na,
1879 [ITEM_ICMP6_ND_OPT] = {
1880 .name = "icmp6_nd_opt",
1881 .help = "match presence of any ICMPv6 neighbor discovery"
1883 .priv = PRIV_ITEM(ICMP6_ND_OPT,
1884 sizeof(struct rte_flow_item_icmp6_nd_opt)),
1885 .next = NEXT(item_icmp6_nd_opt),
1888 [ITEM_ICMP6_ND_OPT_TYPE] = {
1890 .help = "ND option type",
1891 .next = NEXT(item_icmp6_nd_opt, NEXT_ENTRY(UNSIGNED),
1893 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_opt,
1896 [ITEM_ICMP6_ND_OPT_SLA_ETH] = {
1897 .name = "icmp6_nd_opt_sla_eth",
1898 .help = "match ICMPv6 neighbor discovery source Ethernet"
1899 " link-layer address option",
1901 (ICMP6_ND_OPT_SLA_ETH,
1902 sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),
1903 .next = NEXT(item_icmp6_nd_opt_sla_eth),
1906 [ITEM_ICMP6_ND_OPT_SLA_ETH_SLA] = {
1908 .help = "source Ethernet LLA",
1909 .next = NEXT(item_icmp6_nd_opt_sla_eth, NEXT_ENTRY(MAC_ADDR),
1911 .args = ARGS(ARGS_ENTRY_HTON
1912 (struct rte_flow_item_icmp6_nd_opt_sla_eth, sla)),
1914 [ITEM_ICMP6_ND_OPT_TLA_ETH] = {
1915 .name = "icmp6_nd_opt_tla_eth",
1916 .help = "match ICMPv6 neighbor discovery target Ethernet"
1917 " link-layer address option",
1919 (ICMP6_ND_OPT_TLA_ETH,
1920 sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),
1921 .next = NEXT(item_icmp6_nd_opt_tla_eth),
1924 [ITEM_ICMP6_ND_OPT_TLA_ETH_TLA] = {
1926 .help = "target Ethernet LLA",
1927 .next = NEXT(item_icmp6_nd_opt_tla_eth, NEXT_ENTRY(MAC_ADDR),
1929 .args = ARGS(ARGS_ENTRY_HTON
1930 (struct rte_flow_item_icmp6_nd_opt_tla_eth, tla)),
1933 /* Validate/create actions. */
1936 .help = "submit a list of associated actions",
1937 .next = NEXT(next_action),
1942 .help = "specify next action",
1943 .next = NEXT(next_action),
1947 .help = "end list of actions",
1948 .priv = PRIV_ACTION(END, 0),
1953 .help = "no-op action",
1954 .priv = PRIV_ACTION(VOID, 0),
1955 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
1958 [ACTION_PASSTHRU] = {
1960 .help = "let subsequent rule process matched packets",
1961 .priv = PRIV_ACTION(PASSTHRU, 0),
1962 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
1967 .help = "redirect traffic to a given group",
1968 .priv = PRIV_ACTION(JUMP, sizeof(struct rte_flow_action_jump)),
1969 .next = NEXT(action_jump),
1972 [ACTION_JUMP_GROUP] = {
1974 .help = "group to redirect traffic to",
1975 .next = NEXT(action_jump, NEXT_ENTRY(UNSIGNED)),
1976 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_jump, group)),
1977 .call = parse_vc_conf,
1981 .help = "attach 32 bit value to packets",
1982 .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
1983 .next = NEXT(action_mark),
1986 [ACTION_MARK_ID] = {
1988 .help = "32 bit value to return with packets",
1989 .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
1990 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)),
1991 .call = parse_vc_conf,
1995 .help = "flag packets",
1996 .priv = PRIV_ACTION(FLAG, 0),
1997 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2002 .help = "assign packets to a given queue index",
2003 .priv = PRIV_ACTION(QUEUE,
2004 sizeof(struct rte_flow_action_queue)),
2005 .next = NEXT(action_queue),
2008 [ACTION_QUEUE_INDEX] = {
2010 .help = "queue index to use",
2011 .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
2012 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)),
2013 .call = parse_vc_conf,
2017 .help = "drop packets (note: passthru has priority)",
2018 .priv = PRIV_ACTION(DROP, 0),
2019 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2024 .help = "enable counters for this rule",
2025 .priv = PRIV_ACTION(COUNT, 0),
2026 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2031 .help = "spread packets among several queues",
2032 .priv = PRIV_ACTION(RSS, sizeof(struct action_rss_data)),
2033 .next = NEXT(action_rss),
2034 .call = parse_vc_action_rss,
2036 [ACTION_RSS_FUNC] = {
2038 .help = "RSS hash function to apply",
2039 .next = NEXT(action_rss,
2040 NEXT_ENTRY(ACTION_RSS_FUNC_DEFAULT,
2041 ACTION_RSS_FUNC_TOEPLITZ,
2042 ACTION_RSS_FUNC_SIMPLE_XOR)),
2044 [ACTION_RSS_FUNC_DEFAULT] = {
2046 .help = "default hash function",
2047 .call = parse_vc_action_rss_func,
2049 [ACTION_RSS_FUNC_TOEPLITZ] = {
2051 .help = "Toeplitz hash function",
2052 .call = parse_vc_action_rss_func,
2054 [ACTION_RSS_FUNC_SIMPLE_XOR] = {
2055 .name = "simple_xor",
2056 .help = "simple XOR hash function",
2057 .call = parse_vc_action_rss_func,
2059 [ACTION_RSS_LEVEL] = {
2061 .help = "encapsulation level for \"types\"",
2062 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2063 .args = ARGS(ARGS_ENTRY_ARB
2064 (offsetof(struct action_rss_data, conf) +
2065 offsetof(struct rte_flow_action_rss, level),
2066 sizeof(((struct rte_flow_action_rss *)0)->
2069 [ACTION_RSS_TYPES] = {
2071 .help = "specific RSS hash types",
2072 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_TYPE)),
2074 [ACTION_RSS_TYPE] = {
2076 .help = "RSS hash type",
2077 .call = parse_vc_action_rss_type,
2078 .comp = comp_vc_action_rss_type,
2080 [ACTION_RSS_KEY] = {
2082 .help = "RSS hash key",
2083 .next = NEXT(action_rss, NEXT_ENTRY(STRING)),
2084 .args = ARGS(ARGS_ENTRY_ARB(0, 0),
2086 (offsetof(struct action_rss_data, conf) +
2087 offsetof(struct rte_flow_action_rss, key_len),
2088 sizeof(((struct rte_flow_action_rss *)0)->
2090 ARGS_ENTRY(struct action_rss_data, key)),
2092 [ACTION_RSS_KEY_LEN] = {
2094 .help = "RSS hash key length in bytes",
2095 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2096 .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
2097 (offsetof(struct action_rss_data, conf) +
2098 offsetof(struct rte_flow_action_rss, key_len),
2099 sizeof(((struct rte_flow_action_rss *)0)->
2102 RSS_HASH_KEY_LENGTH)),
2104 [ACTION_RSS_QUEUES] = {
2106 .help = "queue indices to use",
2107 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
2108 .call = parse_vc_conf,
2110 [ACTION_RSS_QUEUE] = {
2112 .help = "queue index",
2113 .call = parse_vc_action_rss_queue,
2114 .comp = comp_vc_action_rss_queue,
2118 .help = "direct traffic to physical function",
2119 .priv = PRIV_ACTION(PF, 0),
2120 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2125 .help = "direct traffic to a virtual function ID",
2126 .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
2127 .next = NEXT(action_vf),
2130 [ACTION_VF_ORIGINAL] = {
2132 .help = "use original VF ID if possible",
2133 .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
2134 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
2136 .call = parse_vc_conf,
2141 .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
2142 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
2143 .call = parse_vc_conf,
2145 [ACTION_PHY_PORT] = {
2147 .help = "direct packets to physical port index",
2148 .priv = PRIV_ACTION(PHY_PORT,
2149 sizeof(struct rte_flow_action_phy_port)),
2150 .next = NEXT(action_phy_port),
2153 [ACTION_PHY_PORT_ORIGINAL] = {
2155 .help = "use original port index if possible",
2156 .next = NEXT(action_phy_port, NEXT_ENTRY(BOOLEAN)),
2157 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_phy_port,
2159 .call = parse_vc_conf,
2161 [ACTION_PHY_PORT_INDEX] = {
2163 .help = "physical port index",
2164 .next = NEXT(action_phy_port, NEXT_ENTRY(UNSIGNED)),
2165 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_phy_port,
2167 .call = parse_vc_conf,
2169 [ACTION_PORT_ID] = {
2171 .help = "direct matching traffic to a given DPDK port ID",
2172 .priv = PRIV_ACTION(PORT_ID,
2173 sizeof(struct rte_flow_action_port_id)),
2174 .next = NEXT(action_port_id),
2177 [ACTION_PORT_ID_ORIGINAL] = {
2179 .help = "use original DPDK port ID if possible",
2180 .next = NEXT(action_port_id, NEXT_ENTRY(BOOLEAN)),
2181 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_port_id,
2183 .call = parse_vc_conf,
2185 [ACTION_PORT_ID_ID] = {
2187 .help = "DPDK port ID",
2188 .next = NEXT(action_port_id, NEXT_ENTRY(UNSIGNED)),
2189 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_port_id, id)),
2190 .call = parse_vc_conf,
2194 .help = "meter the directed packets at given id",
2195 .priv = PRIV_ACTION(METER,
2196 sizeof(struct rte_flow_action_meter)),
2197 .next = NEXT(action_meter),
2200 [ACTION_METER_ID] = {
2202 .help = "meter id to use",
2203 .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
2204 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
2205 .call = parse_vc_conf,
2207 [ACTION_OF_SET_MPLS_TTL] = {
2208 .name = "of_set_mpls_ttl",
2209 .help = "OpenFlow's OFPAT_SET_MPLS_TTL",
2212 sizeof(struct rte_flow_action_of_set_mpls_ttl)),
2213 .next = NEXT(action_of_set_mpls_ttl),
2216 [ACTION_OF_SET_MPLS_TTL_MPLS_TTL] = {
2219 .next = NEXT(action_of_set_mpls_ttl, NEXT_ENTRY(UNSIGNED)),
2220 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_mpls_ttl,
2222 .call = parse_vc_conf,
2224 [ACTION_OF_DEC_MPLS_TTL] = {
2225 .name = "of_dec_mpls_ttl",
2226 .help = "OpenFlow's OFPAT_DEC_MPLS_TTL",
2227 .priv = PRIV_ACTION(OF_DEC_MPLS_TTL, 0),
2228 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2231 [ACTION_OF_SET_NW_TTL] = {
2232 .name = "of_set_nw_ttl",
2233 .help = "OpenFlow's OFPAT_SET_NW_TTL",
2236 sizeof(struct rte_flow_action_of_set_nw_ttl)),
2237 .next = NEXT(action_of_set_nw_ttl),
2240 [ACTION_OF_SET_NW_TTL_NW_TTL] = {
2243 .next = NEXT(action_of_set_nw_ttl, NEXT_ENTRY(UNSIGNED)),
2244 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_nw_ttl,
2246 .call = parse_vc_conf,
2248 [ACTION_OF_DEC_NW_TTL] = {
2249 .name = "of_dec_nw_ttl",
2250 .help = "OpenFlow's OFPAT_DEC_NW_TTL",
2251 .priv = PRIV_ACTION(OF_DEC_NW_TTL, 0),
2252 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2255 [ACTION_OF_COPY_TTL_OUT] = {
2256 .name = "of_copy_ttl_out",
2257 .help = "OpenFlow's OFPAT_COPY_TTL_OUT",
2258 .priv = PRIV_ACTION(OF_COPY_TTL_OUT, 0),
2259 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2262 [ACTION_OF_COPY_TTL_IN] = {
2263 .name = "of_copy_ttl_in",
2264 .help = "OpenFlow's OFPAT_COPY_TTL_IN",
2265 .priv = PRIV_ACTION(OF_COPY_TTL_IN, 0),
2266 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2269 [ACTION_OF_POP_VLAN] = {
2270 .name = "of_pop_vlan",
2271 .help = "OpenFlow's OFPAT_POP_VLAN",
2272 .priv = PRIV_ACTION(OF_POP_VLAN, 0),
2273 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2276 [ACTION_OF_PUSH_VLAN] = {
2277 .name = "of_push_vlan",
2278 .help = "OpenFlow's OFPAT_PUSH_VLAN",
2281 sizeof(struct rte_flow_action_of_push_vlan)),
2282 .next = NEXT(action_of_push_vlan),
2285 [ACTION_OF_PUSH_VLAN_ETHERTYPE] = {
2286 .name = "ethertype",
2287 .help = "EtherType",
2288 .next = NEXT(action_of_push_vlan, NEXT_ENTRY(UNSIGNED)),
2289 .args = ARGS(ARGS_ENTRY_HTON
2290 (struct rte_flow_action_of_push_vlan,
2292 .call = parse_vc_conf,
2294 [ACTION_OF_SET_VLAN_VID] = {
2295 .name = "of_set_vlan_vid",
2296 .help = "OpenFlow's OFPAT_SET_VLAN_VID",
2299 sizeof(struct rte_flow_action_of_set_vlan_vid)),
2300 .next = NEXT(action_of_set_vlan_vid),
2303 [ACTION_OF_SET_VLAN_VID_VLAN_VID] = {
2306 .next = NEXT(action_of_set_vlan_vid, NEXT_ENTRY(UNSIGNED)),
2307 .args = ARGS(ARGS_ENTRY_HTON
2308 (struct rte_flow_action_of_set_vlan_vid,
2310 .call = parse_vc_conf,
2312 [ACTION_OF_SET_VLAN_PCP] = {
2313 .name = "of_set_vlan_pcp",
2314 .help = "OpenFlow's OFPAT_SET_VLAN_PCP",
2317 sizeof(struct rte_flow_action_of_set_vlan_pcp)),
2318 .next = NEXT(action_of_set_vlan_pcp),
2321 [ACTION_OF_SET_VLAN_PCP_VLAN_PCP] = {
2323 .help = "VLAN priority",
2324 .next = NEXT(action_of_set_vlan_pcp, NEXT_ENTRY(UNSIGNED)),
2325 .args = ARGS(ARGS_ENTRY_HTON
2326 (struct rte_flow_action_of_set_vlan_pcp,
2328 .call = parse_vc_conf,
2330 [ACTION_OF_POP_MPLS] = {
2331 .name = "of_pop_mpls",
2332 .help = "OpenFlow's OFPAT_POP_MPLS",
2333 .priv = PRIV_ACTION(OF_POP_MPLS,
2334 sizeof(struct rte_flow_action_of_pop_mpls)),
2335 .next = NEXT(action_of_pop_mpls),
2338 [ACTION_OF_POP_MPLS_ETHERTYPE] = {
2339 .name = "ethertype",
2340 .help = "EtherType",
2341 .next = NEXT(action_of_pop_mpls, NEXT_ENTRY(UNSIGNED)),
2342 .args = ARGS(ARGS_ENTRY_HTON
2343 (struct rte_flow_action_of_pop_mpls,
2345 .call = parse_vc_conf,
2347 [ACTION_OF_PUSH_MPLS] = {
2348 .name = "of_push_mpls",
2349 .help = "OpenFlow's OFPAT_PUSH_MPLS",
2352 sizeof(struct rte_flow_action_of_push_mpls)),
2353 .next = NEXT(action_of_push_mpls),
2356 [ACTION_OF_PUSH_MPLS_ETHERTYPE] = {
2357 .name = "ethertype",
2358 .help = "EtherType",
2359 .next = NEXT(action_of_push_mpls, NEXT_ENTRY(UNSIGNED)),
2360 .args = ARGS(ARGS_ENTRY_HTON
2361 (struct rte_flow_action_of_push_mpls,
2363 .call = parse_vc_conf,
2367 /** Remove and return last entry from argument stack. */
2368 static const struct arg *
2369 pop_args(struct context *ctx)
2371 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
2374 /** Add entry on top of the argument stack. */
2376 push_args(struct context *ctx, const struct arg *arg)
2378 if (ctx->args_num == CTX_STACK_SIZE)
2380 ctx->args[ctx->args_num++] = arg;
2384 /** Spread value into buffer according to bit-mask. */
2386 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
2388 uint32_t i = arg->size;
2396 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
2405 unsigned int shift = 0;
2406 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
2408 for (shift = 0; arg->mask[i] >> shift; ++shift) {
2409 if (!(arg->mask[i] & (1 << shift)))
2414 *buf &= ~(1 << shift);
2415 *buf |= (val & 1) << shift;
2423 /** Compare a string with a partial one of a given length. */
2425 strcmp_partial(const char *full, const char *partial, size_t partial_len)
2427 int r = strncmp(full, partial, partial_len);
2431 if (strlen(full) <= partial_len)
2433 return full[partial_len];
2437 * Parse a prefix length and generate a bit-mask.
2439 * Last argument (ctx->args) is retrieved to determine mask size, storage
2440 * location and whether the result must use network byte ordering.
2443 parse_prefix(struct context *ctx, const struct token *token,
2444 const char *str, unsigned int len,
2445 void *buf, unsigned int size)
2447 const struct arg *arg = pop_args(ctx);
2448 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
2455 /* Argument is expected. */
2459 u = strtoumax(str, &end, 0);
2460 if (errno || (size_t)(end - str) != len)
2465 extra = arg_entry_bf_fill(NULL, 0, arg);
2474 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
2475 !arg_entry_bf_fill(ctx->objmask, -1, arg))
2482 if (bytes > size || bytes + !!extra > size)
2486 buf = (uint8_t *)ctx->object + arg->offset;
2487 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
2489 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
2490 memset(buf, 0x00, size - bytes);
2492 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
2496 memset(buf, 0xff, bytes);
2497 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
2499 ((uint8_t *)buf)[bytes] = conv[extra];
2502 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
2505 push_args(ctx, arg);
2509 /** Default parsing function for token name matching. */
2511 parse_default(struct context *ctx, const struct token *token,
2512 const char *str, unsigned int len,
2513 void *buf, unsigned int size)
2518 if (strcmp_partial(token->name, str, len))
2523 /** Parse flow command, initialize output buffer for subsequent tokens. */
2525 parse_init(struct context *ctx, const struct token *token,
2526 const char *str, unsigned int len,
2527 void *buf, unsigned int size)
2529 struct buffer *out = buf;
2531 /* Token name must match. */
2532 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2534 /* Nothing else to do if there is no buffer. */
2537 /* Make sure buffer is large enough. */
2538 if (size < sizeof(*out))
2540 /* Initialize buffer. */
2541 memset(out, 0x00, sizeof(*out));
2542 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
2545 ctx->objmask = NULL;
2549 /** Parse tokens for validate/create commands. */
2551 parse_vc(struct context *ctx, const struct token *token,
2552 const char *str, unsigned int len,
2553 void *buf, unsigned int size)
2555 struct buffer *out = buf;
2559 /* Token name must match. */
2560 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2562 /* Nothing else to do if there is no buffer. */
2565 if (!out->command) {
2566 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
2568 if (sizeof(*out) > size)
2570 out->command = ctx->curr;
2573 ctx->objmask = NULL;
2574 out->args.vc.data = (uint8_t *)out + size;
2578 ctx->object = &out->args.vc.attr;
2579 ctx->objmask = NULL;
2580 switch (ctx->curr) {
2585 out->args.vc.attr.ingress = 1;
2588 out->args.vc.attr.egress = 1;
2591 out->args.vc.attr.transfer = 1;
2594 out->args.vc.pattern =
2595 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
2597 ctx->object = out->args.vc.pattern;
2598 ctx->objmask = NULL;
2601 out->args.vc.actions =
2602 (void *)RTE_ALIGN_CEIL((uintptr_t)
2603 (out->args.vc.pattern +
2604 out->args.vc.pattern_n),
2606 ctx->object = out->args.vc.actions;
2607 ctx->objmask = NULL;
2614 if (!out->args.vc.actions) {
2615 const struct parse_item_priv *priv = token->priv;
2616 struct rte_flow_item *item =
2617 out->args.vc.pattern + out->args.vc.pattern_n;
2619 data_size = priv->size * 3; /* spec, last, mask */
2620 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
2621 (out->args.vc.data - data_size),
2623 if ((uint8_t *)item + sizeof(*item) > data)
2625 *item = (struct rte_flow_item){
2628 ++out->args.vc.pattern_n;
2630 ctx->objmask = NULL;
2632 const struct parse_action_priv *priv = token->priv;
2633 struct rte_flow_action *action =
2634 out->args.vc.actions + out->args.vc.actions_n;
2636 data_size = priv->size; /* configuration */
2637 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
2638 (out->args.vc.data - data_size),
2640 if ((uint8_t *)action + sizeof(*action) > data)
2642 *action = (struct rte_flow_action){
2644 .conf = data_size ? data : NULL,
2646 ++out->args.vc.actions_n;
2647 ctx->object = action;
2648 ctx->objmask = NULL;
2650 memset(data, 0, data_size);
2651 out->args.vc.data = data;
2652 ctx->objdata = data_size;
2656 /** Parse pattern item parameter type. */
2658 parse_vc_spec(struct context *ctx, const struct token *token,
2659 const char *str, unsigned int len,
2660 void *buf, unsigned int size)
2662 struct buffer *out = buf;
2663 struct rte_flow_item *item;
2669 /* Token name must match. */
2670 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2672 /* Parse parameter types. */
2673 switch (ctx->curr) {
2674 static const enum index prefix[] = NEXT_ENTRY(PREFIX);
2680 case ITEM_PARAM_SPEC:
2683 case ITEM_PARAM_LAST:
2686 case ITEM_PARAM_PREFIX:
2687 /* Modify next token to expect a prefix. */
2688 if (ctx->next_num < 2)
2690 ctx->next[ctx->next_num - 2] = prefix;
2692 case ITEM_PARAM_MASK:
2698 /* Nothing else to do if there is no buffer. */
2701 if (!out->args.vc.pattern_n)
2703 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
2704 data_size = ctx->objdata / 3; /* spec, last, mask */
2705 /* Point to selected object. */
2706 ctx->object = out->args.vc.data + (data_size * index);
2708 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
2709 item->mask = ctx->objmask;
2711 ctx->objmask = NULL;
2712 /* Update relevant item pointer. */
2713 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
2718 /** Parse action configuration field. */
2720 parse_vc_conf(struct context *ctx, const struct token *token,
2721 const char *str, unsigned int len,
2722 void *buf, unsigned int size)
2724 struct buffer *out = buf;
2727 /* Token name must match. */
2728 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2730 /* Nothing else to do if there is no buffer. */
2733 /* Point to selected object. */
2734 ctx->object = out->args.vc.data;
2735 ctx->objmask = NULL;
2739 /** Parse RSS action. */
2741 parse_vc_action_rss(struct context *ctx, const struct token *token,
2742 const char *str, unsigned int len,
2743 void *buf, unsigned int size)
2745 struct buffer *out = buf;
2746 struct rte_flow_action *action;
2747 struct action_rss_data *action_rss_data;
2751 ret = parse_vc(ctx, token, str, len, buf, size);
2754 /* Nothing else to do if there is no buffer. */
2757 if (!out->args.vc.actions_n)
2759 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
2760 /* Point to selected object. */
2761 ctx->object = out->args.vc.data;
2762 ctx->objmask = NULL;
2763 /* Set up default configuration. */
2764 action_rss_data = ctx->object;
2765 *action_rss_data = (struct action_rss_data){
2766 .conf = (struct rte_flow_action_rss){
2767 .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
2770 .key_len = sizeof(action_rss_data->key),
2771 .queue_num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
2772 .key = action_rss_data->key,
2773 .queue = action_rss_data->queue,
2775 .key = "testpmd's default RSS hash key",
2778 for (i = 0; i < action_rss_data->conf.queue_num; ++i)
2779 action_rss_data->queue[i] = i;
2780 if (!port_id_is_invalid(ctx->port, DISABLED_WARN) &&
2781 ctx->port != (portid_t)RTE_PORT_ALL) {
2782 struct rte_eth_dev_info info;
2784 rte_eth_dev_info_get(ctx->port, &info);
2785 action_rss_data->conf.key_len =
2786 RTE_MIN(sizeof(action_rss_data->key),
2787 info.hash_key_size);
2789 action->conf = &action_rss_data->conf;
2794 * Parse func field for RSS action.
2796 * The RTE_ETH_HASH_FUNCTION_* value to assign is derived from the
2797 * ACTION_RSS_FUNC_* index that called this function.
2800 parse_vc_action_rss_func(struct context *ctx, const struct token *token,
2801 const char *str, unsigned int len,
2802 void *buf, unsigned int size)
2804 struct action_rss_data *action_rss_data;
2805 enum rte_eth_hash_function func;
2809 /* Token name must match. */
2810 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2812 switch (ctx->curr) {
2813 case ACTION_RSS_FUNC_DEFAULT:
2814 func = RTE_ETH_HASH_FUNCTION_DEFAULT;
2816 case ACTION_RSS_FUNC_TOEPLITZ:
2817 func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
2819 case ACTION_RSS_FUNC_SIMPLE_XOR:
2820 func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
2827 action_rss_data = ctx->object;
2828 action_rss_data->conf.func = func;
2833 * Parse type field for RSS action.
2835 * Valid tokens are type field names and the "end" token.
2838 parse_vc_action_rss_type(struct context *ctx, const struct token *token,
2839 const char *str, unsigned int len,
2840 void *buf, unsigned int size)
2842 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_TYPE);
2843 struct action_rss_data *action_rss_data;
2849 if (ctx->curr != ACTION_RSS_TYPE)
2851 if (!(ctx->objdata >> 16) && ctx->object) {
2852 action_rss_data = ctx->object;
2853 action_rss_data->conf.types = 0;
2855 if (!strcmp_partial("end", str, len)) {
2856 ctx->objdata &= 0xffff;
2859 for (i = 0; rss_type_table[i].str; ++i)
2860 if (!strcmp_partial(rss_type_table[i].str, str, len))
2862 if (!rss_type_table[i].str)
2864 ctx->objdata = 1 << 16 | (ctx->objdata & 0xffff);
2866 if (ctx->next_num == RTE_DIM(ctx->next))
2868 ctx->next[ctx->next_num++] = next;
2871 action_rss_data = ctx->object;
2872 action_rss_data->conf.types |= rss_type_table[i].rss_type;
2877 * Parse queue field for RSS action.
2879 * Valid tokens are queue indices and the "end" token.
2882 parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
2883 const char *str, unsigned int len,
2884 void *buf, unsigned int size)
2886 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
2887 struct action_rss_data *action_rss_data;
2894 if (ctx->curr != ACTION_RSS_QUEUE)
2896 i = ctx->objdata >> 16;
2897 if (!strcmp_partial("end", str, len)) {
2898 ctx->objdata &= 0xffff;
2901 if (i >= ACTION_RSS_QUEUE_NUM)
2904 ARGS_ENTRY_ARB(offsetof(struct action_rss_data, queue) +
2905 i * sizeof(action_rss_data->queue[i]),
2906 sizeof(action_rss_data->queue[i]))))
2908 ret = parse_int(ctx, token, str, len, NULL, 0);
2914 ctx->objdata = i << 16 | (ctx->objdata & 0xffff);
2916 if (ctx->next_num == RTE_DIM(ctx->next))
2918 ctx->next[ctx->next_num++] = next;
2921 action_rss_data = ctx->object;
2922 action_rss_data->conf.queue_num = i;
2923 action_rss_data->conf.queue = i ? action_rss_data->queue : NULL;
2927 /** Parse tokens for destroy command. */
2929 parse_destroy(struct context *ctx, const struct token *token,
2930 const char *str, unsigned int len,
2931 void *buf, unsigned int size)
2933 struct buffer *out = buf;
2935 /* Token name must match. */
2936 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2938 /* Nothing else to do if there is no buffer. */
2941 if (!out->command) {
2942 if (ctx->curr != DESTROY)
2944 if (sizeof(*out) > size)
2946 out->command = ctx->curr;
2949 ctx->objmask = NULL;
2950 out->args.destroy.rule =
2951 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
2955 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
2956 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
2959 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
2960 ctx->objmask = NULL;
2964 /** Parse tokens for flush command. */
2966 parse_flush(struct context *ctx, const struct token *token,
2967 const char *str, unsigned int len,
2968 void *buf, unsigned int size)
2970 struct buffer *out = buf;
2972 /* Token name must match. */
2973 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
2975 /* Nothing else to do if there is no buffer. */
2978 if (!out->command) {
2979 if (ctx->curr != FLUSH)
2981 if (sizeof(*out) > size)
2983 out->command = ctx->curr;
2986 ctx->objmask = NULL;
2991 /** Parse tokens for query command. */
2993 parse_query(struct context *ctx, const struct token *token,
2994 const char *str, unsigned int len,
2995 void *buf, unsigned int size)
2997 struct buffer *out = buf;
2999 /* Token name must match. */
3000 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3002 /* Nothing else to do if there is no buffer. */
3005 if (!out->command) {
3006 if (ctx->curr != QUERY)
3008 if (sizeof(*out) > size)
3010 out->command = ctx->curr;
3013 ctx->objmask = NULL;
3018 /** Parse action names. */
3020 parse_action(struct context *ctx, const struct token *token,
3021 const char *str, unsigned int len,
3022 void *buf, unsigned int size)
3024 struct buffer *out = buf;
3025 const struct arg *arg = pop_args(ctx);
3029 /* Argument is expected. */
3032 /* Parse action name. */
3033 for (i = 0; next_action[i]; ++i) {
3034 const struct parse_action_priv *priv;
3036 token = &token_list[next_action[i]];
3037 if (strcmp_partial(token->name, str, len))
3043 memcpy((uint8_t *)ctx->object + arg->offset,
3049 push_args(ctx, arg);
3053 /** Parse tokens for list command. */
3055 parse_list(struct context *ctx, const struct token *token,
3056 const char *str, unsigned int len,
3057 void *buf, unsigned int size)
3059 struct buffer *out = buf;
3061 /* Token name must match. */
3062 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3064 /* Nothing else to do if there is no buffer. */
3067 if (!out->command) {
3068 if (ctx->curr != LIST)
3070 if (sizeof(*out) > size)
3072 out->command = ctx->curr;
3075 ctx->objmask = NULL;
3076 out->args.list.group =
3077 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
3081 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
3082 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
3085 ctx->object = out->args.list.group + out->args.list.group_n++;
3086 ctx->objmask = NULL;
3090 /** Parse tokens for isolate command. */
3092 parse_isolate(struct context *ctx, const struct token *token,
3093 const char *str, unsigned int len,
3094 void *buf, unsigned int size)
3096 struct buffer *out = buf;
3098 /* Token name must match. */
3099 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3101 /* Nothing else to do if there is no buffer. */
3104 if (!out->command) {
3105 if (ctx->curr != ISOLATE)
3107 if (sizeof(*out) > size)
3109 out->command = ctx->curr;
3112 ctx->objmask = NULL;
3118 * Parse signed/unsigned integers 8 to 64-bit long.
3120 * Last argument (ctx->args) is retrieved to determine integer type and
3124 parse_int(struct context *ctx, const struct token *token,
3125 const char *str, unsigned int len,
3126 void *buf, unsigned int size)
3128 const struct arg *arg = pop_args(ctx);
3133 /* Argument is expected. */
3138 (uintmax_t)strtoimax(str, &end, 0) :
3139 strtoumax(str, &end, 0);
3140 if (errno || (size_t)(end - str) != len)
3143 ((arg->sign && ((intmax_t)u < (intmax_t)arg->min ||
3144 (intmax_t)u > (intmax_t)arg->max)) ||
3145 (!arg->sign && (u < arg->min || u > arg->max))))
3150 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
3151 !arg_entry_bf_fill(ctx->objmask, -1, arg))
3155 buf = (uint8_t *)ctx->object + arg->offset;
3159 case sizeof(uint8_t):
3160 *(uint8_t *)buf = u;
3162 case sizeof(uint16_t):
3163 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
3165 case sizeof(uint8_t [3]):
3166 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
3168 ((uint8_t *)buf)[0] = u;
3169 ((uint8_t *)buf)[1] = u >> 8;
3170 ((uint8_t *)buf)[2] = u >> 16;
3174 ((uint8_t *)buf)[0] = u >> 16;
3175 ((uint8_t *)buf)[1] = u >> 8;
3176 ((uint8_t *)buf)[2] = u;
3178 case sizeof(uint32_t):
3179 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
3181 case sizeof(uint64_t):
3182 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
3187 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
3189 buf = (uint8_t *)ctx->objmask + arg->offset;
3194 push_args(ctx, arg);
3201 * Three arguments (ctx->args) are retrieved from the stack to store data,
3202 * its actual length and address (in that order).
3205 parse_string(struct context *ctx, const struct token *token,
3206 const char *str, unsigned int len,
3207 void *buf, unsigned int size)
3209 const struct arg *arg_data = pop_args(ctx);
3210 const struct arg *arg_len = pop_args(ctx);
3211 const struct arg *arg_addr = pop_args(ctx);
3212 char tmp[16]; /* Ought to be enough. */
3215 /* Arguments are expected. */
3219 push_args(ctx, arg_data);
3223 push_args(ctx, arg_len);
3224 push_args(ctx, arg_data);
3227 size = arg_data->size;
3228 /* Bit-mask fill is not supported. */
3229 if (arg_data->mask || size < len)
3233 /* Let parse_int() fill length information first. */
3234 ret = snprintf(tmp, sizeof(tmp), "%u", len);
3237 push_args(ctx, arg_len);
3238 ret = parse_int(ctx, token, tmp, ret, NULL, 0);
3243 buf = (uint8_t *)ctx->object + arg_data->offset;
3244 /* Output buffer is not necessarily NUL-terminated. */
3245 memcpy(buf, str, len);
3246 memset((uint8_t *)buf + len, 0x00, size - len);
3248 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
3249 /* Save address if requested. */
3250 if (arg_addr->size) {
3251 memcpy((uint8_t *)ctx->object + arg_addr->offset,
3253 (uint8_t *)ctx->object + arg_data->offset
3257 memcpy((uint8_t *)ctx->objmask + arg_addr->offset,
3259 (uint8_t *)ctx->objmask + arg_data->offset
3265 push_args(ctx, arg_addr);
3266 push_args(ctx, arg_len);
3267 push_args(ctx, arg_data);
3272 * Parse a MAC address.
3274 * Last argument (ctx->args) is retrieved to determine storage size and
3278 parse_mac_addr(struct context *ctx, const struct token *token,
3279 const char *str, unsigned int len,
3280 void *buf, unsigned int size)
3282 const struct arg *arg = pop_args(ctx);
3283 struct ether_addr tmp;
3287 /* Argument is expected. */
3291 /* Bit-mask fill is not supported. */
3292 if (arg->mask || size != sizeof(tmp))
3294 /* Only network endian is supported. */
3297 ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
3298 if (ret < 0 || (unsigned int)ret != len)
3302 buf = (uint8_t *)ctx->object + arg->offset;
3303 memcpy(buf, &tmp, size);
3305 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
3308 push_args(ctx, arg);
3313 * Parse an IPv4 address.
3315 * Last argument (ctx->args) is retrieved to determine storage size and
3319 parse_ipv4_addr(struct context *ctx, const struct token *token,
3320 const char *str, unsigned int len,
3321 void *buf, unsigned int size)
3323 const struct arg *arg = pop_args(ctx);
3328 /* Argument is expected. */
3332 /* Bit-mask fill is not supported. */
3333 if (arg->mask || size != sizeof(tmp))
3335 /* Only network endian is supported. */
3338 memcpy(str2, str, len);
3340 ret = inet_pton(AF_INET, str2, &tmp);
3342 /* Attempt integer parsing. */
3343 push_args(ctx, arg);
3344 return parse_int(ctx, token, str, len, buf, size);
3348 buf = (uint8_t *)ctx->object + arg->offset;
3349 memcpy(buf, &tmp, size);
3351 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
3354 push_args(ctx, arg);
3359 * Parse an IPv6 address.
3361 * Last argument (ctx->args) is retrieved to determine storage size and
3365 parse_ipv6_addr(struct context *ctx, const struct token *token,
3366 const char *str, unsigned int len,
3367 void *buf, unsigned int size)
3369 const struct arg *arg = pop_args(ctx);
3371 struct in6_addr tmp;
3375 /* Argument is expected. */
3379 /* Bit-mask fill is not supported. */
3380 if (arg->mask || size != sizeof(tmp))
3382 /* Only network endian is supported. */
3385 memcpy(str2, str, len);
3387 ret = inet_pton(AF_INET6, str2, &tmp);
3392 buf = (uint8_t *)ctx->object + arg->offset;
3393 memcpy(buf, &tmp, size);
3395 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
3398 push_args(ctx, arg);
3402 /** Boolean values (even indices stand for false). */
3403 static const char *const boolean_name[] = {
3413 * Parse a boolean value.
3415 * Last argument (ctx->args) is retrieved to determine storage size and
3419 parse_boolean(struct context *ctx, const struct token *token,
3420 const char *str, unsigned int len,
3421 void *buf, unsigned int size)
3423 const struct arg *arg = pop_args(ctx);
3427 /* Argument is expected. */
3430 for (i = 0; boolean_name[i]; ++i)
3431 if (!strcmp_partial(boolean_name[i], str, len))
3433 /* Process token as integer. */
3434 if (boolean_name[i])
3435 str = i & 1 ? "1" : "0";
3436 push_args(ctx, arg);
3437 ret = parse_int(ctx, token, str, strlen(str), buf, size);
3438 return ret > 0 ? (int)len : ret;
3441 /** Parse port and update context. */
3443 parse_port(struct context *ctx, const struct token *token,
3444 const char *str, unsigned int len,
3445 void *buf, unsigned int size)
3447 struct buffer *out = &(struct buffer){ .port = 0 };
3455 ctx->objmask = NULL;
3456 size = sizeof(*out);
3458 ret = parse_int(ctx, token, str, len, out, size);
3460 ctx->port = out->port;
3466 /** No completion. */
3468 comp_none(struct context *ctx, const struct token *token,
3469 unsigned int ent, char *buf, unsigned int size)
3479 /** Complete boolean values. */
3481 comp_boolean(struct context *ctx, const struct token *token,
3482 unsigned int ent, char *buf, unsigned int size)
3488 for (i = 0; boolean_name[i]; ++i)
3489 if (buf && i == ent)
3490 return snprintf(buf, size, "%s", boolean_name[i]);
3496 /** Complete action names. */
3498 comp_action(struct context *ctx, const struct token *token,
3499 unsigned int ent, char *buf, unsigned int size)
3505 for (i = 0; next_action[i]; ++i)
3506 if (buf && i == ent)
3507 return snprintf(buf, size, "%s",
3508 token_list[next_action[i]].name);
3514 /** Complete available ports. */
3516 comp_port(struct context *ctx, const struct token *token,
3517 unsigned int ent, char *buf, unsigned int size)
3524 RTE_ETH_FOREACH_DEV(p) {
3525 if (buf && i == ent)
3526 return snprintf(buf, size, "%u", p);
3534 /** Complete available rule IDs. */
3536 comp_rule_id(struct context *ctx, const struct token *token,
3537 unsigned int ent, char *buf, unsigned int size)
3540 struct rte_port *port;
3541 struct port_flow *pf;
3544 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
3545 ctx->port == (portid_t)RTE_PORT_ALL)
3547 port = &ports[ctx->port];
3548 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
3549 if (buf && i == ent)
3550 return snprintf(buf, size, "%u", pf->id);
3558 /** Complete type field for RSS action. */
3560 comp_vc_action_rss_type(struct context *ctx, const struct token *token,
3561 unsigned int ent, char *buf, unsigned int size)
3567 for (i = 0; rss_type_table[i].str; ++i)
3572 return snprintf(buf, size, "%s", rss_type_table[ent].str);
3574 return snprintf(buf, size, "end");
3578 /** Complete queue field for RSS action. */
3580 comp_vc_action_rss_queue(struct context *ctx, const struct token *token,
3581 unsigned int ent, char *buf, unsigned int size)
3588 return snprintf(buf, size, "%u", ent);
3590 return snprintf(buf, size, "end");
3594 /** Internal context. */
3595 static struct context cmd_flow_context;
3597 /** Global parser instance (cmdline API). */
3598 cmdline_parse_inst_t cmd_flow;
3600 /** Initialize context. */
3602 cmd_flow_context_init(struct context *ctx)
3604 /* A full memset() is not necessary. */
3614 ctx->objmask = NULL;
3617 /** Parse a token (cmdline API). */
3619 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
3622 struct context *ctx = &cmd_flow_context;
3623 const struct token *token;
3624 const enum index *list;
3629 token = &token_list[ctx->curr];
3630 /* Check argument length. */
3633 for (len = 0; src[len]; ++len)
3634 if (src[len] == '#' || isspace(src[len]))
3638 /* Last argument and EOL detection. */
3639 for (i = len; src[i]; ++i)
3640 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
3642 else if (!isspace(src[i])) {
3647 if (src[i] == '\r' || src[i] == '\n') {
3651 /* Initialize context if necessary. */
3652 if (!ctx->next_num) {
3655 ctx->next[ctx->next_num++] = token->next[0];
3657 /* Process argument through candidates. */
3658 ctx->prev = ctx->curr;
3659 list = ctx->next[ctx->next_num - 1];
3660 for (i = 0; list[i]; ++i) {
3661 const struct token *next = &token_list[list[i]];
3664 ctx->curr = list[i];
3666 tmp = next->call(ctx, next, src, len, result, size);
3668 tmp = parse_default(ctx, next, src, len, result, size);
3669 if (tmp == -1 || tmp != len)
3677 /* Push subsequent tokens if any. */
3679 for (i = 0; token->next[i]; ++i) {
3680 if (ctx->next_num == RTE_DIM(ctx->next))
3682 ctx->next[ctx->next_num++] = token->next[i];
3684 /* Push arguments if any. */
3686 for (i = 0; token->args[i]; ++i) {
3687 if (ctx->args_num == RTE_DIM(ctx->args))
3689 ctx->args[ctx->args_num++] = token->args[i];
3694 /** Return number of completion entries (cmdline API). */
3696 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
3698 struct context *ctx = &cmd_flow_context;
3699 const struct token *token = &token_list[ctx->curr];
3700 const enum index *list;
3704 /* Count number of tokens in current list. */
3706 list = ctx->next[ctx->next_num - 1];
3708 list = token->next[0];
3709 for (i = 0; list[i]; ++i)
3714 * If there is a single token, use its completion callback, otherwise
3715 * return the number of entries.
3717 token = &token_list[list[0]];
3718 if (i == 1 && token->comp) {
3719 /* Save index for cmd_flow_get_help(). */
3720 ctx->prev = list[0];
3721 return token->comp(ctx, token, 0, NULL, 0);
3726 /** Return a completion entry (cmdline API). */
3728 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
3729 char *dst, unsigned int size)
3731 struct context *ctx = &cmd_flow_context;
3732 const struct token *token = &token_list[ctx->curr];
3733 const enum index *list;
3737 /* Count number of tokens in current list. */
3739 list = ctx->next[ctx->next_num - 1];
3741 list = token->next[0];
3742 for (i = 0; list[i]; ++i)
3746 /* If there is a single token, use its completion callback. */
3747 token = &token_list[list[0]];
3748 if (i == 1 && token->comp) {
3749 /* Save index for cmd_flow_get_help(). */
3750 ctx->prev = list[0];
3751 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
3753 /* Otherwise make sure the index is valid and use defaults. */
3756 token = &token_list[list[index]];
3757 snprintf(dst, size, "%s", token->name);
3758 /* Save index for cmd_flow_get_help(). */
3759 ctx->prev = list[index];
3763 /** Populate help strings for current token (cmdline API). */
3765 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
3767 struct context *ctx = &cmd_flow_context;
3768 const struct token *token = &token_list[ctx->prev];
3773 /* Set token type and update global help with details. */
3774 snprintf(dst, size, "%s", (token->type ? token->type : "TOKEN"));
3776 cmd_flow.help_str = token->help;
3778 cmd_flow.help_str = token->name;
3782 /** Token definition template (cmdline API). */
3783 static struct cmdline_token_hdr cmd_flow_token_hdr = {
3784 .ops = &(struct cmdline_token_ops){
3785 .parse = cmd_flow_parse,
3786 .complete_get_nb = cmd_flow_complete_get_nb,
3787 .complete_get_elt = cmd_flow_complete_get_elt,
3788 .get_help = cmd_flow_get_help,
3793 /** Populate the next dynamic token. */
3795 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
3796 cmdline_parse_token_hdr_t **hdr_inst)
3798 struct context *ctx = &cmd_flow_context;
3800 /* Always reinitialize context before requesting the first token. */
3801 if (!(hdr_inst - cmd_flow.tokens))
3802 cmd_flow_context_init(ctx);
3803 /* Return NULL when no more tokens are expected. */
3804 if (!ctx->next_num && ctx->curr) {
3808 /* Determine if command should end here. */
3809 if (ctx->eol && ctx->last && ctx->next_num) {
3810 const enum index *list = ctx->next[ctx->next_num - 1];
3813 for (i = 0; list[i]; ++i) {
3820 *hdr = &cmd_flow_token_hdr;
3823 /** Dispatch parsed buffer to function calls. */
3825 cmd_flow_parsed(const struct buffer *in)
3827 switch (in->command) {
3829 port_flow_validate(in->port, &in->args.vc.attr,
3830 in->args.vc.pattern, in->args.vc.actions);
3833 port_flow_create(in->port, &in->args.vc.attr,
3834 in->args.vc.pattern, in->args.vc.actions);
3837 port_flow_destroy(in->port, in->args.destroy.rule_n,
3838 in->args.destroy.rule);
3841 port_flow_flush(in->port);
3844 port_flow_query(in->port, in->args.query.rule,
3845 &in->args.query.action);
3848 port_flow_list(in->port, in->args.list.group_n,
3849 in->args.list.group);
3852 port_flow_isolate(in->port, in->args.isolate.set);
3859 /** Token generator and output processing callback (cmdline API). */
3861 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
3864 cmd_flow_tok(arg0, arg2);
3866 cmd_flow_parsed(arg0);
3869 /** Global parser instance (cmdline API). */
3870 cmdline_parse_inst_t cmd_flow = {
3872 .data = NULL, /**< Unused. */
3873 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
3876 }, /**< Tokens are returned by cmd_flow_tok(). */