1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016 6WIND S.A.
3 * Copyright 2016 Mellanox Technologies, Ltd
13 #include <arpa/inet.h>
14 #include <sys/socket.h>
16 #include <rte_string_fns.h>
17 #include <rte_common.h>
18 #include <rte_ethdev.h>
19 #include <rte_byteorder.h>
20 #include <cmdline_parse.h>
25 /** 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,
150 ITEM_GRE_C_RSVD0_VER,
166 ITEM_ARP_ETH_IPV4_SHA,
167 ITEM_ARP_ETH_IPV4_SPA,
168 ITEM_ARP_ETH_IPV4_THA,
169 ITEM_ARP_ETH_IPV4_TPA,
171 ITEM_IPV6_EXT_NEXT_HDR,
176 ITEM_ICMP6_ND_NS_TARGET_ADDR,
178 ITEM_ICMP6_ND_NA_TARGET_ADDR,
180 ITEM_ICMP6_ND_OPT_TYPE,
181 ITEM_ICMP6_ND_OPT_SLA_ETH,
182 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
183 ITEM_ICMP6_ND_OPT_TLA_ETH,
184 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
190 /* Validate/create actions. */
210 ACTION_RSS_FUNC_DEFAULT,
211 ACTION_RSS_FUNC_TOEPLITZ,
212 ACTION_RSS_FUNC_SIMPLE_XOR,
224 ACTION_PHY_PORT_ORIGINAL,
225 ACTION_PHY_PORT_INDEX,
227 ACTION_PORT_ID_ORIGINAL,
231 ACTION_OF_SET_MPLS_TTL,
232 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
233 ACTION_OF_DEC_MPLS_TTL,
234 ACTION_OF_SET_NW_TTL,
235 ACTION_OF_SET_NW_TTL_NW_TTL,
236 ACTION_OF_DEC_NW_TTL,
237 ACTION_OF_COPY_TTL_OUT,
238 ACTION_OF_COPY_TTL_IN,
241 ACTION_OF_PUSH_VLAN_ETHERTYPE,
242 ACTION_OF_SET_VLAN_VID,
243 ACTION_OF_SET_VLAN_VID_VLAN_VID,
244 ACTION_OF_SET_VLAN_PCP,
245 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
247 ACTION_OF_POP_MPLS_ETHERTYPE,
249 ACTION_OF_PUSH_MPLS_ETHERTYPE,
256 ACTION_MPLSOGRE_ENCAP,
257 ACTION_MPLSOGRE_DECAP,
258 ACTION_MPLSOUDP_ENCAP,
259 ACTION_MPLSOUDP_DECAP,
261 ACTION_SET_IPV4_SRC_IPV4_SRC,
263 ACTION_SET_IPV4_DST_IPV4_DST,
265 ACTION_SET_IPV6_SRC_IPV6_SRC,
267 ACTION_SET_IPV6_DST_IPV6_DST,
269 ACTION_SET_TP_SRC_TP_SRC,
271 ACTION_SET_TP_DST_TP_DST,
277 ACTION_SET_MAC_SRC_MAC_SRC,
279 ACTION_SET_MAC_DST_MAC_DST,
281 ACTION_INC_TCP_SEQ_VALUE,
283 ACTION_DEC_TCP_SEQ_VALUE,
285 ACTION_INC_TCP_ACK_VALUE,
287 ACTION_DEC_TCP_ACK_VALUE,
290 /** Maximum size for pattern in struct rte_flow_item_raw. */
291 #define ITEM_RAW_PATTERN_SIZE 40
293 /** Storage size for struct rte_flow_item_raw including pattern. */
294 #define ITEM_RAW_SIZE \
295 (sizeof(struct rte_flow_item_raw) + ITEM_RAW_PATTERN_SIZE)
297 /** Maximum number of queue indices in struct rte_flow_action_rss. */
298 #define ACTION_RSS_QUEUE_NUM 32
300 /** Storage for struct rte_flow_action_rss including external data. */
301 struct action_rss_data {
302 struct rte_flow_action_rss conf;
303 uint8_t key[RSS_HASH_KEY_LENGTH];
304 uint16_t queue[ACTION_RSS_QUEUE_NUM];
307 /** Maximum number of items in struct rte_flow_action_vxlan_encap. */
308 #define ACTION_VXLAN_ENCAP_ITEMS_NUM 6
310 /** Storage for struct rte_flow_action_vxlan_encap including external data. */
311 struct action_vxlan_encap_data {
312 struct rte_flow_action_vxlan_encap conf;
313 struct rte_flow_item items[ACTION_VXLAN_ENCAP_ITEMS_NUM];
314 struct rte_flow_item_eth item_eth;
315 struct rte_flow_item_vlan item_vlan;
317 struct rte_flow_item_ipv4 item_ipv4;
318 struct rte_flow_item_ipv6 item_ipv6;
320 struct rte_flow_item_udp item_udp;
321 struct rte_flow_item_vxlan item_vxlan;
324 /** Maximum number of items in struct rte_flow_action_nvgre_encap. */
325 #define ACTION_NVGRE_ENCAP_ITEMS_NUM 5
327 /** Storage for struct rte_flow_action_nvgre_encap including external data. */
328 struct action_nvgre_encap_data {
329 struct rte_flow_action_nvgre_encap conf;
330 struct rte_flow_item items[ACTION_NVGRE_ENCAP_ITEMS_NUM];
331 struct rte_flow_item_eth item_eth;
332 struct rte_flow_item_vlan item_vlan;
334 struct rte_flow_item_ipv4 item_ipv4;
335 struct rte_flow_item_ipv6 item_ipv6;
337 struct rte_flow_item_nvgre item_nvgre;
340 /** Maximum data size in struct rte_flow_action_raw_encap. */
341 #define ACTION_RAW_ENCAP_MAX_DATA 128
343 /** Storage for struct rte_flow_action_raw_encap including external data. */
344 struct action_raw_encap_data {
345 struct rte_flow_action_raw_encap conf;
346 uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
347 uint8_t preserve[ACTION_RAW_ENCAP_MAX_DATA];
350 /** Storage for struct rte_flow_action_raw_decap including external data. */
351 struct action_raw_decap_data {
352 struct rte_flow_action_raw_decap conf;
353 uint8_t data[ACTION_RAW_ENCAP_MAX_DATA];
356 /** Maximum number of subsequent tokens and arguments on the stack. */
357 #define CTX_STACK_SIZE 16
359 /** Parser context. */
361 /** Stack of subsequent token lists to process. */
362 const enum index *next[CTX_STACK_SIZE];
363 /** Arguments for stacked tokens. */
364 const void *args[CTX_STACK_SIZE];
365 enum index curr; /**< Current token index. */
366 enum index prev; /**< Index of the last token seen. */
367 int next_num; /**< Number of entries in next[]. */
368 int args_num; /**< Number of entries in args[]. */
369 uint32_t eol:1; /**< EOL has been detected. */
370 uint32_t last:1; /**< No more arguments. */
371 portid_t port; /**< Current port ID (for completions). */
372 uint32_t objdata; /**< Object-specific data. */
373 void *object; /**< Address of current object for relative offsets. */
374 void *objmask; /**< Object a full mask must be written to. */
377 /** Token argument. */
379 uint32_t hton:1; /**< Use network byte ordering. */
380 uint32_t sign:1; /**< Value is signed. */
381 uint32_t bounded:1; /**< Value is bounded. */
382 uintmax_t min; /**< Minimum value if bounded. */
383 uintmax_t max; /**< Maximum value if bounded. */
384 uint32_t offset; /**< Relative offset from ctx->object. */
385 uint32_t size; /**< Field size. */
386 const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
389 /** Parser token definition. */
391 /** Type displayed during completion (defaults to "TOKEN"). */
393 /** Help displayed during completion (defaults to token name). */
395 /** Private data used by parser functions. */
398 * Lists of subsequent tokens to push on the stack. Each call to the
399 * parser consumes the last entry of that stack.
401 const enum index *const *next;
402 /** Arguments stack for subsequent tokens that need them. */
403 const struct arg *const *args;
405 * Token-processing callback, returns -1 in case of error, the
406 * length of the matched string otherwise. If NULL, attempts to
407 * match the token name.
409 * If buf is not NULL, the result should be stored in it according
410 * to context. An error is returned if not large enough.
412 int (*call)(struct context *ctx, const struct token *token,
413 const char *str, unsigned int len,
414 void *buf, unsigned int size);
416 * Callback that provides possible values for this token, used for
417 * completion. Returns -1 in case of error, the number of possible
418 * values otherwise. If NULL, the token name is used.
420 * If buf is not NULL, entry index ent is written to buf and the
421 * full length of the entry is returned (same behavior as
424 int (*comp)(struct context *ctx, const struct token *token,
425 unsigned int ent, char *buf, unsigned int size);
426 /** Mandatory token name, no default value. */
430 /** Static initializer for the next field. */
431 #define NEXT(...) (const enum index *const []){ __VA_ARGS__, NULL, }
433 /** Static initializer for a NEXT() entry. */
434 #define NEXT_ENTRY(...) (const enum index []){ __VA_ARGS__, ZERO, }
436 /** Static initializer for the args field. */
437 #define ARGS(...) (const struct arg *const []){ __VA_ARGS__, NULL, }
439 /** Static initializer for ARGS() to target a field. */
440 #define ARGS_ENTRY(s, f) \
441 (&(const struct arg){ \
442 .offset = offsetof(s, f), \
443 .size = sizeof(((s *)0)->f), \
446 /** Static initializer for ARGS() to target a bit-field. */
447 #define ARGS_ENTRY_BF(s, f, b) \
448 (&(const struct arg){ \
450 .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
453 /** Static initializer for ARGS() to target an arbitrary bit-mask. */
454 #define ARGS_ENTRY_MASK(s, f, m) \
455 (&(const struct arg){ \
456 .offset = offsetof(s, f), \
457 .size = sizeof(((s *)0)->f), \
458 .mask = (const void *)(m), \
461 /** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */
462 #define ARGS_ENTRY_MASK_HTON(s, f, m) \
463 (&(const struct arg){ \
465 .offset = offsetof(s, f), \
466 .size = sizeof(((s *)0)->f), \
467 .mask = (const void *)(m), \
470 /** Static initializer for ARGS() to target a pointer. */
471 #define ARGS_ENTRY_PTR(s, f) \
472 (&(const struct arg){ \
473 .size = sizeof(*((s *)0)->f), \
476 /** Static initializer for ARGS() with arbitrary offset and size. */
477 #define ARGS_ENTRY_ARB(o, s) \
478 (&(const struct arg){ \
483 /** Same as ARGS_ENTRY_ARB() with bounded values. */
484 #define ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
485 (&(const struct arg){ \
493 /** Same as ARGS_ENTRY() using network byte ordering. */
494 #define ARGS_ENTRY_HTON(s, f) \
495 (&(const struct arg){ \
497 .offset = offsetof(s, f), \
498 .size = sizeof(((s *)0)->f), \
501 /** Same as ARGS_ENTRY_HTON() for a single argument, without structure. */
502 #define ARG_ENTRY_HTON(s) \
503 (&(const struct arg){ \
509 /** Parser output buffer layout expected by cmd_flow_parsed(). */
511 enum index command; /**< Flow command. */
512 portid_t port; /**< Affected port ID. */
515 struct rte_flow_attr attr;
516 struct rte_flow_item *pattern;
517 struct rte_flow_action *actions;
521 } vc; /**< Validate/create arguments. */
525 } destroy; /**< Destroy arguments. */
528 struct rte_flow_action action;
529 } query; /**< Query arguments. */
533 } list; /**< List arguments. */
536 } isolate; /**< Isolated mode arguments. */
537 } args; /**< Command arguments. */
540 /** Private data for pattern items. */
541 struct parse_item_priv {
542 enum rte_flow_item_type type; /**< Item type. */
543 uint32_t size; /**< Size of item specification structure. */
546 #define PRIV_ITEM(t, s) \
547 (&(const struct parse_item_priv){ \
548 .type = RTE_FLOW_ITEM_TYPE_ ## t, \
552 /** Private data for actions. */
553 struct parse_action_priv {
554 enum rte_flow_action_type type; /**< Action type. */
555 uint32_t size; /**< Size of action configuration structure. */
558 #define PRIV_ACTION(t, s) \
559 (&(const struct parse_action_priv){ \
560 .type = RTE_FLOW_ACTION_TYPE_ ## t, \
564 static const enum index next_vc_attr[] = {
574 static const enum index next_destroy_attr[] = {
580 static const enum index next_list_attr[] = {
586 static const enum index item_param[] = {
595 static const enum index next_item[] = {
631 ITEM_ICMP6_ND_OPT_SLA_ETH,
632 ITEM_ICMP6_ND_OPT_TLA_ETH,
638 static const enum index item_fuzzy[] = {
644 static const enum index item_any[] = {
650 static const enum index item_vf[] = {
656 static const enum index item_phy_port[] = {
662 static const enum index item_port_id[] = {
668 static const enum index item_mark[] = {
674 static const enum index item_raw[] = {
684 static const enum index item_eth[] = {
692 static const enum index item_vlan[] = {
697 ITEM_VLAN_INNER_TYPE,
702 static const enum index item_ipv4[] = {
712 static const enum index item_ipv6[] = {
723 static const enum index item_icmp[] = {
730 static const enum index item_udp[] = {
737 static const enum index item_tcp[] = {
745 static const enum index item_sctp[] = {
754 static const enum index item_vxlan[] = {
760 static const enum index item_e_tag[] = {
761 ITEM_E_TAG_GRP_ECID_B,
766 static const enum index item_nvgre[] = {
772 static const enum index item_mpls[] = {
778 static const enum index item_gre[] = {
780 ITEM_GRE_C_RSVD0_VER,
788 static const enum index item_gre_key[] = {
794 static const enum index item_gtp[] = {
800 static const enum index item_geneve[] = {
807 static const enum index item_vxlan_gpe[] = {
813 static const enum index item_arp_eth_ipv4[] = {
814 ITEM_ARP_ETH_IPV4_SHA,
815 ITEM_ARP_ETH_IPV4_SPA,
816 ITEM_ARP_ETH_IPV4_THA,
817 ITEM_ARP_ETH_IPV4_TPA,
822 static const enum index item_ipv6_ext[] = {
823 ITEM_IPV6_EXT_NEXT_HDR,
828 static const enum index item_icmp6[] = {
835 static const enum index item_icmp6_nd_ns[] = {
836 ITEM_ICMP6_ND_NS_TARGET_ADDR,
841 static const enum index item_icmp6_nd_na[] = {
842 ITEM_ICMP6_ND_NA_TARGET_ADDR,
847 static const enum index item_icmp6_nd_opt[] = {
848 ITEM_ICMP6_ND_OPT_TYPE,
853 static const enum index item_icmp6_nd_opt_sla_eth[] = {
854 ITEM_ICMP6_ND_OPT_SLA_ETH_SLA,
859 static const enum index item_icmp6_nd_opt_tla_eth[] = {
860 ITEM_ICMP6_ND_OPT_TLA_ETH_TLA,
865 static const enum index item_meta[] = {
871 static const enum index next_action[] = {
887 ACTION_OF_SET_MPLS_TTL,
888 ACTION_OF_DEC_MPLS_TTL,
889 ACTION_OF_SET_NW_TTL,
890 ACTION_OF_DEC_NW_TTL,
891 ACTION_OF_COPY_TTL_OUT,
892 ACTION_OF_COPY_TTL_IN,
895 ACTION_OF_SET_VLAN_VID,
896 ACTION_OF_SET_VLAN_PCP,
905 ACTION_MPLSOGRE_ENCAP,
906 ACTION_MPLSOGRE_DECAP,
907 ACTION_MPLSOUDP_ENCAP,
908 ACTION_MPLSOUDP_DECAP,
927 static const enum index action_mark[] = {
933 static const enum index action_queue[] = {
939 static const enum index action_count[] = {
946 static const enum index action_rss[] = {
957 static const enum index action_vf[] = {
964 static const enum index action_phy_port[] = {
965 ACTION_PHY_PORT_ORIGINAL,
966 ACTION_PHY_PORT_INDEX,
971 static const enum index action_port_id[] = {
972 ACTION_PORT_ID_ORIGINAL,
978 static const enum index action_meter[] = {
984 static const enum index action_of_set_mpls_ttl[] = {
985 ACTION_OF_SET_MPLS_TTL_MPLS_TTL,
990 static const enum index action_of_set_nw_ttl[] = {
991 ACTION_OF_SET_NW_TTL_NW_TTL,
996 static const enum index action_of_push_vlan[] = {
997 ACTION_OF_PUSH_VLAN_ETHERTYPE,
1002 static const enum index action_of_set_vlan_vid[] = {
1003 ACTION_OF_SET_VLAN_VID_VLAN_VID,
1008 static const enum index action_of_set_vlan_pcp[] = {
1009 ACTION_OF_SET_VLAN_PCP_VLAN_PCP,
1014 static const enum index action_of_pop_mpls[] = {
1015 ACTION_OF_POP_MPLS_ETHERTYPE,
1020 static const enum index action_of_push_mpls[] = {
1021 ACTION_OF_PUSH_MPLS_ETHERTYPE,
1026 static const enum index action_set_ipv4_src[] = {
1027 ACTION_SET_IPV4_SRC_IPV4_SRC,
1032 static const enum index action_set_mac_src[] = {
1033 ACTION_SET_MAC_SRC_MAC_SRC,
1038 static const enum index action_set_ipv4_dst[] = {
1039 ACTION_SET_IPV4_DST_IPV4_DST,
1044 static const enum index action_set_ipv6_src[] = {
1045 ACTION_SET_IPV6_SRC_IPV6_SRC,
1050 static const enum index action_set_ipv6_dst[] = {
1051 ACTION_SET_IPV6_DST_IPV6_DST,
1056 static const enum index action_set_tp_src[] = {
1057 ACTION_SET_TP_SRC_TP_SRC,
1062 static const enum index action_set_tp_dst[] = {
1063 ACTION_SET_TP_DST_TP_DST,
1068 static const enum index action_set_ttl[] = {
1074 static const enum index action_jump[] = {
1080 static const enum index action_set_mac_dst[] = {
1081 ACTION_SET_MAC_DST_MAC_DST,
1086 static const enum index action_inc_tcp_seq[] = {
1087 ACTION_INC_TCP_SEQ_VALUE,
1092 static const enum index action_dec_tcp_seq[] = {
1093 ACTION_DEC_TCP_SEQ_VALUE,
1098 static const enum index action_inc_tcp_ack[] = {
1099 ACTION_INC_TCP_ACK_VALUE,
1104 static const enum index action_dec_tcp_ack[] = {
1105 ACTION_DEC_TCP_ACK_VALUE,
1110 static int parse_init(struct context *, const struct token *,
1111 const char *, unsigned int,
1112 void *, unsigned int);
1113 static int parse_vc(struct context *, const struct token *,
1114 const char *, unsigned int,
1115 void *, unsigned int);
1116 static int parse_vc_spec(struct context *, const struct token *,
1117 const char *, unsigned int, void *, unsigned int);
1118 static int parse_vc_conf(struct context *, const struct token *,
1119 const char *, unsigned int, void *, unsigned int);
1120 static int parse_vc_action_rss(struct context *, const struct token *,
1121 const char *, unsigned int, void *,
1123 static int parse_vc_action_rss_func(struct context *, const struct token *,
1124 const char *, unsigned int, void *,
1126 static int parse_vc_action_rss_type(struct context *, const struct token *,
1127 const char *, unsigned int, void *,
1129 static int parse_vc_action_rss_queue(struct context *, const struct token *,
1130 const char *, unsigned int, void *,
1132 static int parse_vc_action_vxlan_encap(struct context *, const struct token *,
1133 const char *, unsigned int, void *,
1135 static int parse_vc_action_nvgre_encap(struct context *, const struct token *,
1136 const char *, unsigned int, void *,
1138 static int parse_vc_action_l2_encap(struct context *, const struct token *,
1139 const char *, unsigned int, void *,
1141 static int parse_vc_action_l2_decap(struct context *, const struct token *,
1142 const char *, unsigned int, void *,
1144 static int parse_vc_action_mplsogre_encap(struct context *,
1145 const struct token *, const char *,
1146 unsigned int, void *, unsigned int);
1147 static int parse_vc_action_mplsogre_decap(struct context *,
1148 const struct token *, const char *,
1149 unsigned int, void *, unsigned int);
1150 static int parse_vc_action_mplsoudp_encap(struct context *,
1151 const struct token *, const char *,
1152 unsigned int, void *, unsigned int);
1153 static int parse_vc_action_mplsoudp_decap(struct context *,
1154 const struct token *, const char *,
1155 unsigned int, void *, unsigned int);
1156 static int parse_destroy(struct context *, const struct token *,
1157 const char *, unsigned int,
1158 void *, unsigned int);
1159 static int parse_flush(struct context *, const struct token *,
1160 const char *, unsigned int,
1161 void *, unsigned int);
1162 static int parse_query(struct context *, const struct token *,
1163 const char *, unsigned int,
1164 void *, unsigned int);
1165 static int parse_action(struct context *, const struct token *,
1166 const char *, unsigned int,
1167 void *, unsigned int);
1168 static int parse_list(struct context *, const struct token *,
1169 const char *, unsigned int,
1170 void *, unsigned int);
1171 static int parse_isolate(struct context *, const struct token *,
1172 const char *, unsigned int,
1173 void *, unsigned int);
1174 static int parse_int(struct context *, const struct token *,
1175 const char *, unsigned int,
1176 void *, unsigned int);
1177 static int parse_prefix(struct context *, const struct token *,
1178 const char *, unsigned int,
1179 void *, unsigned int);
1180 static int parse_boolean(struct context *, const struct token *,
1181 const char *, unsigned int,
1182 void *, unsigned int);
1183 static int parse_string(struct context *, const struct token *,
1184 const char *, unsigned int,
1185 void *, unsigned int);
1186 static int parse_hex(struct context *ctx, const struct token *token,
1187 const char *str, unsigned int len,
1188 void *buf, unsigned int size);
1189 static int parse_mac_addr(struct context *, const struct token *,
1190 const char *, unsigned int,
1191 void *, unsigned int);
1192 static int parse_ipv4_addr(struct context *, const struct token *,
1193 const char *, unsigned int,
1194 void *, unsigned int);
1195 static int parse_ipv6_addr(struct context *, const struct token *,
1196 const char *, unsigned int,
1197 void *, unsigned int);
1198 static int parse_port(struct context *, const struct token *,
1199 const char *, unsigned int,
1200 void *, unsigned int);
1201 static int comp_none(struct context *, const struct token *,
1202 unsigned int, char *, unsigned int);
1203 static int comp_boolean(struct context *, const struct token *,
1204 unsigned int, char *, unsigned int);
1205 static int comp_action(struct context *, const struct token *,
1206 unsigned int, char *, unsigned int);
1207 static int comp_port(struct context *, const struct token *,
1208 unsigned int, char *, unsigned int);
1209 static int comp_rule_id(struct context *, const struct token *,
1210 unsigned int, char *, unsigned int);
1211 static int comp_vc_action_rss_type(struct context *, const struct token *,
1212 unsigned int, char *, unsigned int);
1213 static int comp_vc_action_rss_queue(struct context *, const struct token *,
1214 unsigned int, char *, unsigned int);
1216 /** Token definitions. */
1217 static const struct token token_list[] = {
1218 /* Special tokens. */
1221 .help = "null entry, abused as the entry point",
1222 .next = NEXT(NEXT_ENTRY(FLOW)),
1227 .help = "command may end here",
1229 /* Common tokens. */
1233 .help = "integer value",
1238 .name = "{unsigned}",
1240 .help = "unsigned integer value",
1247 .help = "prefix length for bit-mask",
1248 .call = parse_prefix,
1252 .name = "{boolean}",
1254 .help = "any boolean value",
1255 .call = parse_boolean,
1256 .comp = comp_boolean,
1261 .help = "fixed string",
1262 .call = parse_string,
1268 .help = "fixed string",
1273 .name = "{MAC address}",
1275 .help = "standard MAC address notation",
1276 .call = parse_mac_addr,
1280 .name = "{IPv4 address}",
1281 .type = "IPV4 ADDRESS",
1282 .help = "standard IPv4 address notation",
1283 .call = parse_ipv4_addr,
1287 .name = "{IPv6 address}",
1288 .type = "IPV6 ADDRESS",
1289 .help = "standard IPv6 address notation",
1290 .call = parse_ipv6_addr,
1294 .name = "{rule id}",
1296 .help = "rule identifier",
1298 .comp = comp_rule_id,
1301 .name = "{port_id}",
1303 .help = "port identifier",
1308 .name = "{group_id}",
1310 .help = "group identifier",
1314 [PRIORITY_LEVEL] = {
1317 .help = "priority level",
1321 /* Top-level command. */
1324 .type = "{command} {port_id} [{arg} [...]]",
1325 .help = "manage ingress/egress flow rules",
1326 .next = NEXT(NEXT_ENTRY
1336 /* Sub-level commands. */
1339 .help = "check whether a flow rule can be created",
1340 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1341 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1346 .help = "create a flow rule",
1347 .next = NEXT(next_vc_attr, NEXT_ENTRY(PORT_ID)),
1348 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1353 .help = "destroy specific flow rules",
1354 .next = NEXT(NEXT_ENTRY(DESTROY_RULE), NEXT_ENTRY(PORT_ID)),
1355 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1356 .call = parse_destroy,
1360 .help = "destroy all flow rules",
1361 .next = NEXT(NEXT_ENTRY(PORT_ID)),
1362 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1363 .call = parse_flush,
1367 .help = "query an existing flow rule",
1368 .next = NEXT(NEXT_ENTRY(QUERY_ACTION),
1369 NEXT_ENTRY(RULE_ID),
1370 NEXT_ENTRY(PORT_ID)),
1371 .args = ARGS(ARGS_ENTRY(struct buffer, args.query.action.type),
1372 ARGS_ENTRY(struct buffer, args.query.rule),
1373 ARGS_ENTRY(struct buffer, port)),
1374 .call = parse_query,
1378 .help = "list existing flow rules",
1379 .next = NEXT(next_list_attr, NEXT_ENTRY(PORT_ID)),
1380 .args = ARGS(ARGS_ENTRY(struct buffer, port)),
1385 .help = "restrict ingress traffic to the defined flow rules",
1386 .next = NEXT(NEXT_ENTRY(BOOLEAN),
1387 NEXT_ENTRY(PORT_ID)),
1388 .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
1389 ARGS_ENTRY(struct buffer, port)),
1390 .call = parse_isolate,
1392 /* Destroy arguments. */
1395 .help = "specify a rule identifier",
1396 .next = NEXT(next_destroy_attr, NEXT_ENTRY(RULE_ID)),
1397 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
1398 .call = parse_destroy,
1400 /* Query arguments. */
1404 .help = "action to query, must be part of the rule",
1405 .call = parse_action,
1406 .comp = comp_action,
1408 /* List arguments. */
1411 .help = "specify a group",
1412 .next = NEXT(next_list_attr, NEXT_ENTRY(GROUP_ID)),
1413 .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
1416 /* Validate/create attributes. */
1419 .help = "specify a group",
1420 .next = NEXT(next_vc_attr, NEXT_ENTRY(GROUP_ID)),
1421 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, group)),
1426 .help = "specify a priority level",
1427 .next = NEXT(next_vc_attr, NEXT_ENTRY(PRIORITY_LEVEL)),
1428 .args = ARGS(ARGS_ENTRY(struct rte_flow_attr, priority)),
1433 .help = "affect rule to ingress",
1434 .next = NEXT(next_vc_attr),
1439 .help = "affect rule to egress",
1440 .next = NEXT(next_vc_attr),
1445 .help = "apply rule directly to endpoints found in pattern",
1446 .next = NEXT(next_vc_attr),
1449 /* Validate/create pattern. */
1452 .help = "submit a list of pattern items",
1453 .next = NEXT(next_item),
1458 .help = "match value perfectly (with full bit-mask)",
1459 .call = parse_vc_spec,
1461 [ITEM_PARAM_SPEC] = {
1463 .help = "match value according to configured bit-mask",
1464 .call = parse_vc_spec,
1466 [ITEM_PARAM_LAST] = {
1468 .help = "specify upper bound to establish a range",
1469 .call = parse_vc_spec,
1471 [ITEM_PARAM_MASK] = {
1473 .help = "specify bit-mask with relevant bits set to one",
1474 .call = parse_vc_spec,
1476 [ITEM_PARAM_PREFIX] = {
1478 .help = "generate bit-mask from a prefix length",
1479 .call = parse_vc_spec,
1483 .help = "specify next pattern item",
1484 .next = NEXT(next_item),
1488 .help = "end list of pattern items",
1489 .priv = PRIV_ITEM(END, 0),
1490 .next = NEXT(NEXT_ENTRY(ACTIONS)),
1495 .help = "no-op pattern item",
1496 .priv = PRIV_ITEM(VOID, 0),
1497 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1502 .help = "perform actions when pattern does not match",
1503 .priv = PRIV_ITEM(INVERT, 0),
1504 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1509 .help = "match any protocol for the current layer",
1510 .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)),
1511 .next = NEXT(item_any),
1516 .help = "number of layers covered",
1517 .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param),
1518 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)),
1522 .help = "match traffic from/to the physical function",
1523 .priv = PRIV_ITEM(PF, 0),
1524 .next = NEXT(NEXT_ENTRY(ITEM_NEXT)),
1529 .help = "match traffic from/to a virtual function ID",
1530 .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)),
1531 .next = NEXT(item_vf),
1537 .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param),
1538 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)),
1542 .help = "match traffic from/to a specific physical port",
1543 .priv = PRIV_ITEM(PHY_PORT,
1544 sizeof(struct rte_flow_item_phy_port)),
1545 .next = NEXT(item_phy_port),
1548 [ITEM_PHY_PORT_INDEX] = {
1550 .help = "physical port index",
1551 .next = NEXT(item_phy_port, NEXT_ENTRY(UNSIGNED), item_param),
1552 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_phy_port, index)),
1556 .help = "match traffic from/to a given DPDK port ID",
1557 .priv = PRIV_ITEM(PORT_ID,
1558 sizeof(struct rte_flow_item_port_id)),
1559 .next = NEXT(item_port_id),
1562 [ITEM_PORT_ID_ID] = {
1564 .help = "DPDK port ID",
1565 .next = NEXT(item_port_id, NEXT_ENTRY(UNSIGNED), item_param),
1566 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port_id, id)),
1570 .help = "match traffic against value set in previously matched rule",
1571 .priv = PRIV_ITEM(MARK, sizeof(struct rte_flow_item_mark)),
1572 .next = NEXT(item_mark),
1577 .help = "Integer value to match against",
1578 .next = NEXT(item_mark, NEXT_ENTRY(UNSIGNED), item_param),
1579 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_mark, id)),
1583 .help = "match an arbitrary byte string",
1584 .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE),
1585 .next = NEXT(item_raw),
1588 [ITEM_RAW_RELATIVE] = {
1590 .help = "look for pattern after the previous item",
1591 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1592 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1595 [ITEM_RAW_SEARCH] = {
1597 .help = "search pattern from offset (see also limit)",
1598 .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param),
1599 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw,
1602 [ITEM_RAW_OFFSET] = {
1604 .help = "absolute or relative offset for pattern",
1605 .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param),
1606 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)),
1608 [ITEM_RAW_LIMIT] = {
1610 .help = "search area limit for start of pattern",
1611 .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param),
1612 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)),
1614 [ITEM_RAW_PATTERN] = {
1616 .help = "byte string to look for",
1617 .next = NEXT(item_raw,
1619 NEXT_ENTRY(ITEM_PARAM_IS,
1622 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, pattern),
1623 ARGS_ENTRY(struct rte_flow_item_raw, length),
1624 ARGS_ENTRY_ARB(sizeof(struct rte_flow_item_raw),
1625 ITEM_RAW_PATTERN_SIZE)),
1629 .help = "match Ethernet header",
1630 .priv = PRIV_ITEM(ETH, sizeof(struct rte_flow_item_eth)),
1631 .next = NEXT(item_eth),
1636 .help = "destination MAC",
1637 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1638 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, dst)),
1642 .help = "source MAC",
1643 .next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
1644 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, src)),
1648 .help = "EtherType",
1649 .next = NEXT(item_eth, NEXT_ENTRY(UNSIGNED), item_param),
1650 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)),
1654 .help = "match 802.1Q/ad VLAN tag",
1655 .priv = PRIV_ITEM(VLAN, sizeof(struct rte_flow_item_vlan)),
1656 .next = NEXT(item_vlan),
1661 .help = "tag control information",
1662 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1663 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
1667 .help = "priority code point",
1668 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1669 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1674 .help = "drop eligible indicator",
1675 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1676 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1681 .help = "VLAN identifier",
1682 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1683 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
1686 [ITEM_VLAN_INNER_TYPE] = {
1687 .name = "inner_type",
1688 .help = "inner EtherType",
1689 .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
1690 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan,
1695 .help = "match IPv4 header",
1696 .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)),
1697 .next = NEXT(item_ipv4),
1702 .help = "type of service",
1703 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1704 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1705 hdr.type_of_service)),
1709 .help = "time to live",
1710 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1711 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1714 [ITEM_IPV4_PROTO] = {
1716 .help = "next protocol ID",
1717 .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
1718 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1719 hdr.next_proto_id)),
1723 .help = "source address",
1724 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1725 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1730 .help = "destination address",
1731 .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param),
1732 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
1737 .help = "match IPv6 header",
1738 .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)),
1739 .next = NEXT(item_ipv6),
1744 .help = "traffic class",
1745 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1746 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1748 "\x0f\xf0\x00\x00")),
1750 [ITEM_IPV6_FLOW] = {
1752 .help = "flow label",
1753 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1754 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
1756 "\x00\x0f\xff\xff")),
1758 [ITEM_IPV6_PROTO] = {
1760 .help = "protocol (next header)",
1761 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1762 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1767 .help = "hop limit",
1768 .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
1769 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1774 .help = "source address",
1775 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1776 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1781 .help = "destination address",
1782 .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param),
1783 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
1788 .help = "match ICMP header",
1789 .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)),
1790 .next = NEXT(item_icmp),
1793 [ITEM_ICMP_TYPE] = {
1795 .help = "ICMP packet type",
1796 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1797 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1800 [ITEM_ICMP_CODE] = {
1802 .help = "ICMP packet code",
1803 .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param),
1804 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp,
1809 .help = "match UDP header",
1810 .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)),
1811 .next = NEXT(item_udp),
1816 .help = "UDP source port",
1817 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1818 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1823 .help = "UDP destination port",
1824 .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param),
1825 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp,
1830 .help = "match TCP header",
1831 .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
1832 .next = NEXT(item_tcp),
1837 .help = "TCP source port",
1838 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1839 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1844 .help = "TCP destination port",
1845 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1846 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1849 [ITEM_TCP_FLAGS] = {
1851 .help = "TCP flags",
1852 .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
1853 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
1858 .help = "match SCTP header",
1859 .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
1860 .next = NEXT(item_sctp),
1865 .help = "SCTP source port",
1866 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1867 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1872 .help = "SCTP destination port",
1873 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1874 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1879 .help = "validation tag",
1880 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1881 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1884 [ITEM_SCTP_CKSUM] = {
1887 .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
1888 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
1893 .help = "match VXLAN header",
1894 .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
1895 .next = NEXT(item_vxlan),
1898 [ITEM_VXLAN_VNI] = {
1900 .help = "VXLAN identifier",
1901 .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
1902 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)),
1906 .help = "match E-Tag header",
1907 .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
1908 .next = NEXT(item_e_tag),
1911 [ITEM_E_TAG_GRP_ECID_B] = {
1912 .name = "grp_ecid_b",
1913 .help = "GRP and E-CID base",
1914 .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param),
1915 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag,
1921 .help = "match NVGRE header",
1922 .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
1923 .next = NEXT(item_nvgre),
1926 [ITEM_NVGRE_TNI] = {
1928 .help = "virtual subnet ID",
1929 .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param),
1930 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)),
1934 .help = "match MPLS header",
1935 .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
1936 .next = NEXT(item_mpls),
1939 [ITEM_MPLS_LABEL] = {
1941 .help = "MPLS label",
1942 .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
1943 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
1949 .help = "match GRE header",
1950 .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
1951 .next = NEXT(item_gre),
1954 [ITEM_GRE_PROTO] = {
1956 .help = "GRE protocol type",
1957 .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
1958 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
1961 [ITEM_GRE_C_RSVD0_VER] = {
1962 .name = "c_rsvd0_ver",
1964 "checksum (1b), undefined (1b), key bit (1b),"
1965 " sequence number (1b), reserved 0 (9b),"
1967 .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
1968 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
1971 [ITEM_GRE_C_BIT] = {
1973 .help = "checksum bit (C)",
1974 .next = NEXT(item_gre, NEXT_ENTRY(BOOLEAN), item_param),
1975 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_gre,
1977 "\x80\x00\x00\x00")),
1979 [ITEM_GRE_S_BIT] = {
1981 .help = "sequence number bit (S)",
1982 .next = NEXT(item_gre, NEXT_ENTRY(BOOLEAN), item_param),
1983 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_gre,
1985 "\x10\x00\x00\x00")),
1987 [ITEM_GRE_K_BIT] = {
1989 .help = "key bit (K)",
1990 .next = NEXT(item_gre, NEXT_ENTRY(BOOLEAN), item_param),
1991 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_gre,
1993 "\x20\x00\x00\x00")),
1997 .help = "fuzzy pattern match, expect faster than default",
1998 .priv = PRIV_ITEM(FUZZY,
1999 sizeof(struct rte_flow_item_fuzzy)),
2000 .next = NEXT(item_fuzzy),
2003 [ITEM_FUZZY_THRESH] = {
2005 .help = "match accuracy threshold",
2006 .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param),
2007 .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy,
2012 .help = "match GTP header",
2013 .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
2014 .next = NEXT(item_gtp),
2019 .help = "tunnel endpoint identifier",
2020 .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
2021 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)),
2025 .help = "match GTP header",
2026 .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
2027 .next = NEXT(item_gtp),
2032 .help = "match GTP header",
2033 .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
2034 .next = NEXT(item_gtp),
2039 .help = "match GENEVE header",
2040 .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
2041 .next = NEXT(item_geneve),
2044 [ITEM_GENEVE_VNI] = {
2046 .help = "virtual network identifier",
2047 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
2048 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)),
2050 [ITEM_GENEVE_PROTO] = {
2052 .help = "GENEVE protocol type",
2053 .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
2054 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
2057 [ITEM_VXLAN_GPE] = {
2058 .name = "vxlan-gpe",
2059 .help = "match VXLAN-GPE header",
2060 .priv = PRIV_ITEM(VXLAN_GPE,
2061 sizeof(struct rte_flow_item_vxlan_gpe)),
2062 .next = NEXT(item_vxlan_gpe),
2065 [ITEM_VXLAN_GPE_VNI] = {
2067 .help = "VXLAN-GPE identifier",
2068 .next = NEXT(item_vxlan_gpe, NEXT_ENTRY(UNSIGNED), item_param),
2069 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan_gpe,
2072 [ITEM_ARP_ETH_IPV4] = {
2073 .name = "arp_eth_ipv4",
2074 .help = "match ARP header for Ethernet/IPv4",
2075 .priv = PRIV_ITEM(ARP_ETH_IPV4,
2076 sizeof(struct rte_flow_item_arp_eth_ipv4)),
2077 .next = NEXT(item_arp_eth_ipv4),
2080 [ITEM_ARP_ETH_IPV4_SHA] = {
2082 .help = "sender hardware address",
2083 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
2085 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
2088 [ITEM_ARP_ETH_IPV4_SPA] = {
2090 .help = "sender IPv4 address",
2091 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
2093 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
2096 [ITEM_ARP_ETH_IPV4_THA] = {
2098 .help = "target hardware address",
2099 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(MAC_ADDR),
2101 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
2104 [ITEM_ARP_ETH_IPV4_TPA] = {
2106 .help = "target IPv4 address",
2107 .next = NEXT(item_arp_eth_ipv4, NEXT_ENTRY(IPV4_ADDR),
2109 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_arp_eth_ipv4,
2114 .help = "match presence of any IPv6 extension header",
2115 .priv = PRIV_ITEM(IPV6_EXT,
2116 sizeof(struct rte_flow_item_ipv6_ext)),
2117 .next = NEXT(item_ipv6_ext),
2120 [ITEM_IPV6_EXT_NEXT_HDR] = {
2122 .help = "next header",
2123 .next = NEXT(item_ipv6_ext, NEXT_ENTRY(UNSIGNED), item_param),
2124 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6_ext,
2129 .help = "match any ICMPv6 header",
2130 .priv = PRIV_ITEM(ICMP6, sizeof(struct rte_flow_item_icmp6)),
2131 .next = NEXT(item_icmp6),
2134 [ITEM_ICMP6_TYPE] = {
2136 .help = "ICMPv6 type",
2137 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
2138 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
2141 [ITEM_ICMP6_CODE] = {
2143 .help = "ICMPv6 code",
2144 .next = NEXT(item_icmp6, NEXT_ENTRY(UNSIGNED), item_param),
2145 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6,
2148 [ITEM_ICMP6_ND_NS] = {
2149 .name = "icmp6_nd_ns",
2150 .help = "match ICMPv6 neighbor discovery solicitation",
2151 .priv = PRIV_ITEM(ICMP6_ND_NS,
2152 sizeof(struct rte_flow_item_icmp6_nd_ns)),
2153 .next = NEXT(item_icmp6_nd_ns),
2156 [ITEM_ICMP6_ND_NS_TARGET_ADDR] = {
2157 .name = "target_addr",
2158 .help = "target address",
2159 .next = NEXT(item_icmp6_nd_ns, NEXT_ENTRY(IPV6_ADDR),
2161 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_ns,
2164 [ITEM_ICMP6_ND_NA] = {
2165 .name = "icmp6_nd_na",
2166 .help = "match ICMPv6 neighbor discovery advertisement",
2167 .priv = PRIV_ITEM(ICMP6_ND_NA,
2168 sizeof(struct rte_flow_item_icmp6_nd_na)),
2169 .next = NEXT(item_icmp6_nd_na),
2172 [ITEM_ICMP6_ND_NA_TARGET_ADDR] = {
2173 .name = "target_addr",
2174 .help = "target address",
2175 .next = NEXT(item_icmp6_nd_na, NEXT_ENTRY(IPV6_ADDR),
2177 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_na,
2180 [ITEM_ICMP6_ND_OPT] = {
2181 .name = "icmp6_nd_opt",
2182 .help = "match presence of any ICMPv6 neighbor discovery"
2184 .priv = PRIV_ITEM(ICMP6_ND_OPT,
2185 sizeof(struct rte_flow_item_icmp6_nd_opt)),
2186 .next = NEXT(item_icmp6_nd_opt),
2189 [ITEM_ICMP6_ND_OPT_TYPE] = {
2191 .help = "ND option type",
2192 .next = NEXT(item_icmp6_nd_opt, NEXT_ENTRY(UNSIGNED),
2194 .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp6_nd_opt,
2197 [ITEM_ICMP6_ND_OPT_SLA_ETH] = {
2198 .name = "icmp6_nd_opt_sla_eth",
2199 .help = "match ICMPv6 neighbor discovery source Ethernet"
2200 " link-layer address option",
2202 (ICMP6_ND_OPT_SLA_ETH,
2203 sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),
2204 .next = NEXT(item_icmp6_nd_opt_sla_eth),
2207 [ITEM_ICMP6_ND_OPT_SLA_ETH_SLA] = {
2209 .help = "source Ethernet LLA",
2210 .next = NEXT(item_icmp6_nd_opt_sla_eth, NEXT_ENTRY(MAC_ADDR),
2212 .args = ARGS(ARGS_ENTRY_HTON
2213 (struct rte_flow_item_icmp6_nd_opt_sla_eth, sla)),
2215 [ITEM_ICMP6_ND_OPT_TLA_ETH] = {
2216 .name = "icmp6_nd_opt_tla_eth",
2217 .help = "match ICMPv6 neighbor discovery target Ethernet"
2218 " link-layer address option",
2220 (ICMP6_ND_OPT_TLA_ETH,
2221 sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),
2222 .next = NEXT(item_icmp6_nd_opt_tla_eth),
2225 [ITEM_ICMP6_ND_OPT_TLA_ETH_TLA] = {
2227 .help = "target Ethernet LLA",
2228 .next = NEXT(item_icmp6_nd_opt_tla_eth, NEXT_ENTRY(MAC_ADDR),
2230 .args = ARGS(ARGS_ENTRY_HTON
2231 (struct rte_flow_item_icmp6_nd_opt_tla_eth, tla)),
2235 .help = "match metadata header",
2236 .priv = PRIV_ITEM(META, sizeof(struct rte_flow_item_meta)),
2237 .next = NEXT(item_meta),
2240 [ITEM_META_DATA] = {
2242 .help = "metadata value",
2243 .next = NEXT(item_meta, NEXT_ENTRY(UNSIGNED), item_param),
2244 .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_meta,
2245 data, "\xff\xff\xff\xff")),
2249 .help = "match GRE key",
2250 .priv = PRIV_ITEM(GRE_KEY, sizeof(rte_be32_t)),
2251 .next = NEXT(item_gre_key),
2254 [ITEM_GRE_KEY_VALUE] = {
2256 .help = "key value",
2257 .next = NEXT(item_gre_key, NEXT_ENTRY(UNSIGNED), item_param),
2258 .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
2261 /* Validate/create actions. */
2264 .help = "submit a list of associated actions",
2265 .next = NEXT(next_action),
2270 .help = "specify next action",
2271 .next = NEXT(next_action),
2275 .help = "end list of actions",
2276 .priv = PRIV_ACTION(END, 0),
2281 .help = "no-op action",
2282 .priv = PRIV_ACTION(VOID, 0),
2283 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2286 [ACTION_PASSTHRU] = {
2288 .help = "let subsequent rule process matched packets",
2289 .priv = PRIV_ACTION(PASSTHRU, 0),
2290 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2295 .help = "redirect traffic to a given group",
2296 .priv = PRIV_ACTION(JUMP, sizeof(struct rte_flow_action_jump)),
2297 .next = NEXT(action_jump),
2300 [ACTION_JUMP_GROUP] = {
2302 .help = "group to redirect traffic to",
2303 .next = NEXT(action_jump, NEXT_ENTRY(UNSIGNED)),
2304 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_jump, group)),
2305 .call = parse_vc_conf,
2309 .help = "attach 32 bit value to packets",
2310 .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
2311 .next = NEXT(action_mark),
2314 [ACTION_MARK_ID] = {
2316 .help = "32 bit value to return with packets",
2317 .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)),
2318 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)),
2319 .call = parse_vc_conf,
2323 .help = "flag packets",
2324 .priv = PRIV_ACTION(FLAG, 0),
2325 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2330 .help = "assign packets to a given queue index",
2331 .priv = PRIV_ACTION(QUEUE,
2332 sizeof(struct rte_flow_action_queue)),
2333 .next = NEXT(action_queue),
2336 [ACTION_QUEUE_INDEX] = {
2338 .help = "queue index to use",
2339 .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)),
2340 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)),
2341 .call = parse_vc_conf,
2345 .help = "drop packets (note: passthru has priority)",
2346 .priv = PRIV_ACTION(DROP, 0),
2347 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2352 .help = "enable counters for this rule",
2353 .priv = PRIV_ACTION(COUNT,
2354 sizeof(struct rte_flow_action_count)),
2355 .next = NEXT(action_count),
2358 [ACTION_COUNT_ID] = {
2359 .name = "identifier",
2360 .help = "counter identifier to use",
2361 .next = NEXT(action_count, NEXT_ENTRY(UNSIGNED)),
2362 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_count, id)),
2363 .call = parse_vc_conf,
2365 [ACTION_COUNT_SHARED] = {
2367 .help = "shared counter",
2368 .next = NEXT(action_count, NEXT_ENTRY(BOOLEAN)),
2369 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_count,
2371 .call = parse_vc_conf,
2375 .help = "spread packets among several queues",
2376 .priv = PRIV_ACTION(RSS, sizeof(struct action_rss_data)),
2377 .next = NEXT(action_rss),
2378 .call = parse_vc_action_rss,
2380 [ACTION_RSS_FUNC] = {
2382 .help = "RSS hash function to apply",
2383 .next = NEXT(action_rss,
2384 NEXT_ENTRY(ACTION_RSS_FUNC_DEFAULT,
2385 ACTION_RSS_FUNC_TOEPLITZ,
2386 ACTION_RSS_FUNC_SIMPLE_XOR)),
2388 [ACTION_RSS_FUNC_DEFAULT] = {
2390 .help = "default hash function",
2391 .call = parse_vc_action_rss_func,
2393 [ACTION_RSS_FUNC_TOEPLITZ] = {
2395 .help = "Toeplitz hash function",
2396 .call = parse_vc_action_rss_func,
2398 [ACTION_RSS_FUNC_SIMPLE_XOR] = {
2399 .name = "simple_xor",
2400 .help = "simple XOR hash function",
2401 .call = parse_vc_action_rss_func,
2403 [ACTION_RSS_LEVEL] = {
2405 .help = "encapsulation level for \"types\"",
2406 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2407 .args = ARGS(ARGS_ENTRY_ARB
2408 (offsetof(struct action_rss_data, conf) +
2409 offsetof(struct rte_flow_action_rss, level),
2410 sizeof(((struct rte_flow_action_rss *)0)->
2413 [ACTION_RSS_TYPES] = {
2415 .help = "specific RSS hash types",
2416 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_TYPE)),
2418 [ACTION_RSS_TYPE] = {
2420 .help = "RSS hash type",
2421 .call = parse_vc_action_rss_type,
2422 .comp = comp_vc_action_rss_type,
2424 [ACTION_RSS_KEY] = {
2426 .help = "RSS hash key",
2427 .next = NEXT(action_rss, NEXT_ENTRY(HEX)),
2428 .args = ARGS(ARGS_ENTRY_ARB(0, 0),
2430 (offsetof(struct action_rss_data, conf) +
2431 offsetof(struct rte_flow_action_rss, key_len),
2432 sizeof(((struct rte_flow_action_rss *)0)->
2434 ARGS_ENTRY(struct action_rss_data, key)),
2436 [ACTION_RSS_KEY_LEN] = {
2438 .help = "RSS hash key length in bytes",
2439 .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
2440 .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
2441 (offsetof(struct action_rss_data, conf) +
2442 offsetof(struct rte_flow_action_rss, key_len),
2443 sizeof(((struct rte_flow_action_rss *)0)->
2446 RSS_HASH_KEY_LENGTH)),
2448 [ACTION_RSS_QUEUES] = {
2450 .help = "queue indices to use",
2451 .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)),
2452 .call = parse_vc_conf,
2454 [ACTION_RSS_QUEUE] = {
2456 .help = "queue index",
2457 .call = parse_vc_action_rss_queue,
2458 .comp = comp_vc_action_rss_queue,
2462 .help = "direct traffic to physical function",
2463 .priv = PRIV_ACTION(PF, 0),
2464 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2469 .help = "direct traffic to a virtual function ID",
2470 .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)),
2471 .next = NEXT(action_vf),
2474 [ACTION_VF_ORIGINAL] = {
2476 .help = "use original VF ID if possible",
2477 .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)),
2478 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf,
2480 .call = parse_vc_conf,
2485 .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)),
2486 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
2487 .call = parse_vc_conf,
2489 [ACTION_PHY_PORT] = {
2491 .help = "direct packets to physical port index",
2492 .priv = PRIV_ACTION(PHY_PORT,
2493 sizeof(struct rte_flow_action_phy_port)),
2494 .next = NEXT(action_phy_port),
2497 [ACTION_PHY_PORT_ORIGINAL] = {
2499 .help = "use original port index if possible",
2500 .next = NEXT(action_phy_port, NEXT_ENTRY(BOOLEAN)),
2501 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_phy_port,
2503 .call = parse_vc_conf,
2505 [ACTION_PHY_PORT_INDEX] = {
2507 .help = "physical port index",
2508 .next = NEXT(action_phy_port, NEXT_ENTRY(UNSIGNED)),
2509 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_phy_port,
2511 .call = parse_vc_conf,
2513 [ACTION_PORT_ID] = {
2515 .help = "direct matching traffic to a given DPDK port ID",
2516 .priv = PRIV_ACTION(PORT_ID,
2517 sizeof(struct rte_flow_action_port_id)),
2518 .next = NEXT(action_port_id),
2521 [ACTION_PORT_ID_ORIGINAL] = {
2523 .help = "use original DPDK port ID if possible",
2524 .next = NEXT(action_port_id, NEXT_ENTRY(BOOLEAN)),
2525 .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_port_id,
2527 .call = parse_vc_conf,
2529 [ACTION_PORT_ID_ID] = {
2531 .help = "DPDK port ID",
2532 .next = NEXT(action_port_id, NEXT_ENTRY(UNSIGNED)),
2533 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_port_id, id)),
2534 .call = parse_vc_conf,
2538 .help = "meter the directed packets at given id",
2539 .priv = PRIV_ACTION(METER,
2540 sizeof(struct rte_flow_action_meter)),
2541 .next = NEXT(action_meter),
2544 [ACTION_METER_ID] = {
2546 .help = "meter id to use",
2547 .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
2548 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
2549 .call = parse_vc_conf,
2551 [ACTION_OF_SET_MPLS_TTL] = {
2552 .name = "of_set_mpls_ttl",
2553 .help = "OpenFlow's OFPAT_SET_MPLS_TTL",
2556 sizeof(struct rte_flow_action_of_set_mpls_ttl)),
2557 .next = NEXT(action_of_set_mpls_ttl),
2560 [ACTION_OF_SET_MPLS_TTL_MPLS_TTL] = {
2563 .next = NEXT(action_of_set_mpls_ttl, NEXT_ENTRY(UNSIGNED)),
2564 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_mpls_ttl,
2566 .call = parse_vc_conf,
2568 [ACTION_OF_DEC_MPLS_TTL] = {
2569 .name = "of_dec_mpls_ttl",
2570 .help = "OpenFlow's OFPAT_DEC_MPLS_TTL",
2571 .priv = PRIV_ACTION(OF_DEC_MPLS_TTL, 0),
2572 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2575 [ACTION_OF_SET_NW_TTL] = {
2576 .name = "of_set_nw_ttl",
2577 .help = "OpenFlow's OFPAT_SET_NW_TTL",
2580 sizeof(struct rte_flow_action_of_set_nw_ttl)),
2581 .next = NEXT(action_of_set_nw_ttl),
2584 [ACTION_OF_SET_NW_TTL_NW_TTL] = {
2587 .next = NEXT(action_of_set_nw_ttl, NEXT_ENTRY(UNSIGNED)),
2588 .args = ARGS(ARGS_ENTRY(struct rte_flow_action_of_set_nw_ttl,
2590 .call = parse_vc_conf,
2592 [ACTION_OF_DEC_NW_TTL] = {
2593 .name = "of_dec_nw_ttl",
2594 .help = "OpenFlow's OFPAT_DEC_NW_TTL",
2595 .priv = PRIV_ACTION(OF_DEC_NW_TTL, 0),
2596 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2599 [ACTION_OF_COPY_TTL_OUT] = {
2600 .name = "of_copy_ttl_out",
2601 .help = "OpenFlow's OFPAT_COPY_TTL_OUT",
2602 .priv = PRIV_ACTION(OF_COPY_TTL_OUT, 0),
2603 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2606 [ACTION_OF_COPY_TTL_IN] = {
2607 .name = "of_copy_ttl_in",
2608 .help = "OpenFlow's OFPAT_COPY_TTL_IN",
2609 .priv = PRIV_ACTION(OF_COPY_TTL_IN, 0),
2610 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2613 [ACTION_OF_POP_VLAN] = {
2614 .name = "of_pop_vlan",
2615 .help = "OpenFlow's OFPAT_POP_VLAN",
2616 .priv = PRIV_ACTION(OF_POP_VLAN, 0),
2617 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2620 [ACTION_OF_PUSH_VLAN] = {
2621 .name = "of_push_vlan",
2622 .help = "OpenFlow's OFPAT_PUSH_VLAN",
2625 sizeof(struct rte_flow_action_of_push_vlan)),
2626 .next = NEXT(action_of_push_vlan),
2629 [ACTION_OF_PUSH_VLAN_ETHERTYPE] = {
2630 .name = "ethertype",
2631 .help = "EtherType",
2632 .next = NEXT(action_of_push_vlan, NEXT_ENTRY(UNSIGNED)),
2633 .args = ARGS(ARGS_ENTRY_HTON
2634 (struct rte_flow_action_of_push_vlan,
2636 .call = parse_vc_conf,
2638 [ACTION_OF_SET_VLAN_VID] = {
2639 .name = "of_set_vlan_vid",
2640 .help = "OpenFlow's OFPAT_SET_VLAN_VID",
2643 sizeof(struct rte_flow_action_of_set_vlan_vid)),
2644 .next = NEXT(action_of_set_vlan_vid),
2647 [ACTION_OF_SET_VLAN_VID_VLAN_VID] = {
2650 .next = NEXT(action_of_set_vlan_vid, NEXT_ENTRY(UNSIGNED)),
2651 .args = ARGS(ARGS_ENTRY_HTON
2652 (struct rte_flow_action_of_set_vlan_vid,
2654 .call = parse_vc_conf,
2656 [ACTION_OF_SET_VLAN_PCP] = {
2657 .name = "of_set_vlan_pcp",
2658 .help = "OpenFlow's OFPAT_SET_VLAN_PCP",
2661 sizeof(struct rte_flow_action_of_set_vlan_pcp)),
2662 .next = NEXT(action_of_set_vlan_pcp),
2665 [ACTION_OF_SET_VLAN_PCP_VLAN_PCP] = {
2667 .help = "VLAN priority",
2668 .next = NEXT(action_of_set_vlan_pcp, NEXT_ENTRY(UNSIGNED)),
2669 .args = ARGS(ARGS_ENTRY_HTON
2670 (struct rte_flow_action_of_set_vlan_pcp,
2672 .call = parse_vc_conf,
2674 [ACTION_OF_POP_MPLS] = {
2675 .name = "of_pop_mpls",
2676 .help = "OpenFlow's OFPAT_POP_MPLS",
2677 .priv = PRIV_ACTION(OF_POP_MPLS,
2678 sizeof(struct rte_flow_action_of_pop_mpls)),
2679 .next = NEXT(action_of_pop_mpls),
2682 [ACTION_OF_POP_MPLS_ETHERTYPE] = {
2683 .name = "ethertype",
2684 .help = "EtherType",
2685 .next = NEXT(action_of_pop_mpls, NEXT_ENTRY(UNSIGNED)),
2686 .args = ARGS(ARGS_ENTRY_HTON
2687 (struct rte_flow_action_of_pop_mpls,
2689 .call = parse_vc_conf,
2691 [ACTION_OF_PUSH_MPLS] = {
2692 .name = "of_push_mpls",
2693 .help = "OpenFlow's OFPAT_PUSH_MPLS",
2696 sizeof(struct rte_flow_action_of_push_mpls)),
2697 .next = NEXT(action_of_push_mpls),
2700 [ACTION_OF_PUSH_MPLS_ETHERTYPE] = {
2701 .name = "ethertype",
2702 .help = "EtherType",
2703 .next = NEXT(action_of_push_mpls, NEXT_ENTRY(UNSIGNED)),
2704 .args = ARGS(ARGS_ENTRY_HTON
2705 (struct rte_flow_action_of_push_mpls,
2707 .call = parse_vc_conf,
2709 [ACTION_VXLAN_ENCAP] = {
2710 .name = "vxlan_encap",
2711 .help = "VXLAN encapsulation, uses configuration set by \"set"
2713 .priv = PRIV_ACTION(VXLAN_ENCAP,
2714 sizeof(struct action_vxlan_encap_data)),
2715 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2716 .call = parse_vc_action_vxlan_encap,
2718 [ACTION_VXLAN_DECAP] = {
2719 .name = "vxlan_decap",
2720 .help = "Performs a decapsulation action by stripping all"
2721 " headers of the VXLAN tunnel network overlay from the"
2723 .priv = PRIV_ACTION(VXLAN_DECAP, 0),
2724 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2727 [ACTION_NVGRE_ENCAP] = {
2728 .name = "nvgre_encap",
2729 .help = "NVGRE encapsulation, uses configuration set by \"set"
2731 .priv = PRIV_ACTION(NVGRE_ENCAP,
2732 sizeof(struct action_nvgre_encap_data)),
2733 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2734 .call = parse_vc_action_nvgre_encap,
2736 [ACTION_NVGRE_DECAP] = {
2737 .name = "nvgre_decap",
2738 .help = "Performs a decapsulation action by stripping all"
2739 " headers of the NVGRE tunnel network overlay from the"
2741 .priv = PRIV_ACTION(NVGRE_DECAP, 0),
2742 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2745 [ACTION_L2_ENCAP] = {
2747 .help = "l2 encap, uses configuration set by"
2748 " \"set l2_encap\"",
2749 .priv = PRIV_ACTION(RAW_ENCAP,
2750 sizeof(struct action_raw_encap_data)),
2751 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2752 .call = parse_vc_action_l2_encap,
2754 [ACTION_L2_DECAP] = {
2756 .help = "l2 decap, uses configuration set by"
2757 " \"set l2_decap\"",
2758 .priv = PRIV_ACTION(RAW_DECAP,
2759 sizeof(struct action_raw_decap_data)),
2760 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2761 .call = parse_vc_action_l2_decap,
2763 [ACTION_MPLSOGRE_ENCAP] = {
2764 .name = "mplsogre_encap",
2765 .help = "mplsogre encapsulation, uses configuration set by"
2766 " \"set mplsogre_encap\"",
2767 .priv = PRIV_ACTION(RAW_ENCAP,
2768 sizeof(struct action_raw_encap_data)),
2769 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2770 .call = parse_vc_action_mplsogre_encap,
2772 [ACTION_MPLSOGRE_DECAP] = {
2773 .name = "mplsogre_decap",
2774 .help = "mplsogre decapsulation, uses configuration set by"
2775 " \"set mplsogre_decap\"",
2776 .priv = PRIV_ACTION(RAW_DECAP,
2777 sizeof(struct action_raw_decap_data)),
2778 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2779 .call = parse_vc_action_mplsogre_decap,
2781 [ACTION_MPLSOUDP_ENCAP] = {
2782 .name = "mplsoudp_encap",
2783 .help = "mplsoudp encapsulation, uses configuration set by"
2784 " \"set mplsoudp_encap\"",
2785 .priv = PRIV_ACTION(RAW_ENCAP,
2786 sizeof(struct action_raw_encap_data)),
2787 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2788 .call = parse_vc_action_mplsoudp_encap,
2790 [ACTION_MPLSOUDP_DECAP] = {
2791 .name = "mplsoudp_decap",
2792 .help = "mplsoudp decapsulation, uses configuration set by"
2793 " \"set mplsoudp_decap\"",
2794 .priv = PRIV_ACTION(RAW_DECAP,
2795 sizeof(struct action_raw_decap_data)),
2796 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2797 .call = parse_vc_action_mplsoudp_decap,
2799 [ACTION_SET_IPV4_SRC] = {
2800 .name = "set_ipv4_src",
2801 .help = "Set a new IPv4 source address in the outermost"
2803 .priv = PRIV_ACTION(SET_IPV4_SRC,
2804 sizeof(struct rte_flow_action_set_ipv4)),
2805 .next = NEXT(action_set_ipv4_src),
2808 [ACTION_SET_IPV4_SRC_IPV4_SRC] = {
2809 .name = "ipv4_addr",
2810 .help = "new IPv4 source address to set",
2811 .next = NEXT(action_set_ipv4_src, NEXT_ENTRY(IPV4_ADDR)),
2812 .args = ARGS(ARGS_ENTRY_HTON
2813 (struct rte_flow_action_set_ipv4, ipv4_addr)),
2814 .call = parse_vc_conf,
2816 [ACTION_SET_IPV4_DST] = {
2817 .name = "set_ipv4_dst",
2818 .help = "Set a new IPv4 destination address in the outermost"
2820 .priv = PRIV_ACTION(SET_IPV4_DST,
2821 sizeof(struct rte_flow_action_set_ipv4)),
2822 .next = NEXT(action_set_ipv4_dst),
2825 [ACTION_SET_IPV4_DST_IPV4_DST] = {
2826 .name = "ipv4_addr",
2827 .help = "new IPv4 destination address to set",
2828 .next = NEXT(action_set_ipv4_dst, NEXT_ENTRY(IPV4_ADDR)),
2829 .args = ARGS(ARGS_ENTRY_HTON
2830 (struct rte_flow_action_set_ipv4, ipv4_addr)),
2831 .call = parse_vc_conf,
2833 [ACTION_SET_IPV6_SRC] = {
2834 .name = "set_ipv6_src",
2835 .help = "Set a new IPv6 source address in the outermost"
2837 .priv = PRIV_ACTION(SET_IPV6_SRC,
2838 sizeof(struct rte_flow_action_set_ipv6)),
2839 .next = NEXT(action_set_ipv6_src),
2842 [ACTION_SET_IPV6_SRC_IPV6_SRC] = {
2843 .name = "ipv6_addr",
2844 .help = "new IPv6 source address to set",
2845 .next = NEXT(action_set_ipv6_src, NEXT_ENTRY(IPV6_ADDR)),
2846 .args = ARGS(ARGS_ENTRY_HTON
2847 (struct rte_flow_action_set_ipv6, ipv6_addr)),
2848 .call = parse_vc_conf,
2850 [ACTION_SET_IPV6_DST] = {
2851 .name = "set_ipv6_dst",
2852 .help = "Set a new IPv6 destination address in the outermost"
2854 .priv = PRIV_ACTION(SET_IPV6_DST,
2855 sizeof(struct rte_flow_action_set_ipv6)),
2856 .next = NEXT(action_set_ipv6_dst),
2859 [ACTION_SET_IPV6_DST_IPV6_DST] = {
2860 .name = "ipv6_addr",
2861 .help = "new IPv6 destination address to set",
2862 .next = NEXT(action_set_ipv6_dst, NEXT_ENTRY(IPV6_ADDR)),
2863 .args = ARGS(ARGS_ENTRY_HTON
2864 (struct rte_flow_action_set_ipv6, ipv6_addr)),
2865 .call = parse_vc_conf,
2867 [ACTION_SET_TP_SRC] = {
2868 .name = "set_tp_src",
2869 .help = "set a new source port number in the outermost"
2871 .priv = PRIV_ACTION(SET_TP_SRC,
2872 sizeof(struct rte_flow_action_set_tp)),
2873 .next = NEXT(action_set_tp_src),
2876 [ACTION_SET_TP_SRC_TP_SRC] = {
2878 .help = "new source port number to set",
2879 .next = NEXT(action_set_tp_src, NEXT_ENTRY(UNSIGNED)),
2880 .args = ARGS(ARGS_ENTRY_HTON
2881 (struct rte_flow_action_set_tp, port)),
2882 .call = parse_vc_conf,
2884 [ACTION_SET_TP_DST] = {
2885 .name = "set_tp_dst",
2886 .help = "set a new destination port number in the outermost"
2888 .priv = PRIV_ACTION(SET_TP_DST,
2889 sizeof(struct rte_flow_action_set_tp)),
2890 .next = NEXT(action_set_tp_dst),
2893 [ACTION_SET_TP_DST_TP_DST] = {
2895 .help = "new destination port number to set",
2896 .next = NEXT(action_set_tp_dst, NEXT_ENTRY(UNSIGNED)),
2897 .args = ARGS(ARGS_ENTRY_HTON
2898 (struct rte_flow_action_set_tp, port)),
2899 .call = parse_vc_conf,
2901 [ACTION_MAC_SWAP] = {
2903 .help = "Swap the source and destination MAC addresses"
2904 " in the outermost Ethernet header",
2905 .priv = PRIV_ACTION(MAC_SWAP, 0),
2906 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2909 [ACTION_DEC_TTL] = {
2911 .help = "decrease network TTL if available",
2912 .priv = PRIV_ACTION(DEC_TTL, 0),
2913 .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
2916 [ACTION_SET_TTL] = {
2918 .help = "set ttl value",
2919 .priv = PRIV_ACTION(SET_TTL,
2920 sizeof(struct rte_flow_action_set_ttl)),
2921 .next = NEXT(action_set_ttl),
2924 [ACTION_SET_TTL_TTL] = {
2925 .name = "ttl_value",
2926 .help = "new ttl value to set",
2927 .next = NEXT(action_set_ttl, NEXT_ENTRY(UNSIGNED)),
2928 .args = ARGS(ARGS_ENTRY_HTON
2929 (struct rte_flow_action_set_ttl, ttl_value)),
2930 .call = parse_vc_conf,
2932 [ACTION_SET_MAC_SRC] = {
2933 .name = "set_mac_src",
2934 .help = "set source mac address",
2935 .priv = PRIV_ACTION(SET_MAC_SRC,
2936 sizeof(struct rte_flow_action_set_mac)),
2937 .next = NEXT(action_set_mac_src),
2940 [ACTION_SET_MAC_SRC_MAC_SRC] = {
2942 .help = "new source mac address",
2943 .next = NEXT(action_set_mac_src, NEXT_ENTRY(MAC_ADDR)),
2944 .args = ARGS(ARGS_ENTRY_HTON
2945 (struct rte_flow_action_set_mac, mac_addr)),
2946 .call = parse_vc_conf,
2948 [ACTION_SET_MAC_DST] = {
2949 .name = "set_mac_dst",
2950 .help = "set destination mac address",
2951 .priv = PRIV_ACTION(SET_MAC_DST,
2952 sizeof(struct rte_flow_action_set_mac)),
2953 .next = NEXT(action_set_mac_dst),
2956 [ACTION_SET_MAC_DST_MAC_DST] = {
2958 .help = "new destination mac address to set",
2959 .next = NEXT(action_set_mac_dst, NEXT_ENTRY(MAC_ADDR)),
2960 .args = ARGS(ARGS_ENTRY_HTON
2961 (struct rte_flow_action_set_mac, mac_addr)),
2962 .call = parse_vc_conf,
2964 [ACTION_INC_TCP_SEQ] = {
2965 .name = "inc_tcp_seq",
2966 .help = "increase TCP sequence number",
2967 .priv = PRIV_ACTION(INC_TCP_SEQ, sizeof(rte_be32_t)),
2968 .next = NEXT(action_inc_tcp_seq),
2971 [ACTION_INC_TCP_SEQ_VALUE] = {
2973 .help = "the value to increase TCP sequence number by",
2974 .next = NEXT(action_inc_tcp_seq, NEXT_ENTRY(UNSIGNED)),
2975 .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
2976 .call = parse_vc_conf,
2978 [ACTION_DEC_TCP_SEQ] = {
2979 .name = "dec_tcp_seq",
2980 .help = "decrease TCP sequence number",
2981 .priv = PRIV_ACTION(DEC_TCP_SEQ, sizeof(rte_be32_t)),
2982 .next = NEXT(action_dec_tcp_seq),
2985 [ACTION_DEC_TCP_SEQ_VALUE] = {
2987 .help = "the value to decrease TCP sequence number by",
2988 .next = NEXT(action_dec_tcp_seq, NEXT_ENTRY(UNSIGNED)),
2989 .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
2990 .call = parse_vc_conf,
2992 [ACTION_INC_TCP_ACK] = {
2993 .name = "inc_tcp_ack",
2994 .help = "increase TCP acknowledgment number",
2995 .priv = PRIV_ACTION(INC_TCP_ACK, sizeof(rte_be32_t)),
2996 .next = NEXT(action_inc_tcp_ack),
2999 [ACTION_INC_TCP_ACK_VALUE] = {
3001 .help = "the value to increase TCP acknowledgment number by",
3002 .next = NEXT(action_inc_tcp_ack, NEXT_ENTRY(UNSIGNED)),
3003 .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
3004 .call = parse_vc_conf,
3006 [ACTION_DEC_TCP_ACK] = {
3007 .name = "dec_tcp_ack",
3008 .help = "decrease TCP acknowledgment number",
3009 .priv = PRIV_ACTION(DEC_TCP_ACK, sizeof(rte_be32_t)),
3010 .next = NEXT(action_dec_tcp_ack),
3013 [ACTION_DEC_TCP_ACK_VALUE] = {
3015 .help = "the value to decrease TCP acknowledgment number by",
3016 .next = NEXT(action_dec_tcp_ack, NEXT_ENTRY(UNSIGNED)),
3017 .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
3018 .call = parse_vc_conf,
3022 /** Remove and return last entry from argument stack. */
3023 static const struct arg *
3024 pop_args(struct context *ctx)
3026 return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
3029 /** Add entry on top of the argument stack. */
3031 push_args(struct context *ctx, const struct arg *arg)
3033 if (ctx->args_num == CTX_STACK_SIZE)
3035 ctx->args[ctx->args_num++] = arg;
3039 /** Spread value into buffer according to bit-mask. */
3041 arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
3043 uint32_t i = arg->size;
3051 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
3060 unsigned int shift = 0;
3061 uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
3063 for (shift = 0; arg->mask[i] >> shift; ++shift) {
3064 if (!(arg->mask[i] & (1 << shift)))
3069 *buf &= ~(1 << shift);
3070 *buf |= (val & 1) << shift;
3078 /** Compare a string with a partial one of a given length. */
3080 strcmp_partial(const char *full, const char *partial, size_t partial_len)
3082 int r = strncmp(full, partial, partial_len);
3086 if (strlen(full) <= partial_len)
3088 return full[partial_len];
3092 * Parse a prefix length and generate a bit-mask.
3094 * Last argument (ctx->args) is retrieved to determine mask size, storage
3095 * location and whether the result must use network byte ordering.
3098 parse_prefix(struct context *ctx, const struct token *token,
3099 const char *str, unsigned int len,
3100 void *buf, unsigned int size)
3102 const struct arg *arg = pop_args(ctx);
3103 static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
3110 /* Argument is expected. */
3114 u = strtoumax(str, &end, 0);
3115 if (errno || (size_t)(end - str) != len)
3120 extra = arg_entry_bf_fill(NULL, 0, arg);
3129 if (!arg_entry_bf_fill(ctx->object, v, arg) ||
3130 !arg_entry_bf_fill(ctx->objmask, -1, arg))
3137 if (bytes > size || bytes + !!extra > size)
3141 buf = (uint8_t *)ctx->object + arg->offset;
3142 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
3144 memset((uint8_t *)buf + size - bytes, 0xff, bytes);
3145 memset(buf, 0x00, size - bytes);
3147 ((uint8_t *)buf)[size - bytes - 1] = conv[extra];
3151 memset(buf, 0xff, bytes);
3152 memset((uint8_t *)buf + bytes, 0x00, size - bytes);
3154 ((uint8_t *)buf)[bytes] = conv[extra];
3157 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
3160 push_args(ctx, arg);
3164 /** Default parsing function for token name matching. */
3166 parse_default(struct context *ctx, const struct token *token,
3167 const char *str, unsigned int len,
3168 void *buf, unsigned int size)
3173 if (strcmp_partial(token->name, str, len))
3178 /** Parse flow command, initialize output buffer for subsequent tokens. */
3180 parse_init(struct context *ctx, const struct token *token,
3181 const char *str, unsigned int len,
3182 void *buf, unsigned int size)
3184 struct buffer *out = buf;
3186 /* Token name must match. */
3187 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3189 /* Nothing else to do if there is no buffer. */
3192 /* Make sure buffer is large enough. */
3193 if (size < sizeof(*out))
3195 /* Initialize buffer. */
3196 memset(out, 0x00, sizeof(*out));
3197 memset((uint8_t *)out + sizeof(*out), 0x22, size - sizeof(*out));
3200 ctx->objmask = NULL;
3204 /** Parse tokens for validate/create commands. */
3206 parse_vc(struct context *ctx, const struct token *token,
3207 const char *str, unsigned int len,
3208 void *buf, unsigned int size)
3210 struct buffer *out = buf;
3214 /* Token name must match. */
3215 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3217 /* Nothing else to do if there is no buffer. */
3220 if (!out->command) {
3221 if (ctx->curr != VALIDATE && ctx->curr != CREATE)
3223 if (sizeof(*out) > size)
3225 out->command = ctx->curr;
3228 ctx->objmask = NULL;
3229 out->args.vc.data = (uint8_t *)out + size;
3233 ctx->object = &out->args.vc.attr;
3234 ctx->objmask = NULL;
3235 switch (ctx->curr) {
3240 out->args.vc.attr.ingress = 1;
3243 out->args.vc.attr.egress = 1;
3246 out->args.vc.attr.transfer = 1;
3249 out->args.vc.pattern =
3250 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
3252 ctx->object = out->args.vc.pattern;
3253 ctx->objmask = NULL;
3256 out->args.vc.actions =
3257 (void *)RTE_ALIGN_CEIL((uintptr_t)
3258 (out->args.vc.pattern +
3259 out->args.vc.pattern_n),
3261 ctx->object = out->args.vc.actions;
3262 ctx->objmask = NULL;
3269 if (!out->args.vc.actions) {
3270 const struct parse_item_priv *priv = token->priv;
3271 struct rte_flow_item *item =
3272 out->args.vc.pattern + out->args.vc.pattern_n;
3274 data_size = priv->size * 3; /* spec, last, mask */
3275 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
3276 (out->args.vc.data - data_size),
3278 if ((uint8_t *)item + sizeof(*item) > data)
3280 *item = (struct rte_flow_item){
3283 ++out->args.vc.pattern_n;
3285 ctx->objmask = NULL;
3287 const struct parse_action_priv *priv = token->priv;
3288 struct rte_flow_action *action =
3289 out->args.vc.actions + out->args.vc.actions_n;
3291 data_size = priv->size; /* configuration */
3292 data = (void *)RTE_ALIGN_FLOOR((uintptr_t)
3293 (out->args.vc.data - data_size),
3295 if ((uint8_t *)action + sizeof(*action) > data)
3297 *action = (struct rte_flow_action){
3299 .conf = data_size ? data : NULL,
3301 ++out->args.vc.actions_n;
3302 ctx->object = action;
3303 ctx->objmask = NULL;
3305 memset(data, 0, data_size);
3306 out->args.vc.data = data;
3307 ctx->objdata = data_size;
3311 /** Parse pattern item parameter type. */
3313 parse_vc_spec(struct context *ctx, const struct token *token,
3314 const char *str, unsigned int len,
3315 void *buf, unsigned int size)
3317 struct buffer *out = buf;
3318 struct rte_flow_item *item;
3324 /* Token name must match. */
3325 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3327 /* Parse parameter types. */
3328 switch (ctx->curr) {
3329 static const enum index prefix[] = NEXT_ENTRY(PREFIX);
3335 case ITEM_PARAM_SPEC:
3338 case ITEM_PARAM_LAST:
3341 case ITEM_PARAM_PREFIX:
3342 /* Modify next token to expect a prefix. */
3343 if (ctx->next_num < 2)
3345 ctx->next[ctx->next_num - 2] = prefix;
3347 case ITEM_PARAM_MASK:
3353 /* Nothing else to do if there is no buffer. */
3356 if (!out->args.vc.pattern_n)
3358 item = &out->args.vc.pattern[out->args.vc.pattern_n - 1];
3359 data_size = ctx->objdata / 3; /* spec, last, mask */
3360 /* Point to selected object. */
3361 ctx->object = out->args.vc.data + (data_size * index);
3363 ctx->objmask = out->args.vc.data + (data_size * 2); /* mask */
3364 item->mask = ctx->objmask;
3366 ctx->objmask = NULL;
3367 /* Update relevant item pointer. */
3368 *((const void **[]){ &item->spec, &item->last, &item->mask })[index] =
3373 /** Parse action configuration field. */
3375 parse_vc_conf(struct context *ctx, const struct token *token,
3376 const char *str, unsigned int len,
3377 void *buf, unsigned int size)
3379 struct buffer *out = buf;
3382 /* Token name must match. */
3383 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3385 /* Nothing else to do if there is no buffer. */
3388 /* Point to selected object. */
3389 ctx->object = out->args.vc.data;
3390 ctx->objmask = NULL;
3394 /** Parse RSS action. */
3396 parse_vc_action_rss(struct context *ctx, const struct token *token,
3397 const char *str, unsigned int len,
3398 void *buf, unsigned int size)
3400 struct buffer *out = buf;
3401 struct rte_flow_action *action;
3402 struct action_rss_data *action_rss_data;
3406 ret = parse_vc(ctx, token, str, len, buf, size);
3409 /* Nothing else to do if there is no buffer. */
3412 if (!out->args.vc.actions_n)
3414 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3415 /* Point to selected object. */
3416 ctx->object = out->args.vc.data;
3417 ctx->objmask = NULL;
3418 /* Set up default configuration. */
3419 action_rss_data = ctx->object;
3420 *action_rss_data = (struct action_rss_data){
3421 .conf = (struct rte_flow_action_rss){
3422 .func = RTE_ETH_HASH_FUNCTION_DEFAULT,
3425 .key_len = sizeof(action_rss_data->key),
3426 .queue_num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
3427 .key = action_rss_data->key,
3428 .queue = action_rss_data->queue,
3430 .key = "testpmd's default RSS hash key, "
3431 "override it for better balancing",
3434 for (i = 0; i < action_rss_data->conf.queue_num; ++i)
3435 action_rss_data->queue[i] = i;
3436 if (!port_id_is_invalid(ctx->port, DISABLED_WARN) &&
3437 ctx->port != (portid_t)RTE_PORT_ALL) {
3438 struct rte_eth_dev_info info;
3440 rte_eth_dev_info_get(ctx->port, &info);
3441 action_rss_data->conf.key_len =
3442 RTE_MIN(sizeof(action_rss_data->key),
3443 info.hash_key_size);
3445 action->conf = &action_rss_data->conf;
3450 * Parse func field for RSS action.
3452 * The RTE_ETH_HASH_FUNCTION_* value to assign is derived from the
3453 * ACTION_RSS_FUNC_* index that called this function.
3456 parse_vc_action_rss_func(struct context *ctx, const struct token *token,
3457 const char *str, unsigned int len,
3458 void *buf, unsigned int size)
3460 struct action_rss_data *action_rss_data;
3461 enum rte_eth_hash_function func;
3465 /* Token name must match. */
3466 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
3468 switch (ctx->curr) {
3469 case ACTION_RSS_FUNC_DEFAULT:
3470 func = RTE_ETH_HASH_FUNCTION_DEFAULT;
3472 case ACTION_RSS_FUNC_TOEPLITZ:
3473 func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
3475 case ACTION_RSS_FUNC_SIMPLE_XOR:
3476 func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
3483 action_rss_data = ctx->object;
3484 action_rss_data->conf.func = func;
3489 * Parse type field for RSS action.
3491 * Valid tokens are type field names and the "end" token.
3494 parse_vc_action_rss_type(struct context *ctx, const struct token *token,
3495 const char *str, unsigned int len,
3496 void *buf, unsigned int size)
3498 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_TYPE);
3499 struct action_rss_data *action_rss_data;
3505 if (ctx->curr != ACTION_RSS_TYPE)
3507 if (!(ctx->objdata >> 16) && ctx->object) {
3508 action_rss_data = ctx->object;
3509 action_rss_data->conf.types = 0;
3511 if (!strcmp_partial("end", str, len)) {
3512 ctx->objdata &= 0xffff;
3515 for (i = 0; rss_type_table[i].str; ++i)
3516 if (!strcmp_partial(rss_type_table[i].str, str, len))
3518 if (!rss_type_table[i].str)
3520 ctx->objdata = 1 << 16 | (ctx->objdata & 0xffff);
3522 if (ctx->next_num == RTE_DIM(ctx->next))
3524 ctx->next[ctx->next_num++] = next;
3527 action_rss_data = ctx->object;
3528 action_rss_data->conf.types |= rss_type_table[i].rss_type;
3533 * Parse queue field for RSS action.
3535 * Valid tokens are queue indices and the "end" token.
3538 parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
3539 const char *str, unsigned int len,
3540 void *buf, unsigned int size)
3542 static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
3543 struct action_rss_data *action_rss_data;
3544 const struct arg *arg;
3551 if (ctx->curr != ACTION_RSS_QUEUE)
3553 i = ctx->objdata >> 16;
3554 if (!strcmp_partial("end", str, len)) {
3555 ctx->objdata &= 0xffff;
3558 if (i >= ACTION_RSS_QUEUE_NUM)
3560 arg = ARGS_ENTRY_ARB(offsetof(struct action_rss_data, queue) +
3561 i * sizeof(action_rss_data->queue[i]),
3562 sizeof(action_rss_data->queue[i]));
3563 if (push_args(ctx, arg))
3565 ret = parse_int(ctx, token, str, len, NULL, 0);
3571 ctx->objdata = i << 16 | (ctx->objdata & 0xffff);
3573 if (ctx->next_num == RTE_DIM(ctx->next))
3575 ctx->next[ctx->next_num++] = next;
3579 action_rss_data = ctx->object;
3580 action_rss_data->conf.queue_num = i;
3581 action_rss_data->conf.queue = i ? action_rss_data->queue : NULL;
3585 /** Parse VXLAN encap action. */
3587 parse_vc_action_vxlan_encap(struct context *ctx, const struct token *token,
3588 const char *str, unsigned int len,
3589 void *buf, unsigned int size)
3591 struct buffer *out = buf;
3592 struct rte_flow_action *action;
3593 struct action_vxlan_encap_data *action_vxlan_encap_data;
3596 ret = parse_vc(ctx, token, str, len, buf, size);
3599 /* Nothing else to do if there is no buffer. */
3602 if (!out->args.vc.actions_n)
3604 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3605 /* Point to selected object. */
3606 ctx->object = out->args.vc.data;
3607 ctx->objmask = NULL;
3608 /* Set up default configuration. */
3609 action_vxlan_encap_data = ctx->object;
3610 *action_vxlan_encap_data = (struct action_vxlan_encap_data){
3611 .conf = (struct rte_flow_action_vxlan_encap){
3612 .definition = action_vxlan_encap_data->items,
3616 .type = RTE_FLOW_ITEM_TYPE_ETH,
3617 .spec = &action_vxlan_encap_data->item_eth,
3618 .mask = &rte_flow_item_eth_mask,
3621 .type = RTE_FLOW_ITEM_TYPE_VLAN,
3622 .spec = &action_vxlan_encap_data->item_vlan,
3623 .mask = &rte_flow_item_vlan_mask,
3626 .type = RTE_FLOW_ITEM_TYPE_IPV4,
3627 .spec = &action_vxlan_encap_data->item_ipv4,
3628 .mask = &rte_flow_item_ipv4_mask,
3631 .type = RTE_FLOW_ITEM_TYPE_UDP,
3632 .spec = &action_vxlan_encap_data->item_udp,
3633 .mask = &rte_flow_item_udp_mask,
3636 .type = RTE_FLOW_ITEM_TYPE_VXLAN,
3637 .spec = &action_vxlan_encap_data->item_vxlan,
3638 .mask = &rte_flow_item_vxlan_mask,
3641 .type = RTE_FLOW_ITEM_TYPE_END,
3646 .tci = vxlan_encap_conf.vlan_tci,
3650 .src_addr = vxlan_encap_conf.ipv4_src,
3651 .dst_addr = vxlan_encap_conf.ipv4_dst,
3654 .src_port = vxlan_encap_conf.udp_src,
3655 .dst_port = vxlan_encap_conf.udp_dst,
3657 .item_vxlan.flags = 0,
3659 memcpy(action_vxlan_encap_data->item_eth.dst.addr_bytes,
3660 vxlan_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
3661 memcpy(action_vxlan_encap_data->item_eth.src.addr_bytes,
3662 vxlan_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
3663 if (!vxlan_encap_conf.select_ipv4) {
3664 memcpy(&action_vxlan_encap_data->item_ipv6.hdr.src_addr,
3665 &vxlan_encap_conf.ipv6_src,
3666 sizeof(vxlan_encap_conf.ipv6_src));
3667 memcpy(&action_vxlan_encap_data->item_ipv6.hdr.dst_addr,
3668 &vxlan_encap_conf.ipv6_dst,
3669 sizeof(vxlan_encap_conf.ipv6_dst));
3670 action_vxlan_encap_data->items[2] = (struct rte_flow_item){
3671 .type = RTE_FLOW_ITEM_TYPE_IPV6,
3672 .spec = &action_vxlan_encap_data->item_ipv6,
3673 .mask = &rte_flow_item_ipv6_mask,
3676 if (!vxlan_encap_conf.select_vlan)
3677 action_vxlan_encap_data->items[1].type =
3678 RTE_FLOW_ITEM_TYPE_VOID;
3679 if (vxlan_encap_conf.select_tos_ttl) {
3680 if (vxlan_encap_conf.select_ipv4) {
3681 static struct rte_flow_item_ipv4 ipv4_mask_tos;
3683 memcpy(&ipv4_mask_tos, &rte_flow_item_ipv4_mask,
3684 sizeof(ipv4_mask_tos));
3685 ipv4_mask_tos.hdr.type_of_service = 0xff;
3686 ipv4_mask_tos.hdr.time_to_live = 0xff;
3687 action_vxlan_encap_data->item_ipv4.hdr.type_of_service =
3688 vxlan_encap_conf.ip_tos;
3689 action_vxlan_encap_data->item_ipv4.hdr.time_to_live =
3690 vxlan_encap_conf.ip_ttl;
3691 action_vxlan_encap_data->items[2].mask =
3694 static struct rte_flow_item_ipv6 ipv6_mask_tos;
3696 memcpy(&ipv6_mask_tos, &rte_flow_item_ipv6_mask,
3697 sizeof(ipv6_mask_tos));
3698 ipv6_mask_tos.hdr.vtc_flow |=
3699 RTE_BE32(0xfful << RTE_IPV6_HDR_TC_SHIFT);
3700 ipv6_mask_tos.hdr.hop_limits = 0xff;
3701 action_vxlan_encap_data->item_ipv6.hdr.vtc_flow |=
3703 ((uint32_t)vxlan_encap_conf.ip_tos <<
3704 RTE_IPV6_HDR_TC_SHIFT);
3705 action_vxlan_encap_data->item_ipv6.hdr.hop_limits =
3706 vxlan_encap_conf.ip_ttl;
3707 action_vxlan_encap_data->items[2].mask =
3711 memcpy(action_vxlan_encap_data->item_vxlan.vni, vxlan_encap_conf.vni,
3712 RTE_DIM(vxlan_encap_conf.vni));
3713 action->conf = &action_vxlan_encap_data->conf;
3717 /** Parse NVGRE encap action. */
3719 parse_vc_action_nvgre_encap(struct context *ctx, const struct token *token,
3720 const char *str, unsigned int len,
3721 void *buf, unsigned int size)
3723 struct buffer *out = buf;
3724 struct rte_flow_action *action;
3725 struct action_nvgre_encap_data *action_nvgre_encap_data;
3728 ret = parse_vc(ctx, token, str, len, buf, size);
3731 /* Nothing else to do if there is no buffer. */
3734 if (!out->args.vc.actions_n)
3736 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3737 /* Point to selected object. */
3738 ctx->object = out->args.vc.data;
3739 ctx->objmask = NULL;
3740 /* Set up default configuration. */
3741 action_nvgre_encap_data = ctx->object;
3742 *action_nvgre_encap_data = (struct action_nvgre_encap_data){
3743 .conf = (struct rte_flow_action_nvgre_encap){
3744 .definition = action_nvgre_encap_data->items,
3748 .type = RTE_FLOW_ITEM_TYPE_ETH,
3749 .spec = &action_nvgre_encap_data->item_eth,
3750 .mask = &rte_flow_item_eth_mask,
3753 .type = RTE_FLOW_ITEM_TYPE_VLAN,
3754 .spec = &action_nvgre_encap_data->item_vlan,
3755 .mask = &rte_flow_item_vlan_mask,
3758 .type = RTE_FLOW_ITEM_TYPE_IPV4,
3759 .spec = &action_nvgre_encap_data->item_ipv4,
3760 .mask = &rte_flow_item_ipv4_mask,
3763 .type = RTE_FLOW_ITEM_TYPE_NVGRE,
3764 .spec = &action_nvgre_encap_data->item_nvgre,
3765 .mask = &rte_flow_item_nvgre_mask,
3768 .type = RTE_FLOW_ITEM_TYPE_END,
3773 .tci = nvgre_encap_conf.vlan_tci,
3777 .src_addr = nvgre_encap_conf.ipv4_src,
3778 .dst_addr = nvgre_encap_conf.ipv4_dst,
3780 .item_nvgre.flow_id = 0,
3782 memcpy(action_nvgre_encap_data->item_eth.dst.addr_bytes,
3783 nvgre_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
3784 memcpy(action_nvgre_encap_data->item_eth.src.addr_bytes,
3785 nvgre_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
3786 if (!nvgre_encap_conf.select_ipv4) {
3787 memcpy(&action_nvgre_encap_data->item_ipv6.hdr.src_addr,
3788 &nvgre_encap_conf.ipv6_src,
3789 sizeof(nvgre_encap_conf.ipv6_src));
3790 memcpy(&action_nvgre_encap_data->item_ipv6.hdr.dst_addr,
3791 &nvgre_encap_conf.ipv6_dst,
3792 sizeof(nvgre_encap_conf.ipv6_dst));
3793 action_nvgre_encap_data->items[2] = (struct rte_flow_item){
3794 .type = RTE_FLOW_ITEM_TYPE_IPV6,
3795 .spec = &action_nvgre_encap_data->item_ipv6,
3796 .mask = &rte_flow_item_ipv6_mask,
3799 if (!nvgre_encap_conf.select_vlan)
3800 action_nvgre_encap_data->items[1].type =
3801 RTE_FLOW_ITEM_TYPE_VOID;
3802 memcpy(action_nvgre_encap_data->item_nvgre.tni, nvgre_encap_conf.tni,
3803 RTE_DIM(nvgre_encap_conf.tni));
3804 action->conf = &action_nvgre_encap_data->conf;
3808 /** Parse l2 encap action. */
3810 parse_vc_action_l2_encap(struct context *ctx, const struct token *token,
3811 const char *str, unsigned int len,
3812 void *buf, unsigned int size)
3814 struct buffer *out = buf;
3815 struct rte_flow_action *action;
3816 struct action_raw_encap_data *action_encap_data;
3817 struct rte_flow_item_eth eth = { .type = 0, };
3818 struct rte_flow_item_vlan vlan = {
3819 .tci = mplsoudp_encap_conf.vlan_tci,
3825 ret = parse_vc(ctx, token, str, len, buf, size);
3828 /* Nothing else to do if there is no buffer. */
3831 if (!out->args.vc.actions_n)
3833 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3834 /* Point to selected object. */
3835 ctx->object = out->args.vc.data;
3836 ctx->objmask = NULL;
3837 /* Copy the headers to the buffer. */
3838 action_encap_data = ctx->object;
3839 *action_encap_data = (struct action_raw_encap_data) {
3840 .conf = (struct rte_flow_action_raw_encap){
3841 .data = action_encap_data->data,
3845 header = action_encap_data->data;
3846 if (l2_encap_conf.select_vlan)
3847 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
3848 else if (l2_encap_conf.select_ipv4)
3849 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
3851 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
3852 memcpy(eth.dst.addr_bytes,
3853 l2_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
3854 memcpy(eth.src.addr_bytes,
3855 l2_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
3856 memcpy(header, ð, sizeof(eth));
3857 header += sizeof(eth);
3858 if (l2_encap_conf.select_vlan) {
3859 if (l2_encap_conf.select_ipv4)
3860 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
3862 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
3863 memcpy(header, &vlan, sizeof(vlan));
3864 header += sizeof(vlan);
3866 action_encap_data->conf.size = header -
3867 action_encap_data->data;
3868 action->conf = &action_encap_data->conf;
3872 /** Parse l2 decap action. */
3874 parse_vc_action_l2_decap(struct context *ctx, const struct token *token,
3875 const char *str, unsigned int len,
3876 void *buf, unsigned int size)
3878 struct buffer *out = buf;
3879 struct rte_flow_action *action;
3880 struct action_raw_decap_data *action_decap_data;
3881 struct rte_flow_item_eth eth = { .type = 0, };
3882 struct rte_flow_item_vlan vlan = {
3883 .tci = mplsoudp_encap_conf.vlan_tci,
3889 ret = parse_vc(ctx, token, str, len, buf, size);
3892 /* Nothing else to do if there is no buffer. */
3895 if (!out->args.vc.actions_n)
3897 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3898 /* Point to selected object. */
3899 ctx->object = out->args.vc.data;
3900 ctx->objmask = NULL;
3901 /* Copy the headers to the buffer. */
3902 action_decap_data = ctx->object;
3903 *action_decap_data = (struct action_raw_decap_data) {
3904 .conf = (struct rte_flow_action_raw_decap){
3905 .data = action_decap_data->data,
3909 header = action_decap_data->data;
3910 if (l2_decap_conf.select_vlan)
3911 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
3912 memcpy(header, ð, sizeof(eth));
3913 header += sizeof(eth);
3914 if (l2_decap_conf.select_vlan) {
3915 memcpy(header, &vlan, sizeof(vlan));
3916 header += sizeof(vlan);
3918 action_decap_data->conf.size = header -
3919 action_decap_data->data;
3920 action->conf = &action_decap_data->conf;
3924 #define ETHER_TYPE_MPLS_UNICAST 0x8847
3926 /** Parse MPLSOGRE encap action. */
3928 parse_vc_action_mplsogre_encap(struct context *ctx, const struct token *token,
3929 const char *str, unsigned int len,
3930 void *buf, unsigned int size)
3932 struct buffer *out = buf;
3933 struct rte_flow_action *action;
3934 struct action_raw_encap_data *action_encap_data;
3935 struct rte_flow_item_eth eth = { .type = 0, };
3936 struct rte_flow_item_vlan vlan = {
3937 .tci = mplsogre_encap_conf.vlan_tci,
3940 struct rte_flow_item_ipv4 ipv4 = {
3942 .src_addr = mplsogre_encap_conf.ipv4_src,
3943 .dst_addr = mplsogre_encap_conf.ipv4_dst,
3944 .next_proto_id = IPPROTO_GRE,
3945 .version_ihl = RTE_IPV4_VHL_DEF,
3946 .time_to_live = IPDEFTTL,
3949 struct rte_flow_item_ipv6 ipv6 = {
3951 .proto = IPPROTO_GRE,
3952 .hop_limits = IPDEFTTL,
3955 struct rte_flow_item_gre gre = {
3956 .protocol = rte_cpu_to_be_16(ETHER_TYPE_MPLS_UNICAST),
3958 struct rte_flow_item_mpls mpls;
3962 ret = parse_vc(ctx, token, str, len, buf, size);
3965 /* Nothing else to do if there is no buffer. */
3968 if (!out->args.vc.actions_n)
3970 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
3971 /* Point to selected object. */
3972 ctx->object = out->args.vc.data;
3973 ctx->objmask = NULL;
3974 /* Copy the headers to the buffer. */
3975 action_encap_data = ctx->object;
3976 *action_encap_data = (struct action_raw_encap_data) {
3977 .conf = (struct rte_flow_action_raw_encap){
3978 .data = action_encap_data->data,
3983 header = action_encap_data->data;
3984 if (mplsogre_encap_conf.select_vlan)
3985 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
3986 else if (mplsogre_encap_conf.select_ipv4)
3987 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
3989 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
3990 memcpy(eth.dst.addr_bytes,
3991 mplsogre_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
3992 memcpy(eth.src.addr_bytes,
3993 mplsogre_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
3994 memcpy(header, ð, sizeof(eth));
3995 header += sizeof(eth);
3996 if (mplsogre_encap_conf.select_vlan) {
3997 if (mplsogre_encap_conf.select_ipv4)
3998 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
4000 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
4001 memcpy(header, &vlan, sizeof(vlan));
4002 header += sizeof(vlan);
4004 if (mplsogre_encap_conf.select_ipv4) {
4005 memcpy(header, &ipv4, sizeof(ipv4));
4006 header += sizeof(ipv4);
4008 memcpy(&ipv6.hdr.src_addr,
4009 &mplsogre_encap_conf.ipv6_src,
4010 sizeof(mplsogre_encap_conf.ipv6_src));
4011 memcpy(&ipv6.hdr.dst_addr,
4012 &mplsogre_encap_conf.ipv6_dst,
4013 sizeof(mplsogre_encap_conf.ipv6_dst));
4014 memcpy(header, &ipv6, sizeof(ipv6));
4015 header += sizeof(ipv6);
4017 memcpy(header, &gre, sizeof(gre));
4018 header += sizeof(gre);
4019 memcpy(mpls.label_tc_s, mplsogre_encap_conf.label,
4020 RTE_DIM(mplsogre_encap_conf.label));
4021 mpls.label_tc_s[2] |= 0x1;
4022 memcpy(header, &mpls, sizeof(mpls));
4023 header += sizeof(mpls);
4024 action_encap_data->conf.size = header -
4025 action_encap_data->data;
4026 action->conf = &action_encap_data->conf;
4030 /** Parse MPLSOGRE decap action. */
4032 parse_vc_action_mplsogre_decap(struct context *ctx, const struct token *token,
4033 const char *str, unsigned int len,
4034 void *buf, unsigned int size)
4036 struct buffer *out = buf;
4037 struct rte_flow_action *action;
4038 struct action_raw_decap_data *action_decap_data;
4039 struct rte_flow_item_eth eth = { .type = 0, };
4040 struct rte_flow_item_vlan vlan = {.tci = 0};
4041 struct rte_flow_item_ipv4 ipv4 = {
4043 .next_proto_id = IPPROTO_GRE,
4046 struct rte_flow_item_ipv6 ipv6 = {
4048 .proto = IPPROTO_GRE,
4051 struct rte_flow_item_gre gre = {
4052 .protocol = rte_cpu_to_be_16(ETHER_TYPE_MPLS_UNICAST),
4054 struct rte_flow_item_mpls mpls;
4058 ret = parse_vc(ctx, token, str, len, buf, size);
4061 /* Nothing else to do if there is no buffer. */
4064 if (!out->args.vc.actions_n)
4066 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
4067 /* Point to selected object. */
4068 ctx->object = out->args.vc.data;
4069 ctx->objmask = NULL;
4070 /* Copy the headers to the buffer. */
4071 action_decap_data = ctx->object;
4072 *action_decap_data = (struct action_raw_decap_data) {
4073 .conf = (struct rte_flow_action_raw_decap){
4074 .data = action_decap_data->data,
4078 header = action_decap_data->data;
4079 if (mplsogre_decap_conf.select_vlan)
4080 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
4081 else if (mplsogre_encap_conf.select_ipv4)
4082 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
4084 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
4085 memcpy(eth.dst.addr_bytes,
4086 mplsogre_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
4087 memcpy(eth.src.addr_bytes,
4088 mplsogre_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
4089 memcpy(header, ð, sizeof(eth));
4090 header += sizeof(eth);
4091 if (mplsogre_encap_conf.select_vlan) {
4092 if (mplsogre_encap_conf.select_ipv4)
4093 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
4095 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
4096 memcpy(header, &vlan, sizeof(vlan));
4097 header += sizeof(vlan);
4099 if (mplsogre_encap_conf.select_ipv4) {
4100 memcpy(header, &ipv4, sizeof(ipv4));
4101 header += sizeof(ipv4);
4103 memcpy(header, &ipv6, sizeof(ipv6));
4104 header += sizeof(ipv6);
4106 memcpy(header, &gre, sizeof(gre));
4107 header += sizeof(gre);
4108 memset(&mpls, 0, sizeof(mpls));
4109 memcpy(header, &mpls, sizeof(mpls));
4110 header += sizeof(mpls);
4111 action_decap_data->conf.size = header -
4112 action_decap_data->data;
4113 action->conf = &action_decap_data->conf;
4117 /** Parse MPLSOUDP encap action. */
4119 parse_vc_action_mplsoudp_encap(struct context *ctx, const struct token *token,
4120 const char *str, unsigned int len,
4121 void *buf, unsigned int size)
4123 struct buffer *out = buf;
4124 struct rte_flow_action *action;
4125 struct action_raw_encap_data *action_encap_data;
4126 struct rte_flow_item_eth eth = { .type = 0, };
4127 struct rte_flow_item_vlan vlan = {
4128 .tci = mplsoudp_encap_conf.vlan_tci,
4131 struct rte_flow_item_ipv4 ipv4 = {
4133 .src_addr = mplsoudp_encap_conf.ipv4_src,
4134 .dst_addr = mplsoudp_encap_conf.ipv4_dst,
4135 .next_proto_id = IPPROTO_UDP,
4136 .version_ihl = RTE_IPV4_VHL_DEF,
4137 .time_to_live = IPDEFTTL,
4140 struct rte_flow_item_ipv6 ipv6 = {
4142 .proto = IPPROTO_UDP,
4143 .hop_limits = IPDEFTTL,
4146 struct rte_flow_item_udp udp = {
4148 .src_port = mplsoudp_encap_conf.udp_src,
4149 .dst_port = mplsoudp_encap_conf.udp_dst,
4152 struct rte_flow_item_mpls mpls;
4156 ret = parse_vc(ctx, token, str, len, buf, size);
4159 /* Nothing else to do if there is no buffer. */
4162 if (!out->args.vc.actions_n)
4164 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
4165 /* Point to selected object. */
4166 ctx->object = out->args.vc.data;
4167 ctx->objmask = NULL;
4168 /* Copy the headers to the buffer. */
4169 action_encap_data = ctx->object;
4170 *action_encap_data = (struct action_raw_encap_data) {
4171 .conf = (struct rte_flow_action_raw_encap){
4172 .data = action_encap_data->data,
4177 header = action_encap_data->data;
4178 if (mplsoudp_encap_conf.select_vlan)
4179 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
4180 else if (mplsoudp_encap_conf.select_ipv4)
4181 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
4183 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
4184 memcpy(eth.dst.addr_bytes,
4185 mplsoudp_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
4186 memcpy(eth.src.addr_bytes,
4187 mplsoudp_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
4188 memcpy(header, ð, sizeof(eth));
4189 header += sizeof(eth);
4190 if (mplsoudp_encap_conf.select_vlan) {
4191 if (mplsoudp_encap_conf.select_ipv4)
4192 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
4194 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
4195 memcpy(header, &vlan, sizeof(vlan));
4196 header += sizeof(vlan);
4198 if (mplsoudp_encap_conf.select_ipv4) {
4199 memcpy(header, &ipv4, sizeof(ipv4));
4200 header += sizeof(ipv4);
4202 memcpy(&ipv6.hdr.src_addr,
4203 &mplsoudp_encap_conf.ipv6_src,
4204 sizeof(mplsoudp_encap_conf.ipv6_src));
4205 memcpy(&ipv6.hdr.dst_addr,
4206 &mplsoudp_encap_conf.ipv6_dst,
4207 sizeof(mplsoudp_encap_conf.ipv6_dst));
4208 memcpy(header, &ipv6, sizeof(ipv6));
4209 header += sizeof(ipv6);
4211 memcpy(header, &udp, sizeof(udp));
4212 header += sizeof(udp);
4213 memcpy(mpls.label_tc_s, mplsoudp_encap_conf.label,
4214 RTE_DIM(mplsoudp_encap_conf.label));
4215 mpls.label_tc_s[2] |= 0x1;
4216 memcpy(header, &mpls, sizeof(mpls));
4217 header += sizeof(mpls);
4218 action_encap_data->conf.size = header -
4219 action_encap_data->data;
4220 action->conf = &action_encap_data->conf;
4224 /** Parse MPLSOUDP decap action. */
4226 parse_vc_action_mplsoudp_decap(struct context *ctx, const struct token *token,
4227 const char *str, unsigned int len,
4228 void *buf, unsigned int size)
4230 struct buffer *out = buf;
4231 struct rte_flow_action *action;
4232 struct action_raw_decap_data *action_decap_data;
4233 struct rte_flow_item_eth eth = { .type = 0, };
4234 struct rte_flow_item_vlan vlan = {.tci = 0};
4235 struct rte_flow_item_ipv4 ipv4 = {
4237 .next_proto_id = IPPROTO_UDP,
4240 struct rte_flow_item_ipv6 ipv6 = {
4242 .proto = IPPROTO_UDP,
4245 struct rte_flow_item_udp udp = {
4247 .dst_port = rte_cpu_to_be_16(6635),
4250 struct rte_flow_item_mpls mpls;
4254 ret = parse_vc(ctx, token, str, len, buf, size);
4257 /* Nothing else to do if there is no buffer. */
4260 if (!out->args.vc.actions_n)
4262 action = &out->args.vc.actions[out->args.vc.actions_n - 1];
4263 /* Point to selected object. */
4264 ctx->object = out->args.vc.data;
4265 ctx->objmask = NULL;
4266 /* Copy the headers to the buffer. */
4267 action_decap_data = ctx->object;
4268 *action_decap_data = (struct action_raw_decap_data) {
4269 .conf = (struct rte_flow_action_raw_decap){
4270 .data = action_decap_data->data,
4274 header = action_decap_data->data;
4275 if (mplsoudp_decap_conf.select_vlan)
4276 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_VLAN);
4277 else if (mplsoudp_encap_conf.select_ipv4)
4278 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
4280 eth.type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
4281 memcpy(eth.dst.addr_bytes,
4282 mplsoudp_encap_conf.eth_dst, RTE_ETHER_ADDR_LEN);
4283 memcpy(eth.src.addr_bytes,
4284 mplsoudp_encap_conf.eth_src, RTE_ETHER_ADDR_LEN);
4285 memcpy(header, ð, sizeof(eth));
4286 header += sizeof(eth);
4287 if (mplsoudp_encap_conf.select_vlan) {
4288 if (mplsoudp_encap_conf.select_ipv4)
4289 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
4291 vlan.inner_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6);
4292 memcpy(header, &vlan, sizeof(vlan));
4293 header += sizeof(vlan);
4295 if (mplsoudp_encap_conf.select_ipv4) {
4296 memcpy(header, &ipv4, sizeof(ipv4));
4297 header += sizeof(ipv4);
4299 memcpy(header, &ipv6, sizeof(ipv6));
4300 header += sizeof(ipv6);
4302 memcpy(header, &udp, sizeof(udp));
4303 header += sizeof(udp);
4304 memset(&mpls, 0, sizeof(mpls));
4305 memcpy(header, &mpls, sizeof(mpls));
4306 header += sizeof(mpls);
4307 action_decap_data->conf.size = header -
4308 action_decap_data->data;
4309 action->conf = &action_decap_data->conf;
4313 /** Parse tokens for destroy command. */
4315 parse_destroy(struct context *ctx, const struct token *token,
4316 const char *str, unsigned int len,
4317 void *buf, unsigned int size)
4319 struct buffer *out = buf;
4321 /* Token name must match. */
4322 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4324 /* Nothing else to do if there is no buffer. */
4327 if (!out->command) {
4328 if (ctx->curr != DESTROY)
4330 if (sizeof(*out) > size)
4332 out->command = ctx->curr;
4335 ctx->objmask = NULL;
4336 out->args.destroy.rule =
4337 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
4341 if (((uint8_t *)(out->args.destroy.rule + out->args.destroy.rule_n) +
4342 sizeof(*out->args.destroy.rule)) > (uint8_t *)out + size)
4345 ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++;
4346 ctx->objmask = NULL;
4350 /** Parse tokens for flush command. */
4352 parse_flush(struct context *ctx, const struct token *token,
4353 const char *str, unsigned int len,
4354 void *buf, unsigned int size)
4356 struct buffer *out = buf;
4358 /* Token name must match. */
4359 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4361 /* Nothing else to do if there is no buffer. */
4364 if (!out->command) {
4365 if (ctx->curr != FLUSH)
4367 if (sizeof(*out) > size)
4369 out->command = ctx->curr;
4372 ctx->objmask = NULL;
4377 /** Parse tokens for query command. */
4379 parse_query(struct context *ctx, const struct token *token,
4380 const char *str, unsigned int len,
4381 void *buf, unsigned int size)
4383 struct buffer *out = buf;
4385 /* Token name must match. */
4386 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4388 /* Nothing else to do if there is no buffer. */
4391 if (!out->command) {
4392 if (ctx->curr != QUERY)
4394 if (sizeof(*out) > size)
4396 out->command = ctx->curr;
4399 ctx->objmask = NULL;
4404 /** Parse action names. */
4406 parse_action(struct context *ctx, const struct token *token,
4407 const char *str, unsigned int len,
4408 void *buf, unsigned int size)
4410 struct buffer *out = buf;
4411 const struct arg *arg = pop_args(ctx);
4415 /* Argument is expected. */
4418 /* Parse action name. */
4419 for (i = 0; next_action[i]; ++i) {
4420 const struct parse_action_priv *priv;
4422 token = &token_list[next_action[i]];
4423 if (strcmp_partial(token->name, str, len))
4429 memcpy((uint8_t *)ctx->object + arg->offset,
4435 push_args(ctx, arg);
4439 /** Parse tokens for list command. */
4441 parse_list(struct context *ctx, const struct token *token,
4442 const char *str, unsigned int len,
4443 void *buf, unsigned int size)
4445 struct buffer *out = buf;
4447 /* Token name must match. */
4448 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4450 /* Nothing else to do if there is no buffer. */
4453 if (!out->command) {
4454 if (ctx->curr != LIST)
4456 if (sizeof(*out) > size)
4458 out->command = ctx->curr;
4461 ctx->objmask = NULL;
4462 out->args.list.group =
4463 (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
4467 if (((uint8_t *)(out->args.list.group + out->args.list.group_n) +
4468 sizeof(*out->args.list.group)) > (uint8_t *)out + size)
4471 ctx->object = out->args.list.group + out->args.list.group_n++;
4472 ctx->objmask = NULL;
4476 /** Parse tokens for isolate command. */
4478 parse_isolate(struct context *ctx, const struct token *token,
4479 const char *str, unsigned int len,
4480 void *buf, unsigned int size)
4482 struct buffer *out = buf;
4484 /* Token name must match. */
4485 if (parse_default(ctx, token, str, len, NULL, 0) < 0)
4487 /* Nothing else to do if there is no buffer. */
4490 if (!out->command) {
4491 if (ctx->curr != ISOLATE)
4493 if (sizeof(*out) > size)
4495 out->command = ctx->curr;
4498 ctx->objmask = NULL;
4504 * Parse signed/unsigned integers 8 to 64-bit long.
4506 * Last argument (ctx->args) is retrieved to determine integer type and
4510 parse_int(struct context *ctx, const struct token *token,
4511 const char *str, unsigned int len,
4512 void *buf, unsigned int size)
4514 const struct arg *arg = pop_args(ctx);
4519 /* Argument is expected. */
4524 (uintmax_t)strtoimax(str, &end, 0) :
4525 strtoumax(str, &end, 0);
4526 if (errno || (size_t)(end - str) != len)
4529 ((arg->sign && ((intmax_t)u < (intmax_t)arg->min ||
4530 (intmax_t)u > (intmax_t)arg->max)) ||
4531 (!arg->sign && (u < arg->min || u > arg->max))))
4536 if (!arg_entry_bf_fill(ctx->object, u, arg) ||
4537 !arg_entry_bf_fill(ctx->objmask, -1, arg))
4541 buf = (uint8_t *)ctx->object + arg->offset;
4543 if (u > RTE_LEN2MASK(size * CHAR_BIT, uint64_t))
4547 case sizeof(uint8_t):
4548 *(uint8_t *)buf = u;
4550 case sizeof(uint16_t):
4551 *(uint16_t *)buf = arg->hton ? rte_cpu_to_be_16(u) : u;
4553 case sizeof(uint8_t [3]):
4554 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
4556 ((uint8_t *)buf)[0] = u;
4557 ((uint8_t *)buf)[1] = u >> 8;
4558 ((uint8_t *)buf)[2] = u >> 16;
4562 ((uint8_t *)buf)[0] = u >> 16;
4563 ((uint8_t *)buf)[1] = u >> 8;
4564 ((uint8_t *)buf)[2] = u;
4566 case sizeof(uint32_t):
4567 *(uint32_t *)buf = arg->hton ? rte_cpu_to_be_32(u) : u;
4569 case sizeof(uint64_t):
4570 *(uint64_t *)buf = arg->hton ? rte_cpu_to_be_64(u) : u;
4575 if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) {
4577 buf = (uint8_t *)ctx->objmask + arg->offset;
4582 push_args(ctx, arg);
4589 * Three arguments (ctx->args) are retrieved from the stack to store data,
4590 * its actual length and address (in that order).
4593 parse_string(struct context *ctx, const struct token *token,
4594 const char *str, unsigned int len,
4595 void *buf, unsigned int size)
4597 const struct arg *arg_data = pop_args(ctx);
4598 const struct arg *arg_len = pop_args(ctx);
4599 const struct arg *arg_addr = pop_args(ctx);
4600 char tmp[16]; /* Ought to be enough. */
4603 /* Arguments are expected. */
4607 push_args(ctx, arg_data);
4611 push_args(ctx, arg_len);
4612 push_args(ctx, arg_data);
4615 size = arg_data->size;
4616 /* Bit-mask fill is not supported. */
4617 if (arg_data->mask || size < len)
4621 /* Let parse_int() fill length information first. */
4622 ret = snprintf(tmp, sizeof(tmp), "%u", len);
4625 push_args(ctx, arg_len);
4626 ret = parse_int(ctx, token, tmp, ret, NULL, 0);
4631 buf = (uint8_t *)ctx->object + arg_data->offset;
4632 /* Output buffer is not necessarily NUL-terminated. */
4633 memcpy(buf, str, len);
4634 memset((uint8_t *)buf + len, 0x00, size - len);
4636 memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
4637 /* Save address if requested. */
4638 if (arg_addr->size) {
4639 memcpy((uint8_t *)ctx->object + arg_addr->offset,
4641 (uint8_t *)ctx->object + arg_data->offset
4645 memcpy((uint8_t *)ctx->objmask + arg_addr->offset,
4647 (uint8_t *)ctx->objmask + arg_data->offset
4653 push_args(ctx, arg_addr);
4654 push_args(ctx, arg_len);
4655 push_args(ctx, arg_data);
4660 parse_hex_string(const char *src, uint8_t *dst, uint32_t *size)
4666 /* Check input parameters */
4667 if ((src == NULL) ||
4673 /* Convert chars to bytes */
4674 for (i = 0, len = 0; i < *size; i += 2) {
4675 snprintf(tmp, 3, "%s", src + i);
4676 dst[len++] = strtoul(tmp, &c, 16);
4691 parse_hex(struct context *ctx, const struct token *token,
4692 const char *str, unsigned int len,
4693 void *buf, unsigned int size)
4695 const struct arg *arg_data = pop_args(ctx);
4696 const struct arg *arg_len = pop_args(ctx);
4697 const struct arg *arg_addr = pop_args(ctx);
4698 char tmp[16]; /* Ought to be enough. */
4700 unsigned int hexlen = len;
4701 unsigned int length = 256;
4702 uint8_t hex_tmp[length];
4704 /* Arguments are expected. */
4708 push_args(ctx, arg_data);
4712 push_args(ctx, arg_len);
4713 push_args(ctx, arg_data);
4716 size = arg_data->size;
4717 /* Bit-mask fill is not supported. */
4723 /* translate bytes string to array. */
4724 if (str[0] == '0' && ((str[1] == 'x') ||
4729 if (hexlen > length)
4731 ret = parse_hex_string(str, hex_tmp, &hexlen);
4734 /* Let parse_int() fill length information first. */
4735 ret = snprintf(tmp, sizeof(tmp), "%u", hexlen);
4738 push_args(ctx, arg_len);
4739 ret = parse_int(ctx, token, tmp, ret, NULL, 0);
4744 buf = (uint8_t *)ctx->object + arg_data->offset;
4745 /* Output buffer is not necessarily NUL-terminated. */
4746 memcpy(buf, hex_tmp, hexlen);
4747 memset((uint8_t *)buf + hexlen, 0x00, size - hexlen);
4749 memset((uint8_t *)ctx->objmask + arg_data->offset,
4751 /* Save address if requested. */
4752 if (arg_addr->size) {
4753 memcpy((uint8_t *)ctx->object + arg_addr->offset,
4755 (uint8_t *)ctx->object + arg_data->offset
4759 memcpy((uint8_t *)ctx->objmask + arg_addr->offset,
4761 (uint8_t *)ctx->objmask + arg_data->offset
4767 push_args(ctx, arg_addr);
4768 push_args(ctx, arg_len);
4769 push_args(ctx, arg_data);
4775 * Parse a MAC address.
4777 * Last argument (ctx->args) is retrieved to determine storage size and
4781 parse_mac_addr(struct context *ctx, const struct token *token,
4782 const char *str, unsigned int len,
4783 void *buf, unsigned int size)
4785 const struct arg *arg = pop_args(ctx);
4786 struct rte_ether_addr tmp;
4790 /* Argument is expected. */
4794 /* Bit-mask fill is not supported. */
4795 if (arg->mask || size != sizeof(tmp))
4797 /* Only network endian is supported. */
4800 ret = rte_ether_unformat_addr(str, &tmp);
4805 buf = (uint8_t *)ctx->object + arg->offset;
4806 memcpy(buf, &tmp, size);
4808 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
4811 push_args(ctx, arg);
4816 * Parse an IPv4 address.
4818 * Last argument (ctx->args) is retrieved to determine storage size and
4822 parse_ipv4_addr(struct context *ctx, const struct token *token,
4823 const char *str, unsigned int len,
4824 void *buf, unsigned int size)
4826 const struct arg *arg = pop_args(ctx);
4831 /* Argument is expected. */
4835 /* Bit-mask fill is not supported. */
4836 if (arg->mask || size != sizeof(tmp))
4838 /* Only network endian is supported. */
4841 memcpy(str2, str, len);
4843 ret = inet_pton(AF_INET, str2, &tmp);
4845 /* Attempt integer parsing. */
4846 push_args(ctx, arg);
4847 return parse_int(ctx, token, str, len, buf, size);
4851 buf = (uint8_t *)ctx->object + arg->offset;
4852 memcpy(buf, &tmp, size);
4854 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
4857 push_args(ctx, arg);
4862 * Parse an IPv6 address.
4864 * Last argument (ctx->args) is retrieved to determine storage size and
4868 parse_ipv6_addr(struct context *ctx, const struct token *token,
4869 const char *str, unsigned int len,
4870 void *buf, unsigned int size)
4872 const struct arg *arg = pop_args(ctx);
4874 struct in6_addr tmp;
4878 /* Argument is expected. */
4882 /* Bit-mask fill is not supported. */
4883 if (arg->mask || size != sizeof(tmp))
4885 /* Only network endian is supported. */
4888 memcpy(str2, str, len);
4890 ret = inet_pton(AF_INET6, str2, &tmp);
4895 buf = (uint8_t *)ctx->object + arg->offset;
4896 memcpy(buf, &tmp, size);
4898 memset((uint8_t *)ctx->objmask + arg->offset, 0xff, size);
4901 push_args(ctx, arg);
4905 /** Boolean values (even indices stand for false). */
4906 static const char *const boolean_name[] = {
4916 * Parse a boolean value.
4918 * Last argument (ctx->args) is retrieved to determine storage size and
4922 parse_boolean(struct context *ctx, const struct token *token,
4923 const char *str, unsigned int len,
4924 void *buf, unsigned int size)
4926 const struct arg *arg = pop_args(ctx);
4930 /* Argument is expected. */
4933 for (i = 0; boolean_name[i]; ++i)
4934 if (!strcmp_partial(boolean_name[i], str, len))
4936 /* Process token as integer. */
4937 if (boolean_name[i])
4938 str = i & 1 ? "1" : "0";
4939 push_args(ctx, arg);
4940 ret = parse_int(ctx, token, str, strlen(str), buf, size);
4941 return ret > 0 ? (int)len : ret;
4944 /** Parse port and update context. */
4946 parse_port(struct context *ctx, const struct token *token,
4947 const char *str, unsigned int len,
4948 void *buf, unsigned int size)
4950 struct buffer *out = &(struct buffer){ .port = 0 };
4958 ctx->objmask = NULL;
4959 size = sizeof(*out);
4961 ret = parse_int(ctx, token, str, len, out, size);
4963 ctx->port = out->port;
4969 /** No completion. */
4971 comp_none(struct context *ctx, const struct token *token,
4972 unsigned int ent, char *buf, unsigned int size)
4982 /** Complete boolean values. */
4984 comp_boolean(struct context *ctx, const struct token *token,
4985 unsigned int ent, char *buf, unsigned int size)
4991 for (i = 0; boolean_name[i]; ++i)
4992 if (buf && i == ent)
4993 return strlcpy(buf, boolean_name[i], size);
4999 /** Complete action names. */
5001 comp_action(struct context *ctx, const struct token *token,
5002 unsigned int ent, char *buf, unsigned int size)
5008 for (i = 0; next_action[i]; ++i)
5009 if (buf && i == ent)
5010 return strlcpy(buf, token_list[next_action[i]].name,
5017 /** Complete available ports. */
5019 comp_port(struct context *ctx, const struct token *token,
5020 unsigned int ent, char *buf, unsigned int size)
5027 RTE_ETH_FOREACH_DEV(p) {
5028 if (buf && i == ent)
5029 return snprintf(buf, size, "%u", p);
5037 /** Complete available rule IDs. */
5039 comp_rule_id(struct context *ctx, const struct token *token,
5040 unsigned int ent, char *buf, unsigned int size)
5043 struct rte_port *port;
5044 struct port_flow *pf;
5047 if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
5048 ctx->port == (portid_t)RTE_PORT_ALL)
5050 port = &ports[ctx->port];
5051 for (pf = port->flow_list; pf != NULL; pf = pf->next) {
5052 if (buf && i == ent)
5053 return snprintf(buf, size, "%u", pf->id);
5061 /** Complete type field for RSS action. */
5063 comp_vc_action_rss_type(struct context *ctx, const struct token *token,
5064 unsigned int ent, char *buf, unsigned int size)
5070 for (i = 0; rss_type_table[i].str; ++i)
5075 return strlcpy(buf, rss_type_table[ent].str, size);
5077 return snprintf(buf, size, "end");
5081 /** Complete queue field for RSS action. */
5083 comp_vc_action_rss_queue(struct context *ctx, const struct token *token,
5084 unsigned int ent, char *buf, unsigned int size)
5091 return snprintf(buf, size, "%u", ent);
5093 return snprintf(buf, size, "end");
5097 /** Internal context. */
5098 static struct context cmd_flow_context;
5100 /** Global parser instance (cmdline API). */
5101 cmdline_parse_inst_t cmd_flow;
5103 /** Initialize context. */
5105 cmd_flow_context_init(struct context *ctx)
5107 /* A full memset() is not necessary. */
5117 ctx->objmask = NULL;
5120 /** Parse a token (cmdline API). */
5122 cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
5125 struct context *ctx = &cmd_flow_context;
5126 const struct token *token;
5127 const enum index *list;
5132 token = &token_list[ctx->curr];
5133 /* Check argument length. */
5136 for (len = 0; src[len]; ++len)
5137 if (src[len] == '#' || isspace(src[len]))
5141 /* Last argument and EOL detection. */
5142 for (i = len; src[i]; ++i)
5143 if (src[i] == '#' || src[i] == '\r' || src[i] == '\n')
5145 else if (!isspace(src[i])) {
5150 if (src[i] == '\r' || src[i] == '\n') {
5154 /* Initialize context if necessary. */
5155 if (!ctx->next_num) {
5158 ctx->next[ctx->next_num++] = token->next[0];
5160 /* Process argument through candidates. */
5161 ctx->prev = ctx->curr;
5162 list = ctx->next[ctx->next_num - 1];
5163 for (i = 0; list[i]; ++i) {
5164 const struct token *next = &token_list[list[i]];
5167 ctx->curr = list[i];
5169 tmp = next->call(ctx, next, src, len, result, size);
5171 tmp = parse_default(ctx, next, src, len, result, size);
5172 if (tmp == -1 || tmp != len)
5180 /* Push subsequent tokens if any. */
5182 for (i = 0; token->next[i]; ++i) {
5183 if (ctx->next_num == RTE_DIM(ctx->next))
5185 ctx->next[ctx->next_num++] = token->next[i];
5187 /* Push arguments if any. */
5189 for (i = 0; token->args[i]; ++i) {
5190 if (ctx->args_num == RTE_DIM(ctx->args))
5192 ctx->args[ctx->args_num++] = token->args[i];
5197 /** Return number of completion entries (cmdline API). */
5199 cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
5201 struct context *ctx = &cmd_flow_context;
5202 const struct token *token = &token_list[ctx->curr];
5203 const enum index *list;
5207 /* Count number of tokens in current list. */
5209 list = ctx->next[ctx->next_num - 1];
5211 list = token->next[0];
5212 for (i = 0; list[i]; ++i)
5217 * If there is a single token, use its completion callback, otherwise
5218 * return the number of entries.
5220 token = &token_list[list[0]];
5221 if (i == 1 && token->comp) {
5222 /* Save index for cmd_flow_get_help(). */
5223 ctx->prev = list[0];
5224 return token->comp(ctx, token, 0, NULL, 0);
5229 /** Return a completion entry (cmdline API). */
5231 cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
5232 char *dst, unsigned int size)
5234 struct context *ctx = &cmd_flow_context;
5235 const struct token *token = &token_list[ctx->curr];
5236 const enum index *list;
5240 /* Count number of tokens in current list. */
5242 list = ctx->next[ctx->next_num - 1];
5244 list = token->next[0];
5245 for (i = 0; list[i]; ++i)
5249 /* If there is a single token, use its completion callback. */
5250 token = &token_list[list[0]];
5251 if (i == 1 && token->comp) {
5252 /* Save index for cmd_flow_get_help(). */
5253 ctx->prev = list[0];
5254 return token->comp(ctx, token, index, dst, size) < 0 ? -1 : 0;
5256 /* Otherwise make sure the index is valid and use defaults. */
5259 token = &token_list[list[index]];
5260 strlcpy(dst, token->name, size);
5261 /* Save index for cmd_flow_get_help(). */
5262 ctx->prev = list[index];
5266 /** Populate help strings for current token (cmdline API). */
5268 cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
5270 struct context *ctx = &cmd_flow_context;
5271 const struct token *token = &token_list[ctx->prev];
5276 /* Set token type and update global help with details. */
5277 strlcpy(dst, (token->type ? token->type : "TOKEN"), size);
5279 cmd_flow.help_str = token->help;
5281 cmd_flow.help_str = token->name;
5285 /** Token definition template (cmdline API). */
5286 static struct cmdline_token_hdr cmd_flow_token_hdr = {
5287 .ops = &(struct cmdline_token_ops){
5288 .parse = cmd_flow_parse,
5289 .complete_get_nb = cmd_flow_complete_get_nb,
5290 .complete_get_elt = cmd_flow_complete_get_elt,
5291 .get_help = cmd_flow_get_help,
5296 /** Populate the next dynamic token. */
5298 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
5299 cmdline_parse_token_hdr_t **hdr_inst)
5301 struct context *ctx = &cmd_flow_context;
5303 /* Always reinitialize context before requesting the first token. */
5304 if (!(hdr_inst - cmd_flow.tokens))
5305 cmd_flow_context_init(ctx);
5306 /* Return NULL when no more tokens are expected. */
5307 if (!ctx->next_num && ctx->curr) {
5311 /* Determine if command should end here. */
5312 if (ctx->eol && ctx->last && ctx->next_num) {
5313 const enum index *list = ctx->next[ctx->next_num - 1];
5316 for (i = 0; list[i]; ++i) {
5323 *hdr = &cmd_flow_token_hdr;
5326 /** Dispatch parsed buffer to function calls. */
5328 cmd_flow_parsed(const struct buffer *in)
5330 switch (in->command) {
5332 port_flow_validate(in->port, &in->args.vc.attr,
5333 in->args.vc.pattern, in->args.vc.actions);
5336 port_flow_create(in->port, &in->args.vc.attr,
5337 in->args.vc.pattern, in->args.vc.actions);
5340 port_flow_destroy(in->port, in->args.destroy.rule_n,
5341 in->args.destroy.rule);
5344 port_flow_flush(in->port);
5347 port_flow_query(in->port, in->args.query.rule,
5348 &in->args.query.action);
5351 port_flow_list(in->port, in->args.list.group_n,
5352 in->args.list.group);
5355 port_flow_isolate(in->port, in->args.isolate.set);
5362 /** Token generator and output processing callback (cmdline API). */
5364 cmd_flow_cb(void *arg0, struct cmdline *cl, void *arg2)
5367 cmd_flow_tok(arg0, arg2);
5369 cmd_flow_parsed(arg0);
5372 /** Global parser instance (cmdline API). */
5373 cmdline_parse_inst_t cmd_flow = {
5375 .data = NULL, /**< Unused. */
5376 .help_str = NULL, /**< Updated by cmd_flow_get_help(). */
5379 }, /**< Tokens are returned by cmd_flow_tok(). */