-/*-
- * BSD LICENSE
- *
- * Copyright 2016 6WIND S.A.
- * Copyright 2016 Mellanox.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of 6WIND S.A. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016 6WIND S.A.
+ * Copyright 2016 Mellanox.
*/
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include <arpa/inet.h>
+#include <sys/socket.h>
#include <rte_common.h>
#include <rte_ethdev.h>
FLUSH,
QUERY,
LIST,
+ ISOLATE,
/* Destroy arguments. */
DESTROY_RULE,
ITEM_VLAN,
ITEM_VLAN_TPID,
ITEM_VLAN_TCI,
+ ITEM_VLAN_PCP,
+ ITEM_VLAN_DEI,
+ ITEM_VLAN_VID,
ITEM_IPV4,
+ ITEM_IPV4_TOS,
+ ITEM_IPV4_TTL,
+ ITEM_IPV4_PROTO,
ITEM_IPV4_SRC,
ITEM_IPV4_DST,
ITEM_IPV6,
+ ITEM_IPV6_TC,
+ ITEM_IPV6_FLOW,
+ ITEM_IPV6_PROTO,
+ ITEM_IPV6_HOP,
ITEM_IPV6_SRC,
ITEM_IPV6_DST,
ITEM_ICMP,
ITEM_TCP,
ITEM_TCP_SRC,
ITEM_TCP_DST,
+ ITEM_TCP_FLAGS,
ITEM_SCTP,
ITEM_SCTP_SRC,
ITEM_SCTP_DST,
+ ITEM_SCTP_TAG,
+ ITEM_SCTP_CKSUM,
ITEM_VXLAN,
ITEM_VXLAN_VNI,
+ ITEM_E_TAG,
+ ITEM_E_TAG_GRP_ECID_B,
+ ITEM_NVGRE,
+ ITEM_NVGRE_TNI,
+ ITEM_MPLS,
+ ITEM_MPLS_LABEL,
+ ITEM_GRE,
+ ITEM_GRE_PROTO,
+ ITEM_FUZZY,
+ ITEM_FUZZY_THRESH,
+ ITEM_GTP,
+ ITEM_GTP_TEID,
+ ITEM_GTPC,
+ ITEM_GTPU,
+ ITEM_GENEVE,
+ ITEM_GENEVE_VNI,
+ ITEM_GENEVE_PROTO,
/* Validate/create actions. */
ACTIONS,
ACTION_VF,
ACTION_VF_ORIGINAL,
ACTION_VF_ID,
+ ACTION_METER,
+ ACTION_METER_ID,
};
/** Size of pattern[] field in struct rte_flow_item_raw. */
enum index prev; /**< Index of the last token seen. */
int next_num; /**< Number of entries in next[]. */
int args_num; /**< Number of entries in args[]. */
- uint32_t reparse:1; /**< Start over from the beginning. */
uint32_t eol:1; /**< EOL has been detected. */
uint32_t last:1; /**< No more arguments. */
- uint16_t port; /**< Current port ID (for completions). */
+ portid_t port; /**< Current port ID (for completions). */
uint32_t objdata; /**< Object-specific data. */
void *object; /**< Address of current object for relative offsets. */
void *objmask; /**< Object a full mask must be written to. */
.mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \
})
+/** Static initializer for ARGS() to target an arbitrary bit-mask. */
+#define ARGS_ENTRY_MASK(s, f, m) \
+ (&(const struct arg){ \
+ .offset = offsetof(s, f), \
+ .size = sizeof(((s *)0)->f), \
+ .mask = (const void *)(m), \
+ })
+
+/** Same as ARGS_ENTRY_MASK() using network byte ordering for the value. */
+#define ARGS_ENTRY_MASK_HTON(s, f, m) \
+ (&(const struct arg){ \
+ .hton = 1, \
+ .offset = offsetof(s, f), \
+ .size = sizeof(((s *)0)->f), \
+ .mask = (const void *)(m), \
+ })
+
/** Static initializer for ARGS() to target a pointer. */
#define ARGS_ENTRY_PTR(s, f) \
(&(const struct arg){ \
/** Parser output buffer layout expected by cmd_flow_parsed(). */
struct buffer {
enum index command; /**< Flow command. */
- uint16_t port; /**< Affected port ID. */
+ portid_t port; /**< Affected port ID. */
union {
struct {
struct rte_flow_attr attr;
uint32_t *group;
uint32_t group_n;
} list; /**< List arguments. */
+ struct {
+ int set;
+ } isolate; /**< Isolated mode arguments. */
} args; /**< Command arguments. */
};
ITEM_TCP,
ITEM_SCTP,
ITEM_VXLAN,
+ ITEM_E_TAG,
+ ITEM_NVGRE,
+ ITEM_MPLS,
+ ITEM_GRE,
+ ITEM_FUZZY,
+ ITEM_GTP,
+ ITEM_GTPC,
+ ITEM_GTPU,
+ ITEM_GENEVE,
+ ZERO,
+};
+
+static const enum index item_fuzzy[] = {
+ ITEM_FUZZY_THRESH,
+ ITEM_NEXT,
ZERO,
};
static const enum index item_vlan[] = {
ITEM_VLAN_TPID,
ITEM_VLAN_TCI,
+ ITEM_VLAN_PCP,
+ ITEM_VLAN_DEI,
+ ITEM_VLAN_VID,
ITEM_NEXT,
ZERO,
};
static const enum index item_ipv4[] = {
+ ITEM_IPV4_TOS,
+ ITEM_IPV4_TTL,
+ ITEM_IPV4_PROTO,
ITEM_IPV4_SRC,
ITEM_IPV4_DST,
ITEM_NEXT,
};
static const enum index item_ipv6[] = {
+ ITEM_IPV6_TC,
+ ITEM_IPV6_FLOW,
+ ITEM_IPV6_PROTO,
+ ITEM_IPV6_HOP,
ITEM_IPV6_SRC,
ITEM_IPV6_DST,
ITEM_NEXT,
static const enum index item_tcp[] = {
ITEM_TCP_SRC,
ITEM_TCP_DST,
+ ITEM_TCP_FLAGS,
ITEM_NEXT,
ZERO,
};
static const enum index item_sctp[] = {
ITEM_SCTP_SRC,
ITEM_SCTP_DST,
+ ITEM_SCTP_TAG,
+ ITEM_SCTP_CKSUM,
ITEM_NEXT,
ZERO,
};
ZERO,
};
+static const enum index item_e_tag[] = {
+ ITEM_E_TAG_GRP_ECID_B,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_nvgre[] = {
+ ITEM_NVGRE_TNI,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_mpls[] = {
+ ITEM_MPLS_LABEL,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_gre[] = {
+ ITEM_GRE_PROTO,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_gtp[] = {
+ ITEM_GTP_TEID,
+ ITEM_NEXT,
+ ZERO,
+};
+
+static const enum index item_geneve[] = {
+ ITEM_GENEVE_VNI,
+ ITEM_GENEVE_PROTO,
+ ITEM_NEXT,
+ ZERO,
+};
+
static const enum index next_action[] = {
ACTION_END,
ACTION_VOID,
ACTION_RSS,
ACTION_PF,
ACTION_VF,
+ ACTION_METER,
ZERO,
};
ZERO,
};
+static const enum index action_meter[] = {
+ ACTION_METER_ID,
+ ACTION_NEXT,
+ ZERO,
+};
+
static int parse_init(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
static int parse_list(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
+static int parse_isolate(struct context *, const struct token *,
+ const char *, unsigned int,
+ void *, unsigned int);
static int parse_int(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
DESTROY,
FLUSH,
LIST,
- QUERY)),
+ QUERY,
+ ISOLATE)),
.call = parse_init,
},
/* Sub-level commands. */
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_list,
},
+ [ISOLATE] = {
+ .name = "isolate",
+ .help = "restrict ingress traffic to the defined flow rules",
+ .next = NEXT(NEXT_ENTRY(BOOLEAN),
+ NEXT_ENTRY(PORT_ID)),
+ .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
+ ARGS_ENTRY(struct buffer, port)),
+ .call = parse_isolate,
+ },
/* Destroy arguments. */
[DESTROY_RULE] = {
.name = "rule",
.name = "dst",
.help = "destination MAC",
.next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
- .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, dst)),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, dst)),
},
[ITEM_ETH_SRC] = {
.name = "src",
.help = "source MAC",
.next = NEXT(item_eth, NEXT_ENTRY(MAC_ADDR), item_param),
- .args = ARGS(ARGS_ENTRY(struct rte_flow_item_eth, src)),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, src)),
},
[ITEM_ETH_TYPE] = {
.name = "type",
.next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)),
},
+ [ITEM_VLAN_PCP] = {
+ .name = "pcp",
+ .help = "priority code point",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+ tci, "\xe0\x00")),
+ },
+ [ITEM_VLAN_DEI] = {
+ .name = "dei",
+ .help = "drop eligible indicator",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+ tci, "\x10\x00")),
+ },
+ [ITEM_VLAN_VID] = {
+ .name = "vid",
+ .help = "VLAN identifier",
+ .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan,
+ tci, "\x0f\xff")),
+ },
[ITEM_IPV4] = {
.name = "ipv4",
.help = "match IPv4 header",
.next = NEXT(item_ipv4),
.call = parse_vc,
},
+ [ITEM_IPV4_TOS] = {
+ .name = "tos",
+ .help = "type of service",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.type_of_service)),
+ },
+ [ITEM_IPV4_TTL] = {
+ .name = "ttl",
+ .help = "time to live",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.time_to_live)),
+ },
+ [ITEM_IPV4_PROTO] = {
+ .name = "proto",
+ .help = "next protocol ID",
+ .next = NEXT(item_ipv4, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4,
+ hdr.next_proto_id)),
+ },
[ITEM_IPV4_SRC] = {
.name = "src",
.help = "source address",
.next = NEXT(item_ipv6),
.call = parse_vc,
},
+ [ITEM_IPV6_TC] = {
+ .name = "tc",
+ .help = "traffic class",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
+ hdr.vtc_flow,
+ "\x0f\xf0\x00\x00")),
+ },
+ [ITEM_IPV6_FLOW] = {
+ .name = "flow",
+ .help = "flow label",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_ipv6,
+ hdr.vtc_flow,
+ "\x00\x0f\xff\xff")),
+ },
+ [ITEM_IPV6_PROTO] = {
+ .name = "proto",
+ .help = "protocol (next header)",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+ hdr.proto)),
+ },
+ [ITEM_IPV6_HOP] = {
+ .name = "hop",
+ .help = "hop limit",
+ .next = NEXT(item_ipv6, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6,
+ hdr.hop_limits)),
+ },
[ITEM_IPV6_SRC] = {
.name = "src",
.help = "source address",
.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
hdr.dst_port)),
},
+ [ITEM_TCP_FLAGS] = {
+ .name = "flags",
+ .help = "TCP flags",
+ .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
+ hdr.tcp_flags)),
+ },
[ITEM_SCTP] = {
.name = "sctp",
.help = "match SCTP header",
.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
hdr.dst_port)),
},
+ [ITEM_SCTP_TAG] = {
+ .name = "tag",
+ .help = "validation tag",
+ .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+ hdr.tag)),
+ },
+ [ITEM_SCTP_CKSUM] = {
+ .name = "cksum",
+ .help = "checksum",
+ .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp,
+ hdr.cksum)),
+ },
[ITEM_VXLAN] = {
.name = "vxlan",
.help = "match VXLAN header",
.next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param),
.args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)),
},
+ [ITEM_E_TAG] = {
+ .name = "e_tag",
+ .help = "match E-Tag header",
+ .priv = PRIV_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
+ .next = NEXT(item_e_tag),
+ .call = parse_vc,
+ },
+ [ITEM_E_TAG_GRP_ECID_B] = {
+ .name = "grp_ecid_b",
+ .help = "GRP and E-CID base",
+ .next = NEXT(item_e_tag, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_e_tag,
+ rsvd_grp_ecid_b,
+ "\x3f\xff")),
+ },
+ [ITEM_NVGRE] = {
+ .name = "nvgre",
+ .help = "match NVGRE header",
+ .priv = PRIV_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
+ .next = NEXT(item_nvgre),
+ .call = parse_vc,
+ },
+ [ITEM_NVGRE_TNI] = {
+ .name = "tni",
+ .help = "virtual subnet ID",
+ .next = NEXT(item_nvgre, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_nvgre, tni)),
+ },
+ [ITEM_MPLS] = {
+ .name = "mpls",
+ .help = "match MPLS header",
+ .priv = PRIV_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
+ .next = NEXT(item_mpls),
+ .call = parse_vc,
+ },
+ [ITEM_MPLS_LABEL] = {
+ .name = "label",
+ .help = "MPLS label",
+ .next = NEXT(item_mpls, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_mpls,
+ label_tc_s,
+ "\xff\xff\xf0")),
+ },
+ [ITEM_GRE] = {
+ .name = "gre",
+ .help = "match GRE header",
+ .priv = PRIV_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
+ .next = NEXT(item_gre),
+ .call = parse_vc,
+ },
+ [ITEM_GRE_PROTO] = {
+ .name = "protocol",
+ .help = "GRE protocol type",
+ .next = NEXT(item_gre, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
+ protocol)),
+ },
+ [ITEM_FUZZY] = {
+ .name = "fuzzy",
+ .help = "fuzzy pattern match, expect faster than default",
+ .priv = PRIV_ITEM(FUZZY,
+ sizeof(struct rte_flow_item_fuzzy)),
+ .next = NEXT(item_fuzzy),
+ .call = parse_vc,
+ },
+ [ITEM_FUZZY_THRESH] = {
+ .name = "thresh",
+ .help = "match accuracy threshold",
+ .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy,
+ thresh)),
+ },
+ [ITEM_GTP] = {
+ .name = "gtp",
+ .help = "match GTP header",
+ .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
+ .next = NEXT(item_gtp),
+ .call = parse_vc,
+ },
+ [ITEM_GTP_TEID] = {
+ .name = "teid",
+ .help = "tunnel endpoint identifier",
+ .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)),
+ },
+ [ITEM_GTPC] = {
+ .name = "gtpc",
+ .help = "match GTP header",
+ .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
+ .next = NEXT(item_gtp),
+ .call = parse_vc,
+ },
+ [ITEM_GTPU] = {
+ .name = "gtpu",
+ .help = "match GTP header",
+ .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
+ .next = NEXT(item_gtp),
+ .call = parse_vc,
+ },
+ [ITEM_GENEVE] = {
+ .name = "geneve",
+ .help = "match GENEVE header",
+ .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
+ .next = NEXT(item_geneve),
+ .call = parse_vc,
+ },
+ [ITEM_GENEVE_VNI] = {
+ .name = "vni",
+ .help = "virtual network identifier",
+ .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)),
+ },
+ [ITEM_GENEVE_PROTO] = {
+ .name = "protocol",
+ .help = "GENEVE protocol type",
+ .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
+ .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
+ protocol)),
+ },
+
/* Validate/create actions. */
[ACTIONS] = {
.name = "actions",
.args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
.call = parse_vc_conf,
},
+ [ACTION_METER] = {
+ .name = "meter",
+ .help = "meter the directed packets at given id",
+ .priv = PRIV_ACTION(METER,
+ sizeof(struct rte_flow_action_meter)),
+ .next = NEXT(action_meter),
+ .call = parse_vc,
+ },
+ [ACTION_METER_ID] = {
+ .name = "mtr_id",
+ .help = "meter id to use",
+ .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
+ .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
+ .call = parse_vc_conf,
+ },
};
/** Remove and return last entry from argument stack. */
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.
*
(void)ctx;
(void)buf;
(void)size;
- if (strncmp(str, token->name, len))
+ if (strcmp_partial(token->name, str, len))
return -1;
return len;
}
return -1;
/* Parse parameter types. */
switch (ctx->curr) {
+ static const enum index prefix[] = NEXT_ENTRY(PREFIX);
+
case ITEM_PARAM_IS:
index = 0;
objmask = 1;
/* Modify next token to expect a prefix. */
if (ctx->next_num < 2)
return -1;
- ctx->next[ctx->next_num - 2] = NEXT_ENTRY(PREFIX);
+ ctx->next[ctx->next_num - 2] = prefix;
/* Fall through. */
case ITEM_PARAM_MASK:
index = 2;
if (ctx->curr != ACTION_RSS_QUEUE)
return -1;
i = ctx->objdata >> 16;
- if (!strncmp(str, "end", len)) {
+ if (!strcmp_partial("end", str, len)) {
ctx->objdata &= 0xffff;
return len;
}
const struct parse_action_priv *priv;
token = &token_list[next_action[i]];
- if (strncmp(token->name, str, len))
+ if (strcmp_partial(token->name, str, len))
continue;
priv = token->priv;
if (!priv)
return len;
}
+/** Parse tokens for isolate command. */
+static int
+parse_isolate(struct context *ctx, const struct token *token,
+ const char *str, unsigned int len,
+ void *buf, unsigned int size)
+{
+ struct buffer *out = buf;
+
+ /* Token name must match. */
+ if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+ return -1;
+ /* Nothing else to do if there is no buffer. */
+ if (!out)
+ return len;
+ if (!out->command) {
+ if (ctx->curr != ISOLATE)
+ return -1;
+ if (sizeof(*out) > size)
+ return -1;
+ out->command = ctx->curr;
+ ctx->objdata = 0;
+ ctx->object = out;
+ ctx->objmask = NULL;
+ }
+ return len;
+}
+
/**
* Parse signed/unsigned integers 8 to 64-bit long.
*
/* Bit-mask fill is not supported. */
if (arg->mask || size != sizeof(tmp))
goto error;
+ /* Only network endian is supported. */
+ if (!arg->hton)
+ goto error;
ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
if (ret < 0 || (unsigned int)ret != len)
goto error;
if (!arg)
return -1;
for (i = 0; boolean_name[i]; ++i)
- if (!strncmp(str, boolean_name[i], len))
+ if (!strcmp_partial(boolean_name[i], str, len))
break;
/* Process token as integer. */
if (boolean_name[i])
(void)ctx;
(void)token;
- FOREACH_PORT(p, ports) {
+ RTE_ETH_FOREACH_DEV(p) {
if (buf && i == ent)
return snprintf(buf, size, "%u", p);
++i;
(void)token;
if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
- ctx->port == (uint16_t)RTE_PORT_ALL)
+ ctx->port == (portid_t)RTE_PORT_ALL)
return -1;
port = &ports[ctx->port];
for (pf = port->flow_list; pf != NULL; pf = pf->next) {
ctx->prev = ZERO;
ctx->next_num = 0;
ctx->args_num = 0;
- ctx->reparse = 0;
ctx->eol = 0;
ctx->last = 0;
ctx->port = 0;
int i;
(void)hdr;
- /* Restart as requested. */
- if (ctx->reparse)
- cmd_flow_context_init(ctx);
token = &token_list[ctx->curr];
/* Check argument length. */
ctx->eol = 0;
int i;
(void)hdr;
- /* Tell cmd_flow_parse() that context must be reinitialized. */
- ctx->reparse = 1;
/* Count number of tokens in current list. */
if (ctx->next_num)
list = ctx->next[ctx->next_num - 1];
int i;
(void)hdr;
- /* Tell cmd_flow_parse() that context must be reinitialized. */
- ctx->reparse = 1;
/* Count number of tokens in current list. */
if (ctx->next_num)
list = ctx->next[ctx->next_num - 1];
const struct token *token = &token_list[ctx->prev];
(void)hdr;
- /* Tell cmd_flow_parse() that context must be reinitialized. */
- ctx->reparse = 1;
if (!size)
return -1;
/* Set token type and update global help with details. */
/** Populate the next dynamic token. */
static void
cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
- cmdline_parse_token_hdr_t *(*hdrs)[])
+ cmdline_parse_token_hdr_t **hdr_inst)
{
struct context *ctx = &cmd_flow_context;
/* Always reinitialize context before requesting the first token. */
- if (!(hdr - *hdrs))
+ if (!(hdr_inst - cmd_flow.tokens))
cmd_flow_context_init(ctx);
/* Return NULL when no more tokens are expected. */
if (!ctx->next_num && ctx->curr) {
port_flow_list(in->port, in->args.list.group_n,
in->args.list.group);
break;
+ case ISOLATE:
+ port_flow_isolate(in->port, in->args.isolate.set);
+ break;
default:
break;
}