ethdev: add isolated mode to flow API
Isolated mode can be requested by applications on individual ports to avoid ingress traffic outside of the flow rules they define. Besides making ingress more deterministic, it allows PMDs to safely reuse resources otherwise assigned to handle the remaining traffic, such as global RSS configuration settings, VLAN filters, MAC address entries, legacy filter API rules and so on in order to expand the set of possible flow rule types. To minimize code complexity, PMDs implementing this mode may provide partial (or even no) support for flow rules when not enabled (e.g. no priorities, no RSS action). Applications written to use the flow API are therefore encouraged to enable it. Once effective, leaving isolated mode may not be possible depending on PMD implementation. Signed-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com> Acked-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com> Acked-by: Andrew Rybchenko <arybchenko@solarflare.com>
This commit is contained in:
parent
d2e0260445
commit
323f811a4a
@ -906,6 +906,10 @@ static void cmd_help_long_parsed(void *parsed_result,
|
||||
"flow list {port_id} [group {group_id}] [...]\n"
|
||||
" List existing flow rules sorted by priority,"
|
||||
" filtered by group identifiers.\n\n"
|
||||
|
||||
"flow isolate {port_id} {boolean}\n"
|
||||
" Restrict ingress traffic to the defined"
|
||||
" flow rules\n\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ enum index {
|
||||
FLUSH,
|
||||
QUERY,
|
||||
LIST,
|
||||
ISOLATE,
|
||||
|
||||
/* Destroy arguments. */
|
||||
DESTROY_RULE,
|
||||
@ -366,6 +367,9 @@ struct buffer {
|
||||
uint32_t *group;
|
||||
uint32_t group_n;
|
||||
} list; /**< List arguments. */
|
||||
struct {
|
||||
int set;
|
||||
} isolate; /**< Isolated mode arguments. */
|
||||
} args; /**< Command arguments. */
|
||||
};
|
||||
|
||||
@ -651,6 +655,9 @@ static int parse_action(struct context *, const struct token *,
|
||||
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);
|
||||
@ -797,7 +804,8 @@ static const struct token token_list[] = {
|
||||
DESTROY,
|
||||
FLUSH,
|
||||
LIST,
|
||||
QUERY)),
|
||||
QUERY,
|
||||
ISOLATE)),
|
||||
.call = parse_init,
|
||||
},
|
||||
/* Sub-level commands. */
|
||||
@ -847,6 +855,15 @@ static const struct token token_list[] = {
|
||||
.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",
|
||||
@ -2096,6 +2113,33 @@ parse_list(struct context *ctx, const struct token *token,
|
||||
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.
|
||||
*
|
||||
@ -2795,6 +2839,9 @@ cmd_flow_parsed(const struct buffer *in)
|
||||
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;
|
||||
}
|
||||
|
@ -1411,6 +1411,22 @@ port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
|
||||
}
|
||||
}
|
||||
|
||||
/** Restrict ingress traffic to the defined flow rules. */
|
||||
int
|
||||
port_flow_isolate(portid_t port_id, int set)
|
||||
{
|
||||
struct rte_flow_error error;
|
||||
|
||||
/* Poisoning to make sure PMDs update it in case of error. */
|
||||
memset(&error, 0x66, sizeof(error));
|
||||
if (rte_flow_isolate(port_id, set, &error))
|
||||
return port_flow_complain(&error);
|
||||
printf("Ingress traffic on port %u is %s to the defined flow rules\n",
|
||||
port_id,
|
||||
set ? "now restricted" : "not restricted anymore");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* RX/TX ring descriptors display functions.
|
||||
*/
|
||||
|
@ -543,6 +543,7 @@ int port_flow_flush(portid_t port_id);
|
||||
int port_flow_query(portid_t port_id, uint32_t rule,
|
||||
enum rte_flow_action_type action);
|
||||
void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group);
|
||||
int port_flow_isolate(portid_t port_id, int set);
|
||||
|
||||
void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);
|
||||
void tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id);
|
||||
|
@ -1517,6 +1517,73 @@ Return values:
|
||||
|
||||
- 0 on success, a negative errno value otherwise and ``rte_errno`` is set.
|
||||
|
||||
Isolated mode
|
||||
-------------
|
||||
|
||||
The general expectation for ingress traffic is that flow rules process it
|
||||
first; the remaining unmatched or pass-through traffic usually ends up in a
|
||||
queue (with or without RSS, locally or in some sub-device instance)
|
||||
depending on the global configuration settings of a port.
|
||||
|
||||
While fine from a compatibility standpoint, this approach makes drivers more
|
||||
complex as they have to check for possible side effects outside of this API
|
||||
when creating or destroying flow rules. It results in a more limited set of
|
||||
available rule types due to the way device resources are assigned (e.g. no
|
||||
support for the RSS action even on capable hardware).
|
||||
|
||||
Given that nonspecific traffic can be handled by flow rules as well,
|
||||
isolated mode is a means for applications to tell a driver that ingress on
|
||||
the underlying port must be injected from the defined flow rules only; that
|
||||
no default traffic is expected outside those rules.
|
||||
|
||||
This has the following benefits:
|
||||
|
||||
- Applications get finer-grained control over the kind of traffic they want
|
||||
to receive (no traffic by default).
|
||||
|
||||
- More importantly they control at what point nonspecific traffic is handled
|
||||
relative to other flow rules, by adjusting priority levels.
|
||||
|
||||
- Drivers can assign more hardware resources to flow rules and expand the
|
||||
set of supported rule types.
|
||||
|
||||
Because toggling isolated mode may cause profound changes to the ingress
|
||||
processing path of a driver, it may not be possible to leave it once
|
||||
entered. Likewise, existing flow rules or global configuration settings may
|
||||
prevent a driver from entering isolated mode.
|
||||
|
||||
Applications relying on this mode are therefore encouraged to toggle it as
|
||||
soon as possible after device initialization, ideally before the first call
|
||||
to ``rte_eth_dev_configure()`` to avoid possible failures due to conflicting
|
||||
settings.
|
||||
|
||||
Once effective, the following functionality has no effect on the underlying
|
||||
port and may return errors such as ``ENOTSUP`` ("not supported"):
|
||||
|
||||
- Toggling promiscuous mode.
|
||||
- Toggling allmulticast mode.
|
||||
- Configuring MAC addresses.
|
||||
- Configuring multicast addresses.
|
||||
- Configuring VLAN filters.
|
||||
- Configuring Rx filters through the legacy API (e.g. FDIR).
|
||||
- Configuring global RSS settings.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int
|
||||
rte_flow_isolate(uint8_t port_id, int set, struct rte_flow_error *error);
|
||||
|
||||
Arguments:
|
||||
|
||||
- ``port_id``: port identifier of Ethernet device.
|
||||
- ``set``: nonzero to enter isolated mode, attempt to leave it otherwise.
|
||||
- ``error``: perform verbose error reporting if not NULL. PMDs initialize
|
||||
this structure in case of error only.
|
||||
|
||||
Return values:
|
||||
|
||||
- 0 on success, a negative errno value otherwise and ``rte_errno`` is set.
|
||||
|
||||
Verbose error reporting
|
||||
-----------------------
|
||||
|
||||
|
@ -2264,7 +2264,8 @@ Flow rules management
|
||||
---------------------
|
||||
|
||||
Control of the generic flow API (*rte_flow*) is fully exposed through the
|
||||
``flow`` command (validation, creation, destruction and queries).
|
||||
``flow`` command (validation, creation, destruction, queries and operation
|
||||
modes).
|
||||
|
||||
Considering *rte_flow* overlaps with all `Filter Functions`_, using both
|
||||
features simultaneously may cause undefined side-effects and is therefore
|
||||
@ -2318,6 +2319,10 @@ following sections.
|
||||
|
||||
flow list {port_id} [group {group_id}] [...]
|
||||
|
||||
- Restrict ingress traffic to the defined flow rules::
|
||||
|
||||
flow isolate {port_id} {boolean}
|
||||
|
||||
Validating flow rules
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -2894,6 +2899,46 @@ Output can be limited to specific groups::
|
||||
7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE
|
||||
testpmd>
|
||||
|
||||
Toggling isolated mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``flow isolate`` can be used to tell the underlying PMD that ingress traffic
|
||||
must only be injected from the defined flow rules; that no default traffic
|
||||
is expected outside those rules and the driver is free to assign more
|
||||
resources to handle them. It is bound to ``rte_flow_isolate()``::
|
||||
|
||||
flow isolate {port_id} {boolean}
|
||||
|
||||
If successful, enabling or disabling isolated mode shows either::
|
||||
|
||||
Ingress traffic on port [...]
|
||||
is now restricted to the defined flow rules
|
||||
|
||||
Or::
|
||||
|
||||
Ingress traffic on port [...]
|
||||
is not restricted anymore to the defined flow rules
|
||||
|
||||
Otherwise, in case of error::
|
||||
|
||||
Caught error type [...] ([...]): [...]
|
||||
|
||||
Mainly due to its side effects, PMDs supporting this mode may not have the
|
||||
ability to toggle it more than once without reinitializing affected ports
|
||||
first (e.g. by exiting testpmd).
|
||||
|
||||
Enabling isolated mode::
|
||||
|
||||
testpmd> flow isolate 0 true
|
||||
Ingress traffic on port 0 is now restricted to the defined flow rules
|
||||
testpmd>
|
||||
|
||||
Disabling isolated mode::
|
||||
|
||||
testpmd> flow isolate 0 false
|
||||
Ingress traffic on port 0 is not restricted anymore to the defined flow rules
|
||||
testpmd>
|
||||
|
||||
Sample QinQ flow rules
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -2942,4 +2987,3 @@ Validate and create a QinQ rule on port 0 to steer traffic to a queue on the hos
|
||||
ID Group Prio Attr Rule
|
||||
0 0 0 i- ETH VLAN VLAN=>VF QUEUE
|
||||
1 0 0 i- ETH VLAN VLAN=>PF QUEUE
|
||||
|
||||
|
@ -1673,9 +1673,8 @@ igb_flow_flush(struct rte_eth_dev *dev,
|
||||
}
|
||||
|
||||
const struct rte_flow_ops igb_flow_ops = {
|
||||
igb_flow_validate,
|
||||
igb_flow_create,
|
||||
igb_flow_destroy,
|
||||
igb_flow_flush,
|
||||
NULL,
|
||||
.validate = igb_flow_validate,
|
||||
.create = igb_flow_create,
|
||||
.destroy = igb_flow_destroy,
|
||||
.flush = igb_flow_flush,
|
||||
};
|
||||
|
@ -2897,9 +2897,8 @@ ixgbe_flow_flush(struct rte_eth_dev *dev,
|
||||
}
|
||||
|
||||
const struct rte_flow_ops ixgbe_flow_ops = {
|
||||
ixgbe_flow_validate,
|
||||
ixgbe_flow_create,
|
||||
ixgbe_flow_destroy,
|
||||
ixgbe_flow_flush,
|
||||
NULL,
|
||||
.validate = ixgbe_flow_validate,
|
||||
.create = ixgbe_flow_create,
|
||||
.destroy = ixgbe_flow_destroy,
|
||||
.flush = ixgbe_flow_flush,
|
||||
};
|
||||
|
@ -147,3 +147,10 @@ DPDK_17.05 {
|
||||
rte_eth_xstats_get_names_by_id;
|
||||
|
||||
} DPDK_17.02;
|
||||
|
||||
DPDK_17.08 {
|
||||
global:
|
||||
|
||||
rte_flow_isolate;
|
||||
|
||||
} DPDK_17.05;
|
||||
|
@ -157,3 +157,21 @@ rte_flow_query(uint8_t port_id,
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, rte_strerror(ENOSYS));
|
||||
}
|
||||
|
||||
/* Restrict ingress traffic to the defined flow rules. */
|
||||
int
|
||||
rte_flow_isolate(uint8_t port_id,
|
||||
int set,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
struct rte_eth_dev *dev = &rte_eth_devices[port_id];
|
||||
const struct rte_flow_ops *ops = rte_flow_ops_get(port_id, error);
|
||||
|
||||
if (!ops)
|
||||
return -rte_errno;
|
||||
if (likely(!!ops->isolate))
|
||||
return ops->isolate(dev, set, error);
|
||||
return -rte_flow_error_set(error, ENOSYS,
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, rte_strerror(ENOSYS));
|
||||
}
|
||||
|
@ -1191,6 +1191,50 @@ rte_flow_query(uint8_t port_id,
|
||||
void *data,
|
||||
struct rte_flow_error *error);
|
||||
|
||||
/**
|
||||
* Restrict ingress traffic to the defined flow rules.
|
||||
*
|
||||
* Isolated mode guarantees that all ingress traffic comes from defined flow
|
||||
* rules only (current and future).
|
||||
*
|
||||
* Besides making ingress more deterministic, it allows PMDs to safely reuse
|
||||
* resources otherwise assigned to handle the remaining traffic, such as
|
||||
* global RSS configuration settings, VLAN filters, MAC address entries,
|
||||
* legacy filter API rules and so on in order to expand the set of possible
|
||||
* flow rule types.
|
||||
*
|
||||
* Calling this function as soon as possible after device initialization,
|
||||
* ideally before the first call to rte_eth_dev_configure(), is recommended
|
||||
* to avoid possible failures due to conflicting settings.
|
||||
*
|
||||
* Once effective, leaving isolated mode may not be possible depending on
|
||||
* PMD implementation.
|
||||
*
|
||||
* Additionally, the following functionality has no effect on the underlying
|
||||
* port and may return errors such as ENOTSUP ("not supported"):
|
||||
*
|
||||
* - Toggling promiscuous mode.
|
||||
* - Toggling allmulticast mode.
|
||||
* - Configuring MAC addresses.
|
||||
* - Configuring multicast addresses.
|
||||
* - Configuring VLAN filters.
|
||||
* - Configuring Rx filters through the legacy API (e.g. FDIR).
|
||||
* - Configuring global RSS settings.
|
||||
*
|
||||
* @param port_id
|
||||
* Port identifier of Ethernet device.
|
||||
* @param set
|
||||
* Nonzero to enter isolated mode, attempt to leave it otherwise.
|
||||
* @param[out] error
|
||||
* Perform verbose error reporting if not NULL. PMDs initialize this
|
||||
* structure in case of error only.
|
||||
*
|
||||
* @return
|
||||
* 0 on success, a negative errno value otherwise and rte_errno is set.
|
||||
*/
|
||||
int
|
||||
rte_flow_isolate(uint8_t port_id, int set, struct rte_flow_error *error);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -120,6 +120,11 @@ struct rte_flow_ops {
|
||||
enum rte_flow_action_type,
|
||||
void *,
|
||||
struct rte_flow_error *);
|
||||
/** See rte_flow_isolate(). */
|
||||
int (*isolate)
|
||||
(struct rte_eth_dev *,
|
||||
int,
|
||||
struct rte_flow_error *);
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user