+ [ACTION_INC_TCP_SEQ] = {
+ .name = "inc_tcp_seq",
+ .help = "increase TCP sequence number",
+ .priv = PRIV_ACTION(INC_TCP_SEQ, sizeof(rte_be32_t)),
+ .next = NEXT(action_inc_tcp_seq),
+ .call = parse_vc,
+ },
+ [ACTION_INC_TCP_SEQ_VALUE] = {
+ .name = "value",
+ .help = "the value to increase TCP sequence number by",
+ .next = NEXT(action_inc_tcp_seq, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_DEC_TCP_SEQ] = {
+ .name = "dec_tcp_seq",
+ .help = "decrease TCP sequence number",
+ .priv = PRIV_ACTION(DEC_TCP_SEQ, sizeof(rte_be32_t)),
+ .next = NEXT(action_dec_tcp_seq),
+ .call = parse_vc,
+ },
+ [ACTION_DEC_TCP_SEQ_VALUE] = {
+ .name = "value",
+ .help = "the value to decrease TCP sequence number by",
+ .next = NEXT(action_dec_tcp_seq, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_INC_TCP_ACK] = {
+ .name = "inc_tcp_ack",
+ .help = "increase TCP acknowledgment number",
+ .priv = PRIV_ACTION(INC_TCP_ACK, sizeof(rte_be32_t)),
+ .next = NEXT(action_inc_tcp_ack),
+ .call = parse_vc,
+ },
+ [ACTION_INC_TCP_ACK_VALUE] = {
+ .name = "value",
+ .help = "the value to increase TCP acknowledgment number by",
+ .next = NEXT(action_inc_tcp_ack, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_DEC_TCP_ACK] = {
+ .name = "dec_tcp_ack",
+ .help = "decrease TCP acknowledgment number",
+ .priv = PRIV_ACTION(DEC_TCP_ACK, sizeof(rte_be32_t)),
+ .next = NEXT(action_dec_tcp_ack),
+ .call = parse_vc,
+ },
+ [ACTION_DEC_TCP_ACK_VALUE] = {
+ .name = "value",
+ .help = "the value to decrease TCP acknowledgment number by",
+ .next = NEXT(action_dec_tcp_ack, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARG_ENTRY_HTON(rte_be32_t)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_RAW_ENCAP] = {
+ .name = "raw_encap",
+ .help = "encapsulation data, defined by set raw_encap",
+ .priv = PRIV_ACTION(RAW_ENCAP,
+ sizeof(struct action_raw_encap_data)),
+ .next = NEXT(action_raw_encap),
+ .call = parse_vc_action_raw_encap,
+ },
+ [ACTION_RAW_ENCAP_INDEX] = {
+ .name = "index",
+ .help = "the index of raw_encap_confs",
+ .next = NEXT(NEXT_ENTRY(ACTION_RAW_ENCAP_INDEX_VALUE)),
+ },
+ [ACTION_RAW_ENCAP_INDEX_VALUE] = {
+ .name = "{index}",
+ .type = "UNSIGNED",
+ .help = "unsigned integer value",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_raw_encap_index,
+ .comp = comp_set_raw_index,
+ },
+ [ACTION_RAW_DECAP] = {
+ .name = "raw_decap",
+ .help = "decapsulation data, defined by set raw_encap",
+ .priv = PRIV_ACTION(RAW_DECAP,
+ sizeof(struct action_raw_decap_data)),
+ .next = NEXT(action_raw_decap),
+ .call = parse_vc_action_raw_decap,
+ },
+ [ACTION_RAW_DECAP_INDEX] = {
+ .name = "index",
+ .help = "the index of raw_encap_confs",
+ .next = NEXT(NEXT_ENTRY(ACTION_RAW_DECAP_INDEX_VALUE)),
+ },
+ [ACTION_RAW_DECAP_INDEX_VALUE] = {
+ .name = "{index}",
+ .type = "UNSIGNED",
+ .help = "unsigned integer value",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_raw_decap_index,
+ .comp = comp_set_raw_index,
+ },
+ [ACTION_MODIFY_FIELD] = {
+ .name = "modify_field",
+ .help = "modify destination field with data from source field",
+ .priv = PRIV_ACTION(MODIFY_FIELD, ACTION_MODIFY_SIZE),
+ .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)),
+ .call = parse_vc,
+ },
+ [ACTION_MODIFY_FIELD_OP] = {
+ .name = "op",
+ .help = "operation type",
+ .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE),
+ NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_OP_VALUE] = {
+ .name = "{operation}",
+ .help = "operation type value",
+ .call = parse_vc_modify_field_op,
+ .comp = comp_set_modify_field_op,
+ },
+ [ACTION_MODIFY_FIELD_DST_TYPE] = {
+ .name = "dst_type",
+ .help = "destination field type",
+ .next = NEXT(action_modify_field_dst,
+ NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = {
+ .name = "{dst_type}",
+ .help = "destination field type value",
+ .call = parse_vc_modify_field_id,
+ .comp = comp_set_modify_field_id,
+ },
+ [ACTION_MODIFY_FIELD_DST_LEVEL] = {
+ .name = "dst_level",
+ .help = "destination field level",
+ .next = NEXT(action_modify_field_dst,
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+ dst.level)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_DST_OFFSET] = {
+ .name = "dst_offset",
+ .help = "destination field bit offset",
+ .next = NEXT(action_modify_field_dst,
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+ dst.offset)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_SRC_TYPE] = {
+ .name = "src_type",
+ .help = "source field type",
+ .next = NEXT(action_modify_field_src,
+ NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = {
+ .name = "{src_type}",
+ .help = "source field type value",
+ .call = parse_vc_modify_field_id,
+ .comp = comp_set_modify_field_id,
+ },
+ [ACTION_MODIFY_FIELD_SRC_LEVEL] = {
+ .name = "src_level",
+ .help = "source field level",
+ .next = NEXT(action_modify_field_src,
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+ src.level)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_SRC_OFFSET] = {
+ .name = "src_offset",
+ .help = "source field bit offset",
+ .next = NEXT(action_modify_field_src,
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+ src.offset)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_SRC_VALUE] = {
+ .name = "src_value",
+ .help = "source immediate value",
+ .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH),
+ NEXT_ENTRY(COMMON_HEX)),
+ .args = ARGS(ARGS_ENTRY_ARB(0, 0),
+ ARGS_ENTRY_ARB(0, 0),
+ ARGS_ENTRY(struct rte_flow_action_modify_field,
+ src.value)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_SRC_POINTER] = {
+ .name = "src_ptr",
+ .help = "pointer to source immediate value",
+ .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH),
+ NEXT_ENTRY(COMMON_HEX)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+ src.pvalue),
+ ARGS_ENTRY_ARB(0, 0),
+ ARGS_ENTRY_ARB
+ (sizeof(struct rte_flow_action_modify_field),
+ ACTION_MODIFY_PATTERN_SIZE)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_MODIFY_FIELD_WIDTH] = {
+ .name = "width",
+ .help = "number of bits to copy",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+ width)),
+ .call = parse_vc_conf,
+ },
+ /* Top level command. */
+ [SET] = {
+ .name = "set",
+ .help = "set raw encap/decap/sample data",
+ .type = "set raw_encap|raw_decap <index> <pattern>"
+ " or set sample_actions <index> <action>",
+ .next = NEXT(NEXT_ENTRY
+ (SET_RAW_ENCAP,
+ SET_RAW_DECAP,
+ SET_SAMPLE_ACTIONS)),
+ .call = parse_set_init,
+ },
+ /* Sub-level commands. */
+ [SET_RAW_ENCAP] = {
+ .name = "raw_encap",
+ .help = "set raw encap data",
+ .next = NEXT(next_set_raw),
+ .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct buffer, port),
+ sizeof(((struct buffer *)0)->port),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1)),
+ .call = parse_set_raw_encap_decap,
+ },
+ [SET_RAW_DECAP] = {
+ .name = "raw_decap",
+ .help = "set raw decap data",
+ .next = NEXT(next_set_raw),
+ .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct buffer, port),
+ sizeof(((struct buffer *)0)->port),
+ 0, RAW_ENCAP_CONFS_MAX_NUM - 1)),
+ .call = parse_set_raw_encap_decap,
+ },
+ [SET_RAW_INDEX] = {
+ .name = "{index}",
+ .type = "COMMON_UNSIGNED",
+ .help = "index of raw_encap/raw_decap data",
+ .next = NEXT(next_item),
+ .call = parse_port,
+ },
+ [SET_SAMPLE_INDEX] = {
+ .name = "{index}",
+ .type = "UNSIGNED",
+ .help = "index of sample actions",
+ .next = NEXT(next_action_sample),
+ .call = parse_port,
+ },
+ [SET_SAMPLE_ACTIONS] = {
+ .name = "sample_actions",
+ .help = "set sample actions list",
+ .next = NEXT(NEXT_ENTRY(SET_SAMPLE_INDEX)),
+ .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+ (offsetof(struct buffer, port),
+ sizeof(((struct buffer *)0)->port),
+ 0, RAW_SAMPLE_CONFS_MAX_NUM - 1)),
+ .call = parse_set_sample_action,
+ },
+ [ACTION_SET_TAG] = {
+ .name = "set_tag",
+ .help = "set tag",
+ .priv = PRIV_ACTION(SET_TAG,
+ sizeof(struct rte_flow_action_set_tag)),
+ .next = NEXT(action_set_tag),
+ .call = parse_vc,
+ },
+ [ACTION_SET_TAG_INDEX] = {
+ .name = "index",
+ .help = "index of tag array",
+ .next = NEXT(action_set_tag, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_set_tag, index)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_TAG_DATA] = {
+ .name = "data",
+ .help = "tag value",
+ .next = NEXT(action_set_tag, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_tag, data)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_TAG_MASK] = {
+ .name = "mask",
+ .help = "mask for tag value",
+ .next = NEXT(action_set_tag, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_tag, mask)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_META] = {
+ .name = "set_meta",
+ .help = "set metadata",
+ .priv = PRIV_ACTION(SET_META,
+ sizeof(struct rte_flow_action_set_meta)),
+ .next = NEXT(action_set_meta),
+ .call = parse_vc_action_set_meta,
+ },
+ [ACTION_SET_META_DATA] = {
+ .name = "data",
+ .help = "metadata value",
+ .next = NEXT(action_set_meta, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_meta, data)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_META_MASK] = {
+ .name = "mask",
+ .help = "mask for metadata value",
+ .next = NEXT(action_set_meta, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_meta, mask)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_IPV4_DSCP] = {
+ .name = "set_ipv4_dscp",
+ .help = "set DSCP value",
+ .priv = PRIV_ACTION(SET_IPV4_DSCP,
+ sizeof(struct rte_flow_action_set_dscp)),
+ .next = NEXT(action_set_ipv4_dscp),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV4_DSCP_VALUE] = {
+ .name = "dscp_value",
+ .help = "new IPv4 DSCP value to set",
+ .next = NEXT(action_set_ipv4_dscp, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_dscp, dscp)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SET_IPV6_DSCP] = {
+ .name = "set_ipv6_dscp",
+ .help = "set DSCP value",
+ .priv = PRIV_ACTION(SET_IPV6_DSCP,
+ sizeof(struct rte_flow_action_set_dscp)),
+ .next = NEXT(action_set_ipv6_dscp),
+ .call = parse_vc,
+ },
+ [ACTION_SET_IPV6_DSCP_VALUE] = {
+ .name = "dscp_value",
+ .help = "new IPv6 DSCP value to set",
+ .next = NEXT(action_set_ipv6_dscp, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY
+ (struct rte_flow_action_set_dscp, dscp)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_AGE] = {
+ .name = "age",
+ .help = "set a specific metadata header",
+ .next = NEXT(action_age),
+ .priv = PRIV_ACTION(AGE,
+ sizeof(struct rte_flow_action_age)),
+ .call = parse_vc,
+ },
+ [ACTION_AGE_TIMEOUT] = {
+ .name = "timeout",
+ .help = "flow age timeout value",
+ .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_age,
+ timeout, 24)),
+ .next = NEXT(action_age, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_SAMPLE] = {
+ .name = "sample",
+ .help = "set a sample action",
+ .next = NEXT(action_sample),
+ .priv = PRIV_ACTION(SAMPLE,
+ sizeof(struct action_sample_data)),
+ .call = parse_vc_action_sample,
+ },
+ [ACTION_SAMPLE_RATIO] = {
+ .name = "ratio",
+ .help = "flow sample ratio value",
+ .next = NEXT(action_sample, NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY_ARB
+ (offsetof(struct action_sample_data, conf) +
+ offsetof(struct rte_flow_action_sample, ratio),
+ sizeof(((struct rte_flow_action_sample *)0)->
+ ratio))),
+ },
+ [ACTION_SAMPLE_INDEX] = {
+ .name = "index",
+ .help = "the index of sample actions list",
+ .next = NEXT(NEXT_ENTRY(ACTION_SAMPLE_INDEX_VALUE)),
+ },
+ [ACTION_SAMPLE_INDEX_VALUE] = {
+ .name = "{index}",
+ .type = "COMMON_UNSIGNED",
+ .help = "unsigned integer value",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_vc_action_sample_index,
+ .comp = comp_set_sample_index,
+ },
+ [ACTION_CONNTRACK] = {
+ .name = "conntrack",
+ .help = "create a conntrack object",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .priv = PRIV_ACTION(CONNTRACK,
+ sizeof(struct rte_flow_action_conntrack)),
+ .call = parse_vc,
+ },
+ [ACTION_CONNTRACK_UPDATE] = {
+ .name = "conntrack_update",
+ .help = "update a conntrack object",
+ .next = NEXT(action_update_conntrack),
+ .priv = PRIV_ACTION(CONNTRACK,
+ sizeof(struct rte_flow_modify_conntrack)),
+ .call = parse_vc,
+ },
+ [ACTION_CONNTRACK_UPDATE_DIR] = {
+ .name = "dir",
+ .help = "update a conntrack object direction",
+ .next = NEXT(action_update_conntrack),
+ .call = parse_vc_action_conntrack_update,
+ },
+ [ACTION_CONNTRACK_UPDATE_CTX] = {
+ .name = "ctx",
+ .help = "update a conntrack object context",
+ .next = NEXT(action_update_conntrack),
+ .call = parse_vc_action_conntrack_update,
+ },
+ [ACTION_PORT_REPRESENTOR] = {
+ .name = "port_representor",
+ .help = "at embedded switch level, send matching traffic to the given ethdev",
+ .priv = PRIV_ACTION(PORT_REPRESENTOR,
+ sizeof(struct rte_flow_action_ethdev)),
+ .next = NEXT(action_port_representor),
+ .call = parse_vc,
+ },
+ [ACTION_PORT_REPRESENTOR_PORT_ID] = {
+ .name = "port_id",
+ .help = "ethdev port ID",
+ .next = NEXT(action_port_representor,
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_ethdev,
+ port_id)),
+ .call = parse_vc_conf,
+ },
+ [ACTION_REPRESENTED_PORT] = {
+ .name = "represented_port",
+ .help = "at embedded switch level, send matching traffic to the entity represented by the given ethdev",
+ .priv = PRIV_ACTION(REPRESENTED_PORT,
+ sizeof(struct rte_flow_action_ethdev)),
+ .next = NEXT(action_represented_port),
+ .call = parse_vc,
+ },
+ [ACTION_REPRESENTED_PORT_ETHDEV_PORT_ID] = {
+ .name = "ethdev_port_id",
+ .help = "ethdev port ID",
+ .next = NEXT(action_represented_port,
+ NEXT_ENTRY(COMMON_UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_ethdev,
+ port_id)),
+ .call = parse_vc_conf,
+ },
+ /* Indirect action destroy arguments. */
+ [INDIRECT_ACTION_DESTROY_ID] = {
+ .name = "action_id",
+ .help = "specify a indirect action id to destroy",
+ .next = NEXT(next_ia_destroy_attr,
+ NEXT_ENTRY(COMMON_INDIRECT_ACTION_ID)),
+ .args = ARGS(ARGS_ENTRY_PTR(struct buffer,
+ args.ia_destroy.action_id)),
+ .call = parse_ia_destroy,
+ },
+ /* Indirect action create arguments. */
+ [INDIRECT_ACTION_CREATE_ID] = {
+ .name = "action_id",
+ .help = "specify a indirect action id to create",
+ .next = NEXT(next_ia_create_attr,
+ NEXT_ENTRY(COMMON_INDIRECT_ACTION_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, args.vc.attr.group)),
+ },
+ [ACTION_INDIRECT] = {
+ .name = "indirect",
+ .help = "apply indirect action by id",
+ .priv = PRIV_ACTION(INDIRECT, 0),
+ .next = NEXT(NEXT_ENTRY(INDIRECT_ACTION_ID2PTR)),
+ .args = ARGS(ARGS_ENTRY_ARB(0, sizeof(uint32_t))),
+ .call = parse_vc,
+ },
+ [INDIRECT_ACTION_ID2PTR] = {
+ .name = "{action_id}",
+ .type = "INDIRECT_ACTION_ID",
+ .help = "indirect action id",
+ .next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+ .call = parse_ia_id2ptr,
+ .comp = comp_none,
+ },
+ [INDIRECT_ACTION_INGRESS] = {
+ .name = "ingress",
+ .help = "affect rule to ingress",
+ .next = NEXT(next_ia_create_attr),
+ .call = parse_ia,
+ },
+ [INDIRECT_ACTION_EGRESS] = {
+ .name = "egress",
+ .help = "affect rule to egress",
+ .next = NEXT(next_ia_create_attr),
+ .call = parse_ia,
+ },
+ [INDIRECT_ACTION_TRANSFER] = {
+ .name = "transfer",
+ .help = "affect rule to transfer",
+ .next = NEXT(next_ia_create_attr),
+ .call = parse_ia,
+ },
+ [INDIRECT_ACTION_SPEC] = {
+ .name = "action",
+ .help = "specify action to create indirect handle",
+ .next = NEXT(next_action),
+ },
+ [ACTION_POL_G] = {
+ .name = "g_actions",
+ .help = "submit a list of associated actions for green",
+ .next = NEXT(next_action),
+ .call = parse_mp,
+ },
+ [ACTION_POL_Y] = {
+ .name = "y_actions",
+ .help = "submit a list of associated actions for yellow",
+ .next = NEXT(next_action),
+ },
+ [ACTION_POL_R] = {
+ .name = "r_actions",
+ .help = "submit a list of associated actions for red",
+ .next = NEXT(next_action),
+ },
+
+ /* Top-level command. */
+ [ADD] = {
+ .name = "add",
+ .type = "port meter policy {port_id} {arg}",
+ .help = "add port meter policy",
+ .next = NEXT(NEXT_ENTRY(ITEM_POL_PORT)),
+ .call = parse_init,
+ },
+ /* Sub-level commands. */
+ [ITEM_POL_PORT] = {
+ .name = "port",
+ .help = "add port meter policy",
+ .next = NEXT(NEXT_ENTRY(ITEM_POL_METER)),
+ },
+ [ITEM_POL_METER] = {
+ .name = "meter",
+ .help = "add port meter policy",
+ .next = NEXT(NEXT_ENTRY(ITEM_POL_POLICY)),
+ },
+ [ITEM_POL_POLICY] = {
+ .name = "policy",
+ .help = "add port meter policy",
+ .next = NEXT(NEXT_ENTRY(ACTION_POL_R),
+ NEXT_ENTRY(ACTION_POL_Y),
+ NEXT_ENTRY(ACTION_POL_G),
+ NEXT_ENTRY(COMMON_POLICY_ID),
+ NEXT_ENTRY(COMMON_PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, args.policy.policy_id),
+ ARGS_ENTRY(struct buffer, port)),
+ .call = parse_mp,
+ },
+};
+
+/** Remove and return last entry from argument stack. */
+static const struct arg *
+pop_args(struct context *ctx)
+{
+ return ctx->args_num ? ctx->args[--ctx->args_num] : NULL;
+}
+
+/** Add entry on top of the argument stack. */
+static int
+push_args(struct context *ctx, const struct arg *arg)
+{
+ if (ctx->args_num == CTX_STACK_SIZE)
+ return -1;
+ ctx->args[ctx->args_num++] = arg;
+ return 0;
+}
+
+/** Spread value into buffer according to bit-mask. */
+static size_t
+arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
+{
+ uint32_t i = arg->size;
+ uint32_t end = 0;
+ int sub = 1;
+ int add = 0;
+ size_t len = 0;
+
+ if (!arg->mask)
+ return 0;
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+ if (!arg->hton) {
+ i = 0;
+ end = arg->size;
+ sub = 0;
+ add = 1;
+ }
+#endif
+ while (i != end) {
+ unsigned int shift = 0;
+ uint8_t *buf = (uint8_t *)dst + arg->offset + (i -= sub);
+
+ for (shift = 0; arg->mask[i] >> shift; ++shift) {
+ if (!(arg->mask[i] & (1 << shift)))
+ continue;
+ ++len;
+ if (!dst)
+ continue;
+ *buf &= ~(1 << shift);
+ *buf |= (val & 1) << shift;
+ val >>= 1;
+ }
+ i += add;
+ }
+ return len;
+}
+
+/** Compare a string with a partial one of a given length. */
+static int
+strcmp_partial(const char *full, const char *partial, size_t partial_len)
+{
+ int r = strncmp(full, partial, partial_len);
+
+ if (r)
+ return r;
+ if (strlen(full) <= partial_len)
+ return 0;
+ return full[partial_len];
+}
+
+/**
+ * Parse a prefix length and generate a bit-mask.
+ *
+ * Last argument (ctx->args) is retrieved to determine mask size, storage
+ * location and whether the result must use network byte ordering.
+ */
+static int
+parse_prefix(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ const struct arg *arg = pop_args(ctx);
+ static const uint8_t conv[] = "\x00\x80\xc0\xe0\xf0\xf8\xfc\xfe\xff";
+ char *end;
+ uintmax_t u;
+ unsigned int bytes;
+ unsigned int extra;