Generic flow director/filtering/classification API
PATCH v2 25/25 doc: describe testpmd flow command
In reply to Adrien MazarguilDocument syntax, interaction with rte_flow and provide usage examples.
--- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 612 +++++++++++++++++++++++ 1 file changed, 612 insertions(+)
doc/guides/testpmd_app_ug/testpmd_funcs.rst +612 -0
@@ -1631,6 +1631,9 @@ Filter Functions This section details the available filter functions that are available. +Note these functions interface the deprecated legacy filtering framework, +superseded by *rte_flow*. See `Flow rules management`_. + ethertype_filter ~~~~~~~~~~~~~~~~~~~~
@@ -2041,3 +2044,612 @@ Set different GRE key length for input set:: For example to set GRE key length for input set to 4 bytes on port 0:: testpmd> global_config 0 gre-key-len 4 + + +.. _testpmd_rte_flow: + +Flow rules management +--------------------- + +Control of the generic flow API (*rte_flow*) is fully exposed through the +``flow`` command (validation, creation, destruction and queries). + +Considering *rte_flow* overlaps with all `Filter Functions`_, using both +features simultaneously may cause undefined side-effects and is therefore +not recommended. + +``flow`` syntax +~~~~~~~~~~~~~~~ + +Because the ``flow`` command uses dynamic tokens to handle the large number +of possible flow rules combinations, its behavior differs slightly from +other commands, in particular: + +- Pressing *?* or the *<tab>* key displays contextual help for the current + token, not that of the entire command. + +- Optional and repeated parameters are supported (provided they are listed + in the contextual help). + +The first parameter stands for the operation mode. Possible operations and +their general syntax are described below. They are covered in detail in the +following sections. + +- Check whether a flow rule can be created:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Create a flow rule:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Destroy specific flow rules:: + + flow destroy {port_id} rule {rule_id} [...] + +- Destroy all flow rules:: + + flow flush {port_id} + +- Query an existing flow rule:: + + flow query {port_id} {rule_id} {action} + +- List existing flow rules sorted by priority, filtered by group + identifiers:: + + flow list {port_id} [group {group_id}] [...] + +Validating flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow validate`` reports whether a flow rule would be accepted by the +underlying device in its current state but stops short of creating it. It is +bound to ``rte_flow_validate()``:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will show:: + + Flow rule validated + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +This command uses the same parameters as ``flow create``, their format is +described in `Creating flow rules`_. + +Check whether redirecting any Ethernet packet received on port 0 to RX queue +index 6 is supported:: + + testpmd> flow validate 1 ingress pattern eth / end + actions queue index 6 / end + Flow rule validated + testpmd> + +Port 0 does not support TCPv6 rules:: + + testpmd> flow validate 0 ingress pattern eth / ipv6 / tcp / end + actions drop / end + Caught error type 9 (specific pattern item): Invalid argument. + testpmd> + +Creating flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow create`` validates and creates the specified flow rule. It is bound +to ``rte_flow_create()``:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will return a flow rule ID usable with other commands:: + + Flow rule #[...] created + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +Parameters describe in the following order: + +- Attributes (*group*, *priority*, *ingress*, *egress* tokens). +- A matching pattern, starting with the *pattern* token and terminated by an + *end* pattern item. +- Actions, starting with the *actions* token and terminated by an *end* + action. + +These translate directly to *rte_flow* objects provided as-is to the +underlying functions. + +The shortest valid definition only comprises mandatory tokens:: + + testpmd> flow create 0 pattern end actions end + +Note that PMDs may refuse rules that essentially do nothing such as this +one. + +**All unspecified object values are automatically initialized to 0.** + +Attributes +^^^^^^^^^^ + +These tokens affect flow rule attributes (``struct rte_flow_attr``) and are +specified before the ``pattern`` token. + +- ``group {group id}``: priority group. +- ``priority {level}``: priority level within group. +- ``ingress``: rule applies to ingress traffic. +- ``egress``: rule applies to egress traffic. + +Each instance of an attribute specified several times overrides the previous +value as shown below (group 4 is used):: + + testpmd> flow create 0 group 42 group 24 group 4 [...] + +Note that once enabled, ``ingress`` and ``egress`` cannot be disabled. + +While not specifying a direction is an error, some rules may allow both +simultaneously. + +Most rules affect RX therefore contain the ``ingress`` token:: + + testpmd> flow create 0 ingress pattern [...] + +Matching pattern +^^^^^^^^^^^^^^^^ + +A matching pattern starts after the ``pattern`` token. It is made of pattern +items and is terminated by a mandatory ``end`` item. + +Items are named after their type (*RTE_FLOW_ITEM_TYPE_* from ``enum +rte_flow_item_type``). + +The ``/`` token is used as a separator between pattern items as shown +below:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end [...] + +Note that protocol items like these must be stacked from lowest to highest +layer to make sense. For instance, the following rule is either invalid or +unlikely to match any packet:: + + testpmd> flow create 0 ingress pattern eth / udp / ipv4 / end [...] + +More information on these restrictions can be found in the *rte_flow* +documentation. + +Several items support additional specification structures, for example +``ipv4`` allows specifying source and destination addresses as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 src is 10.1.1.1 + dst is 10.2.0.0 / end [...] + +This rule matches all IPv4 traffic with the specified properties. + +In this example, ``src`` and ``dst`` are field names of the underlying +``struct rte_flow_item_ipv4`` object. All item properties can be specified +in a similar fashion. + +The ``is`` token means that the subsequent value must be matched exactly, +and assigns ``spec`` and ``mask`` fields in ``struct rte_flow_item`` +accordingly. Possible assignment tokens are: + +- ``is``: match value perfectly (with full bit-mask). +- ``spec``: match value according to configured bit-mask. +- ``last``: specify upper bound to establish a range. +- ``mask``: specify bit-mask with relevant bits set to one. +- ``prefix``: generate bit-mask from a prefix length. + +These yield identical results:: + + ipv4 src is 10.1.1.1 + +:: + + ipv4 src spec 10.1.1.1 src mask 255.255.255.255 + +:: + + ipv4 src spec 10.1.1.1 src prefix 32 + +:: + + ipv4 src is 10.1.1.1 src last 10.1.1.1 # range with a single value + +:: + + ipv4 src is 10.1.1.1 src last 0 # 0 disables range + +Inclusive ranges can be defined with ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 # 10.1.1.1 to 10.2.3.4 + +Note that ``mask`` affects both ``spec`` and ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 src mask 255.255.0.0 + # matches 10.1.0.0 to 10.2.255.255 + +Properties can be modified multiple times:: + + ipv4 src is 10.1.1.1 src is 10.1.2.3 src is 10.2.3.4 # matches 10.2.3.4 + +:: + + ipv4 src is 10.1.1.1 src prefix 24 src prefix 16 # matches 10.1.0.0/16 + +Pattern items +^^^^^^^^^^^^^ + +This section lists supported pattern items and their attributes, if any. + +- ``end``: end list of pattern items. + +- ``void``: no-op pattern item. + +- ``invert``: perform actions when pattern does not match. + +- ``any``: match any protocol for the current layer. + + - ``num {unsigned}``: number of layers covered. + +- ``pf``: match packets addressed to the physical function. + +- ``vf``: match packets addressed to a virtual function ID. + + - ``id {unsigned}``: destination VF ID. + +- ``port``: device-specific physical port index to use. + + - ``index {unsigned}``: physical port index. + +- ``raw``: match an arbitrary byte string. + + - ``relative {boolean}``: look for pattern after the previous item. + - ``search {boolean}``: search pattern from offset (see also limit). + - ``offset {integer}``: absolute or relative offset for pattern. + - ``limit {unsigned}``: search area limit for start of pattern. + - ``pattern {string}``: byte string to look for. + +- ``eth``: match Ethernet header. + + - ``dst {MAC-48}``: destination MAC. + - ``src {MAC-48}``: source MAC. + - ``type {unsigned}``: EtherType. + +- ``vlan``: match 802.1Q/ad VLAN tag. + + - ``tpid {unsigned}``: tag protocol identifier. + - ``tci {unsigned}``: tag control information. + +- ``ipv4``: match IPv4 header. + + - ``src {ipv4 address}``: source address. + - ``dst {ipv4 address}``: destination address. + +- ``ipv6``: match IPv6 header. + + - ``src {ipv6 address}``: source address. + - ``dst {ipv6 address}``: destination address. + +- ``icmp``: match ICMP header. + + - ``type {unsigned}``: ICMP packet type. + - ``code {unsigned}``: ICMP packet code. + +- ``udp``: match UDP header. + + - ``src {unsigned}``: UDP source port. + - ``dst {unsigned}``: UDP destination port. + +- ``tcp``: match TCP header. + + - ``src {unsigned}``: TCP source port. + - ``dst {unsigned}``: TCP destination port. + +- ``sctp``: match SCTP header. + + - ``src {unsigned}``: SCTP source port. + - ``dst {unsigned}``: SCTP destination port. + +- ``vxlan``: match VXLAN header. + + - ``vni {unsigned}``: VXLAN identifier. + +Actions list +^^^^^^^^^^^^ + +A list of actions starts after the ``actions`` token in the same fashion as +`Matching pattern`_; actions are separated by ``/`` tokens and the list is +terminated by a mandatory ``end`` action. + +Actions are named after their type (*RTE_FLOW_ACTION_TYPE_* from ``enum +rte_flow_action_type``). + +Dropping all incoming UDPv4 packets can be expressed as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions drop / end + +Several actions have configurable properties which must be specified when +there is no valid default value. For example, ``queue`` requires a target +queue index. + +This rule redirects incoming UDPv4 traffic to queue index 6:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue index 6 / end + +While this one could be rejected by PMDs (unspecified queue index):: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue / end + +As defined by *rte_flow*, the list is not ordered, all actions of a given +rule are performed simultaneously. These are equivalent:: + + queue index 6 / void / mark id 42 / end + +:: + + void / mark id 42 / queue index 6 / end + +All actions in a list should have different types, otherwise only the last +action of a given type is taken into account:: + + queue index 4 / queue index 5 / queue index 6 / end # will use queue 6 + +:: + + drop / drop / drop / end # drop is performed only once + +:: + + mark id 42 / queue index 3 / mark id 24 / end # mark will be 24 + +Considering they are performed simultaneously, opposite and overlapping +actions can sometimes be combined when the end result is unambiguous:: + + drop / queue index 6 / end # drop has no effect + +:: + + drop / dup index 6 / end # same as above + +:: + + queue index 6 / rss queues 6 7 8 / end # queue has no effect + +:: + + drop / passthru / end # drop has no effect + +Note that PMDs may still refuse such combinations. + +Actions +^^^^^^^ + +This section lists supported actions and their attributes, if any. + +- ``end``: end list of actions. + +- ``void``: no-op action. + +- ``passthru``: let subsequent rule process matched packets. + +- ``mark``: attach 32 bit value to packets. + + - ``id {unsigned}``: 32 bit value to return with packets. + +- ``flag``: flag packets. + +- ``queue``: assign packets to a given queue index. + + - ``index {unsigned}``: queue index to use. + +- ``drop``: drop packets (note: passthru has priority). + +- ``count``: enable counters for this rule. + +- ``dup``: duplicate packets to a given queue index. + + - ``index {unsigned}``: queue index to duplicate packets to. + +- ``rss``: spread packets among several queues. + + - ``queues [{unsigned} [...]] end``: queue indices to use. + +- ``pf``: redirect packets to physical device function. + +- ``vf``: redirect packets to virtual device function. + + - ``original {boolean}``: use original VF ID if possible. + - ``id {unsigned}``: VF ID to redirect packets to. + +Destroying flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow destroy`` destroys one or more rules from their rule ID (as returned +by ``flow create``), this command calls ``rte_flow_destroy()`` as many +times as necessary:: + + flow destroy {port_id} rule {rule_id} [...] + +If successful, it will show:: + + Flow rule #[...] destroyed + +It does not report anything for rule IDs that do not exist. The usual error +message is shown when a rule cannot be destroyed:: + + Caught error type [...] ([...]): [...] + +``flow flush`` destroys all rules on a device and does not take extra +arguments. It is bound to ``rte_flow_flush()``:: + + flow flush {port_id} + +Any errors are reported as above. + +Creating several rules and destroying them:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 0 rule 1 + Flow rule #1 destroyed + Flow rule #0 destroyed + testpmd> + +The same result can be achieved using ``flow flush``:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow flush 0 + testpmd> + +Non-existent rule IDs are ignored:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 42 rule 10 rule 2 + testpmd> + testpmd> flow destroy 0 rule 0 + Flow rule #0 destroyed + testpmd> + +Querying flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow query`` queries a specific action of a flow rule having that +ability. Such actions collect information that can be reported using this +command. It is bound to ``rte_flow_query()``:: + + flow query {port_id} {rule_id} {action} + +If successful, it will display either the retrieved data for known actions +or the following message:: + + Cannot display result for action type [...] ([...]) + +Otherwise, it will complain either that the rule does not exist or that some +error occurred:: + + Flow rule #[...] not found + +:: + + Caught error type [...] ([...]): [...] + +Currently only the ``count`` action is supported. This action reports the +number of packets that hit the flow rule and the total number of bytes. Its +output has the following format:: + + count: + hits_set: [...] # whether "hits" contains a valid value + bytes_set: [...] # whether "bytes" contains a valid value + hits: [...] # number of packets + bytes: [...] # number of bytes + +Querying counters for TCPv6 packets redirected to queue 6:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / tcp / end + actions queue index 6 / count / end + Flow rule #4 created + testpmd> flow query 0 4 count + count: + hits_set: 1 + bytes_set: 0 + hits: 386446 + bytes: 0 + testpmd> + +Listing flow rules +~~~~~~~~~~~~~~~~~~ + +``flow list`` lists existing flow rules sorted by priority and optionally +filtered by group identifiers:: + + flow list {port_id} [group {group_id}] [...] + +This command only fails with the following message if the device does not +exist:: + + Invalid port [...] + +Output consists of a header line followed by a short description of each +flow rule, one per line. There is no output at all when no flow rules are +configured on the device:: + + ID Group Prio Attr Rule + [...] [...] [...] [...] [...] + +``Attr`` column flags: + +- ``i`` for ``ingress``. +- ``e`` for ``egress``. + +Creating several flow rules and listing them:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 6 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #1 created + testpmd> flow create 0 priority 5 ingress pattern eth / ipv4 / udp / end + actions rss queues 6 7 8 end / end + Flow rule #2 created + testpmd> flow list 0 + ID Group Prio Attr Rule + 0 0 0 i- ETH IPV4 => QUEUE + 1 0 0 i- ETH IPV6 => QUEUE + 2 0 5 i- ETH IPV4 UDP => RSS + testpmd> + +Rules are sorted by priority (i.e. group ID first, then priority level):: + + testpmd> flow list 1 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 1 24 0 i- ETH IPV4 UDP => QUEUE + 4 24 10 i- ETH IPV4 TCP => DROP + 3 24 20 i- ETH IPV4 => DROP + 2 24 42 i- ETH IPV4 UDP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd> + +Output can be limited to specific groups:: + + testpmd> flow list 1 group 0 group 63 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd>
Signature · 1 line
2.1.4
Re: [PATCH v2 00/25] Generic flow API (rte_flow)
In reply to Adrien MazarguilQuoted 114 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Friday, December 16, 2016 6:25 PM
To: [email protected]
Subject: [dpdk-dev] [PATCH v2 00/25] Generic flow API (rte_flow)As previously discussed in RFC v1 [1], RFC v2 [2], with changes described in
[3] (also pasted below), here is the first non-draft series for this new API.Its capabilities are so generic that its name had to be vague, it may be called "Generic flow API", "Generic flow interface" (possibly shortened as "GFI") to refer to the name of the new filter type, or "
rte_flow" from the prefix used for its public symbols. I personally favor the latter.While it is currently meant to supersede existing filter types in order for all PMDs to expose a common filtering/classification interface, it may eventually evolve to cover the following ideas as well:
- Rx/Tx offloads configuration through automatic offloads for specific packets, e.g. performing checksum on TCP packets could be expressed with an egress rule with a TCP pattern and a kind of checksum action.
- RSS configuration (already defined actually). Could be global or per rule depending on hardware capabilities.
- Switching configuration for devices with many physical ports; rules doing both ingress and egress could even be used to completely bypass software if supported by hardware.
[1] http://dpdk.org/ml/archives/dev/2016-July/043365.html
[2] http://dpdk.org/ml/archives/dev/2016-August/045383.html
[3] http://dpdk.org/ml/archives/dev/2016-November/050044.htmlChanges since v1 series:
- Added programmer's guide documentation for
rte_flow.- Added depreciation notice for the legacy API.
- Documented testpmd flow command.
- Fixed missing
rte_flow_flushsymbol in rte_ether_version.map.- Cleaned up API documentation in
rte_flow.h.- Replaced "min/max" parameters with "num" in struct
rte_flow_item_any, to
align behavior with other item definitions.- Fixed "type" (EtherType) size in struct
rte_flow_item_eth.- Renamed "queues" to "num" in struct
rte_flow_action_rss.- Fixed missing const in
rte_flow_error_set()prototype definition.- Fixed testpmd flow create command that did not save the
rte_flowobject pointer, causing crashes.- Hopefully fixed all the remaining ICC/clang errors.
- Replaced testpmd flow command's "fix" token with "is" for clarity.
Changes since RFC v2:
- New separate VLAN pattern item (previously part of the ETH definition), found to be much more convenient.
- Removed useless "any" field from VF pattern item, the same effect can be achieved by not providing a specification structure.
- Replaced bit-fields from the VXLAN pattern item to avoid endianness conversion issues on 24-bit fields.
- Updated struct
rte_flow_itemwith a new "last" field to create inclusive ranges. They are defined as the interval between (spec & mask) and (last & mask). All three parameters are optional.- Renamed ID action MARK.
- Renamed "queue" fields in actions QUEUE and DUP to "index".
- "
rss_conf" field in RSS action is now const.- VF action now uses a 32 bit ID like its pattern item counterpart.
- Removed redundant struct
rte_flow_pattern, API functions now expect struct
rte_flow_itemlists terminated by END items.- Replaced struct
rte_flow_actionsfor the same reason, with structrte_flow_actionlists terminated by END actions.- Error types (enum
rte_flow_error_type) have been updated and the cause pointer in structrte_flow_erroris now const.- Function prototypes (
rte_flow_create,rte_flow_validate) have also been updated for clarity.Additions:
- Public wrapper functions rte_flow_{validate|create|destroy|flush|query} are now implemented in
rte_flow.c, with their symbols exported and versioned. Related filter typeRTE_ETH_FILTER_GENERIChas been added.- A separate header (
rte_flow_driver.h) has been added for driver-side functionality, in particular structrte_flow_opswhich contains PMD callbacks returned byRTE_ETH_FILTER_GENERICquery.- testpmd now exposes most of this API through the new "flow" command.
What remains to be done:
- Using endian-aware integer types (
rte_beX_t) where necessary for clarity.
Quoted 9 lines
- API documentation (based on RFC).
- testpmd flow command documentation (although context-aware command completion should already help quite a bit in this regard).
- A few pattern item / action properties cannot be configured yet (e.g.
rss_confparameter for RSS action) and a few completions (e.g. possible queue IDs) should be added.
v3 cover Generic flow API (rte_flow)
In reply to Adrien MazarguilAs previously discussed in RFC v1 [1], RFC v2 [2], with changes described in [3] (also pasted below), here is the first non-draft series for this new API.
Its capabilities are so generic that its name had to be vague, it may be called "Generic flow API", "Generic flow interface" (possibly shortened as "GFI") to refer to the name of the new filter type, or "rte_flow" from the prefix used for its public symbols. I personally favor the latter.
While it is currently meant to supersede existing filter types in order for all PMDs to expose a common filtering/classification interface, it may eventually evolve to cover the following ideas as well:
- Rx/Tx offloads configuration through automatic offloads for specific packets, e.g. performing checksum on TCP packets could be expressed with an egress rule with a TCP pattern and a kind of checksum action.
- RSS configuration (already defined actually). Could be global or per rule depending on hardware capabilities.
- Switching configuration for devices with many physical ports; rules doing both ingress and egress could even be used to completely bypass software if supported by hardware.
[1] http://dpdk.org/ml/archives/dev/2016-July/043365.html
[2] http://dpdk.org/ml/archives/dev/2016-August/045383.html
[3] http://dpdk.org/ml/archives/dev/2016-November/050044.html
Changes since v2 series:
- Replaced ENOTSUP with ENOSYS in the code (although doing so triggers spurious checkpatch warnings) to tell apart unimplemented callbacks from unsupported flow rules and match the documented behavior.
- Fixed missing include seen by check-includes.sh in rte_flow_driver.h.
- Made clearer that PMDs must initialize rte_flow_error (if non-NULL) in case of error, added related memory poisoning in testpmd to catch missing initializations.
- Fixed rte_flow programmer's guide according to John Mcnamara's comments (tables, sections header and typos).
- Fixed deprecation notice as well.
Changes since v1 series:
- Added programmer's guide documentation for rte_flow.
- Added depreciation notice for the legacy API.
- Documented testpmd flow command.
- Fixed missing rte_flow_flush symbol in rte_ether_version.map.
- Cleaned up API documentation in rte_flow.h.
- Replaced "min/max" parameters with "num" in struct rte_flow_item_any, to align behavior with other item definitions.
- Fixed "type" (EtherType) size in struct rte_flow_item_eth.
- Renamed "queues" to "num" in struct rte_flow_action_rss.
- Fixed missing const in rte_flow_error_set() prototype definition.
- Fixed testpmd flow create command that did not save the rte_flow object pointer, causing crashes.
- Hopefully fixed all the remaining ICC/clang errors.
- Replaced testpmd flow command's "fix" token with "is" for clarity.
Changes since RFC v2:
- New separate VLAN pattern item (previously part of the ETH definition), found to be much more convenient.
- Removed useless "any" field from VF pattern item, the same effect can be achieved by not providing a specification structure.
- Replaced bit-fields from the VXLAN pattern item to avoid endianness conversion issues on 24-bit fields.
- Updated struct rte_flow_item with a new "last" field to create inclusive ranges. They are defined as the interval between (spec & mask) and (last & mask). All three parameters are optional.
- Renamed ID action MARK.
- Renamed "queue" fields in actions QUEUE and DUP to "index".
- "rss_conf" field in RSS action is now const.
- VF action now uses a 32 bit ID like its pattern item counterpart.
- Removed redundant struct rte_flow_pattern, API functions now expect struct
rte_flow_item lists terminated by END items.
- Replaced struct rte_flow_actions for the same reason, with struct rte_flow_action lists terminated by END actions.
- Error types (enum rte_flow_error_type) have been updated and the cause pointer in struct rte_flow_error is now const.
- Function prototypes (rte_flow_create, rte_flow_validate) have also been updated for clarity.
Additions:
- Public wrapper functions rte_flow_{validate|create|destroy|flush|query} are now implemented in rte_flow.c, with their symbols exported and versioned. Related filter type RTE_ETH_FILTER_GENERIC has been added.
- A separate header (rte_flow_driver.h) has been added for driver-side functionality, in particular struct rte_flow_ops which contains PMD callbacks returned by RTE_ETH_FILTER_GENERIC query.
- testpmd now exposes most of this API through the new "flow" command.
What remains to be done:
- Using endian-aware integer types (rte_beX_t) where necessary for clarity.
- API documentation (based on RFC).
- testpmd flow command documentation (although context-aware command completion should already help quite a bit in this regard).
- A few pattern item / action properties cannot be configured yet (e.g. rss_conf parameter for RSS action) and a few completions (e.g. possible queue IDs) should be added.
Adrien Mazarguil (25):
ethdev: introduce generic flow API
doc: add rte_flow prog guide
doc: announce deprecation of legacy filter types
cmdline: add support for dynamic tokens
cmdline: add alignment constraint app/testpmd: implement basic support for rte_flow app/testpmd: add flow command app/testpmd: add rte_flow integer support app/testpmd: add flow list command app/testpmd: add flow flush command app/testpmd: add flow destroy command app/testpmd: add flow validate/create commands app/testpmd: add flow query command app/testpmd: add rte_flow item spec handler app/testpmd: add rte_flow item spec prefix length app/testpmd: add rte_flow bit-field support app/testpmd: add item any to flow command app/testpmd: add various items to flow command app/testpmd: add item raw to flow command app/testpmd: add items eth/vlan to flow command app/testpmd: add items ipv4/ipv6 to flow command app/testpmd: add L4 items to flow command app/testpmd: add various actions to flow command app/testpmd: add queue actions to flow command
doc: describe testpmd flow command
MAINTAINERS | 4 + app/test-pmd/Makefile | 1 + app/test-pmd/cmdline.c | 32 + app/test-pmd/cmdline_flow.c | 2575 ++++++++++++++++++++++ app/test-pmd/config.c | 498 +++++ app/test-pmd/csumonly.c | 1 + app/test-pmd/flowgen.c | 1 + app/test-pmd/icmpecho.c | 1 + app/test-pmd/ieee1588fwd.c | 1 + app/test-pmd/iofwd.c | 1 + app/test-pmd/macfwd.c | 1 + app/test-pmd/macswap.c | 1 + app/test-pmd/parameters.c | 1 + app/test-pmd/rxonly.c | 1 + app/test-pmd/testpmd.c | 6 + app/test-pmd/testpmd.h | 27 + app/test-pmd/txonly.c | 1 + doc/api/doxy-api-index.md | 2 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/rte_flow.rst | 2042 +++++++++++++++++ doc/guides/rel_notes/deprecation.rst | 8 + doc/guides/testpmd_app_ug/testpmd_funcs.rst | 612 +++++ lib/librte_cmdline/cmdline_parse.c | 67 +- lib/librte_cmdline/cmdline_parse.h | 21 + lib/librte_ether/Makefile | 3 + lib/librte_ether/rte_eth_ctrl.h | 1 + lib/librte_ether/rte_ether_version.map | 11 + lib/librte_ether/rte_flow.c | 159 ++ lib/librte_ether/rte_flow.h | 947 ++++++++ lib/librte_ether/rte_flow_driver.h | 182 ++ 30 files changed, 7200 insertions(+), 9 deletions(-) create mode 100644 app/test-pmd/cmdline_flow.c create mode 100644 doc/guides/prog_guide/rte_flow.rst create mode 100644 lib/librte_ether/rte_flow.c create mode 100644 lib/librte_ether/rte_flow.h create mode 100644 lib/librte_ether/rte_flow_driver.h
Signature · 1 line
2.1.4
PATCH v3 1/25 ethdev: introduce generic flow API
This new API supersedes all the legacy filter types described in rte_eth_ctrl.h. It is slightly higher level and as a result relies more on PMDs to process and validate flow rules.
Benefits:
- A unified API is easier to program for, applications do not have to be written for a specific filter type which may or may not be supported by the underlying device.
- The behavior of a flow rule is the same regardless of the underlying device, applications do not need to be aware of hardware quirks.
- Extensible by design, API/ABI breakage should rarely occur if at all.
- Documentation is self-standing, no need to look up elsewhere.
Existing filter types will be deprecated and removed in the near future.
--- MAINTAINERS | 4 + doc/api/doxy-api-index.md | 2 + lib/librte_ether/Makefile | 3 + lib/librte_ether/rte_eth_ctrl.h | 1 + lib/librte_ether/rte_ether_version.map | 11 + lib/librte_ether/rte_flow.c | 159 +++++ lib/librte_ether/rte_flow.h | 947 ++++++++++++++++++++++++++++ lib/librte_ether/rte_flow_driver.h | 182 ++++++ 8 files changed, 1309 insertions(+)
MAINTAINERS +4 -0
@@ -243,6 +243,10 @@ M: Thomas Monjalon <[email protected]> F: lib/librte_ether/ F: scripts/test-null.sh +Generic flow API +M: Adrien Mazarguil <[email protected]> +F: lib/librte_ether/rte_flow* + Crypto API M: Declan Doherty <[email protected]> F: lib/librte_cryptodev/
doc/api/doxy-api-index.md +2 -0
@@ -39,6 +39,8 @@ There are many libraries, so their headers may be grouped by topics: [dev] (@ref rte_dev.h), [ethdev] (@ref rte_ethdev.h), [ethctrl] (@ref rte_eth_ctrl.h), + [rte_flow] (@ref rte_flow.h), + [rte_flow_driver] (@ref rte_flow_driver.h), [cryptodev] (@ref rte_cryptodev.h), [devargs] (@ref rte_devargs.h), [bond] (@ref rte_eth_bond.h),
lib/librte_ether/Makefile +3 -0
@@ -44,6 +44,7 @@ EXPORT_MAP := rte_ether_version.map LIBABIVER := 5 SRCS-y += rte_ethdev.c +SRCS-y += rte_flow.c # # Export include files
@@ -51,6 +52,8 @@ SRCS-y += rte_ethdev.c SYMLINK-y-include += rte_ethdev.h SYMLINK-y-include += rte_eth_ctrl.h SYMLINK-y-include += rte_dev_info.h +SYMLINK-y-include += rte_flow.h +SYMLINK-y-include += rte_flow_driver.h # this lib depends upon: DEPDIRS-y += lib/librte_net lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
lib/librte_ether/rte_eth_ctrl.h +1 -0
@@ -99,6 +99,7 @@ enum rte_filter_type {RTE_ETH_FILTER_FDIR ,RTE_ETH_FILTER_HASH ,RTE_ETH_FILTER_L2_TUNNEL , +RTE_ETH_FILTER_GENERIC , RTE_ETH_FILTER_MAX };
lib/librte_ether/rte_ether_version.map +11 -0
@@ -147,3 +147,14 @@ DPDK_16.11 { rte_eth_dev_pci_remove; } DPDK_16.07; + +DPDK_17.02 { + global: + + rte_flow_validate; + rte_flow_create; + rte_flow_destroy; + rte_flow_flush; + rte_flow_query; + +} DPDK_16.11;
lib/librte_ether/rte_flow.c new file +159 -0
159 lines not on this page · raw message
lib/librte_ether/rte_flow.h new file +947 -0
947 lines not on this page · raw message
lib/librte_ether/rte_flow_driver.h new file +182 -0
182 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH v3 01/25] ethdev: introduce generic flow API
Hi, Adrien
lib/librte_ether/rte_flow.h
Quoted 8 lines
lib/librte_ether/rte_flow.h new file +8
-0+struct rte_flow_item_raw { +uint32_t relative:1 ;/**< Look for pattern after the previous item. */ +uint32_t search:1 ;/**< Search pattern from offset (see also limit). */ +uint32_t reserved:30 ;/**< Reserved, must be set to zero. */ +int32_t offset;/**< Absolute or relative offset for pattern. */ +uint16_t limit;/**< Search area limit for start of pattern. */ +uint16_t length;/**< Pattern length. */ +uint8_t pattern[];/**< Byte string to look for. */ };
When I use this API to test igb flex filter, I find that
in the struct rte_flow_item_raw, the member pattern is not the same as my purpose.
For example, If I type in " flow create 0 ingress pattern raw relative is 0 pattern is 0123 / end actions queue index 1 / end " What I get in NIC layer is pattern[]={ 0x30, 0x31, 0x32, 0x33, 0x0 <repeats 124 times> }.
But what I need is pattern[]={0x01, 0x23, 0x0 <repeats 126 times>}
About the format change of flex_filter, I have reference to the testpmd function cmd_flex_filter_parsed(), There is details of format change from ASIC code to data, for example:
for (i = 0; i < len; i++) {
c = bytes_ptr[i];
if (isxdigit(c) == 0) {
/* invalid characters. */
printf("invalid input\n");
return;
}
val = xdigit2val(c);
if (i % 2) {
byte |= val;
filter.bytes[j] = byte;
printf("bytes[%d]:%02x ", j, filter.bytes[j]);
j++;
byte = 0;
} else
byte |= val << 4;
} and there is also usage example in the DPDK document testpmd_app_ug-16.11.pdf:
(it also not use ASIC code)
testpmd> flex_filter 0 add len 16 bytes 0x00000000000000000000000008060000 \
mask 000C priority 3 queue 3
so, will our new generic flow API align to the old format in flex byte filter in 17.08 or in the future? At least in the struct rte_flow_item_raw, the member pattern is the same as old filter?
Quoted 1,510 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Tuesday, December 20, 2016 1:49 AM
To: [email protected]
Subject: [dpdk-dev] [PATCH v3 01/25] ethdev: introduce generic flow APIThis new API supersedes all the legacy filter types described in
rte_eth_ctrl.h. It is slightly higher level and as a result relies more on PMDs to process and validate flow rules.Benefits:
- A unified API is easier to program for, applications do not have to be written for a specific filter type which may or may not be supported by the underlying device.
- The behavior of a flow rule is the same regardless of the underlying device, applications do not need to be aware of hardware quirks.
- Extensible by design, API/ABI breakage should rarely occur if at all.
- Documentation is self-standing, no need to look up elsewhere.
Existing filter types will be deprecated and removed in the near future.
Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>--- MAINTAINERS | 4 + doc/api/doxy-api-index.md | 2 + lib/librte_ether/Makefile | 3 + lib/librte_ether/rte_eth_ctrl.h | 1 + lib/librte_ether/rte_ether_version.map | 11 + lib/librte_ether/rte_flow.c | 159 +++++ lib/librte_ether/rte_flow.h | 947 ++++++++++++++++++++++++++++ lib/librte_ether/rte_flow_driver.h | 182 ++++++ 8 files changed, 1309 insertions(+)MAINTAINERS +0
-0@@ -243,6 +243,10 @@ M: Thomas Monjalon<[email protected]>
F:lib/librte_ether/
F:scripts/test-null.shMAINTAINERS +4
-0+Generic flow API +M: Adrien Mazarguil <[email protected]> +F: lib/librte_ether/rte_flow* + Crypto API M: Declan Doherty <[email protected]> F: lib/librte_cryptodev/doc/api/doxy-api-index.md index renamed from doc/api/doxy-api-index.md +0
-0de65b4c..4951552 100644
doc/api/doxy-api-index.md +0
-0@@ -39,6 +39,8 @@ There are many libraries, so their headers may begrouped by topics:
[dev] (@ref rte_dev.h), [ethdev] (@ref rte_ethdev.h), [ethctrl] (@ref rte_eth_ctrl.h),doc/api/doxy-api-index.md +2
-0+ [rte_flow] (@ref rte_flow.h), + [rte_flow_driver] (@ref rte_flow_driver.h), [cryptodev] (@ref rte_cryptodev.h), [devargs] (@ref rte_devargs.h), [bond] (@ref rte_eth_bond.h),lib/librte_ether/Makefile index renamed from lib/librte_ether/Makefile +0
-0efe1e5f..9335361 100644
lib/librte_ether/Makefile +1
-0@@ -44,6 +44,7 @@ EXPORT_MAP := rte_ether_version.map LIBABIVER := 5 SRCS-y += rte_ethdev.c +SRCS-y += rte_flow.c # # Export include files@@ -51,6 +52,8 @@ SRCS-y += rte_ethdev.c SYMLINK-y-include +=
rte_ethdev.hSYMLINK-y-include +=rte_eth_ctrl.hSYMLINK-y-include +=rte_dev_info.hlib/librte_ether/Makefile +2
-0+SYMLINK-y-include += rte_flow.h +SYMLINK-y-include += rte_flow_driver.h # this lib depends upon: DEPDIRS-y += lib/librte_net lib/librte_eal lib/librte_mempool lib/librte_ring
lib/librte_mbufdiff --gita/lib/librte_ether/rte_eth_ctrl.hb/lib/librte_ether/rte_eth_ctrl.hindex fe80eb0..8386904 100644lib/librte_ether/rte_eth_ctrl.h +1
-0@@ -99,6 +99,7 @@ enum rte_filter_type {RTE_ETH_FILTER_FDIR ,RTE_ETH_FILTER_HASH ,RTE_ETH_FILTER_L2_TUNNEL , +RTE_ETH_FILTER_GENERIC , RTE_ETH_FILTER_MAX };lib/librte_ether/rte_ether_version.map +11
-0@@ -147,3 +147,14 @@ DPDK_16.11 { rte_eth_dev_pci_remove; } DPDK_16.07; + +DPDK_17.02 { + global: + + rte_flow_validate; + rte_flow_create; + rte_flow_destroy; + rte_flow_flush; + rte_flow_query; + +} DPDK_16.11;lib/librte_ether/rte_flow.c new file renamed from lib/librte_ether/rte_flow.c +0
-0mode 100644 index 0000000..d98fb1b
lib/librte_ether/rte_flow.c new file +21
-0@@ -0,0 +1,159 @@ +/*- +* 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.
+ */lib/librte_ether/rte_flow.c new file +28
-0+ +#include <stdint.h> + +#include <rte_errno.h> +#include <rte_branch_prediction.h> +#include "rte_ethdev.h" +#include "rte_flow_driver.h" +#include "rte_flow.h" + +/* Get generic flow operations structure from a port. */ const struct +rte_flow_ops *rte_flow_ops_get (uint8_t port_id,struct rte_flow_error +*error) { +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; +const struct rte_flow_ops *ops; +int code; + +if (unlikely (!rte_eth_dev_is_valid_port (port_id))) + code =ENODEV ; +else if (unlikely (!dev->dev_ops->filter_ctrl || + dev->dev_ops->filter_ctrl (dev, +RTE_ETH_FILTER_GENERIC , +RTE_ETH_FILTER_GET , + &ops) || + !ops)) + code =ENOSYS ; +else +return ops; + rte_flow_error_set(error, code,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,lib/librte_ether/rte_flow.c new file +19
-0+ NULL, rte_strerror(code)); +return NULL ; +} + +/* Check whether a flow rule can be created on a given port. */ int +rte_flow_validate (uint8_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item pattern[], +const struct rte_flow_action actions[], +struct rte_flow_error *error) +{ +const struct rte_flow_ops *ops =rte_flow_ops_get (port_id, error); +struct rte_eth_dev *dev = &rte_eth_devices[port_id]; + +if (unlikely (!ops)) +return -rte_errno; +if (likely (!!ops->validate)) +return ops->validate (dev, attr, pattern, actions, error); + rte_flow_error_set(error, ENOSYS,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,lib/librte_ether/rte_flow.c new file +19
-0+ NULL, rte_strerror(ENOSYS)); +return -rte_errno; +} + +/* Create a flow rule on a given port. */ struct rte_flow * +rte_flow_create (uint8_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item pattern[], +const struct rte_flow_action actions[], +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 (unlikely (!ops)) +return NULL ; +if (likely (!!ops->create)) +return ops->create (dev, attr, pattern, actions, error); + rte_flow_error_set(error, ENOSYS,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,lib/librte_ether/rte_flow.c new file +17
-0+ NULL, rte_strerror(ENOSYS)); +return NULL ; +} + +/* Destroy a flow rule on a given port. */ int rte_flow_destroy (uint8_t +port_id, +struct rte_flow *flow, +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 (unlikely (!ops)) +return -rte_errno; +if (likely (!!ops->destroy)) +return ops->destroy (dev, flow, error); + rte_flow_error_set(error, ENOSYS,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,lib/librte_ether/rte_flow.c new file +16
-0+ NULL, rte_strerror(ENOSYS)); +return -rte_errno; +} + +/* Destroy all flow rules associated with a port. */ int +rte_flow_flush (uint8_t port_id, +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 (unlikely (!ops)) +return -rte_errno; +if (likely (!!ops->flush)) +return ops->flush (dev, error); + rte_flow_error_set(error, ENOSYS,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,lib/librte_ether/rte_flow.c new file +20
-0+ NULL, rte_strerror(ENOSYS)); +return -rte_errno; +} + +/* Query an existing flow rule. */ +int +rte_flow_query (uint8_t port_id, +struct rte_flow *flow, +enum rte_flow_action_type action, +void *data, +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->query)) +return ops->query (dev, flow, action, data, error); + rte_flow_error_set(error, ENOSYS,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,lib/librte_ether/rte_flow.c new file +3
-0+ NULL, rte_strerror(ENOSYS)); +return -rte_errno; +}lib/librte_ether/rte_flow.h new file renamed from lib/librte_ether/rte_flow.h +0
-0mode 100644 index 0000000..98084ac
lib/librte_ether/rte_flow.h new file +21
-0@@ -0,0 +1,947 @@ +/*- +* 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.
+ */lib/librte_ether/rte_flow.h new file +80
-0+ +#ifndef RTE_FLOW_H_ +#define RTE_FLOW_H_ + +/** + * @file + * RTE generic flow API + * + * This interface provides the ability to program packet matching and + * associated actions in hardware through flow rules. + */ + +#include <rte_arp.h> +#include <rte_ether.h> +#include <rte_icmp.h> +#include <rte_ip.h> +#include <rte_sctp.h> +#include <rte_tcp.h> +#include <rte_udp.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Flow rule attributes. + * + * Priorities are set on two levels: per group and per rule within groups. + * + * Lower values denote higher priority, the highest priority for both +levels + * is 0, so that a rule with priority 0 in group 8 is always matched +after a + * rule with priority 8 in group 0. + * + * Although optional, applications are encouraged to group similar +rules as + * much as possible to fully take advantage of hardware capabilities + * (e.g. optimized matching) and work around limitations (e.g. a single + * pattern type possibly allowed in a given group). + * + * Group and priority levels are arbitrary and up to the application, +they + * do not need to be contiguous nor start from 0, however the maximum +number + * varies between devices and may be affected by existing flow rules. + * + * If a packet is matched by several rules of a given group for a given + * priority level, the outcome is undefined. It can take any path, may +be + * duplicated or even cause unrecoverable errors. + * + * Note that support for more than a single group and priority level is +not + * guaranteed. + * + * Flow rules can apply to inbound and/or outbound traffic (ingress/egress). + * + * Several pattern items and actions are valid and can be used in both + * directions. Those valid for only one direction are described as such. + * + * At least one direction must be specified. + * + * Specifying both directions at once for a given rule is not +recommended + * but may be valid in a few cases (e.g. shared counter). + */ +struct rte_flow_attr { + uint32_t group; /**< Priority group. */ + uint32_t priority; /**< Priority level within group. */ + uint32_t ingress:1; /**< Rule applies to ingress traffic. */ + uint32_t egress:1; /**< Rule applies to egress traffic. */ + uint32_t reserved:30; /**< Reserved, must be zero. */ }; + +/** + * Matching pattern item types. + * + * Pattern items fall in two categories: + * + * - Matching protocol headers and packet data (ANY, RAW, ETH, VLAN,IPV4,
+ * IPV6, ICMP, UDP, TCP, SCTP, VXLAN and so on), usually associated with a + * specification structure. These must be stacked in the same order as the + * protocol layers to match, starting from the lowest. + * + * - Matching meta-data or affecting pattern processing (END, VOID, INVERT, + * PF, VF, PORT and so on), often without a specification structure. Since + * they do not match packet contents, these can be specified anywhere + * within item lists without affecting others.+ *
+ * See the description of individual types for more information. Those
+ * marked with [META] fall into the second category.
+ */lib/librte_ether/rte_flow.h new file +403
-0+enum rte_flow_item_type { +/** +* [META] +* +* End marker for item lists. Prevents further processing of items, +* thereby ending the pattern. +* +* No associated specification structure. +*/ +RTE_FLOW_ITEM_TYPE_END , + +/** +* [META] +* +* Used as a placeholder for convenience. It is ignored and simply +* discarded by PMDs. +* +* No associated specification structure. +*/ +RTE_FLOW_ITEM_TYPE_VOID , + +/** +* [META] +* +* Inverted matching, i.e. process packets that do not match the +* pattern. +* +* No associated specification structure. +*/ +RTE_FLOW_ITEM_TYPE_INVERT , + +/** +* Matches any protocol in place of the current layer, a single ANY +* may also stand for several protocol layers. +* +* See struct rte_flow_item_any. +*/ +RTE_FLOW_ITEM_TYPE_ANY , + +/** +* [META] +* +* Matches packets addressed to the physical function of the device. +* +* If the underlying device function differs from the one that would +* normally receive the matched traffic, specifying this item +* prevents it from reaching that device unless the flow rule +* contains a PF action. Packets are not duplicated between device +* instances by default. +* +* No associated specification structure. +*/ +RTE_FLOW_ITEM_TYPE_PF , + +/** +* [META] +* +* Matches packets addressed to a virtual function ID of the device. +* +* If the underlying device function differs from the one that would +* normally receive the matched traffic, specifying this item +* prevents it from reaching that device unless the flow rule +* contains a VF action. Packets are not duplicated between device +* instances by default. +* +* See struct rte_flow_item_vf. +*/ +RTE_FLOW_ITEM_TYPE_VF , + +/** +* [META] +* +* Matches packets coming from the specified physical port of the +* underlying device. +* +* The first PORT item overrides the physical port normally +* associated with the specified DPDK input port (port_id). This +* item can be provided several times to match additional physical +* ports. +* +* See struct rte_flow_item_port. +*/ +RTE_FLOW_ITEM_TYPE_PORT , + +/** +* Matches a byte string of a given length at a given offset. +* +* See struct rte_flow_item_raw. +*/ +RTE_FLOW_ITEM_TYPE_RAW , + +/** +* Matches an Ethernet header. +* +* See struct rte_flow_item_eth. +*/ +RTE_FLOW_ITEM_TYPE_ETH , + +/** +* Matches an 802.1Q/ad VLAN tag. +* +* See struct rte_flow_item_vlan. +*/ +RTE_FLOW_ITEM_TYPE_VLAN , + +/** +* Matches an IPv4 header. +* +* See struct rte_flow_item_ipv4. +*/ +RTE_FLOW_ITEM_TYPE_IPV4 , + +/** +* Matches an IPv6 header. +* +* See struct rte_flow_item_ipv6. +*/ +RTE_FLOW_ITEM_TYPE_IPV6 , + +/** +* Matches an ICMP header. +* +* See struct rte_flow_item_icmp. +*/ +RTE_FLOW_ITEM_TYPE_ICMP , + +/** +* Matches a UDP header. +* +* See struct rte_flow_item_udp. +*/ +RTE_FLOW_ITEM_TYPE_UDP , + +/** +* Matches a TCP header. +* +* See struct rte_flow_item_tcp. +*/ +RTE_FLOW_ITEM_TYPE_TCP , + +/** +* Matches a SCTP header. +* +* See struct rte_flow_item_sctp. +*/ +RTE_FLOW_ITEM_TYPE_SCTP , + +/** +* Matches a VXLAN header. +* +* See struct rte_flow_item_vxlan. +*/ +RTE_FLOW_ITEM_TYPE_VXLAN , +}; + +/** +* RTE_FLOW_ITEM_TYPE_ANY +* +* Matches any protocol in place of the current layer, a single ANY may +also +* stand for several protocol layers. +* +* This is usually specified as the first pattern item when looking for +a +* protocol anywhere in a packet. +* +* A zeroed mask stands for any number of layers. +*/ +struct rte_flow_item_any { +uint32_t num;/* Number of layers covered. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_VF +* +* Matches packets addressed to a virtual function ID of the device. +* +* If the underlying device function differs from the one that would +* normally receive the matched traffic, specifying this item prevents +it +* from reaching that device unless the flow rule contains a VF +* action. Packets are not duplicated between device instances by default. +* +* - Likely to return an error or never match any traffic if this causes a +* VF device to match traffic addressed to a different VF. +* - Can be specified multiple times to match traffic addressed to several +* VF IDs. +* - Can be combined with a PF item to match both PF and VF traffic. +* +* A zeroed mask can be used to match any VF ID. +*/ +struct rte_flow_item_vf { +uint32_t id;/**< Destination VF ID. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_PORT +* +* Matches packets coming from the specified physical port of the +underlying +* device. +* +* The first PORT item overrides the physical port normally associated +with +* the specified DPDK input port (port_id). This item can be provided +* several times to match additional physical ports. +* +* Note that physical ports are not necessarily tied to DPDK input +ports +* (port_id) when those are not under DPDK control. Possible values are +* specific to each device, they are not necessarily indexed from zero +and +* may not be contiguous. +* +* As a device property, the list of allowed values as well as the +value +* associated with a port_id should be retrieved by other means. +* +* A zeroed mask can be used to match any port index. +*/ +struct rte_flow_item_port { +uint32_t index;/**< Physical port index. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_RAW +* +* Matches a byte string of a given length at a given offset. +* +* Offset is either absolute (using the start of the packet) or +relative to +* the end of the previous matched item in the stack, in which case +negative +* values are allowed. +* +* If search is enabled, offset is used as the starting point. The +search +* area can be delimited by setting limit to a nonzero value, which is +the +* maximum number of bytes after offset where the pattern may start. +* +* Matching a zero-length pattern is allowed, doing so resets the +relative +* offset for subsequent items. +* +* This type does not support ranges (struct rte_flow_item.last). +*/ +struct rte_flow_item_raw { +uint32_t relative:1 ;/**< Look for pattern after the previous item. */ +uint32_t search:1 ;/**< Search pattern from offset (see also limit). */ +uint32_t reserved:30 ;/**< Reserved, must be set to zero. */ +int32_t offset;/**< Absolute or relative offset for pattern. */ +uint16_t limit;/**< Search area limit for start of pattern. */ +uint16_t length;/**< Pattern length. */ +uint8_t pattern[];/**< Byte string to look for. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_ETH +* +* Matches an Ethernet header. +*/ +struct rte_flow_item_eth { +struct ether_addr dst;/**< Destination MAC. */ +struct ether_addr src;/**< Source MAC. */ +uint16_t type;/**< EtherType. */ +}; + +/** +* RTE_FLOW_ITEM_TYPE_VLAN +* +* Matches an 802.1Q/ad VLAN tag. +* +* This type normally follows either RTE_FLOW_ITEM_TYPE_ETH or +* RTE_FLOW_ITEM_TYPE_VLAN. +*/ +struct rte_flow_item_vlan { +uint16_t tpid;/**< Tag protocol identifier. */ +uint16_t tci;/**< Tag control information. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_IPV4 +* +* Matches an IPv4 header. +* +* Note: IPv4 options are handled by dedicated pattern items. +*/ +struct rte_flow_item_ipv4 { +struct ipv4_hdr hdr;/**< IPv4 header definition. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_IPV6. +* +* Matches an IPv6 header. +* +* Note: IPv6 options are handled by dedicated pattern items. +*/ +struct rte_flow_item_ipv6 { +struct ipv6_hdr hdr;/**< IPv6 header definition. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_ICMP. +* +* Matches an ICMP header. +*/ +struct rte_flow_item_icmp { +struct icmp_hdr hdr;/**< ICMP header definition. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_UDP. +* +* Matches a UDP header. +*/ +struct rte_flow_item_udp { +struct udp_hdr hdr;/**< UDP header definition. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_TCP. +* +* Matches a TCP header. +*/ +struct rte_flow_item_tcp { +struct tcp_hdr hdr;/**< TCP header definition. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_SCTP. +* +* Matches a SCTP header. +*/ +struct rte_flow_item_sctp { +struct sctp_hdr hdr;/**< SCTP header definition. */ }; + +/** +* RTE_FLOW_ITEM_TYPE_VXLAN. +* +* Matches a VXLAN header (RFC 7348). +*/ +struct rte_flow_item_vxlan { +uint8_t flags;/**< Normally 0x08 (I flag). */ +uint8_t rsvd0[3 ];/**< Reserved, normally 0x000000. */ +uint8_t vni[3 ];/**< VXLAN identifier. */ +uint8_t rsvd1;/**< Reserved, normally 0x00. */ }; + +/** +* Matching pattern item definition. +* +* A pattern is formed by stacking items starting from the lowest +protocol +* layer to match. This stacking restriction does not apply to meta +items +* which can be placed anywhere in the stack without affecting the +meaning +* of the resulting pattern. +* +* Patterns are terminated by END items. +* +* The spec field should be a valid pointer to a structure of the +related +* item type. It may be set to NULL in many cases to use default values. +* +* Optionally, last can point to a structure of the same type to define +an +* inclusive range. This is mostly supported by integer and address +fields, +* may cause errors otherwise. Fields that do not support ranges must +be set +* to 0 or to the same value as the corresponding fields in spec. +* +* By default all fields present in spec are considered relevant (see +note +* below). This behavior can be altered by providing a mask structure +of the +* same type with applicable bits set to one. It can also be used to +* partially filter out specific fields (e.g. as an alternate mean to +match +* ranges of IP addresses). +* +* Mask is a simple bit-mask applied before interpreting the contents +of +* spec and last, which may yield unexpected results if not used +* carefully. For example, if for an IPv4 address field, spec provides +* 10.1.2.3, last provides 10.3.4.5 and mask provides 255.255.0.0, the +* effective range becomes 10.1.0.0 to 10.3.255.255. +* +* Note: the defaults for data-matching items such as IPv4 when mask is +not +* specified actually depend on the underlying implementation since +only +* recognized fields can be taken into account. +*/ +struct rte_flow_item { +enum rte_flow_item_type type;/**< Item type. */ +const void *spec;/**< Pointer to item specification structure. */ +const void *last;/**< Defines an inclusive range (spec to last). */ +const void *mask;/**< Bit-mask applied to spec and last. */ }; + +/** +* Action types. +* +* Each possible action is represented by a type. Some have associated +* configuration structures. Several actions combined in a list can be +* affected to a flow rule. That list is not ordered. +* +* They fall in three categories: +* +* - Terminating actions (such as QUEUE, DROP, RSS, PF, VF) that prevent +* processing matched packets by subsequent flow rules, unless overridden
+ * with PASSTHRU.
+ *
+ * - Non terminating actions (PASSTHRU, DUP) that leave matched packets up
+ * for additional processing by subsequent flow rules.
+ *
+ * - Other non terminating meta actions that do not affect the fate of
+ * packets (END, VOID, MARK, FLAG, COUNT).
+ *
+ * When several actions are combined in a flow rule, they should alllib/librte_ether/rte_flow.h new file +83
-0+have +* different types (e.g. dropping a packet twice is not possible). +* +* Only the last action of a given type is taken into account. PMDs +still +* perform error checking on the entire list. +* +* Note that PASSTHRU is the only action able to override a terminating +* rule. +*/ +enum rte_flow_action_type { +/** +* [META] +* +* End marker for action lists. Prevents further processing of +* actions, thereby ending the list. +* +* No associated configuration structure. +*/ +RTE_FLOW_ACTION_TYPE_END , + +/** +* [META] +* +* Used as a placeholder for convenience. It is ignored and simply +* discarded by PMDs. +* +* No associated configuration structure. +*/ +RTE_FLOW_ACTION_TYPE_VOID , + +/** +* Leaves packets up for additional processing by subsequent flow +* rules. This is the default when a rule does not contain a +* terminating action, but can be specified to force a rule to +* become non-terminating. +* +* No associated configuration structure. +*/ +RTE_FLOW_ACTION_TYPE_PASSTHRU , + +/** +* [META] +* +* Attaches a 32 bit value to packets. +* +* See struct rte_flow_action_mark. +*/ +RTE_FLOW_ACTION_TYPE_MARK , + +/** +* [META] +* +* Flag packets. Similar to MARK but only affects ol_flags. +* +* Note: a distinctive flag must be defined for it. +* +* No associated configuration structure. +*/ +RTE_FLOW_ACTION_TYPE_FLAG , + +/** +* Assigns packets to a given queue index. +* +* See struct rte_flow_action_queue. +*/ +RTE_FLOW_ACTION_TYPE_QUEUE , + +/** +* Drops packets. +* +* PASSTHRU overrides this action if both are specified. +* +* No associated configuration structure. +*/ +RTE_FLOW_ACTION_TYPE_DROP , + +/** +* [META] +* +* Enables counters for this rule. +* +* These counters can be retrieved and reset through
rte_flow_query(),lib/librte_ether/rte_flow.h new file +10
-0+* see struct rte_flow_query_count. +* +* No associated configuration structure. +*/ + RTE_FLOW_ACTION_TYPE_COUNT, + +/** +* Duplicates packets to a given queue index. +* +* This is normally combined with QUEUE, however when used alone, it
lib/librte_ether/rte_flow.h new file +87
-0+* is actually similar to QUEUE + PASSTHRU. +* +* See struct rte_flow_action_dup. +*/ +RTE_FLOW_ACTION_TYPE_DUP , + +/** +* Similar to QUEUE, except RSS is additionally performed on packets +* to spread them among several queues according to the provided +* parameters. +* +* See struct rte_flow_action_rss. +*/ +RTE_FLOW_ACTION_TYPE_RSS , + +/** +* Redirects packets to the physical function (PF) of the current +* device. +* +* No associated configuration structure. +*/ +RTE_FLOW_ACTION_TYPE_PF , + +/** +* Redirects packets to the virtual function (VF) of the current +* device with the specified ID. +* +* See struct rte_flow_action_vf. +*/ + RTE_FLOW_ACTION_TYPE_VF, +}; + +/** +* RTE_FLOW_ACTION_TYPE_MARK +* +* Attaches a 32 bit value to packets. +* +* This value is arbitrary and application-defined. For compatibility +with +* FDIR it is returned in the hash.fdir.hi mbuf field. PKT_RX_FDIR_ID +is +* also set in ol_flags. +*/ +struct rte_flow_action_mark { +uint32_t id;/**< 32 bit value to return with packets. */ }; + +/** +* RTE_FLOW_ACTION_TYPE_QUEUE +* +* Assign packets to a given queue index. +* +* Terminating by default. +*/ +struct rte_flow_action_queue { +uint16_t index;/**< Queue index to use. */ }; + +/** +* RTE_FLOW_ACTION_TYPE_COUNT (query) +* +* Query structure to retrieve and reset flow rule counters. +*/ +struct rte_flow_query_count { +uint32_t reset:1 ;/**< Reset counters after query [in]. */ +uint32_t hits_set:1 ;/**< hits field is set [out]. */ +uint32_t bytes_set:1 ;/**< bytes field is set [out]. */ +uint32_t reserved:29 ;/**< Reserved, must be zero [in, out]. */ +uint64_t hits;/**< Number of hits for this rule [out]. */ +uint64_t bytes;/**< Number of bytes through this rule [out]. */ }; + +/** +* RTE_FLOW_ACTION_TYPE_DUP +* +* Duplicates packets to a given queue index. +* +* This is normally combined with QUEUE, however when used alone, it is +* actually similar to QUEUE + PASSTHRU. +* +* Non-terminating by default. +*/ +struct rte_flow_action_dup { +uint16_t index;/**< Queue index to duplicate packets to. */ }; + +/** +* RTE_FLOW_ACTION_TYPE_RSS +* +* Similar to QUEUE, except RSS is additionally performed on packets to +* spread them among several queues according to the provided parameters.
+ *
+ * Note: RSS hash result is normally stored in the hash.rss mbuf field,
+ * however it conflicts with the MARK action as they share the same
+ * space. When both actions are specified, the RSS hash is discardedlib/librte_ether/rte_flow.h new file +71
-0+and +* PKT_RX_RSS_HASH is not set in ol_flags. MARK has priority. The mbuf +* structure should eventually evolve to store both. +* +* Terminating by default. +*/ +struct rte_flow_action_rss { +const struct rte_eth_rss_conf *rss_conf;/**< RSS parameters. */ +uint16_t num;/**< Number of entries in queue[]. */ +uint16_t queue[];/**< Queues indices to use. */ }; + +/** +* RTE_FLOW_ACTION_TYPE_VF +* +* Redirects packets to a virtual function (VF) of the current device. +* +* Packets matched by a VF pattern item can be redirected to their +original +* VF ID instead of the specified one. This parameter may not be +available +* and is not guaranteed to work properly if the VF part is matched by +a +* prior flow rule or if packets are not addressed to a VF in the first +* place. +* +* Terminating by default. +*/ +struct rte_flow_action_vf { +uint32_t original:1 ;/**< Use original VF ID if possible. */ +uint32_t reserved:31 ;/**< Reserved, must be zero. */ +uint32_t id;/**< VF ID to redirect packets to. */ }; + +/** +* Definition of a single action. +* +* A list of actions is terminated by a END action. +* +* For simple actions without a configuration structure, conf remains NULL. +*/ +struct rte_flow_action { +enum rte_flow_action_type type;/**< Action type. */ +const void *conf;/**< Pointer to action configuration structure. */ +}; + +/** +* Opaque type returned after successfully creating a flow. +* +* This handle can be used to manage and query the related flow (e.g. +to +* destroy it or retrieve counters). +*/ +struct rte_flow ; + +/** +* Verbose error types. +* +* Most of them provide the type of the object referenced by struct +* rte_flow_error.cause. +*/ +enum rte_flow_error_type { +RTE_FLOW_ERROR_TYPE_NONE ,/**< No error. */ +RTE_FLOW_ERROR_TYPE_UNSPECIFIED ,/**< Cause unspecified. */ +RTE_FLOW_ERROR_TYPE_HANDLE ,/**< Flow rule (handle). */ +RTE_FLOW_ERROR_TYPE_ATTR_GROUP ,/**< Group field. */ +RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY ,/**< Priority field. */ +RTE_FLOW_ERROR_TYPE_ATTR_INGRESS ,/**< Ingress field. */ +RTE_FLOW_ERROR_TYPE_ATTR_EGRESS ,/**< Egress field. */ +RTE_FLOW_ERROR_TYPE_ATTR ,/**< Attributes structure. */ +RTE_FLOW_ERROR_TYPE_ITEM_NUM ,/**< Pattern length. */ +RTE_FLOW_ERROR_TYPE_ITEM ,/**< Specific pattern item. */ +RTE_FLOW_ERROR_TYPE_ACTION_NUM ,/**< Number of actions. */
lib/librte_ether/rte_flow.h new file +19
-0+ RTE_FLOW_ERROR_TYPE_ACTION, /**< Specific action. */ }; + +/** +* Verbose error structure definition. +* +* This object is normally allocated by applications and set by PMDs, +the +* message points to a constant string which does not need to be freed +by +* the application, however its pointer can be considered valid only as +long +* as its associated DPDK port remains configured. Closing the +underlying +* device or unloading the PMD invalidates it. +* +* Both cause and message may be NULL regardless of the error type. +*/ +struct rte_flow_error { +enum rte_flow_error_type type;/**< Cause field and error types. */
lib/librte_ether/rte_flow.h new file +172
-0+const void *cause;/**< Object responsible for the error. */ + const char *message; /**< Human-readable error message. */ }; + +/** +* Check whether a flow rule can be created on a given port. +* +* While this function has no effect on the target device, the flow +rule is +* validated against its current configuration state and the returned +value +* should be considered valid by the caller for that state only. +* +* The returned value is guaranteed to remain valid only as long as no +* successful calls to rte_flow_create() or rte_flow_destroy() are made +in +* the meantime and no device parameter affecting flow rules in any way +are +* modified, due to possible collisions or resource limitations +(although in +* such cases EINVAL should not be returned). +* +* @param port_id +* Port identifier of Ethernet device. +* @param[in] attr +* Flow rule attributes. +* @param[in] pattern +* Pattern specification (list terminated by the END pattern item). +* @param[in] actions +* Associated actions (list terminated by the END action). +* @param[out] error +* Perform verbose error reporting if not NULL. PMDs initialize this +* structure in case of error only. +* +* @return +* 0 if flow rule is valid and can be created. A negative errno value +* otherwise (rte_errno is also set), the following errors are defined: +* +* -ENOSYS: underlying device does not support this functionality. +* +* -EINVAL: unknown or invalid rule specification. +* +* -ENOTSUP: valid but unsupported rule specification (e.g. partial +* bit-masks are unsupported). +* +* -EEXIST: collision with an existing rule. +* +* -ENOMEM: not enough resources. +* +* -EBUSY: action cannot be performed due to busy device resources, may +* succeed if the affected queues or even the entire port are in a stopped +* state (see rte_eth_dev_rx_queue_stop() and rte_eth_dev_stop()). +*/ +int +rte_flow_validate (uint8_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item pattern[], +const struct rte_flow_action actions[], +struct rte_flow_error *error); + +/** +* Create a flow rule on a given port. +* +* @param port_id +* Port identifier of Ethernet device. +* @param[in] attr +* Flow rule attributes. +* @param[in] pattern +* Pattern specification (list terminated by the END pattern item). +* @param[in] actions +* Associated actions (list terminated by the END action). +* @param[out] error +* Perform verbose error reporting if not NULL. PMDs initialize this +* structure in case of error only. +* +* @return +* A valid handle in case of success, NULL otherwise and rte_errno is set +* to the positive version of one of the error codes defined for +* rte_flow_validate(). +*/ +struct rte_flow * +rte_flow_create (uint8_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item pattern[], +const struct rte_flow_action actions[], +struct rte_flow_error *error); + +/** +* Destroy a flow rule on a given port. +* +* Failure to destroy a flow rule handle may occur when other flow +rules +* depend on it, and destroying it would result in an inconsistent state. +* +* This function is only guaranteed to succeed if handles are destroyed +in +* reverse order of their creation. +* +* @param port_id +* Port identifier of Ethernet device. +* @param flow +* Flow rule handle to destroy. +* @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_destroy (uint8_t port_id, +struct rte_flow *flow, +struct rte_flow_error *error); + +/** +* Destroy all flow rules associated with a port. +* +* In the unlikely event of failure, handles are still considered +destroyed +* and no longer valid but the port must be assumed to be in an +inconsistent +* state. +* +* @param port_id +* Port identifier of Ethernet device. +* @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_flush (uint8_t port_id, +struct rte_flow_error *error); + +/** +* Query an existing flow rule. +* +* This function allows retrieving flow-specific data such as counters. +* Data is gathered by special actions which must be present in the +flow +* rule definition. +* +* \see RTE_FLOW_ACTION_TYPE_COUNT +* +* @param port_id +* Port identifier of Ethernet device. +* @param flow +* Flow rule handle to query. +* @param action +* Action type to query. +* @param[in, out] data +* Pointer to storage for the associated query data type. +* @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_query (uint8_t port_id, +struct rte_flow *flow, +enum rte_flow_action_type action, +void *data, +struct rte_flow_error *error); + +#ifdef __cplusplus +} +#endif + +#endif /* RTE_FLOW_H_ */ lib/librte_ether/rte_flow_driver.h new file +21
-0@@ -0,0 +1,182 @@ +/*- +* 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.
+ */lib/librte_ether/rte_flow_driver.h new file +157
-1+ +#ifndef RTE_FLOW_DRIVER_H_ +#define RTE_FLOW_DRIVER_H_ + +/** +* @file +* RTE generic flow API (driver side) +* +* This file provides implementation helpers for internal use by PMDs, +they +* are not intended to be exposed to applications and are not subject +to ABI +* versioning. +*/ + +#include <stdint.h> + +#include <rte_errno.h> +#include <rte_ethdev.h> +#include "rte_flow.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** +* Generic flow operations structure implemented and returned by PMDs. +* +* To implement this API, PMDs must handle the RTE_ETH_FILTER_GENERIC +filter +* type in their .filter_ctrl callback function (struct eth_dev_ops) as +well +* as the RTE_ETH_FILTER_GET filter operation. +* +* If successful, this operation must result in a pointer to a +PMD-specific +* struct rte_flow_ops written to the argument address as described below: +* +* \code +* +* // PMD filter_ctrl callback +* +* static const struct rte_flow_ops pmd_flow_ops = { ... }; +* +* switch (filter_type) { +* case RTE_ETH_FILTER_GENERIC: +* if (filter_op != RTE_ETH_FILTER_GET) +* return -EINVAL; +* *(const void **)arg = &pmd_flow_ops; +* return 0; +* } +* +* \endcode +* +* See also rte_flow_ops_get(). +* +* These callback functions are not supposed to be used by applications +* directly, which must rely on the API defined in rte_flow.h. +* +* Public-facing wrapper functions perform a few consistency checks so +that +* unimplemented (i.e. NULL) callbacks simply return -ENOTSUP. These +* callbacks otherwise only differ by their first argument (with port +ID +* already resolved to a pointer to struct rte_eth_dev). +*/ +struct rte_flow_ops { +/** See rte_flow_validate(). */ +int (*validate) + (struct rte_eth_dev *, +const struct rte_flow_attr *, +const struct rte_flow_item [], +const struct rte_flow_action [], +struct rte_flow_error *); +/** See rte_flow_create(). */ +struct rte_flow *(*create) + (struct rte_eth_dev *, +const struct rte_flow_attr *, +const struct rte_flow_item [], +const struct rte_flow_action [], +struct rte_flow_error *); +/** See rte_flow_destroy(). */ +int (*destroy) + (struct rte_eth_dev *, +struct rte_flow *, +struct rte_flow_error *); +/** See rte_flow_flush(). */ +int (*flush) + (struct rte_eth_dev *, +struct rte_flow_error *); +/** See rte_flow_query(). */ +int (*query) + (struct rte_eth_dev *, +struct rte_flow *, +enum rte_flow_action_type , +void *, +struct rte_flow_error *); +}; + +/** +* Initialize generic flow error structure. +* +* This function also sets rte_errno to a given value. +* +* @param[out] error +* Pointer to flow error structure (may be NULL). +* @param code +* Related error code (rte_errno). +* @param type +* Cause field and error types. +* @param cause +* Object responsible for the error. +* @param message +* Human-readable error message. +* +* @return +* Pointer to flow error structure. +*/ +static inline struct rte_flow_error * +rte_flow_error_set (struct rte_flow_error *error, +int code, +enum rte_flow_error_type type, +const void *cause, +const char *message) +{ +if (error) { + *error = (struct rte_flow_error ){ + .type = type, + .cause = cause, + .message = message, + }; + } + rte_errno = code; +return error; +} + +/** +* Get generic flow operations structure from a port. +* +* @param port_id +* Port identifier to query. +* @param[out] error +* Pointer to flow error structure. +* +* @return +* The flow operations structure associated with port_id, NULL in case of +* error, in which case rte_errno is set and the error structure contains +* additional details. +*/ +const struct rte_flow_ops * +rte_flow_ops_get (uint8_t port_id,struct rte_flow_error *error); + +#ifdef __cplusplus +} +#endif + +#endif /* RTE_FLOW_DRIVER_H_ */ --2.1.4
Re: [PATCH v3 01/25] ethdev: introduce generic flow API
Hi Wei,
Quoted 16 lines · Wei
Hi, Adrien
lib/librte_ether/rte_flow.h
Quoted 8 lines
lib/librte_ether/rte_flow.h new file +8
-0+struct rte_flow_item_raw { +uint32_t relative:1 ;/**< Look for pattern after the previous item. */ +uint32_t search:1 ;/**< Search pattern from offset (see also limit). */ +uint32_t reserved:30 ;/**< Reserved, must be set to zero. */ +int32_t offset;/**< Absolute or relative offset for pattern. */ +uint16_t limit;/**< Search area limit for start of pattern. */ +uint16_t length;/**< Pattern length. */ +uint8_t pattern[];/**< Byte string to look for. */ };When I use this API to test igb flex filter, I find that
in the structrte_flow_item_raw, the member pattern is not the same as my purpose.
For example, If I type in " flow create 0 ingress pattern raw relative is 0 pattern is 0123 / end actions queue index 1 / end " What I get in NIC layer is pattern[]={0x30,0x31,0x32,0x33,0x0<repeats 124 times> }.
But what I need is pattern[]={0x01,0x23,0x0<repeats 126 times>}
Similar limitation as I answered in [1] then. This is not a problem in the rte_flow API, it's only that the testpmd parser currently provides unprocessed strings to the PMD, and there is currently no method to work around that.
Quoted 21 lines
About the format change of
flex_filter, I have reference to the testpmd functioncmd_flex_filter_parsed(), There is details of format change from ASIC code to data, for example:for (i = 0; i < len; i++) { c = bytes_ptr[i]; if (isxdigit(c) == 0) { /* invalid characters. */ printf("invalid input\n"); return; } val = xdigit2val(c); if (i % 2) { byte |= val; filter.bytes[j] = byte; printf("bytes[%d]:%02x ", j, filter.bytes[j]); j++; byte = 0; } else byte |= val << 4; }
Quoted 5 lines
and there is also usage example in the DPDK document testpmd_app_ug-16.11.pdf:
(it also not use ASIC code)testpmd>
flex_filter0 add len 16 bytes0x00000000000000000000000008060000\
mask 000C priority 3 queue 3
I understand, the difference between both commands is only that unlike flex_filter, flow does not interpret the provided string as hexadecimal.
Quoted 1 line
so, will our new generic flow API align to the old format in flex byte filter in 17.08 or in the future?
What I have in mind instead is a printf-like input method. Using the rule you provided above:
flow create 0 ingress pattern raw relative is 0 pattern is 0123 / end actions queue index 1 / end
Will always yield "0123", however:
flow create 0 ingress pattern raw relative is 0 pattern is \x00\x01\x02\x03 / end actions queue index 1 / end
Will yield the intended pattern. Currently this format is interpreted as is (you'll get "\x00\x01\x02\x03") however escape interpretation is in the plans.
Quoted 1 line
At least in the struct
rte_flow_item_raw, the member pattern is the same as old filter?
It is the same as the old filter, except you cannot provide it in hexadecimal format yet. No changes needed on the PMD side in any case.
Again, this is only a testpmd implementation issue, that doesn't prevent developers from creating programs that directly provide binary data to RAW items, there's no such limitation.
[1] http://dpdk.org/ml/archives/dev/2017-May/065798.html
Signature · 2 lines
Adrien Mazarguil 6WIND
Re: [PATCH v3 01/25] ethdev: introduce generic flow API
Hi,
Quoted 76 lines
-----Original Message-----
From: Adrien Mazarguil [mailto:[email protected]]
Sent: Tuesday, May 23, 2017 5:51 PM
To: Zhao1, Wei <[email protected]>
Cc: [email protected]; Xing, Beilei <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 01/25] ethdev: introduce generic flow APIHi Wei,
Quoted 11 lines · Wei
Hi, Adrien
Quoted 8 lines
+struct
rte_flow_item_raw{
+uint32_trelative:1; /**< Look for pattern after the previous item. */
+uint32_tsearch:1; /**< Search pattern from offset (see also limit). */
+uint32_treserved:30; /**< Reserved, must be set to zero. */
+int32_toffset; /**< Absolute or relative offset for pattern. */
+uint16_tlimit; /**< Search area limit for start of pattern. */
+uint16_tlength; /**< Pattern length. */
+uint8_tpattern[]; /**< Byte string to look for. */ };Quoted 3 lines
When I use this API to test igb flex filter, I find that in the struct
rte_flow_item_raw, the member pattern is not the same as my purpose. For example, If I type in " flow create 0 ingress pattern raw relative is 0pattern is 0123 / end actions queue index 1 / end "
Quoted 1 line
What I get in NIC layer is pattern[]={
0x30,0x31,0x32,0x33,0x0<repeats124 times> }.
Quoted 1 line
But what I need is pattern[]={0x01,
0x23,0x0<repeats 126 times>}Similar limitation as I answered in [1] then. This is not a problem in the
rte_flowAPI, it's only that the testpmd parser currently provides unprocessed strings to the PMD, and there is currently no method to work around that.Quoted 2 lines
About the format change of
flex_filter, I have reference to the testpmd functioncmd_flex_filter_parsed(), There is details of formatchange from ASIC code to data, for example:
Quoted 19 lines
for (i = 0; i < len; i++) { c = bytes_ptr[i]; if (isxdigit(c) == 0) { /* invalid characters. */ printf("invalid input\n"); return; } val = xdigit2val(c); if (i % 2) { byte |= val; filter.bytes[j] = byte; printf("bytes[%d]:%02x ", j, filter.bytes[j]); j++; byte = 0; } else byte |= val << 4; }Quoted 1 line
and there is also usage example in the DPDK document testpmd_app_ug-
16.11.pdf:
Quoted 5 lines
(it also not use ASIC code)
testpmd>
flex_filter0 add len 16 bytes
testpmd>0x00000000000000000000000008060000\
mask 000C priority 3 queue 3I understand, the difference between both commands is only that unlike
flex_filter, flow does not interpret the provided string as hexadecimal.Quoted 1 line
so, will our new generic flow API align to the old format in flex byte filter in
17.08 or in the future?
What I have in mind instead is a printf-like input method. Using the rule you provided above:
flow create 0 ingress pattern raw relative is 0 pattern is 0123 / end actions
queue index 1 / end
Quoted 8 lines
Will always yield "0123", however:
flow create 0 ingress pattern raw relative is 0 pattern is \x00\x01\x02\x03 /
end actions queue index 1 / endWill yield the intended pattern. Currently this format is interpreted as is (you'll get "\x00\x01\x02\x03") however escape interpretation is in the plans.
Thank you for your explanation. But there is some key point I want to repeat:
For example, If I type in " flow create 0 ingress pattern raw relative is 0 pattern is 0123 / end actions queue index 1 / end " Or maybe more accurate, " flow create 0 ingress pattern raw relative is 0 pattern is 0x0123 / end actions queue index 1 / end " what I need is pattern[]={0x01, 0x23, 0x0 <repeats 126 times>}.
not pattern[]={ 0x00, 0x01, 0x02, 0x03, 0x0 <repeats 124 times> }.
And also, not pattern[]={ 0x30, 0x31, 0x32, 0x33, 0x0 <repeats 124 times> }.
And this problem is not a block for code develop for 17.08, but it is needed for tester and user in the feature.
Quoted 15 lines
Quoted 1 line
At least in the struct
rte_flow_item_raw, the member pattern is the sameas old filter?
It is the same as the old filter, except you cannot provide it in hexadecimal format yet. No changes needed on the PMD side in any case.
Again, this is only a testpmd implementation issue, that doesn't prevent developers from creating programs that directly provide binary data to RAW items, there's no such limitation.
[1] http://dpdk.org/ml/archives/dev/2017-May/065798.html
--
Adrien Mazarguil
6WIND
Re: [PATCH v3 01/25] ethdev: introduce generic flow API
Quoted 87 lines · Wei
Hi,
Quoted 76 lines
-----Original Message-----
From: Adrien Mazarguil [mailto:[email protected]]
Sent: Tuesday, May 23, 2017 5:51 PM
To: Zhao1, Wei <[email protected]>
Cc: [email protected]; Xing, Beilei <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 01/25] ethdev: introduce generic flow APIHi Wei,
Quoted 11 lines · Wei
Hi, Adrien
Quoted 8 lines
+struct
rte_flow_item_raw{
+uint32_trelative:1; /**< Look for pattern after the previous item. */
+uint32_tsearch:1; /**< Search pattern from offset (see also limit). */
+uint32_treserved:30; /**< Reserved, must be set to zero. */
+int32_toffset; /**< Absolute or relative offset for pattern. */
+uint16_tlimit; /**< Search area limit for start of pattern. */
+uint16_tlength; /**< Pattern length. */
+uint8_tpattern[]; /**< Byte string to look for. */ };Quoted 3 lines
When I use this API to test igb flex filter, I find that in the struct
rte_flow_item_raw, the member pattern is not the same as my purpose. For example, If I type in " flow create 0 ingress pattern raw relative is 0pattern is 0123 / end actions queue index 1 / end "
Quoted 1 line
What I get in NIC layer is pattern[]={
0x30,0x31,0x32,0x33,0x0<repeats124 times> }.
Quoted 1 line
But what I need is pattern[]={0x01,
0x23,0x0<repeats 126 times>}Similar limitation as I answered in [1] then. This is not a problem in the
rte_flowAPI, it's only that the testpmd parser currently provides unprocessed strings to the PMD, and there is currently no method to work around that.Quoted 2 lines
About the format change of
flex_filter, I have reference to the testpmd functioncmd_flex_filter_parsed(), There is details of formatchange from ASIC code to data, for example:
Quoted 19 lines
for (i = 0; i < len; i++) { c = bytes_ptr[i]; if (isxdigit(c) == 0) { /* invalid characters. */ printf("invalid input\n"); return; } val = xdigit2val(c); if (i % 2) { byte |= val; filter.bytes[j] = byte; printf("bytes[%d]:%02x ", j, filter.bytes[j]); j++; byte = 0; } else byte |= val << 4; }Quoted 1 line
and there is also usage example in the DPDK document testpmd_app_ug-
16.11.pdf:
Quoted 5 lines
(it also not use ASIC code)
testpmd>
flex_filter0 add len 16 bytes
testpmd>0x00000000000000000000000008060000\
mask 000C priority 3 queue 3I understand, the difference between both commands is only that unlike
flex_filter, flow does not interpret the provided string as hexadecimal.Quoted 1 line
so, will our new generic flow API align to the old format in flex byte filter in
17.08 or in the future?
What I have in mind instead is a printf-like input method. Using the rule you provided above:
flow create 0 ingress pattern raw relative is 0 pattern is 0123 / end actions
queue index 1 / endQuoted 8 lines
Will always yield "0123", however:
flow create 0 ingress pattern raw relative is 0 pattern is \x00\x01\x02\x03 /
end actions queue index 1 / endWill yield the intended pattern. Currently this format is interpreted as is (you'll get "\x00\x01\x02\x03") however escape interpretation is in the plans.
Quoted 6 lines
Thank you for your explanation. But there is some key point I want to repeat:
For example, If I type in " flow create 0 ingress pattern raw relative is 0 pattern is 0123 / end actions queue index 1 / end " Or maybe more accurate, " flow create 0 ingress pattern raw relative is 0 pattern is0x0123/ end actions queue index 1 / end " what I need is pattern[]={0x01,0x23,0x0<repeats 126 times>}.
not pattern[]={0x00,0x01,0x02,0x03,0x0<repeats 124 times> }.
And also, not pattern[]={0x30,0x31,0x32,0x33,0x0<repeats 124 times> }.
Right, I misread your original pattern[] intent. You would get such a pattern by specifying \x01\x23 (just like C string literals). It would even accept octal notation "\01\043". Both would yield { 0x01, 0x23 }.
Does something like that satisfy the requirements?
Quoted 1 line
And this problem is not a block for code develop for 17.08, but it is needed for tester and user in the feature.
Well, I've actually started implementing the above long ago in testpmd but didn't have time to clean up the patch and submit it yet (moreover it was not needed until now). If the idea works for your use case, I can attempt to do that soon.
Quoted 15 lines
Quoted 15 lines
Quoted 1 line
At least in the struct
rte_flow_item_raw, the member pattern is the sameas old filter?
It is the same as the old filter, except you cannot provide it in hexadecimal format yet. No changes needed on the PMD side in any case.
Again, this is only a testpmd implementation issue, that doesn't prevent developers from creating programs that directly provide binary data to RAW items, there's no such limitation.
[1] http://dpdk.org/ml/archives/dev/2017-May/065798.html
--
Adrien Mazarguil
6WIND
Signature · 2 lines
Adrien Mazarguil 6WIND
Re: [PATCH v3 01/25] ethdev: introduce generic flow API
Hi, Adrien
Quoted 114 lines
-----Original Message-----
From: Adrien Mazarguil [mailto:[email protected]]
Sent: Wednesday, May 24, 2017 3:32 PM
To: Zhao1, Wei <[email protected]>
Cc: [email protected]; Xing, Beilei <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 01/25] ethdev: introduce generic flow APIQuoted 26 lines · Wei
Hi,
Quoted 24 lines
-----Original Message-----
From: Adrien Mazarguil [mailto:[email protected]]
Sent: Tuesday, May 23, 2017 5:51 PM
To: Zhao1, Wei <[email protected]>
Cc: [email protected]; Xing, Beilei <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 01/25] ethdev: introduce generic flow APIHi Wei,
Quoted 13 lines · Wei
Hi, Adrien
Review
Quoted 8 lines
(quoted diff) +8
-0+struct rte_flow_item_raw { + uint32_t relative:1; /**< Look for pattern after the previous +item. */ uint32_t search:1; /**< Search pattern from offset +(see also limit). */ uint32_t reserved:30; /**< Reserved, must +be set to zero. */ int32_t offset; /**< Absolute or relative +offset for pattern. */ uint16_t limit; /**< Search area limit +for start of pattern. */ uint16_t length; /**< Pattern length. +*/ uint8_t pattern[]; /**< Byte string to look for. */ };When I use this API to test igb flex filter, I find that in the struct
rte_flow_item_raw, the member pattern is not the same as mypurpose.
Quoted 39 lines
Quoted 39 lines
Quoted 2 lines
For example, If I type in " flow create 0 ingress pattern raw relative is 0
pattern is 0123 / end actions queue index 1 / end "
Quoted 2 lines
What I get in NIC layer is pattern[]={
0x30,0x31,0x32,0x33,0x0<repeats124 times> }.
Quoted 1 line
But what I need is pattern[]={0x01,
0x23,0x0<repeats 126 times>}Similar limitation as I answered in [1] then. This is not a problem in the
rte_flowAPI, it's only that the testpmd parser currently provides unprocessed strings to the PMD, and there is currently no method to work around that.Quoted 3 lines
About the format change of
flex_filter, I have reference to the testpmd functioncmd_flex_filter_parsed(), There is details of formatchange from ASIC code to data, for example:
Quoted 19 lines
for (i = 0; i < len; i++) { c = bytes_ptr[i]; if (isxdigit(c) == 0) { /* invalid characters. */ printf("invalid input\n"); return; } val = xdigit2val(c); if (i % 2) { byte |= val; filter.bytes[j] = byte; printf("bytes[%d]:%02x ", j, filter.bytes[j]); j++; byte = 0; } else byte |= val << 4; }Quoted 2 lines
and there is also usage example in the DPDK document testpmd_app_ug-
16.11.pdf:
Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
(it also not use ASIC code)
testpmd>
flex_filter0 add len 16 bytes
testpmd>0x00000000000000000000000008060000\
mask 000C priority 3 queue 3I understand, the difference between both commands is only that unlike
flex_filter, flow does not interpret the provided string ashexadecimal.
Quoted 11 lines
Quoted 11 lines
Quoted 3 lines
so, will our new generic flow API align to the old format in flex byte filter in
17.08 or in the future?
What I have in mind instead is a printf-like input method. Using the rule you provided above:
flow create 0 ingress pattern raw relative is 0 pattern is 0123 /
end actions queue index 1 / endQuoted 7 lines
Quoted 7 lines
Will always yield "0123", however:
flow create 0 ingress pattern raw relative is 0 pattern is
\x00\x01\x02\x03 / end actions queue index 1 / endWill yield the intended pattern. Currently this format is interpreted as is (you'll get "\x00\x01\x02\x03") however escape
interpretation is in the plans.
Quoted 3 lines
Quoted 1 line
Thank you for your explanation. But there is some key point I want to
repeat:
Quoted 1 line
For example, If I type in " flow create 0 ingress pattern raw relative is 0
pattern is 0123 / end actions queue index 1 / end "
Quoted 1 line
Or maybe more accurate, " flow create 0 ingress pattern raw relative is 0
pattern is
0x0123/ end actions queue index 1 / end "Quoted 3 lines
what I need is pattern[]={0x01,
0x23,0x0<repeats 126 times>}. not pattern[]={0x00,0x01,0x02,0x03,0x0<repeats 124 times> }. And also, not pattern[]={0x30,0x31,0x32,0x33,0x0<repeats 124 times> }.
Quoted 5 lines
Right, I misread your original pattern[] intent. You would get such a pattern by specifying \x01\x23 (just like C string literals). It would even accept octal notation "\01\043". Both would yield {
0x01,0x23}.Does something like that satisfy the requirements?
Yes, After the repeat, I think we both understand each other.
Quoted 9 lines
Quoted 2 lines
And this problem is not a block for code develop for 17.08, but it is needed
for tester and user in the feature.
Well, I've actually started implementing the above long ago in testpmd but didn't have time to clean up the patch and submit it yet (moreover it was not needed until now). If the idea works for your use case, I can attempt to do that soon.
All that decision is up to you, and I think it is great.
Quoted 20 lines
Quoted 11 lines
Quoted 11 lines
Quoted 2 lines
At least in the struct
rte_flow_item_raw, the member pattern is the sameas old filter?
It is the same as the old filter, except you cannot provide it in hexadecimal format yet. No changes needed on the PMD side in any case.
Again, this is only a testpmd implementation issue, that doesn't prevent developers from creating programs that directly provide binary data to RAW items, there's no such limitation.
Quoted 5 lines
Quoted 5 lines
[1] http://dpdk.org/ml/archives/dev/2017-May/065798.html
--
Adrien Mazarguil
6WIND--
Adrien Mazarguil
6WIND
PATCH v3 2/25 doc: add rte_flow prog guide
In reply to Adrien MazarguilThis documentation is based on the latest RFC submission, subsequently updated according to feedback from the community.
--- doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/rte_flow.rst | 2042 +++++++++++++++++++++++++++++++ 2 files changed, 2043 insertions(+)
doc/guides/prog_guide/index.rst +1 -0
@@ -42,6 +42,7 @@ Programmer's Guide mempool_lib mbuf_lib poll_mode_drv + rte_flow cryptodev_lib link_bonding_poll_mode_drv_lib timer_lib
doc/guides/prog_guide/rte_flow.rst new file +2042 -0
2,042 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH v3 02/25] doc: add rte_flow prog guide
Hi Adrien,
There seems to be an issue when building the PDF version of the docs due to the width of some of the fields in 2 of the tables. I think this may be a Sphinx/Latex bug since it doesn't happen without the table:: directive.
If you replace the following tables with the format below (the text in between is omitted) it resolves the issue:
.. _table_rte_flow_migration_tunnel:
.. table:: TUNNEL conversion
+-------------------------------------------------------+---------+ | Pattern | Actions | +===+==========================+==========+=============+=========+ | 0 | ETH | ``spec`` | any | QUEUE | | | +----------+-------------+ | | | | ``last`` | unset | | | | +----------+-------------+ | | | | ``mask`` | any | | +---+--------------------------+----------+-------------+ | | 1 | IPV4, IPV6 | ``spec`` | any | | | | +----------+-------------+ | | | | ``last`` | unset | | | | +----------+-------------+ | | | | ``mask`` | any | | +---+--------------------------+----------+-------------+ | | 2 | ANY | ``spec`` | any | | | | +----------+-------------+ | | | | ``last`` | unset | | | | +----------+---------+---+ | | | | ``mask`` | ``num`` | 0 | | +---+--------------------------+----------+---------+---+ | | 3 | VXLAN, GENEVE, TEREDO, | ``spec`` | any | | | | NVGRE, GRE, ... +----------+-------------+ | | | | ``last`` | unset | | | | +----------+-------------+ | | | | ``mask`` | any | | +---+--------------------------+----------+-------------+---------+ | 4 | END | END | +---+---------------------------------------------------+---------+
<text>
.. _table_rte_flow_migration_fdir:
.. table:: FDIR conversion
+----------------------------------------+-----------------------+ | Pattern | Actions | +===+===================+==========+=====+=======================+ | 0 | ETH, RAW | ``spec`` | any | QUEUE, DROP, PASSTHRU | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+-----------------------+ | 1 | IPV4, IPv6 | ``spec`` | any | MARK | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+ | | 2 | TCP, UDP, SCTP | ``spec`` | any | | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+ | | 3 | VF, PF (optional) | ``spec`` | any | | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+-----------------------+ | 4 | END | END | +---+------------------------------------+-----------------------+
PATCH v3 3/25 doc: announce deprecation of legacy filter types
In reply to Adrien MazarguilThey are superseded by the generic flow API (rte_flow). Target release is not defined yet.
--- doc/guides/rel_notes/deprecation.rst | 8 ++++++++ 1 file changed, 8 insertions(+)
doc/guides/rel_notes/deprecation.rst +8 -0
@@ -71,3 +71,11 @@ Deprecation Notices * mempool: The functions for single/multi producer/consumer are deprecated and will be removed in 17.02. It is replaced by ``rte_mempool_generic_get/put`` functions. + +* ethdev: the legacy filter API, including + ``rte_eth_dev_filter_supported()``, ``rte_eth_dev_filter_ctrl()`` as well + as filter types MACVLAN, ETHERTYPE, FLEXIBLE, SYN, NTUPLE, TUNNEL, FDIR, + HASH and L2_TUNNEL, is superseded by the generic flow API (rte_flow) in + PMDs that implement the latter. + Target release for removal of the legacy API will be defined once most + PMDs have switched to rte_flow.
Signature · 1 line
2.1.4
PATCH v3 4/25 cmdline: add support for dynamic tokens
In reply to Adrien MazarguilConsidering tokens must be hard-coded in a list part of the instruction structure, context-dependent tokens cannot be expressed.
This commit adds support for building dynamic token lists through a user-provided function, which is called when the static token list is empty (a single NULL entry).
Because no structures are modified (existing fields are reused), this commit has no impact on the current ABI.
--- lib/librte_cmdline/cmdline_parse.c | 60 +++++++++++++++++++++++++++++---- lib/librte_cmdline/cmdline_parse.h | 21 ++++++++++++ 2 files changed, 74 insertions(+), 7 deletions(-)
lib/librte_cmdline/cmdline_parse.c +53 -7
@@ -146,7 +146,9 @@ nb_common_chars(const char * s1, const char * s2)*/ static int match_inst (cmdline_parse_inst_t *inst,const char *buf, -unsigned int nb_match_token,void *resbuf,unsigned resbuf_size) +unsigned int nb_match_token,void *resbuf,unsigned resbuf_size, +cmdline_parse_token_hdr_t + *(*dyn_tokens)[CMDLINE_PARSE_DYNAMIC_TOKENS ]) {unsigned int token_num=0 ;cmdline_parse_token_hdr_t * token_p;
@@ -155,6 +157,11 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,struct cmdline_token_hdr token_hdr; token_p = inst->tokens[token_num]; +if (!token_p && dyn_tokens && inst->f) { +if (!(*dyn_tokens)[0 ]) + inst->f (&(*dyn_tokens)[0 ],NULL , dyn_tokens); + token_p = (*dyn_tokens)[0 ]; + }if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
@@ -196,7 +203,17 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf, buf += n; token_num ++; - token_p = inst->tokens[token_num]; +if (!inst->tokens[0 ]) { +if (token_num < (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!(*dyn_tokens)[token_num]) + inst->f (&(*dyn_tokens)[token_num], +NULL , + dyn_tokens); + token_p = (*dyn_tokens)[token_num]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[token_num];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr)); }
@@ -239,6 +256,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)cmdline_parse_inst_t *inst;const char *curbuf;char result_buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];void (*f)(void *,struct cmdline *,void *) =NULL ;void *data =NULL ;int comment =0 ;
@@ -255,6 +273,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)return CMDLINE_PARSE_BAD_ARGS ; ctx = cl->ctx; +memset (&dyn_tokens,0 ,sizeof (dyn_tokens));/* * - look if the buffer contains at least one line
@@ -299,7 +318,8 @@ cmdline_parse(struct cmdline *cl, const char * buf)debug_printf ("INST %d\n" , inst_num);/* fully parsed */ - tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf)); + tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf), + &dyn_tokens);if (tok >0 )/* we matched at least one token */ err =CMDLINE_PARSE_BAD_ARGS ;
@@ -355,6 +375,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,cmdline_parse_token_hdr_t *token_p;struct cmdline_token_hdr token_hdr;char tmpbuf[CMDLINE_BUFFER_SIZE ], comp_buf[CMDLINE_BUFFER_SIZE ]; +cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];unsigned int partial_tok_len;int comp_len =-1 ;int tmp_len =-1 ;
@@ -374,6 +395,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,debug_printf ("%s called\n" , __func__);memset (&token_hdr,0 ,sizeof (token_hdr)); +memset (&dyn_tokens,0 ,sizeof (dyn_tokens));/* count the number of complete token to parse */ for (i=0 ; buf[i] ; i++) {
@@ -396,11 +418,24 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state, inst = ctx[inst_num];while (inst) {/* parse the first tokens of the inst */ -if (nb_token &&match_inst (inst, buf, nb_token,NULL ,0 )) +if (nb_token && +match_inst (inst, buf, nb_token,NULL ,0 , + &dyn_tokens)) goto next;debug_printf ("instruction match\n" ); - token_p = inst->tokens[nb_token]; +if (!inst->tokens[0 ]) { +if (nb_token < + (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!dyn_tokens[nb_token]) + inst->f (&dyn_tokens[nb_token], +NULL , + &dyn_tokens); + token_p = dyn_tokens[nb_token]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[nb_token];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
@@ -490,10 +525,21 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,/* we need to redo it */ inst = ctx[inst_num]; -if (nb_token &&match_inst (inst, buf, nb_token,NULL ,0 )) +if (nb_token && +match_inst (inst, buf, nb_token,NULL ,0 , &dyn_tokens)) goto next2; - token_p = inst->tokens[nb_token]; +if (!inst->tokens[0 ]) { +if (nb_token < (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!dyn_tokens[nb_token]) + inst->f (&dyn_tokens[nb_token], +NULL , + &dyn_tokens); + token_p = dyn_tokens[nb_token]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[nb_token];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
lib/librte_cmdline/cmdline_parse.h +21 -0
@@ -83,6 +83,9 @@ extern "C" {/* maximum buffer size for parsed result */ #define CMDLINE_PARSE_RESULT_BUFSIZE 8192 +/* maximum number of dynamic tokens */ +#define CMDLINE_PARSE_DYNAMIC_TOKENS 128 +/** * Stores a pointer to the ops struct, and the offset: the place to * write the parsed result in the destination structure.
@@ -130,6 +133,24 @@ struct cmdline;* Store a instruction, which is a pointer to a callback function and * its parameter that is called when the instruction is parsed, a help * string, and a list of token composing this instruction. +* +* When no tokens are defined (tokens[0] == NULL), they are retrieved +* dynamically by calling f() as follows: +* +* f((struct cmdline_token_hdr **)&token_hdr, +* NULL, +* (struct cmdline_token_hdr *[])tokens)); +* +* The address of the resulting token is expected at the location pointed by +* the first argument. Can be set to NULL to end the list. +* +* The cmdline argument (struct cmdline *) is always NULL. +* +* The last argument points to the NULL-terminated list of dynamic tokens +* defined so far. Since token_hdr points to an index of that list, the +* current index can be derived as follows: +* +* int index = token_hdr - &(*tokens)[0]; */ struct cmdline_inst {/* f(parsed_struct, data) */
Signature · 1 line
2.1.4
PATCH v3 5/25 cmdline: add alignment constraint
In reply to Adrien MazarguilThis prevents sigbus errors on architectures that cannot handle unexpected unaligned accesses to the output buffer.
--- lib/librte_cmdline/cmdline_parse.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
lib/librte_cmdline/cmdline_parse.c +6 -3
@@ -255,7 +255,10 @@ cmdline_parse(struct cmdline *cl, const char * buf)unsigned int inst_num=0 ;cmdline_parse_inst_t *inst;const char *curbuf; -char result_buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +union { +char buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +long double align;/* strong alignment constraint for buf */ + } result;cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];void (*f)(void *,struct cmdline *,void *) =NULL ;void *data =NULL ;
@@ -318,7 +321,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)debug_printf ("INST %d\n" , inst_num);/* fully parsed */ - tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf), + tok =match_inst (inst, buf,0 , result.buf,sizeof (result.buf), &dyn_tokens);if (tok >0 )/* we matched at least one token */
@@ -353,7 +356,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)/* call func */ if (f) { -f (result_buf, cl, data); +f (result.buf, cl, data); }/* no match */
Signature · 1 line
2.1.4
PATCH v3 6/25 app/testpmd: implement basic support for rte_flow
In reply to Adrien MazarguilAdd basic management functions for the generic flow API (validate, create, destroy, flush, query and list). Flow rule objects and properties are arranged in lists associated with each port.
--- app/test-pmd/cmdline.c | 1 + app/test-pmd/config.c | 498 ++++++++++++++++++++++++++++++++++++++++ app/test-pmd/csumonly.c | 1 + app/test-pmd/flowgen.c | 1 + app/test-pmd/icmpecho.c | 1 + app/test-pmd/ieee1588fwd.c | 1 + app/test-pmd/iofwd.c | 1 + app/test-pmd/macfwd.c | 1 + app/test-pmd/macswap.c | 1 + app/test-pmd/parameters.c | 1 + app/test-pmd/rxonly.c | 1 + app/test-pmd/testpmd.c | 6 + app/test-pmd/testpmd.h | 27 +++ app/test-pmd/txonly.c | 1 + 14 files changed, 542 insertions(+)
app/test-pmd/cmdline.c +1 -0
@@ -75,6 +75,7 @@#include <rte_string_fns.h> #include <rte_devargs.h> #include <rte_eth_ctrl.h> +#include <rte_flow.h> #include <cmdline_rdline.h> #include <cmdline_parse.h>
app/test-pmd/config.c +498 -0
510 lines not on this page · raw message
app/test-pmd/csumonly.c +1 -0
@@ -70,6 +70,7 @@#include <rte_sctp.h> #include <rte_prefetch.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" #define IP_DEFTTL 64/* from RFC 1340. */
app/test-pmd/flowgen.c +1 -0
@@ -68,6 +68,7 @@#include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/icmpecho.c +1 -0
@@ -61,6 +61,7 @@#include <rte_ip.h> #include <rte_icmp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/ieee1588fwd.c +1 -0
@@ -34,6 +34,7 @@#include <rte_cycles.h> #include <rte_ethdev.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/iofwd.c +1 -0
@@ -64,6 +64,7 @@#include <rte_ether.h> #include <rte_ethdev.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/macfwd.c +1 -0
@@ -65,6 +65,7 @@#include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/macswap.c +1 -0
@@ -65,6 +65,7 @@#include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/parameters.c +1 -0
@@ -76,6 +76,7 @@#ifdef RTE_LIBRTE_PMD_BOND #include <rte_eth_bond.h> #endif +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/rxonly.c +1 -0
@@ -67,6 +67,7 @@#include <rte_ip.h> #include <rte_udp.h> #include <rte_net.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/testpmd.c +6 -0
@@ -78,6 +78,7 @@#ifdef RTE_LIBRTE_PDUMP #include <rte_pdump.h> #endif +#include <rte_flow.h> #include "testpmd.h"
@@ -1545,6 +1546,8 @@ close_port(portid_t pid)continue ; } +if (port->flow_list) +port_flow_flush (pi);rte_eth_dev_close (pi); if (rte_atomic16_cmpset(&(port->port_status),
@@ -1599,6 +1602,9 @@ detach_port(uint8_t port_id)return ; } +if (ports[port_id].flow_list) +port_flow_flush (port_id); +if (rte_eth_dev_detach (port_id, name))return ;
app/test-pmd/testpmd.h +27 -0
@@ -144,6 +144,19 @@ struct fwd_stream {/** Insert double VLAN header in forward engine */ #define TESTPMD_TX_OFFLOAD_INSERT_QINQ 0x0080 +/** Descriptor for a single flow. */ +struct port_flow { +size_t size;/**< Allocated space including data[]. */ +struct port_flow *next;/**< Next flow in list. */ +struct port_flow *tmp;/**< Temporary linking. */ +uint32_t id;/**< Flow rule ID. */ +struct rte_flow *flow;/**< Opaque flow object returned by PMD. */ +struct rte_flow_attr attr;/**< Attributes. */ +struct rte_flow_item *pattern;/**< Pattern. */ +struct rte_flow_action *actions;/**< Actions. */ +uint8_t data[];/**< Storage for pattern/actions. */ +}; +/** * The data structure associated with each port. */
@@ -177,6 +190,7 @@ struct rte_port {struct ether_addr *mc_addr_pool;/**< pool of multicast addrs */ uint32_t mc_addr_nb;/**< nb. of addr. in mc_addr_pool */ uint8_t slave_flag;/**< bonding slave port */ +struct port_flow *flow_list;/**< Associated flows. */ };extern portid_t __rte_unused
@@ -504,6 +518,19 @@ void port_reg_bit_field_set(portid_t port_id, uint32_t reg_off, uint8_t bit1_pos, uint8_t bit2_pos, uint32_t value);void port_reg_display (portid_t port_id,uint32_t reg_off);void port_reg_set (portid_t port_id,uint32_t reg_off,uint32_t value); +int port_flow_validate (portid_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item *pattern, +const struct rte_flow_action *actions); +int port_flow_create (portid_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item *pattern, +const struct rte_flow_action *actions); +int port_flow_destroy (portid_t port_id,uint32_t n,const uint32_t *rule); +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);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);
app/test-pmd/txonly.c +1 -0
@@ -68,6 +68,7 @@#include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
Signature · 1 line
2.1.4
PATCH v3 7/25 app/testpmd: add flow command
In reply to Adrien MazarguilManaging generic flow API functions from command line requires the use of dynamic tokens for convenience as flow rules are not fixed and cannot be defined statically.
This commit adds specific flexible parser code and object for a new "flow" command in separate file.
--- app/test-pmd/Makefile | 1 + app/test-pmd/cmdline.c | 4 + app/test-pmd/cmdline_flow.c | 439 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+)
app/test-pmd/Makefile +1 -0
@@ -47,6 +47,7 @@ CFLAGS += $(WERROR_FLAGS) SRCS-y := testpmd.c SRCS-y += parameters.c SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c SRCS-y += config.c SRCS-y += iofwd.c SRCS-y += macfwd.c
app/test-pmd/cmdline.c +4 -0
@@ -9567,6 +9567,9 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = { }, }; +/* Generic flow interface command. */ +extern cmdline_parse_inst_t cmd_flow; +/* *** Classification Filters Control *** */ /* *** Get symmetric hash enable per port *** */ struct cmd_get_sym_hash_ena_per_port_result {
@@ -11605,6 +11608,7 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_set_hash_global_config, (cmdline_parse_inst_t *)&cmd_set_hash_input_set, (cmdline_parse_inst_t *)&cmd_set_fdir_input_set, + (cmdline_parse_inst_t *)&cmd_flow, (cmdline_parse_inst_t *)&cmd_mcast_addr, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
app/test-pmd/cmdline_flow.c new file +439 -0
439 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH v3 07/25] app/testpmd: add flow command
Hi Adrien,
Quoted 9 lines · Adrien Mazarguil
Managing generic flow API functions from command line requires the use of dynamic tokens for convenience as flow rules are not fixed and cannot be defined statically.
This commit adds specific flexible parser code and object for a new "flow" command in separate file.
Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>
<...>
app/test-pmd/cmdline_flow.c line 196
Quoted 7 lines
app/test-pmd/cmdline_flow.c new file +7
-0+/** Initialize context. */ +static void +cmd_flow_context_init (struct context *ctx) +{ +/* A full memset() is not necessary. */ + ctx->curr =0 ; + ctx->prev =0 ;
It seems you have cleaned up all compiler warnings, including bunch of ICC e188 ones, instead of ignoring them. Thank you for your effort.
These ones are only remaining ones as far as I can see:ctx->curr = ZERO;ctx->prev = ZERO;
Thanks,
ferruh
<...>
PATCH v3 8/25 app/testpmd: add rte_flow integer support
In reply to Adrien MazarguilParse all integer types and handle conversion to network byte order in a single function.
--- app/test-pmd/cmdline_flow.c | 148 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+)
app/test-pmd/cmdline_flow.c +148 -0
@@ -34,11 +34,14 @@#include <stddef.h> #include <stdint.h> #include <stdio.h> +#include <inttypes.h> +#include <errno.h> #include <ctype.h> #include <string.h> #include <rte_common.h> #include <rte_ethdev.h> +#include <rte_byteorder.h> #include <cmdline_parse.h> #include <rte_flow.h>
@@ -50,6 +53,10 @@ enum index {ZERO =0 ,END , +/* Common tokens. */ +INTEGER , +UNSIGNED , +/* Top-level command. */ FLOW, };
@@ -61,12 +68,24 @@ enum index {struct context {/** Stack of subsequent token lists to process. */ const enum index *next[CTX_STACK_SIZE ]; +/** Arguments for stacked tokens. */ +const void *args[CTX_STACK_SIZE ];enum index curr;/**< Current token index. */ 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. */ +void *object;/**< Address of current object for relative offsets. */ +}; + +/** Token argument. */ +struct arg { +uint32_t hton:1 ;/**< Use network byte ordering. */ +uint32_t sign:1 ;/**< Value is signed. */ +uint32_t offset;/**< Relative offset from ctx->object. */ +uint32_t size;/**< Field size. */ };/** Parser token definition. */
@@ -80,6 +99,8 @@ struct token {* parser consumes the last entry of that stack. */ const enum index *const *next; +/** Arguments stack for subsequent tokens that need them. */ +const struct arg *const *args;/** * Token-processing callback, returns -1 in case of error, the * length of the matched string otherwise. If NULL, attempts to
@@ -112,6 +133,22 @@ struct token {/** Static initializer for a NEXT() entry. */ #define NEXT_ENTRY (...) (const enum index []){ __VA_ARGS__, ZERO, } +/** Static initializer for the args field. */ +#define ARGS (...) (const struct arg *const []){ __VA_ARGS__, NULL, } + +/** Static initializer for ARGS() to target a field. */ +#define ARGS_ENTRY (s, f) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + }) + +/** Static initializer for ARGS() to target a pointer. */ +#define ARGS_ENTRY_PTR (s, f) \ + (&(const struct arg){ \ + .size = sizeof(*((s *)0)->f), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -121,6 +158,11 @@ struct buffer {static int parse_init (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 ); +static int comp_none (struct context *,const struct token *, +unsigned int ,char *,unsigned int );/** Token definitions. */ static const struct token token_list[] = {
@@ -135,6 +177,21 @@ static const struct token token_list[] = { .type = "RETURN", .help = "command may end here", }, +/* Common tokens. */ + [INTEGER] = { + .name = "{int}", + .type = "INTEGER", + .help = "integer value", + .call = parse_int, + .comp = comp_none, + }, + [UNSIGNED] = { + .name = "{unsigned}", + .type = "UNSIGNED", + .help = "unsigned integer value", + .call = parse_int, + .comp = comp_none, + },/* Top-level command. */ [FLOW] = { .name = "flow",
@@ -144,6 +201,23 @@ static const struct token token_list[] = { }, }; +/** 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 ; +} +/** Default parsing function for token name matching. */ static int parse_default(struct context *ctx, const struct token *token,
@@ -178,9 +252,74 @@ parse_init(struct context *ctx, const struct token *token,/* Initialize buffer. */ memset (out,0x00 ,sizeof (*out));memset ((uint8_t *)out +sizeof (*out),0x22 , size -sizeof (*out)); + ctx->object = out;return len; } +/** +* Parse signed/unsigned integers 8 to 64-bit long. +* +* Last argument (ctx->args) is retrieved to determine integer type and +* storage location. +*/ +static int +parse_int (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); +uintmax_t u; +char *end; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + errno =0 ; + u = arg->sign ? + (uintmax_t )strtoimax (str, &end,0 ) : +strtoumax (str, &end,0 ); +if (errno || (size_t )(end - str) != len) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; + size = arg->size; +switch (size) { +case sizeof (uint8_t ): + *(uint8_t *)buf = u; +break ; +case sizeof (uint16_t ): + *(uint16_t *)buf = arg->hton ?rte_cpu_to_be_16 (u) : u; +break ; +case sizeof (uint32_t ): + *(uint32_t *)buf = arg->hton ?rte_cpu_to_be_32 (u) : u; +break ; +case sizeof (uint64_t ): + *(uint64_t *)buf = arg->hton ?rte_cpu_to_be_64 (u) : u; +break ; +default : + goto error; + } +return len; +error: +push_args (ctx, arg); +return -1 ; +} + +/** No completion. */ +static int +comp_none (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ + (void )ctx; + (void )token; + (void )ent; + (void )buf; + (void )size; +return 0 ; +} +/** Internal context. */ static struct context cmd_flow_context;
@@ -195,9 +334,11 @@ cmd_flow_context_init(struct context *ctx) ctx->curr =0 ; ctx->prev =0 ; ctx->next_num =0 ; + ctx->args_num =0 ; ctx->reparse =0 ; ctx->eol =0 ; ctx->last =0 ; + ctx->object =NULL ; }/** Parse a token (cmdline API). */
@@ -270,6 +411,13 @@ cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,return -1 ; ctx->next[ctx->next_num++] = token->next[i]; } +/* Push arguments if any. */ +if (token->args) +for (i =0 ; token->args[i]; ++i) { +if (ctx->args_num ==RTE_DIM (ctx->args)) +return -1 ; + ctx->args[ctx->args_num++] = token->args[i]; + }return len; }
Signature · 1 line
2.1.4
PATCH v3 9/25 app/testpmd: add flow list command
In reply to Adrien MazarguilSyntax:
flow list {port_id} [group {group_id}] [...]
List configured flow rules on a port. Output can optionally be limited to a given set of group identifiers.
--- app/test-pmd/cmdline.c | 4 ++ app/test-pmd/cmdline_flow.c | 141 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+)
app/test-pmd/cmdline.c +4 -0
@@ -810,6 +810,10 @@ static void cmd_help_long_parsed(void *parsed_result,"sctp-src-port|sctp-dst-port|sctp-veri-tag|none)" " (select|add)\n" " Set the input set for FDir.\n\n" + +"flow list {port_id} [group {group_id}] [...]\n" +" List existing flow rules sorted by priority," +" filtered by group identifiers.\n\n" ); } }
app/test-pmd/cmdline_flow.c +141 -0
215 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v3 10/25 app/testpmd: add flow flush command
In reply to Adrien MazarguilSyntax:
flow flush {port_id}
Destroy all flow rules on a port.
--- app/test-pmd/cmdline.c | 3 +++ app/test-pmd/cmdline_flow.c | 43 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow flush {port_id}\n" +" Destroy all flow rules.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," " filtered by group identifiers.\n\n"
app/test-pmd/cmdline_flow.c +42 -1
76 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH v3 10/25] app/testpmd: add flow flush command
Hi, Adrien
Quoted 121 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Tuesday, December 20, 2016 1:49 AM
To: [email protected]
Subject: [dpdk-dev] [PATCH v3 10/25] app/testpmd: add flow flush commandSyntax:
flow flush {
port_id}Destroy all flow rules on a port.
Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>--- app/test-pmd/cmdline.c | 3 +++ app/test-pmd/cmdline_flow.c | 43 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-)app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0
-00dc6c63..6e2b289 100644
app/test-pmd/cmdline.c +3
-0@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow flush {port_id}\n" +" Destroy all flow rules.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," app/test-pmd/cmdline.c +0
-0" filtered by group identifiers.\n\n" app/test-pmd/cmdline_flow.c +39
-1@@ -63,6 +63,7 @@ enum index {FLOW ,/* Sub-level commands. */ +FLUSH , LIST,/* List arguments. */ @@ -179,6 +180,9 @@ static const enum index next_list_attr[] = { static int parse_init(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_flush (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 );@@ -240,10 +244,19 @@ static const struct token token_list[] = { .name = "flow", .type = "{command} {port_id} [{arg} [...]]", .help = "manage ingress/egress flow rules", - .next = NEXT(NEXT_ENTRY(LIST)), + .next =NEXT (NEXT_ENTRY + (FLUSH , + LIST)), .call = parse_init, },/* Sub-level commands. */ + [FLUSH] = { + .name = "flush", + .help = "destroy all flow rules", + .next = NEXT(NEXT_ENTRY(PORT_ID)), + .args = ARGS(ARGS_ENTRY(struct buffer, port)), + .call = parse_flush, + }, [LIST] = { .name = "list", .help = "list existing flow rules",@@ -316,6 +329,31 @@ parse_init(struct context *ctx, const struct token *token, return len; } +/** Parse tokens for flush command. */ +static int +parse_flush (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 !=FLUSH ) +return -1 ; +if (sizeof (*out) > size) +return -1 ; + out->command = ctx->curr; + ctx->object = out; + } +return len; +} +/** Parse tokens for list command. */ static intparse_list(struct context *ctx, const struct token *token, @@ -698,6 +736,9
@@ static voidcmd_flow_parsed(const struct buffer *in){app/test-pmd/cmdline_flow.c +3
-1switch (in->command) { +case FLUSH : +port_flow_flush (in->port); +break ;case LIST :port_flow_list (in->port, in->args.list.group_n, in->args.list.group); --
Quoted 1 line
2.1.4
When user flow flush cmd, PMD will flush all the rule on the specific port, and the memory of which rte_flow point to must be flushed. This memory is returned when flow create, will rte layer flush this memory or PMD is responsible for that memory flush? BTW, there is no argument about rte_flow in flush function pass into PMD layer.
Re: [PATCH v3 10/25] app/testpmd: add flow flush command
Hi Wei,
Quoted 118 lines · Wei
Hi, Adrien
Quoted 116 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Tuesday, December 20, 2016 1:49 AM
To: [email protected]
Subject: [dpdk-dev] [PATCH v3 10/25] app/testpmd: add flow flush commandSyntax:
flow flush {
port_id}Destroy all flow rules on a port.
Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>--- app/test-pmd/cmdline.c | 3 +++ app/test-pmd/cmdline_flow.c | 43 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-)app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0
-00dc6c63..6e2b289 100644
app/test-pmd/cmdline.c +3
-0@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow flush {port_id}\n" +" Destroy all flow rules.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," app/test-pmd/cmdline.c +0
-0" filtered by group identifiers.\n\n" app/test-pmd/cmdline_flow.c +39
-1@@ -63,6 +63,7 @@ enum index {FLOW ,/* Sub-level commands. */ +FLUSH , LIST,/* List arguments. */ @@ -179,6 +180,9 @@ static const enum index next_list_attr[] = { static int parse_init(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_flush (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 );@@ -240,10 +244,19 @@ static const struct token token_list[] = { .name = "flow", .type = "{command} {port_id} [{arg} [...]]", .help = "manage ingress/egress flow rules", - .next = NEXT(NEXT_ENTRY(LIST)), + .next =NEXT (NEXT_ENTRY + (FLUSH , + LIST)), .call = parse_init, },/* Sub-level commands. */ + [FLUSH] = { + .name = "flush", + .help = "destroy all flow rules", + .next = NEXT(NEXT_ENTRY(PORT_ID)), + .args = ARGS(ARGS_ENTRY(struct buffer, port)), + .call = parse_flush, + }, [LIST] = { .name = "list", .help = "list existing flow rules",@@ -316,6 +329,31 @@ parse_init(struct context *ctx, const struct token *token, return len; } +/** Parse tokens for flush command. */ +static int +parse_flush (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 !=FLUSH ) +return -1 ; +if (sizeof (*out) > size) +return -1 ; + out->command = ctx->curr; + ctx->object = out; + } +return len; +} +/** Parse tokens for list command. */ static intparse_list(struct context *ctx, const struct token *token, @@ -698,6 +736,9
@@ static voidcmd_flow_parsed(const struct buffer *in){app/test-pmd/cmdline_flow.c +2
-0switch (in->command) { +case FLUSH : +port_flow_flush (in->port);
Quoted 8 lines
Quoted 6 lines
app/test-pmd/cmdline_flow.c +1
-1+break ;case LIST :port_flow_list (in->port, in->args.list.group_n, in->args.list.group); --2.1.4
When user flow flush cmd, PMD will flush all the rule on the specific port, and the memory of which
rte_flowpoint to must be flushed.
Right.
Quoted 1 line
This memory is returned when flow create, will rte layer flush this memory or PMD is responsible for that memory flush?
All handles are considered destroyed and their memory freed, i.e. no rte_flow object remains valid after flush. Applications still need to clean up the memory they allocated to manage these objects, but that's their problem.
Quoted 1 line
BTW, there is no argument about
rte_flowin flush function pass into PMD layer.
Right, that's because flush does not request the destruction of a specific rule. PMDs that allocate memory for rte_flow objects must link them together somehow to retrieve them during a flush event.
Note this is likely already necessary to clean up the memory allocated for flow rules during dev_close().
Signature · 2 lines
Adrien Mazarguil 6WIND
PATCH v3 11/25 app/testpmd: add flow destroy command
In reply to Adrien MazarguilSyntax:
flow destroy {port_id} rule {rule_id} [...]
Destroy a given set of flow rules associated with a port.
--- app/test-pmd/cmdline.c | 3 ++ app/test-pmd/cmdline_flow.c | 106 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow destroy {port_id} rule {rule_id} [...]\n" +" Destroy specific flow rules.\n\n" +"flow flush {port_id}\n" " Destroy all flow rules.\n\n"
app/test-pmd/cmdline_flow.c +105 -1
185 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v3 12/25 app/testpmd: add flow validate/create commands
In reply to Adrien MazarguilSyntax:
flow (validate|create) {port_id}
[group {group_id}] [priority {level}] [ingress] [egress]
pattern {item} [/ {item} [...]] / end
actions {action} [/ {action} [...]] / endEither check the validity of a flow rule or create it. Any number of pattern items and actions can be provided in any order. Completion is available for convenience.
This commit only adds support for the most basic item and action types, namely:
- END: terminates pattern items and actions lists.
- VOID: item/action filler, no operation.
- INVERT: inverted pattern matching, process packets that do not match.
- PASSTHRU: action that leaves packets up for additional processing by subsequent flow rules.
--- app/test-pmd/cmdline.c | 14 ++ app/test-pmd/cmdline_flow.c | 314 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 327 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +14 -0
@@ -811,6 +811,20 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow validate {port_id}" +" [group {group_id}] [priority {level}]" +" [ingress] [egress]" +" pattern {item} [/ {item} [...]] / end" +" actions {action} [/ {action} [...]] / end\n" +" Check whether a flow rule can be created.\n\n" + +"flow create {port_id}" +" [group {group_id}] [priority {level}]" +" [ingress] [egress]" +" pattern {item} [/ {item} [...]] / end" +" actions {action} [/ {action} [...]] / end\n" +" Create a flow rule.\n\n" +"flow destroy {port_id} rule {rule_id} [...]\n" " Destroy specific flow rules.\n\n"
app/test-pmd/cmdline_flow.c +313 -1
445 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v3 13/25 app/testpmd: add flow query command
In reply to Adrien MazarguilSyntax:
flow query {port_id} {rule_id} {action}
Query a specific action of an existing flow rule.
--- app/test-pmd/cmdline.c | 3 + app/test-pmd/cmdline_flow.c | 121 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -831,6 +831,9 @@ static void cmd_help_long_parsed(void *parsed_result,"flow flush {port_id}\n" " Destroy all flow rules.\n\n" +"flow query {port_id} {rule_id} {action}\n" +" Query an existing flow rule.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," " filtered by group identifiers.\n\n"
app/test-pmd/cmdline_flow.c +120 -1
186 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v3 14/25 app/testpmd: add rte_flow item spec handler
In reply to Adrien MazarguilAdd parser code to fully set individual fields of pattern item specification structures, using the following operators:
- fix: sets field and applies full bit-mask for perfect matching.
- spec: sets field without modifying its bit-mask.
- last: sets upper value of the spec => last range.
- mask: sets bit-mask affecting both spec and last from arbitrary value.
--- app/test-pmd/cmdline_flow.c | 111 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
app/test-pmd/cmdline_flow.c +111 -0
@@ -89,6 +89,10 @@ enum index {/* Validate/create pattern. */ PATTERN , +ITEM_PARAM_IS , +ITEM_PARAM_SPEC , +ITEM_PARAM_LAST , +ITEM_PARAM_MASK ,ITEM_NEXT ,ITEM_END , ITEM_VOID,
@@ -121,6 +125,7 @@ struct context {uint16_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. */ };/** Token argument. */
@@ -267,6 +272,15 @@ static const enum index next_list_attr[] = { ZERO, }; +__rte_unused +static const enum index item_param[] = { +ITEM_PARAM_IS , +ITEM_PARAM_SPEC , +ITEM_PARAM_LAST , +ITEM_PARAM_MASK , +ZERO , +}; +static const enum index next_item[] = {ITEM_END ,ITEM_VOID ,
@@ -287,6 +301,8 @@ static int parse_init(struct context *, const struct token *,static int parse_vc (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_spec (struct context *,const struct token *, +const char *,unsigned int ,void *,unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -492,6 +508,26 @@ static const struct token token_list[] = { .next = NEXT(next_item), .call = parse_vc, }, + [ITEM_PARAM_IS] = { + .name = "is", + .help = "match value perfectly (with full bit-mask)", + .call = parse_vc_spec, + }, + [ITEM_PARAM_SPEC] = { + .name = "spec", + .help = "match value according to configured bit-mask", + .call = parse_vc_spec, + }, + [ITEM_PARAM_LAST] = { + .name = "last", + .help = "specify upper bound to establish a range", + .call = parse_vc_spec, + }, + [ITEM_PARAM_MASK] = { + .name = "mask", + .help = "specify bit-mask with relevant bits set to one", + .call = parse_vc_spec, + }, [ITEM_NEXT] = { .name = "/", .help = "specify next pattern item",
@@ -605,6 +641,7 @@ parse_init(struct context *ctx, const struct token *token,memset ((uint8_t *)out +sizeof (*out),0x22 , size -sizeof (*out)); ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ;return len; }
@@ -632,11 +669,13 @@ parse_vc(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.vc.data = (uint8_t *)out + size;return len; } ctx->objdata =0 ; ctx->object = &out->args.vc.attr; + ctx->objmask =NULL ;switch (ctx->curr) {case GROUP :case PRIORITY :
@@ -652,6 +691,7 @@ parse_vc(struct context *ctx, const struct token *token, (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double )); ctx->object = out->args.vc.pattern; + ctx->objmask =NULL ;return len;case ACTIONS : out->args.vc.actions =
@@ -660,6 +700,7 @@ parse_vc(struct context *ctx, const struct token *token, out->args.vc.pattern_n), sizeof(double)); ctx->object = out->args.vc.actions; + ctx->objmask =NULL ;return len;default :if (!token->priv)
@@ -682,6 +723,7 @@ parse_vc(struct context *ctx, const struct token *token, }; ++out->args.vc.pattern_n; ctx->object = item; + ctx->objmask =NULL ; }else {const struct parse_action_priv *priv = token->priv; struct rte_flow_action *action =
@@ -698,6 +740,7 @@ parse_vc(struct context *ctx, const struct token *token, }; ++out->args.vc.actions_n; ctx->object = action; + ctx->objmask =NULL ; }memset (data,0 , data_size); out->args.vc.data = data;
@@ -705,6 +748,60 @@ parse_vc(struct context *ctx, const struct token *token,return len; } +/** Parse pattern item parameter type. */ +static int +parse_vc_spec (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +struct buffer *out = buf; +struct rte_flow_item *item; +uint32_t data_size; +int index; +int objmask =0 ; + + (void )size; +/* Token name must match. */ +if (parse_default (ctx, token, str, len,NULL ,0 ) <0 ) +return -1 ; +/* Parse parameter types. */ +switch (ctx->curr) { +case ITEM_PARAM_IS : + index =0 ; + objmask =1 ; +break ; +case ITEM_PARAM_SPEC : + index =0 ; +break ; +case ITEM_PARAM_LAST : + index =1 ; +break ; +case ITEM_PARAM_MASK : + index =2 ; +break ; +default : +return -1 ; + } +/* Nothing else to do if there is no buffer. */ +if (!out) +return len; +if (!out->args.vc.pattern_n) +return -1 ; + item = &out->args.vc.pattern[out->args.vc.pattern_n -1 ]; + data_size = ctx->objdata /3 ;/* spec, last, mask */ +/* Point to selected object. */ + ctx->object = out->args.vc.data + (data_size * index); +if (objmask) { + ctx->objmask = out->args.vc.data + (data_size *2 );/* mask */ + item->mask = ctx->objmask; + }else + ctx->objmask =NULL ; +/* Update relevant item pointer. */ + *((const void **[]){ &item->spec, &item->last, &item->mask })[index] = + ctx->object; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
@@ -727,6 +824,7 @@ parse_destroy(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.destroy.rule = (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double ));
@@ -737,6 +835,7 @@ parse_destroy(struct context *ctx, const struct token *token,return -1 ; ctx->objdata =0 ; ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++; + ctx->objmask =NULL ;return len; }
@@ -762,6 +861,7 @@ parse_flush(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; }return len; }
@@ -788,6 +888,7 @@ parse_query(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; }return len; }
@@ -849,6 +950,7 @@ parse_list(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.list.group = (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double ));
@@ -859,6 +961,7 @@ parse_list(struct context *ctx, const struct token *token,return -1 ; ctx->objdata =0 ; ctx->object = out->args.list.group + out->args.list.group_n++; + ctx->objmask =NULL ;return len; }
@@ -891,6 +994,7 @@ parse_int(struct context *ctx, const struct token *token,return len; buf = (uint8_t *)ctx->object + arg->offset; size = arg->size; +objmask:switch (size) {case sizeof (uint8_t ): *(uint8_t *)buf = u;
@@ -907,6 +1011,11 @@ parse_int(struct context *ctx, const struct token *token,default : goto error; } +if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) { + u =-1 ; + buf = (uint8_t *)ctx->objmask + arg->offset; + goto objmask; + }return len; error:push_args (ctx, arg);
@@ -927,6 +1036,7 @@ parse_port(struct context *ctx, const struct token *token,else { ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; size =sizeof (*out); } ret =parse_int (ctx, token, str, len, out, size);
@@ -1033,6 +1143,7 @@ cmd_flow_context_init(struct context *ctx) ctx->port =0 ; ctx->objdata =0 ; ctx->object =NULL ; + ctx->objmask =NULL ; }/** Parse a token (cmdline API). */
Signature · 1 line
2.1.4
PATCH v3 15/25 app/testpmd: add rte_flow item spec prefix length
In reply to Adrien MazarguilGenerating bit-masks from prefix lengths is often more convenient than providing them entirely (e.g. to define IPv4 and IPv6 subnets).
This commit adds the "prefix" operator that assigns generated bit-masks to any pattern item specification field.
--- app/test-pmd/cmdline_flow.c | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
app/test-pmd/cmdline_flow.c +80 -0
@@ -56,6 +56,7 @@ enum index {/* Common tokens. */ INTEGER ,UNSIGNED , +PREFIX ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -93,6 +94,7 @@ enum index {ITEM_PARAM_SPEC ,ITEM_PARAM_LAST ,ITEM_PARAM_MASK , +ITEM_PARAM_PREFIX ,ITEM_NEXT ,ITEM_END , ITEM_VOID,
@@ -278,6 +280,7 @@ static const enum index item_param[] = {ITEM_PARAM_SPEC ,ITEM_PARAM_LAST ,ITEM_PARAM_MASK , +ITEM_PARAM_PREFIX , ZERO, };
@@ -321,6 +324,9 @@ static int parse_list(struct context *, const struct token *,static int parse_int (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_prefix (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -361,6 +367,13 @@ static const struct token token_list[] = { .call = parse_int, .comp = comp_none, }, + [PREFIX] = { + .name = "{prefix}", + .type = "PREFIX", + .help = "prefix length for bit-mask", + .call = parse_prefix, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -528,6 +541,11 @@ static const struct token token_list[] = { .help = "specify bit-mask with relevant bits set to one", .call = parse_vc_spec, }, + [ITEM_PARAM_PREFIX] = { + .name = "prefix", + .help = "generate bit-mask from a prefix length", + .call = parse_vc_spec, + }, [ITEM_NEXT] = { .name = "/", .help = "specify next pattern item",
@@ -605,6 +623,62 @@ push_args(struct context *ctx, const struct arg *arg)return 0 ; } +/** +* 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; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + errno =0 ; + u =strtoumax (str, &end,0 ); +if (errno || (size_t )(end - str) != len) + goto error; + bytes = u /8 ; + extra = u %8 ; + size = arg->size; +if (bytes > size || bytes + !!extra > size) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { +memset ((uint8_t *)buf + size - bytes,0xff , bytes); +memset (buf,0x00 , size - bytes); +if (extra) + ((uint8_t *)buf)[size - bytes -1 ] = conv[extra]; + } else +#endif + { +memset (buf,0xff , bytes); +memset ((uint8_t *)buf + bytes,0x00 , size - bytes); +if (extra) + ((uint8_t *)buf)[bytes] = conv[extra]; + } +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Default parsing function for token name matching. */ static int parse_default(struct context *ctx, const struct token *token,
@@ -776,6 +850,12 @@ parse_vc_spec(struct context *ctx, const struct token *token,case ITEM_PARAM_LAST : index =1 ;break ; +case ITEM_PARAM_PREFIX : +/* Modify next token to expect a prefix. */ +if (ctx->next_num <2 ) +return -1 ; + ctx->next[ctx->next_num -2 ] =NEXT_ENTRY (PREFIX ); +/* Fall through. */ case ITEM_PARAM_MASK : index =2 ;break ;
Signature · 1 line
2.1.4
PATCH v3 16/25 app/testpmd: add rte_flow bit-field support
In reply to Adrien MazarguilSeveral rte_flow structures expose bit-fields that cannot be set in a generic fashion at byte level. Add bit-mask support to handle them.
--- app/test-pmd/cmdline_flow.c | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+)
app/test-pmd/cmdline_flow.c +59 -0
@@ -136,6 +136,7 @@ struct arg { uint32_t sign:1; /**< Value is signed. */uint32_t offset;/**< Relative offset from ctx->object. */ uint32_t size;/**< Field size. */ +const uint8_t *mask;/**< Bit-mask to use instead of offset/size. */ };/** Parser token definition. */
@@ -195,6 +196,13 @@ struct token { .size = sizeof(((s *)0)->f), \ }) +/** Static initializer for ARGS() to target a bit-field. */ +#define ARGS_ENTRY_BF (s, f, b) \ + (&(const struct arg){ \ + .size = sizeof(s), \ + .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \ + }) +/** Static initializer for ARGS() to target a pointer. */ #define ARGS_ENTRY_PTR (s, f) \ (&(const struct arg){ \
@@ -623,6 +631,34 @@ push_args(struct context *ctx, const struct arg *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; +size_t len =0 ; + +/* Endian conversion is not supported on bit-fields. */ +if (!arg->mask || arg->hton) +return 0 ; +for (i =0 ; i != arg->size; ++i) { +unsigned int shift =0 ; +uint8_t *buf = (uint8_t *)dst + i; + +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 ; + } + } +return len; +} +/** * Parse a prefix length and generate a bit-mask. *
@@ -649,6 +685,23 @@ parse_prefix(struct context *ctx, const struct token *token, u =strtoumax (str, &end,0 );if (errno || (size_t )(end - str) != len) goto error; +if (arg->mask) { +uintmax_t v =0 ; + + extra =arg_entry_bf_fill (NULL ,0 , arg); +if (u > extra) + goto error; +if (!ctx->object) +return len; + extra -= u; +while (u--) + (v <<=1 , v |=1 ); + v <<= extra; +if (!arg_entry_bf_fill (ctx->object, v, arg) || + !arg_entry_bf_fill (ctx->objmask,-1 , arg)) + goto error; +return len; + } bytes = u /8 ; extra = u %8 ; size = arg->size;
@@ -1072,6 +1125,12 @@ parse_int(struct context *ctx, const struct token *token, goto error;if (!ctx->object)return len; +if (arg->mask) { +if (!arg_entry_bf_fill (ctx->object, u, arg) || + !arg_entry_bf_fill (ctx->objmask,-1 , arg)) + goto error; +return len; + } buf = (uint8_t *)ctx->object + arg->offset; size = arg->size; objmask:
Signature · 1 line
2.1.4
PATCH v3 17/25 app/testpmd: add item any to flow command
In reply to Adrien MazarguilThis pattern item matches any protocol in place of the current layer and has two properties:
- min: minimum number of layers covered (0 or more).
- max: maximum number of layers covered (0 means infinity).
--- app/test-pmd/cmdline_flow.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
app/test-pmd/cmdline_flow.c +22 -1
@@ -99,6 +99,8 @@ enum index {ITEM_END ,ITEM_VOID ,ITEM_INVERT , +ITEM_ANY , +ITEM_ANY_NUM ,/* Validate/create actions. */ ACTIONS,
@@ -282,7 +284,6 @@ static const enum index next_list_attr[] = { ZERO, }; -__rte_unused static const enum index item_param[] = {ITEM_PARAM_IS ,ITEM_PARAM_SPEC ,
@@ -296,6 +297,13 @@ static const enum index next_item[] = {ITEM_END ,ITEM_VOID ,ITEM_INVERT , +ITEM_ANY , + ZERO, +}; + +static const enum index item_any[] = { +ITEM_ANY_NUM , +ITEM_NEXT ,ZERO , };
@@ -580,6 +588,19 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), .call = parse_vc, }, + [ITEM_ANY] = { + .name = "any", + .help = "match any protocol for the current layer", + .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)), + .next = NEXT(item_any), + .call = parse_vc, + }, + [ITEM_ANY_NUM] = { + .name = "num", + .help = "number of layers covered", + .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
Signature · 1 line
2.1.4
PATCH v3 18/25 app/testpmd: add various items to flow command
In reply to Adrien Mazarguil- PF: match packets addressed to the physical function.
- VF: match packets addressed to a virtual function ID.
- PORT: device-specific physical port index to use.
--- app/test-pmd/cmdline_flow.c | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
app/test-pmd/cmdline_flow.c +53 -0
@@ -101,6 +101,11 @@ enum index {ITEM_INVERT ,ITEM_ANY ,ITEM_ANY_NUM , +ITEM_PF , +ITEM_VF , +ITEM_VF_ID , +ITEM_PORT , +ITEM_PORT_INDEX ,/* Validate/create actions. */ ACTIONS,
@@ -298,6 +303,9 @@ static const enum index next_item[] = {ITEM_VOID ,ITEM_INVERT ,ITEM_ANY , +ITEM_PF , +ITEM_VF , +ITEM_PORT , ZERO, };
@@ -307,6 +315,18 @@ static const enum index item_any[] = { ZERO, }; +static const enum index item_vf[] = { +ITEM_VF_ID , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_port[] = { +ITEM_PORT_INDEX , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -601,6 +621,39 @@ static const struct token token_list[] = { .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), }, + [ITEM_PF] = { + .name = "pf", + .help = "match packets addressed to the physical function", + .priv = PRIV_ITEM(PF, 0), + .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), + .call = parse_vc, + }, + [ITEM_VF] = { + .name = "vf", + .help = "match packets addressed to a virtual function ID", + .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)), + .next = NEXT(item_vf), + .call = parse_vc, + }, + [ITEM_VF_ID] = { + .name = "id", + .help = "destination VF ID", + .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)), + }, + [ITEM_PORT] = { + .name = "port", + .help = "device-specific physical port index to use", + .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)), + .next = NEXT(item_port), + .call = parse_vc, + }, + [ITEM_PORT_INDEX] = { + .name = "index", + .help = "physical port index", + .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
Signature · 1 line
2.1.4
PATCH v3 19/25 app/testpmd: add item raw to flow command
In reply to Adrien MazarguilMatches arbitrary byte strings with properties:
- relative: look for pattern after the previous item.
- search: search pattern from offset (see also limit).
- offset: absolute or relative offset for pattern.
- limit: search area limit for start of pattern.
- length: pattern length.
- pattern: byte string to look for.
--- app/test-pmd/cmdline_flow.c | 208 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+)
app/test-pmd/cmdline_flow.c +208 -0
@@ -57,6 +57,8 @@ enum index {INTEGER ,UNSIGNED ,PREFIX , +BOOLEAN , +STRING ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -106,6 +108,12 @@ enum index {ITEM_VF_ID ,ITEM_PORT ,ITEM_PORT_INDEX , +ITEM_RAW , +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN ,/* Validate/create actions. */ ACTIONS,
@@ -115,6 +123,13 @@ enum index { ACTION_PASSTHRU, }; +/** Size of pattern[] field in struct rte_flow_item_raw. */ +#define ITEM_RAW_PATTERN_SIZE 36 + +/** Storage size for struct rte_flow_item_raw including pattern. */ +#define ITEM_RAW_SIZE \ + (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) +/** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16
@@ -216,6 +231,13 @@ struct token { .size = sizeof(*((s *)0)->f), \ }) +/** Static initializer for ARGS() with arbitrary size. */ +#define ARGS_ENTRY_USZ (s, f, sz) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = (sz), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -306,6 +328,7 @@ static const enum index next_item[] = {ITEM_PF ,ITEM_VF ,ITEM_PORT , +ITEM_RAW , ZERO, };
@@ -327,6 +350,16 @@ static const enum index item_port[] = { ZERO, }; +static const enum index item_raw[] = { +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -363,11 +396,19 @@ static int parse_int(struct context *, const struct token *,static int parse_prefix (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_boolean (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_string (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );static int comp_none (struct context *,const struct token *,unsigned int ,char *,unsigned int ); +static int comp_boolean (struct context *,const struct token *, +unsigned int ,char *,unsigned int );static int comp_action (struct context *,const struct token *,unsigned int ,char *,unsigned int ); static int comp_port(struct context *, const struct token *,
@@ -410,6 +451,20 @@ static const struct token token_list[] = { .call = parse_prefix, .comp = comp_none, }, + [BOOLEAN] = { + .name = "{boolean}", + .type = "BOOLEAN", + .help = "any boolean value", + .call = parse_boolean, + .comp = comp_boolean, + }, + [STRING] = { + .name = "{string}", + .type = "STRING", + .help = "fixed string", + .call = parse_string, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -654,6 +709,52 @@ static const struct token token_list[] = { .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), }, + [ITEM_RAW] = { + .name = "raw", + .help = "match an arbitrary byte string", + .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE), + .next = NEXT(item_raw), + .call = parse_vc, + }, + [ITEM_RAW_RELATIVE] = { + .name = "relative", + .help = "look for pattern after the previous item", + .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + relative, 1)), + }, + [ITEM_RAW_SEARCH] = { + .name = "search", + .help = "search pattern from offset (see also limit)", + .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + search, 1)), + }, + [ITEM_RAW_OFFSET] = { + .name = "offset", + .help = "absolute or relative offset for pattern", + .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)), + }, + [ITEM_RAW_LIMIT] = { + .name = "limit", + .help = "search area limit for start of pattern", + .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)), + }, + [ITEM_RAW_PATTERN] = { + .name = "pattern", + .help = "byte string to look for", + .next =NEXT (item_raw, +NEXT_ENTRY (STRING ), +NEXT_ENTRY (ITEM_PARAM_IS , +ITEM_PARAM_SPEC , + ITEM_PARAM_MASK)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, length), + ARGS_ENTRY_USZ(struct rte_flow_item_raw, + pattern, + ITEM_RAW_PATTERN_SIZE)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1235,6 +1336,96 @@ parse_int(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse a string. +* +* Two arguments (ctx->args) are retrieved from the stack to store data and +* its length (in that order). +*/ +static int +parse_string (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg_data =pop_args (ctx); +const struct arg *arg_len =pop_args (ctx); +char tmp[16 ];/* Ought to be enough. */ +int ret; + +/* Arguments are expected. */ +if (!arg_data) +return -1 ; +if (!arg_len) { +push_args (ctx, arg_data); +return -1 ; + } + size = arg_data->size; +/* Bit-mask fill is not supported. */ +if (arg_data->mask || size < len) + goto error; +if (!ctx->object) +return len; +/* Let parse_int() fill length information first. */ + ret =snprintf (tmp,sizeof (tmp),"%u" , len); +if (ret <0 ) + goto error; +push_args (ctx, arg_len); + ret =parse_int (ctx, token, tmp, ret,NULL ,0 ); +if (ret <0 ) { +pop_args (ctx); + goto error; + } + buf = (uint8_t *)ctx->object + arg_data->offset; +/* Output buffer is not necessarily NUL-terminated. */ +memcpy (buf, str, len); +memset ((uint8_t *)buf + len,0x55 , size - len); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg_data->offset,0xff , len); +return len; +error: +push_args (ctx, arg_len); +push_args (ctx, arg_data); +return -1 ; +} + +/** Boolean values (even indices stand for false). */ +static const char *const boolean_name[] = { +"0" ,"1" , +"false" ,"true" , +"no" ,"yes" , +"N" ,"Y" , +NULL , +}; + +/** +* Parse a boolean value. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_boolean (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); +unsigned int i; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; +for (i =0 ; boolean_name[i]; ++i) +if (!strncmp (str, boolean_name[i], len)) +break ; +/* Process token as integer. */ +if (boolean_name[i]) + str = i &1 ?"1" :"0" ; +push_args (ctx, arg); + ret =parse_int (ctx, token, str,strlen (str), buf, size); +return ret >0 ? (int )len : ret; +} +/** Parse port and update context. */ static int parse_port(struct context *ctx, const struct token *token,
@@ -1273,6 +1464,23 @@ comp_none(struct context *ctx, const struct token *token,return 0 ; } +/** Complete boolean values. */ +static int +comp_boolean (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ +unsigned int i; + + (void )ctx; + (void )token; +for (i =0 ; boolean_name[i]; ++i) +if (buf && i == ent) +return snprintf (buf, size,"%s" , boolean_name[i]); +if (buf) +return -1 ; +return i; +} +/** Complete action names. */ static int comp_action(struct context *ctx, const struct token *token,
Signature · 1 line
2.1.4
PATCH v3 20/25 app/testpmd: add items eth/vlan to flow command
In reply to Adrien MazarguilThese pattern items match basic Ethernet headers (source, destination and type) and related 802.1Q/ad VLAN headers.
--- app/test-pmd/cmdline_flow.c | 126 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+)
app/test-pmd/cmdline_flow.c +126 -0
@@ -43,6 +43,7 @@#include <rte_ethdev.h> #include <rte_byteorder.h> #include <cmdline_parse.h> +#include <cmdline_parse_etheraddr.h> #include <rte_flow.h> #include "testpmd.h"
@@ -59,6 +60,7 @@ enum index {PREFIX ,BOOLEAN ,STRING , +MAC_ADDR ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -114,6 +116,13 @@ enum index {ITEM_RAW_OFFSET ,ITEM_RAW_LIMIT ,ITEM_RAW_PATTERN , +ITEM_ETH , +ITEM_ETH_DST , +ITEM_ETH_SRC , +ITEM_ETH_TYPE , +ITEM_VLAN , +ITEM_VLAN_TPID , +ITEM_VLAN_TCI ,/* Validate/create actions. */ ACTIONS,
@@ -238,6 +247,14 @@ struct token { .size = (sz), \ }) +/** Same as ARGS_ENTRY() using network byte ordering. */ +#define ARGS_ENTRY_HTON (s, f) \ + (&(const struct arg){ \ + .hton = 1, \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -329,6 +346,8 @@ static const enum index next_item[] = {ITEM_VF ,ITEM_PORT ,ITEM_RAW , +ITEM_ETH , +ITEM_VLAN , ZERO, };
@@ -360,6 +379,21 @@ static const enum index item_raw[] = { ZERO, }; +static const enum index item_eth[] = { +ITEM_ETH_DST , +ITEM_ETH_SRC , +ITEM_ETH_TYPE , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_vlan[] = { +ITEM_VLAN_TPID , +ITEM_VLAN_TCI , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -402,6 +436,9 @@ static int parse_boolean(struct context *, const struct token *,static int parse_string (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_mac_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -465,6 +502,13 @@ static const struct token token_list[] = { .call = parse_string, .comp = comp_none, }, + [MAC_ADDR] = { + .name = "{MAC address}", + .type = "MAC-48", + .help = "standard MAC address notation", + .call = parse_mac_addr, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -755,6 +799,50 @@ static const struct token token_list[] = { pattern, ITEM_RAW_PATTERN_SIZE)), }, + [ITEM_ETH ] = { + .name ="eth" , + .help ="match Ethernet header" , + .priv =PRIV_ITEM (ETH ,sizeof (struct rte_flow_item_eth )), + .next =NEXT (item_eth), + .call = parse_vc, + }, + [ITEM_ETH_DST ] = { + .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)), + }, + [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)), + }, + [ITEM_ETH_TYPE ] = { + .name ="type" , + .help ="EtherType" , + .next =NEXT (item_eth,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)), + }, + [ITEM_VLAN ] = { + .name ="vlan" , + .help ="match 802.1Q/ad VLAN tag" , + .priv =PRIV_ITEM (VLAN ,sizeof (struct rte_flow_item_vlan )), + .next =NEXT (item_vlan), + .call = parse_vc, + }, + [ITEM_VLAN_TPID ] = { + .name ="tpid" , + .help ="tag protocol identifier" , + .next =NEXT (item_vlan,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)), + }, + [ITEM_VLAN_TCI ] = { + .name ="tci" , + .help ="tag control information" , + .next =NEXT (item_vlan,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), + }, /* Validate/create actions. */ [ACTIONS ] = { .name ="actions" ,
@@ -1388,6 +1476,44 @@ parse_string(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse a MAC address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_mac_addr (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); +struct ether_addr tmp; +int ret; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; + ret =cmdline_parse_etheraddr (NULL , str, &tmp, size); +if (ret <0 || (unsigned int )ret != len) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Boolean values (even indices stand for false). */ static const char *const boolean_name[] = {"0" ,"1" ,
Signature · 1 line
2.1.4
PATCH v3 21/25 app/testpmd: add items ipv4/ipv6 to flow command
In reply to Adrien MazarguilAdd the ability to match basic fields from IPv4 and IPv6 headers (source and destination addresses only).
--- app/test-pmd/cmdline_flow.c | 177 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+)
app/test-pmd/cmdline_flow.c +177 -0
@@ -38,6 +38,7 @@#include <errno.h> #include <ctype.h> #include <string.h> +#include <arpa/inet.h> #include <rte_common.h> #include <rte_ethdev.h>
@@ -61,6 +62,8 @@ enum index {BOOLEAN ,STRING ,MAC_ADDR , +IPV4_ADDR , +IPV6_ADDR ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -123,6 +126,12 @@ enum index {ITEM_VLAN ,ITEM_VLAN_TPID ,ITEM_VLAN_TCI , +ITEM_IPV4 , +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_IPV6 , +ITEM_IPV6_SRC , +ITEM_IPV6_DST ,/* Validate/create actions. */ ACTIONS,
@@ -348,6 +357,8 @@ static const enum index next_item[] = {ITEM_RAW ,ITEM_ETH ,ITEM_VLAN , +ITEM_IPV4 , +ITEM_IPV6 , ZERO, };
@@ -394,6 +405,20 @@ static const enum index item_vlan[] = { ZERO, }; +static const enum index item_ipv4[] = { +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_ipv6[] = { +ITEM_IPV6_SRC , +ITEM_IPV6_DST , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -439,6 +464,12 @@ static int parse_string(struct context *, const struct token *,static int parse_mac_addr (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_ipv4_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_ipv6_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -509,6 +540,20 @@ static const struct token token_list[] = { .call = parse_mac_addr, .comp = comp_none, }, + [IPV4_ADDR] = { + .name = "{IPv4 address}", + .type = "IPV4 ADDRESS", + .help = "standard IPv4 address notation", + .call = parse_ipv4_addr, + .comp = comp_none, + }, + [IPV6_ADDR] = { + .name = "{IPv6 address}", + .type = "IPV6 ADDRESS", + .help = "standard IPv6 address notation", + .call = parse_ipv6_addr, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -843,6 +888,48 @@ static const struct token token_list[] = { .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), }, + [ITEM_IPV4] = { + .name = "ipv4", + .help = "match IPv4 header", + .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), + .next = NEXT(item_ipv4), + .call = parse_vc, + }, + [ITEM_IPV4_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.src_addr)), + }, + [ITEM_IPV4_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.dst_addr)), + }, + [ITEM_IPV6] = { + .name = "ipv6", + .help = "match IPv6 header", + .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), + .next = NEXT(item_ipv6), + .call = parse_vc, + }, + [ITEM_IPV6_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.src_addr)), + }, + [ITEM_IPV6_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.dst_addr)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1514,6 +1601,96 @@ parse_mac_addr(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse an IPv4 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv4_addr (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); +char str2[len +1 ]; +struct in_addr tmp; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET , str2, &tmp); +if (ret !=1 ) { +/* Attempt integer parsing. */ +push_args (ctx, arg); +return parse_int (ctx, token, str, len, buf, size); + } +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} + +/** +* Parse an IPv6 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv6_addr (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); +char str2[len +1 ]; +struct in6_addr tmp; +int ret; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET6 , str2, &tmp); +if (ret !=1 ) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Boolean values (even indices stand for false). */ static const char *const boolean_name[] = {"0" ,"1" ,
Signature · 1 line
2.1.4
Re: [PATCH v3 21/25] app/testpmd: add items ipv4/ipv6 to flow command
Hi adrien,
Is it possible to support to set ipv4 TOS, ipv4 PROTO, ipv4 TTL and ipv6 tc, ipv6 next-header, ipv6 hop-limits since previous FDIR for i40e already support it.
Best Regards
Yulong Pei
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Tuesday, December 20, 2016 1:49 AM
To: [email protected]
Subject: [dpdk-dev] [PATCH v3 21/25] app/testpmd: add items ipv4/ipv6 to flow command
Add the ability to match basic fields from IPv4 and IPv6 headers (source and destination addresses only).
--- app/test-pmd/cmdline_flow.c | 177 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+)
app/test-pmd/cmdline_flow.c +177 -1
@@ -38,6 +38,7 @@#include <errno.h> #include <ctype.h> #include <string.h> +#include <arpa/inet.h> #include <rte_common.h> #include <rte_ethdev.h>
@@ -61,6 +62,8 @@ enum index {BOOLEAN ,STRING ,MAC_ADDR , +IPV4_ADDR , +IPV6_ADDR ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -123,6 +126,12 @@ enum index {ITEM_VLAN ,ITEM_VLAN_TPID ,ITEM_VLAN_TCI , +ITEM_IPV4 , +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_IPV6 , +ITEM_IPV6_SRC , +ITEM_IPV6_DST ,/* Validate/create actions. */ ACTIONS,
@@ -348,6 +357,8 @@ static const enum index next_item[] = {ITEM_RAW ,ITEM_ETH ,ITEM_VLAN , +ITEM_IPV4 , +ITEM_IPV6 , ZERO, };
@@ -394,6 +405,20 @@ static const enum index item_vlan[] = { ZERO, }; +static const enum index item_ipv4[] = { +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_ipv6[] = { +ITEM_IPV6_SRC , +ITEM_IPV6_DST , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -439,6 +464,12 @@ static int parse_string(struct context *, const struct token *, static int parse_mac_addr(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_ipv4_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_ipv6_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -509,6 +540,20 @@ static const struct token token_list[] = { .call = parse_mac_addr, .comp = comp_none, }, + [IPV4_ADDR] = { + .name = "{IPv4 address}", + .type = "IPV4 ADDRESS", + .help = "standard IPv4 address notation", + .call = parse_ipv4_addr, + .comp = comp_none, + }, + [IPV6_ADDR] = { + .name = "{IPv6 address}", + .type = "IPV6 ADDRESS", + .help = "standard IPv6 address notation", + .call = parse_ipv6_addr, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -843,6 +888,48 @@ static const struct token token_list[] = { .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), }, + [ITEM_IPV4] = { + .name = "ipv4", + .help = "match IPv4 header", + .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), + .next = NEXT(item_ipv4), + .call = parse_vc, + }, + [ITEM_IPV4_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.src_addr)), + }, + [ITEM_IPV4_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.dst_addr)), + }, + [ITEM_IPV6] = { + .name = "ipv6", + .help = "match IPv6 header", + .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), + .next = NEXT(item_ipv6), + .call = parse_vc, + }, + [ITEM_IPV6_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.src_addr)), + }, + [ITEM_IPV6_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.dst_addr)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1514,6 +1601,96 @@ parse_mac_addr(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse an IPv4 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv4_addr (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); +char str2[len +1 ]; +struct in_addr tmp; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET , str2, &tmp); +if (ret !=1 ) { +/* Attempt integer parsing. */ +push_args (ctx, arg); +return parse_int (ctx, token, str, len, buf, size); + } +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} + +/** +* Parse an IPv6 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv6_addr (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); +char str2[len +1 ]; +struct in6_addr tmp; +int ret; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET6 , str2, &tmp); +if (ret !=1 ) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Boolean values (even indices stand for false). */ static const char *const boolean_name[] = {"0" ,"1" , --
2.1.4
Re: [PATCH v3 21/25] app/testpmd: add items ipv4/ipv6 to flow command
Hi Yulong,
Quoted 4 lines · Yulong
Hi adrien,
Is it possible to support to set ipv4 TOS, ipv4 PROTO, ipv4 TTL and ipv6 tc, ipv6 next-header, ipv6 hop-limits since previous FDIR for i40e already support it.
I suggest we add them later (like for SCTP tag, it's just a bunch of new flow tokens to manage in testpmd), it is not blocking for the API itself.
Signature · 2 lines
Adrien Mazarguil 6WIND
PATCH v3 22/25 app/testpmd: add L4 items to flow command
In reply to Adrien MazarguilAdd the ability to match a few properties of common L4[.5] protocol headers:
- ICMP: type and code.
- UDP: source and destination ports.
- TCP: source and destination ports.
- SCTP: source and destination ports.
- VXLAN: network identifier.
--- app/test-pmd/cmdline_flow.c | 163 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+)
app/test-pmd/cmdline_flow.c +163 -0
@@ -132,6 +132,20 @@ enum index {ITEM_IPV6 ,ITEM_IPV6_SRC ,ITEM_IPV6_DST , +ITEM_ICMP , +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_UDP , +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_TCP , +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_SCTP , +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_VXLAN , +ITEM_VXLAN_VNI ,/* Validate/create actions. */ ACTIONS,
@@ -359,6 +373,11 @@ static const enum index next_item[] = {ITEM_VLAN ,ITEM_IPV4 ,ITEM_IPV6 , +ITEM_ICMP , +ITEM_UDP , +ITEM_TCP , +ITEM_SCTP , +ITEM_VXLAN , ZERO, };
@@ -419,6 +438,40 @@ static const enum index item_ipv6[] = { ZERO, }; +static const enum index item_icmp[] = { +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_udp[] = { +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_tcp[] = { +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_sctp[] = { +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_vxlan[] = { +ITEM_VXLAN_VNI , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -930,6 +983,103 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, hdr.dst_addr)), }, + [ITEM_ICMP] = { + .name = "icmp", + .help = "match ICMP header", + .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), + .next = NEXT(item_icmp), + .call = parse_vc, + }, + [ITEM_ICMP_TYPE] = { + .name = "type", + .help = "ICMP packet type", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_type)), + }, + [ITEM_ICMP_CODE] = { + .name = "code", + .help = "ICMP packet code", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_code)), + }, + [ITEM_UDP] = { + .name = "udp", + .help = "match UDP header", + .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)), + .next = NEXT(item_udp), + .call = parse_vc, + }, + [ITEM_UDP_SRC] = { + .name = "src", + .help = "UDP source port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.src_port)), + }, + [ITEM_UDP_DST] = { + .name = "dst", + .help = "UDP destination port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.dst_port)), + }, + [ITEM_TCP] = { + .name = "tcp", + .help = "match TCP header", + .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), + .next = NEXT(item_tcp), + .call = parse_vc, + }, + [ITEM_TCP_SRC] = { + .name = "src", + .help = "TCP source port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.src_port)), + }, + [ITEM_TCP_DST] = { + .name = "dst", + .help = "TCP destination port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.dst_port)), + }, + [ITEM_SCTP] = { + .name = "sctp", + .help = "match SCTP header", + .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), + .next = NEXT(item_sctp), + .call = parse_vc, + }, + [ITEM_SCTP_SRC] = { + .name = "src", + .help = "SCTP source port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.src_port)), + }, + [ITEM_SCTP_DST] = { + .name = "dst", + .help = "SCTP destination port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.dst_port)), + }, + [ITEM_VXLAN] = { + .name = "vxlan", + .help = "match VXLAN header", + .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), + .next = NEXT(item_vxlan), + .call = parse_vc, + }, + [ITEM_VXLAN_VNI] = { + .name = "vni", + .help = "VXLAN identifier", + .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1491,6 +1641,19 @@ parse_int(struct context *ctx, const struct token *token,case sizeof (uint16_t ): *(uint16_t *)buf = arg->hton ?rte_cpu_to_be_16 (u) : u;break ; +case sizeof (uint8_t [3 ]): +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { + ((uint8_t *)buf)[0 ] = u; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u >>16 ; +break ; + } +#endif + ((uint8_t *)buf)[0 ] = u >>16 ; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u; +break ;case sizeof (uint32_t ): *(uint32_t *)buf = arg->hton ?rte_cpu_to_be_32 (u) : u;break ;
Signature · 1 line
2.1.4
Re: [PATCH v3 22/25] app/testpmd: add L4 items to flow command
Hi Adrien,
For SCTP, it may need support to set 'tag' since in FDIR (--pkt-filter-mode=perfect) need set it when filter sctp flow.
struct sctp_hdr {
uint16_t src_port; /**< Source port. */
uint16_t dst_port; /**< Destin port. */
uint32_t tag; /**< Validation tag. */
uint32_t cksum; /**< Checksum. */
} __attribute__((__packed__));testpmd> flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 dst is 192.168.0.2 / sctp
src [TOKEN]: SCTP source port
dst [TOKEN]: SCTP destination port
/ [TOKEN]: specify next pattern item
Best Regards
Yulong Pei
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Tuesday, December 20, 2016 1:49 AM
To: [email protected]
Subject: [dpdk-dev] [PATCH v3 22/25] app/testpmd: add L4 items to flow command
Add the ability to match a few properties of common L4[.5] protocol headers:
- ICMP: type and code.
- UDP: source and destination ports.
- TCP: source and destination ports.
- SCTP: source and destination ports.
- VXLAN: network identifier.
--- app/test-pmd/cmdline_flow.c | 163 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+)
app/test-pmd/cmdline_flow.c +163 -0
@@ -132,6 +132,20 @@ enum index {ITEM_IPV6 ,ITEM_IPV6_SRC ,ITEM_IPV6_DST , +ITEM_ICMP , +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_UDP , +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_TCP , +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_SCTP , +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_VXLAN , +ITEM_VXLAN_VNI ,/* Validate/create actions. */ ACTIONS,
@@ -359,6 +373,11 @@ static const enum index next_item[] = {ITEM_VLAN ,ITEM_IPV4 ,ITEM_IPV6 , +ITEM_ICMP , +ITEM_UDP , +ITEM_TCP , +ITEM_SCTP , +ITEM_VXLAN , ZERO, };
@@ -419,6 +438,40 @@ static const enum index item_ipv6[] = { ZERO, }; +static const enum index item_icmp[] = { +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_udp[] = { +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_tcp[] = { +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_sctp[] = { +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_vxlan[] = { +ITEM_VXLAN_VNI , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -930,6 +983,103 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, hdr.dst_addr)), }, + [ITEM_ICMP] = { + .name = "icmp", + .help = "match ICMP header", + .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), + .next = NEXT(item_icmp), + .call = parse_vc, + }, + [ITEM_ICMP_TYPE] = { + .name = "type", + .help = "ICMP packet type", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_type)), + }, + [ITEM_ICMP_CODE] = { + .name = "code", + .help = "ICMP packet code", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_code)), + }, + [ITEM_UDP] = { + .name = "udp", + .help = "match UDP header", + .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)), + .next = NEXT(item_udp), + .call = parse_vc, + }, + [ITEM_UDP_SRC] = { + .name = "src", + .help = "UDP source port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.src_port)), + }, + [ITEM_UDP_DST] = { + .name = "dst", + .help = "UDP destination port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.dst_port)), + }, + [ITEM_TCP] = { + .name = "tcp", + .help = "match TCP header", + .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), + .next = NEXT(item_tcp), + .call = parse_vc, + }, + [ITEM_TCP_SRC] = { + .name = "src", + .help = "TCP source port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.src_port)), + }, + [ITEM_TCP_DST] = { + .name = "dst", + .help = "TCP destination port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.dst_port)), + }, + [ITEM_SCTP] = { + .name = "sctp", + .help = "match SCTP header", + .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), + .next = NEXT(item_sctp), + .call = parse_vc, + }, + [ITEM_SCTP_SRC] = { + .name = "src", + .help = "SCTP source port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.src_port)), + }, + [ITEM_SCTP_DST] = { + .name = "dst", + .help = "SCTP destination port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.dst_port)), + }, + [ITEM_VXLAN] = { + .name = "vxlan", + .help = "match VXLAN header", + .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), + .next = NEXT(item_vxlan), + .call = parse_vc, + }, + [ITEM_VXLAN_VNI] = { + .name = "vni", + .help = "VXLAN identifier", + .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1491,6 +1641,19 @@ parse_int(struct context *ctx, const struct token *token,case sizeof (uint16_t ): *(uint16_t *)buf = arg->hton ?rte_cpu_to_be_16 (u) : u;break ; +case sizeof (uint8_t [3 ]): +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { + ((uint8_t *)buf)[0 ] = u; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u >>16 ; +break ; + } +#endif + ((uint8_t *)buf)[0 ] = u >>16 ; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u; +break ;case sizeof (uint32_t ): *(uint32_t *)buf = arg->hton ?rte_cpu_to_be_32 (u) : u;break ;
--
2.1.4
Re: [PATCH v3 22/25] app/testpmd: add L4 items to flow command
Hi Yulong,
Quoted 11 lines · Yulong
Hi Adrien,
For SCTP, it may need support to set 'tag' since in FDIR (--pkt-filter-mode=perfect) need set it when filter sctp flow.
struct sctp_hdr { uint16_t src_port; /**< Source port. */ uint16_t dst_port; /**< Destin port. */ uint32_t tag; /**< Validation tag. */ uint32_t cksum; /**< Checksum. */ } __attribute__((__packed__));
Quoted 4 lines
testpmd> flow create 0 ingress pattern eth / ipv4 src is 192.168.0.1 dst is 192.168.0.2 / sctp
src [TOKEN]: SCTP source port
dst [TOKEN]: SCTP destination port
/ [TOKEN]: specify next pattern item
Sure, let's add it in a subsequent patch after this series is applied, it is only a few lines of code in testpmd (basically like all missing protocol fields).
Signature · 2 lines
Adrien Mazarguil 6WIND
PATCH v3 23/25 app/testpmd: add various actions to flow command
In reply to Adrien Mazarguil- MARK: attach 32 bit value to packets.
- FLAG: flag packets.
- DROP: drop packets.
- COUNT: enable counters for a rule.
- PF: redirect packets to physical device function.
- VF: redirect packets to virtual device function.
--- app/test-pmd/cmdline_flow.c | 121 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+)
app/test-pmd/cmdline_flow.c +121 -0
@@ -153,6 +153,15 @@ enum index {ACTION_END ,ACTION_VOID ,ACTION_PASSTHRU , +ACTION_MARK , +ACTION_MARK_ID , +ACTION_FLAG , +ACTION_DROP , +ACTION_COUNT , +ACTION_PF , +ACTION_VF , +ACTION_VF_ORIGINAL , + ACTION_VF_ID, };/** Size of pattern[] field in struct rte_flow_item_raw. */
@@ -476,6 +485,25 @@ static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,ACTION_PASSTHRU , +ACTION_MARK , +ACTION_FLAG , +ACTION_DROP , +ACTION_COUNT , +ACTION_PF , +ACTION_VF , + ZERO, +}; + +static const enum index action_mark[] = { +ACTION_MARK_ID , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_vf[] = { +ACTION_VF_ORIGINAL , +ACTION_VF_ID , +ACTION_NEXT ,ZERO , };
@@ -487,6 +515,8 @@ static int parse_vc(struct context *, const struct token *, void *, unsigned int);static int parse_vc_spec (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_conf (struct context *,const struct token *, +const char *,unsigned int ,void *,unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -1112,6 +1142,70 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_MARK] = { + .name = "mark", + .help = "attach 32 bit value to packets", + .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)), + .next = NEXT(action_mark), + .call = parse_vc, + }, + [ACTION_MARK_ID] = { + .name = "id", + .help = "32 bit value to return with packets", + .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)), + .call = parse_vc_conf, + }, + [ACTION_FLAG] = { + .name = "flag", + .help = "flag packets", + .priv = PRIV_ACTION(FLAG, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_DROP] = { + .name = "drop", + .help = "drop packets (note: passthru has priority)", + .priv = PRIV_ACTION(DROP, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_COUNT] = { + .name = "count", + .help = "enable counters for this rule", + .priv = PRIV_ACTION(COUNT, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_PF] = { + .name = "pf", + .help = "redirect packets to physical device function", + .priv = PRIV_ACTION(PF, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_VF] = { + .name = "vf", + .help = "redirect packets to virtual device function", + .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)), + .next = NEXT(action_vf), + .call = parse_vc, + }, + [ACTION_VF_ORIGINAL] = { + .name = "original", + .help = "use original VF ID if possible", + .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf, + original, 1)), + .call = parse_vc_conf, + }, + [ACTION_VF_ID] = { + .name = "id", + .help = "VF ID to redirect packets to", + .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)), + .call = parse_vc_conf, + }, };/** Remove and return last entry from argument stack. */
@@ -1435,6 +1529,33 @@ parse_vc_spec(struct context *ctx, const struct token *token,return len; } +/** Parse action configuration field. */ +static int +parse_vc_conf (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +struct buffer *out = buf; +struct rte_flow_action *action; + + (void )size; +/* 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->args.vc.actions_n) +return -1 ; + action = &out->args.vc.actions[out->args.vc.actions_n -1 ]; +/* Point to selected object. */ + ctx->object = out->args.vc.data; + ctx->objmask =NULL ; +/* Update configuration pointer. */ + action->conf = ctx->object; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
Signature · 1 line
2.1.4
PATCH v3 24/25 app/testpmd: add queue actions to flow command
In reply to Adrien Mazarguil- QUEUE: assign packets to a given queue index.
- DUP: duplicate packets to a given queue index.
- RSS: spread packets among several queues.
--- app/test-pmd/cmdline_flow.c | 152 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+)
app/test-pmd/cmdline_flow.c +152 -0
@@ -156,8 +156,15 @@ enum index {ACTION_MARK ,ACTION_MARK_ID ,ACTION_FLAG , +ACTION_QUEUE , +ACTION_QUEUE_INDEX ,ACTION_DROP ,ACTION_COUNT , +ACTION_DUP , +ACTION_DUP_INDEX , +ACTION_RSS , +ACTION_RSS_QUEUES , +ACTION_RSS_QUEUE ,ACTION_PF ,ACTION_VF , ACTION_VF_ORIGINAL,
@@ -171,6 +178,14 @@ enum index {#define ITEM_RAW_SIZE \ (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) +/** Number of queue[] entries in struct rte_flow_action_rss. */ +#define ACTION_RSS_NUM 32 + +/** Storage size for struct rte_flow_action_rss including queues. */ +#define ACTION_RSS_SIZE \ + (offsetof(struct rte_flow_action_rss, queue) + \ + sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM) +/** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16
@@ -487,8 +502,11 @@ static const enum index next_action[] = {ACTION_PASSTHRU ,ACTION_MARK ,ACTION_FLAG , +ACTION_QUEUE ,ACTION_DROP ,ACTION_COUNT , +ACTION_DUP , +ACTION_RSS ,ACTION_PF ,ACTION_VF , ZERO,
@@ -500,6 +518,24 @@ static const enum index action_mark[] = { ZERO, }; +static const enum index action_queue[] = { +ACTION_QUEUE_INDEX , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_dup[] = { +ACTION_DUP_INDEX , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_rss[] = { +ACTION_RSS_QUEUES , +ACTION_NEXT , +ZERO , +}; +static const enum index action_vf[] = {ACTION_VF_ORIGINAL ,ACTION_VF_ID ,
@@ -517,6 +553,9 @@ static int parse_vc_spec(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int);static int parse_vc_conf (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_action_rss_queue (struct context *,const struct token *, +const char *,unsigned int ,void *, +unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -566,6 +605,8 @@ static int comp_port(struct context *, const struct token *, unsigned int, char *, unsigned int);static int comp_rule_id (struct context *,const struct token *,unsigned int ,char *,unsigned int ); +static int comp_vc_action_rss_queue (struct context *,const struct token *, +unsigned int ,char *,unsigned int );/** Token definitions. */ static const struct token token_list[] = {
@@ -1163,6 +1204,21 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_QUEUE] = { + .name = "queue", + .help = "assign packets to a given queue index", + .priv =PRIV_ACTION (QUEUE , + sizeof(struct rte_flow_action_queue)), + .next = NEXT(action_queue), + .call = parse_vc, + }, + [ACTION_QUEUE_INDEX] = { + .name = "index", + .help = "queue index to use", + .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)), + .call = parse_vc_conf, + }, [ACTION_DROP] = { .name = "drop", .help = "drop packets (note: passthru has priority)",
@@ -1177,6 +1233,39 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_DUP] = { + .name = "dup", + .help = "duplicate packets to a given queue index", + .priv = PRIV_ACTION(DUP, sizeof(struct rte_flow_action_dup)), + .next = NEXT(action_dup), + .call = parse_vc, + }, + [ACTION_DUP_INDEX] = { + .name = "index", + .help = "queue index to duplicate packets to", + .next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_dup, index)), + .call = parse_vc_conf, + }, + [ACTION_RSS] = { + .name = "rss", + .help = "spread packets among several queues", + .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE), + .next = NEXT(action_rss), + .call = parse_vc, + }, + [ACTION_RSS_QUEUES] = { + .name = "queues", + .help = "queue indices to use", + .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)), + .call = parse_vc_conf, + }, + [ACTION_RSS_QUEUE] = { + .name = "{queue}", + .help = "queue index", + .call = parse_vc_action_rss_queue, + .comp = comp_vc_action_rss_queue, + }, [ACTION_PF] = { .name = "pf", .help = "redirect packets to physical device function",
@@ -1556,6 +1645,51 @@ parse_vc_conf(struct context *ctx, const struct token *token,return len; } +/** +* Parse queue field for RSS action. +* +* Valid tokens are queue indices and the "end" token. +*/ +static int +parse_vc_action_rss_queue (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +static const enum index next[] =NEXT_ENTRY (ACTION_RSS_QUEUE ); +int ret; +int i; + + (void )token; + (void )buf; + (void )size; +if (ctx->curr !=ACTION_RSS_QUEUE ) +return -1 ; + i = ctx->objdata >>16 ; +if (!strncmp (str,"end" , len)) { + ctx->objdata &=0xffff ; +return len; + } +if (i >=ACTION_RSS_NUM ) +return -1 ; + if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i]))) +return -1 ; + ret =parse_int (ctx, token, str, len,NULL ,0 ); +if (ret <0 ) { +pop_args (ctx); +return -1 ; + } + ++i; + ctx->objdata = i <<16 | (ctx->objdata &0xffff ); +/* Repeat token. */ +if (ctx->next_num ==RTE_DIM (ctx->next)) +return -1 ; + ctx->next[ctx->next_num++] = next; +if (!ctx->object) +return len; + ((struct rte_flow_action_rss *)ctx->object)->num = i; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
@@ -2130,6 +2264,24 @@ comp_rule_id(struct context *ctx, const struct token *token,return i; } +/** Complete queue field for RSS action. */ +static int +comp_vc_action_rss_queue (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ +static const char *const str[] = {"" ,"end" ,NULL }; +unsigned int i; + + (void )ctx; + (void )token; +for (i =0 ; str[i] !=NULL ; ++i) +if (buf && i == ent) +return snprintf (buf, size,"%s" , str[i]); +if (buf) +return -1 ; +return i; +} +/** Internal context. */ static struct context cmd_flow_context;
Signature · 1 line
2.1.4
PATCH v3 25/25 doc: describe testpmd flow command
In reply to Adrien MazarguilDocument syntax, interaction with rte_flow and provide usage examples.
--- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 612 +++++++++++++++++++++++ 1 file changed, 612 insertions(+)
doc/guides/testpmd_app_ug/testpmd_funcs.rst +612 -0
@@ -1631,6 +1631,9 @@ Filter Functions This section details the available filter functions that are available. +Note these functions interface the deprecated legacy filtering framework, +superseded by *rte_flow*. See `Flow rules management`_. + ethertype_filter ~~~~~~~~~~~~~~~~~~~~
@@ -2041,3 +2044,612 @@ Set different GRE key length for input set:: For example to set GRE key length for input set to 4 bytes on port 0:: testpmd> global_config 0 gre-key-len 4 + + +.. _testpmd_rte_flow: + +Flow rules management +--------------------- + +Control of the generic flow API (*rte_flow*) is fully exposed through the +``flow`` command (validation, creation, destruction and queries). + +Considering *rte_flow* overlaps with all `Filter Functions`_, using both +features simultaneously may cause undefined side-effects and is therefore +not recommended. + +``flow`` syntax +~~~~~~~~~~~~~~~ + +Because the ``flow`` command uses dynamic tokens to handle the large number +of possible flow rules combinations, its behavior differs slightly from +other commands, in particular: + +- Pressing *?* or the *<tab>* key displays contextual help for the current + token, not that of the entire command. + +- Optional and repeated parameters are supported (provided they are listed + in the contextual help). + +The first parameter stands for the operation mode. Possible operations and +their general syntax are described below. They are covered in detail in the +following sections. + +- Check whether a flow rule can be created:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Create a flow rule:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Destroy specific flow rules:: + + flow destroy {port_id} rule {rule_id} [...] + +- Destroy all flow rules:: + + flow flush {port_id} + +- Query an existing flow rule:: + + flow query {port_id} {rule_id} {action} + +- List existing flow rules sorted by priority, filtered by group + identifiers:: + + flow list {port_id} [group {group_id}] [...] + +Validating flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow validate`` reports whether a flow rule would be accepted by the +underlying device in its current state but stops short of creating it. It is +bound to ``rte_flow_validate()``:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will show:: + + Flow rule validated + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +This command uses the same parameters as ``flow create``, their format is +described in `Creating flow rules`_. + +Check whether redirecting any Ethernet packet received on port 0 to RX queue +index 6 is supported:: + + testpmd> flow validate 1 ingress pattern eth / end + actions queue index 6 / end + Flow rule validated + testpmd> + +Port 0 does not support TCPv6 rules:: + + testpmd> flow validate 0 ingress pattern eth / ipv6 / tcp / end + actions drop / end + Caught error type 9 (specific pattern item): Invalid argument. + testpmd> + +Creating flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow create`` validates and creates the specified flow rule. It is bound +to ``rte_flow_create()``:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will return a flow rule ID usable with other commands:: + + Flow rule #[...] created + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +Parameters describe in the following order: + +- Attributes (*group*, *priority*, *ingress*, *egress* tokens). +- A matching pattern, starting with the *pattern* token and terminated by an + *end* pattern item. +- Actions, starting with the *actions* token and terminated by an *end* + action. + +These translate directly to *rte_flow* objects provided as-is to the +underlying functions. + +The shortest valid definition only comprises mandatory tokens:: + + testpmd> flow create 0 pattern end actions end + +Note that PMDs may refuse rules that essentially do nothing such as this +one. + +**All unspecified object values are automatically initialized to 0.** + +Attributes +^^^^^^^^^^ + +These tokens affect flow rule attributes (``struct rte_flow_attr``) and are +specified before the ``pattern`` token. + +- ``group {group id}``: priority group. +- ``priority {level}``: priority level within group. +- ``ingress``: rule applies to ingress traffic. +- ``egress``: rule applies to egress traffic. + +Each instance of an attribute specified several times overrides the previous +value as shown below (group 4 is used):: + + testpmd> flow create 0 group 42 group 24 group 4 [...] + +Note that once enabled, ``ingress`` and ``egress`` cannot be disabled. + +While not specifying a direction is an error, some rules may allow both +simultaneously. + +Most rules affect RX therefore contain the ``ingress`` token:: + + testpmd> flow create 0 ingress pattern [...] + +Matching pattern +^^^^^^^^^^^^^^^^ + +A matching pattern starts after the ``pattern`` token. It is made of pattern +items and is terminated by a mandatory ``end`` item. + +Items are named after their type (*RTE_FLOW_ITEM_TYPE_* from ``enum +rte_flow_item_type``). + +The ``/`` token is used as a separator between pattern items as shown +below:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end [...] + +Note that protocol items like these must be stacked from lowest to highest +layer to make sense. For instance, the following rule is either invalid or +unlikely to match any packet:: + + testpmd> flow create 0 ingress pattern eth / udp / ipv4 / end [...] + +More information on these restrictions can be found in the *rte_flow* +documentation. + +Several items support additional specification structures, for example +``ipv4`` allows specifying source and destination addresses as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 src is 10.1.1.1 + dst is 10.2.0.0 / end [...] + +This rule matches all IPv4 traffic with the specified properties. + +In this example, ``src`` and ``dst`` are field names of the underlying +``struct rte_flow_item_ipv4`` object. All item properties can be specified +in a similar fashion. + +The ``is`` token means that the subsequent value must be matched exactly, +and assigns ``spec`` and ``mask`` fields in ``struct rte_flow_item`` +accordingly. Possible assignment tokens are: + +- ``is``: match value perfectly (with full bit-mask). +- ``spec``: match value according to configured bit-mask. +- ``last``: specify upper bound to establish a range. +- ``mask``: specify bit-mask with relevant bits set to one. +- ``prefix``: generate bit-mask from a prefix length. + +These yield identical results:: + + ipv4 src is 10.1.1.1 + +:: + + ipv4 src spec 10.1.1.1 src mask 255.255.255.255 + +:: + + ipv4 src spec 10.1.1.1 src prefix 32 + +:: + + ipv4 src is 10.1.1.1 src last 10.1.1.1 # range with a single value + +:: + + ipv4 src is 10.1.1.1 src last 0 # 0 disables range + +Inclusive ranges can be defined with ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 # 10.1.1.1 to 10.2.3.4 + +Note that ``mask`` affects both ``spec`` and ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 src mask 255.255.0.0 + # matches 10.1.0.0 to 10.2.255.255 + +Properties can be modified multiple times:: + + ipv4 src is 10.1.1.1 src is 10.1.2.3 src is 10.2.3.4 # matches 10.2.3.4 + +:: + + ipv4 src is 10.1.1.1 src prefix 24 src prefix 16 # matches 10.1.0.0/16 + +Pattern items +^^^^^^^^^^^^^ + +This section lists supported pattern items and their attributes, if any. + +- ``end``: end list of pattern items. + +- ``void``: no-op pattern item. + +- ``invert``: perform actions when pattern does not match. + +- ``any``: match any protocol for the current layer. + + - ``num {unsigned}``: number of layers covered. + +- ``pf``: match packets addressed to the physical function. + +- ``vf``: match packets addressed to a virtual function ID. + + - ``id {unsigned}``: destination VF ID. + +- ``port``: device-specific physical port index to use. + + - ``index {unsigned}``: physical port index. + +- ``raw``: match an arbitrary byte string. + + - ``relative {boolean}``: look for pattern after the previous item. + - ``search {boolean}``: search pattern from offset (see also limit). + - ``offset {integer}``: absolute or relative offset for pattern. + - ``limit {unsigned}``: search area limit for start of pattern. + - ``pattern {string}``: byte string to look for. + +- ``eth``: match Ethernet header. + + - ``dst {MAC-48}``: destination MAC. + - ``src {MAC-48}``: source MAC. + - ``type {unsigned}``: EtherType. + +- ``vlan``: match 802.1Q/ad VLAN tag. + + - ``tpid {unsigned}``: tag protocol identifier. + - ``tci {unsigned}``: tag control information. + +- ``ipv4``: match IPv4 header. + + - ``src {ipv4 address}``: source address. + - ``dst {ipv4 address}``: destination address. + +- ``ipv6``: match IPv6 header. + + - ``src {ipv6 address}``: source address. + - ``dst {ipv6 address}``: destination address. + +- ``icmp``: match ICMP header. + + - ``type {unsigned}``: ICMP packet type. + - ``code {unsigned}``: ICMP packet code. + +- ``udp``: match UDP header. + + - ``src {unsigned}``: UDP source port. + - ``dst {unsigned}``: UDP destination port. + +- ``tcp``: match TCP header. + + - ``src {unsigned}``: TCP source port. + - ``dst {unsigned}``: TCP destination port. + +- ``sctp``: match SCTP header. + + - ``src {unsigned}``: SCTP source port. + - ``dst {unsigned}``: SCTP destination port. + +- ``vxlan``: match VXLAN header. + + - ``vni {unsigned}``: VXLAN identifier. + +Actions list +^^^^^^^^^^^^ + +A list of actions starts after the ``actions`` token in the same fashion as +`Matching pattern`_; actions are separated by ``/`` tokens and the list is +terminated by a mandatory ``end`` action. + +Actions are named after their type (*RTE_FLOW_ACTION_TYPE_* from ``enum +rte_flow_action_type``). + +Dropping all incoming UDPv4 packets can be expressed as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions drop / end + +Several actions have configurable properties which must be specified when +there is no valid default value. For example, ``queue`` requires a target +queue index. + +This rule redirects incoming UDPv4 traffic to queue index 6:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue index 6 / end + +While this one could be rejected by PMDs (unspecified queue index):: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue / end + +As defined by *rte_flow*, the list is not ordered, all actions of a given +rule are performed simultaneously. These are equivalent:: + + queue index 6 / void / mark id 42 / end + +:: + + void / mark id 42 / queue index 6 / end + +All actions in a list should have different types, otherwise only the last +action of a given type is taken into account:: + + queue index 4 / queue index 5 / queue index 6 / end # will use queue 6 + +:: + + drop / drop / drop / end # drop is performed only once + +:: + + mark id 42 / queue index 3 / mark id 24 / end # mark will be 24 + +Considering they are performed simultaneously, opposite and overlapping +actions can sometimes be combined when the end result is unambiguous:: + + drop / queue index 6 / end # drop has no effect + +:: + + drop / dup index 6 / end # same as above + +:: + + queue index 6 / rss queues 6 7 8 / end # queue has no effect + +:: + + drop / passthru / end # drop has no effect + +Note that PMDs may still refuse such combinations. + +Actions +^^^^^^^ + +This section lists supported actions and their attributes, if any. + +- ``end``: end list of actions. + +- ``void``: no-op action. + +- ``passthru``: let subsequent rule process matched packets. + +- ``mark``: attach 32 bit value to packets. + + - ``id {unsigned}``: 32 bit value to return with packets. + +- ``flag``: flag packets. + +- ``queue``: assign packets to a given queue index. + + - ``index {unsigned}``: queue index to use. + +- ``drop``: drop packets (note: passthru has priority). + +- ``count``: enable counters for this rule. + +- ``dup``: duplicate packets to a given queue index. + + - ``index {unsigned}``: queue index to duplicate packets to. + +- ``rss``: spread packets among several queues. + + - ``queues [{unsigned} [...]] end``: queue indices to use. + +- ``pf``: redirect packets to physical device function. + +- ``vf``: redirect packets to virtual device function. + + - ``original {boolean}``: use original VF ID if possible. + - ``id {unsigned}``: VF ID to redirect packets to. + +Destroying flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow destroy`` destroys one or more rules from their rule ID (as returned +by ``flow create``), this command calls ``rte_flow_destroy()`` as many +times as necessary:: + + flow destroy {port_id} rule {rule_id} [...] + +If successful, it will show:: + + Flow rule #[...] destroyed + +It does not report anything for rule IDs that do not exist. The usual error +message is shown when a rule cannot be destroyed:: + + Caught error type [...] ([...]): [...] + +``flow flush`` destroys all rules on a device and does not take extra +arguments. It is bound to ``rte_flow_flush()``:: + + flow flush {port_id} + +Any errors are reported as above. + +Creating several rules and destroying them:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 0 rule 1 + Flow rule #1 destroyed + Flow rule #0 destroyed + testpmd> + +The same result can be achieved using ``flow flush``:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow flush 0 + testpmd> + +Non-existent rule IDs are ignored:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 42 rule 10 rule 2 + testpmd> + testpmd> flow destroy 0 rule 0 + Flow rule #0 destroyed + testpmd> + +Querying flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow query`` queries a specific action of a flow rule having that +ability. Such actions collect information that can be reported using this +command. It is bound to ``rte_flow_query()``:: + + flow query {port_id} {rule_id} {action} + +If successful, it will display either the retrieved data for known actions +or the following message:: + + Cannot display result for action type [...] ([...]) + +Otherwise, it will complain either that the rule does not exist or that some +error occurred:: + + Flow rule #[...] not found + +:: + + Caught error type [...] ([...]): [...] + +Currently only the ``count`` action is supported. This action reports the +number of packets that hit the flow rule and the total number of bytes. Its +output has the following format:: + + count: + hits_set: [...] # whether "hits" contains a valid value + bytes_set: [...] # whether "bytes" contains a valid value + hits: [...] # number of packets + bytes: [...] # number of bytes + +Querying counters for TCPv6 packets redirected to queue 6:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / tcp / end + actions queue index 6 / count / end + Flow rule #4 created + testpmd> flow query 0 4 count + count: + hits_set: 1 + bytes_set: 0 + hits: 386446 + bytes: 0 + testpmd> + +Listing flow rules +~~~~~~~~~~~~~~~~~~ + +``flow list`` lists existing flow rules sorted by priority and optionally +filtered by group identifiers:: + + flow list {port_id} [group {group_id}] [...] + +This command only fails with the following message if the device does not +exist:: + + Invalid port [...] + +Output consists of a header line followed by a short description of each +flow rule, one per line. There is no output at all when no flow rules are +configured on the device:: + + ID Group Prio Attr Rule + [...] [...] [...] [...] [...] + +``Attr`` column flags: + +- ``i`` for ``ingress``. +- ``e`` for ``egress``. + +Creating several flow rules and listing them:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 6 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #1 created + testpmd> flow create 0 priority 5 ingress pattern eth / ipv4 / udp / end + actions rss queues 6 7 8 end / end + Flow rule #2 created + testpmd> flow list 0 + ID Group Prio Attr Rule + 0 0 0 i- ETH IPV4 => QUEUE + 1 0 0 i- ETH IPV6 => QUEUE + 2 0 5 i- ETH IPV4 UDP => RSS + testpmd> + +Rules are sorted by priority (i.e. group ID first, then priority level):: + + testpmd> flow list 1 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 1 24 0 i- ETH IPV4 UDP => QUEUE + 4 24 10 i- ETH IPV4 TCP => DROP + 3 24 20 i- ETH IPV4 => DROP + 2 24 42 i- ETH IPV4 UDP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd> + +Output can be limited to specific groups:: + + testpmd> flow list 1 group 0 group 63 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd>
Signature · 1 line
2.1.4
Re: [PATCH v3 25/25] doc: describe testpmd flow command
Quoted 27 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Monday, December 19, 2016 5:49 PM
To: [email protected]
Subject: [dpdk-dev] [PATCH v3 25/25] doc: describe testpmd flow commandDocument syntax, interaction with
rte_flowand provide usage examples.Signed-off-by Adrien Mazarguil <[email protected]>...
doc/guides/testpmd_app_ug/testpmd_funcs.rst +13
-0+ +- Check whether a flow rule can be created:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Create a flow rule:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end
doc/guides/testpmd_app_ug/testpmd_funcs.rst Set different GRE key length for input set:: · line 2099
Quoted 10 lines
doc/guides/testpmd_app_ug/testpmd_funcs.rst +10
-0+ actions {action} [/ {action} [...]] / end + +- Destroy specific flow rules:: + + flow destroy {port_id} rule {rule_id} [...] + +- Destroy all flow rules:: + + flow flush {port_id} +
Just a note:
The verbs destroy and flush don't sound right here. Create/destroy are common verbs pairs for objects but these actions are more like add/remove. I guess the names come from the underlying APIs which possibly are creating/freeing objects/structures but maybe they should be called add/remove as well.
And flush generally applies to a pipeline or a queue. The action here is closer to "remove all".
Probably not worth reworking at this stage if it hasn't bothered anyone else.
doc/guides/testpmd_app_ug/testpmd_funcs.rst Set different GRE key length for input set:: · line 2084
Quoted 8 lines
doc/guides/testpmd_app_ug/testpmd_funcs.rst +8
-0+underlying device in its current state but stops short of creating it. +It is bound to ``rte_flow_validate()``:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end +
Here and elsewhere the indentation should be the RST standard 3 spaces, similar to the rest of the doc. This is only worth changing if you do some other revision of this doc.
Otherwise very good documentation.
Re: [PATCH v3 25/25] doc: describe testpmd flow command
Quoted 45 lines · John
Quoted 27 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Monday, December 19, 2016 5:49 PM
To: [email protected]
Subject: [dpdk-dev] [PATCH v3 25/25] doc: describe testpmd flow commandDocument syntax, interaction with
rte_flowand provide usage examples.Signed-off-by Adrien Mazarguil <[email protected]>...
doc/guides/testpmd_app_ug/testpmd_funcs.rst +13
-0+ +- Check whether a flow rule can be created:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Create a flow rule:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / enddoc/guides/testpmd_app_ug/testpmd_funcs.rst Set different GRE key length for input set:: · line 2099
Quoted 10 lines
doc/guides/testpmd_app_ug/testpmd_funcs.rst +10
-0+ actions {action} [/ {action} [...]] / end + +- Destroy specific flow rules:: + + flow destroy {port_id} rule {rule_id} [...] + +- Destroy all flow rules:: + + flow flush {port_id} +Just a note:
The verbs destroy and flush don't sound right here. Create/destroy are common verbs pairs for objects but these actions are more like add/remove. I guess the names come from the underlying APIs which possibly are creating/freeing objects/structures but maybe they should be called add/remove as well.
Quoted 4 lines
And flush generally applies to a pipeline or a queue. The action here is closer to "remove all".
Probably not worth reworking at this stage if it hasn't bothered anyone else.
Well, Kevin Traynor made a similar suggestion to which I replied that the name would be modified if enough people complained [1].
I understand your point but for some reason I keep hearing a flushing noise every time all rules are removed at once, hence the name.
Problem is also that we now have 3 PMD series floating on the ML that depend on the current definition. If we decided to change it, I suggest doing so in a separate fix. A few more complaints from developers are needed before it's too late for 17.02.
Quoted 13 lines
doc/guides/testpmd_app_ug/testpmd_funcs.rst Set different GRE key length for input set:: · line 2084
Quoted 8 lines
doc/guides/testpmd_app_ug/testpmd_funcs.rst +8
-0+underlying device in its current state but stops short of creating it. +It is bound to ``rte_flow_validate()``:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end +Here and elsewhere the indentation should be the RST standard 3 spaces, similar to the rest of the doc. This is only worth changing if you do some other revision of this doc.
Quoted 3 lines
Otherwise very good documentation.
Acked-by John McNamara <[email protected]>
Thanks, I'll make those changes if anything else warrants a v4.
[1] http://dpdk.org/ml/archives/dev/2016-December/050973.html
Signature · 2 lines
Adrien Mazarguil 6WIND
Re: [PATCH v3 25/25] doc: describe testpmd flow command
In reply to Adrien MazarguilQuoted 5 lines · Adrien Mazarguil
Document syntax, interaction with
rte_flowand provide usage examples.Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>---
<...>
doc/guides/testpmd_app_ug/testpmd_funcs.rst Set different GRE key length for input set:: · line 2135
Quoted 5 lines
doc/guides/testpmd_app_ug/testpmd_funcs.rst +5
-0+ +Check whether redirecting any Ethernet packet received on port 0 to RX queue +index 6 is supported:: + + testpmd> flow validate 1 ingress pattern eth / end
Small detail, but since note mentions "port 0", command should be:
testpmd> flow validate 0 ingress pattern eth / end ...
<...>
v4 cover Generic flow API (rte_flow)
In reply to Adrien MazarguilAs previously discussed in RFC v1 [1], RFC v2 [2], with changes described in [3] (also pasted below), here is the first non-draft series for this new API.
Its capabilities are so generic that its name had to be vague, it may be called "Generic flow API", "Generic flow interface" (possibly shortened as "GFI") to refer to the name of the new filter type, or "rte_flow" from the prefix used for its public symbols. I personally favor the latter.
While it is currently meant to supersede existing filter types in order for all PMDs to expose a common filtering/classification interface, it may eventually evolve to cover the following ideas as well:
- Rx/Tx offloads configuration through automatic offloads for specific packets, e.g. performing checksum on TCP packets could be expressed with an egress rule with a TCP pattern and a kind of checksum action.
- RSS configuration (already defined actually). Could be global or per rule depending on hardware capabilities.
- Switching configuration for devices with many physical ports; rules doing both ingress and egress could even be used to completely bypass software if supported by hardware.
[1] http://dpdk.org/ml/archives/dev/2016-July/043365.html
[2] http://dpdk.org/ml/archives/dev/2016-August/045383.html
[3] http://dpdk.org/ml/archives/dev/2016-November/050044.html
Changes since v3 series:
- Fixed documentation tables that broke PDF generation (John Mcnamara / rte_flow.rst).
- Also properly aligned "Action" lines in several tables with their corresponding "Index" (rte_flow.rst).
- Fixed remaining ICC error #188 in testpmd (Ferruh / cmdline_flow.c).
- Indented testpmd examples properly (John / testpmd_funcs.rst).
- Fixed wrong port in example (Ferruh / testpmd_funcs.rst).
Changes since v2 series:
- Replaced ENOTSUP with ENOSYS in the code (although doing so triggers spurious checkpatch warnings) to tell apart unimplemented callbacks from unsupported flow rules and match the documented behavior.
- Fixed missing include seen by check-includes.sh in rte_flow_driver.h.
- Made clearer that PMDs must initialize rte_flow_error (if non-NULL) in case of error, added related memory poisoning in testpmd to catch missing initializations.
- Fixed rte_flow programmer's guide according to John Mcnamara's comments (tables, sections header and typos).
- Fixed deprecation notice as well.
Changes since v1 series:
- Added programmer's guide documentation for rte_flow.
- Added depreciation notice for the legacy API.
- Documented testpmd flow command.
- Fixed missing rte_flow_flush symbol in rte_ether_version.map.
- Cleaned up API documentation in rte_flow.h.
- Replaced "min/max" parameters with "num" in struct rte_flow_item_any, to align behavior with other item definitions.
- Fixed "type" (EtherType) size in struct rte_flow_item_eth.
- Renamed "queues" to "num" in struct rte_flow_action_rss.
- Fixed missing const in rte_flow_error_set() prototype definition.
- Fixed testpmd flow create command that did not save the rte_flow object pointer, causing crashes.
- Hopefully fixed all the remaining ICC/clang errors.
- Replaced testpmd flow command's "fix" token with "is" for clarity.
Changes since RFC v2:
- New separate VLAN pattern item (previously part of the ETH definition), found to be much more convenient.
- Removed useless "any" field from VF pattern item, the same effect can be achieved by not providing a specification structure.
- Replaced bit-fields from the VXLAN pattern item to avoid endianness conversion issues on 24-bit fields.
- Updated struct rte_flow_item with a new "last" field to create inclusive ranges. They are defined as the interval between (spec & mask) and (last & mask). All three parameters are optional.
- Renamed ID action MARK.
- Renamed "queue" fields in actions QUEUE and DUP to "index".
- "rss_conf" field in RSS action is now const.
- VF action now uses a 32 bit ID like its pattern item counterpart.
- Removed redundant struct rte_flow_pattern, API functions now expect struct
rte_flow_item lists terminated by END items.
- Replaced struct rte_flow_actions for the same reason, with struct rte_flow_action lists terminated by END actions.
- Error types (enum rte_flow_error_type) have been updated and the cause pointer in struct rte_flow_error is now const.
- Function prototypes (rte_flow_create, rte_flow_validate) have also been updated for clarity.
Additions:
- Public wrapper functions rte_flow_{validate|create|destroy|flush|query} are now implemented in rte_flow.c, with their symbols exported and versioned. Related filter type RTE_ETH_FILTER_GENERIC has been added.
- A separate header (rte_flow_driver.h) has been added for driver-side functionality, in particular struct rte_flow_ops which contains PMD callbacks returned by RTE_ETH_FILTER_GENERIC query.
- testpmd now exposes most of this API through the new "flow" command.
What remains to be done:
- Using endian-aware integer types (rte_beX_t) where necessary for clarity.
- API documentation (based on RFC).
- testpmd flow command documentation (although context-aware command completion should already help quite a bit in this regard).
- A few pattern item / action properties cannot be configured yet (e.g. rss_conf parameter for RSS action) and a few completions (e.g. possible queue IDs) should be added.
Adrien Mazarguil (25):
ethdev: introduce generic flow API
doc: add rte_flow prog guide
doc: announce deprecation of legacy filter types
cmdline: add support for dynamic tokens
cmdline: add alignment constraint app/testpmd: implement basic support for rte_flow app/testpmd: add flow command app/testpmd: add rte_flow integer support app/testpmd: add flow list command app/testpmd: add flow flush command app/testpmd: add flow destroy command app/testpmd: add flow validate/create commands app/testpmd: add flow query command app/testpmd: add rte_flow item spec handler app/testpmd: add rte_flow item spec prefix length app/testpmd: add rte_flow bit-field support app/testpmd: add item any to flow command app/testpmd: add various items to flow command app/testpmd: add item raw to flow command app/testpmd: add items eth/vlan to flow command app/testpmd: add items ipv4/ipv6 to flow command app/testpmd: add L4 items to flow command app/testpmd: add various actions to flow command app/testpmd: add queue actions to flow command
doc: describe testpmd flow command
MAINTAINERS | 4 + app/test-pmd/Makefile | 1 + app/test-pmd/cmdline.c | 32 + app/test-pmd/cmdline_flow.c | 2575 ++++++++++++++++++++++ app/test-pmd/config.c | 498 +++++ app/test-pmd/csumonly.c | 1 + app/test-pmd/flowgen.c | 1 + app/test-pmd/icmpecho.c | 1 + app/test-pmd/ieee1588fwd.c | 1 + app/test-pmd/iofwd.c | 1 + app/test-pmd/macfwd.c | 1 + app/test-pmd/macswap.c | 1 + app/test-pmd/parameters.c | 1 + app/test-pmd/rxonly.c | 1 + app/test-pmd/testpmd.c | 6 + app/test-pmd/testpmd.h | 27 + app/test-pmd/txonly.c | 1 + doc/api/doxy-api-index.md | 2 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/rte_flow.rst | 2042 +++++++++++++++++ doc/guides/rel_notes/deprecation.rst | 8 + doc/guides/testpmd_app_ug/testpmd_funcs.rst | 612 +++++ lib/librte_cmdline/cmdline_parse.c | 67 +- lib/librte_cmdline/cmdline_parse.h | 21 + lib/librte_ether/Makefile | 3 + lib/librte_ether/rte_eth_ctrl.h | 1 + lib/librte_ether/rte_ether_version.map | 11 + lib/librte_ether/rte_flow.c | 159 ++ lib/librte_ether/rte_flow.h | 947 ++++++++ lib/librte_ether/rte_flow_driver.h | 182 ++ 30 files changed, 7200 insertions(+), 9 deletions(-) create mode 100644 app/test-pmd/cmdline_flow.c create mode 100644 doc/guides/prog_guide/rte_flow.rst create mode 100644 lib/librte_ether/rte_flow.c create mode 100644 lib/librte_ether/rte_flow.h create mode 100644 lib/librte_ether/rte_flow_driver.h
Signature · 1 line
2.1.4
PATCH v4 1/25 ethdev: introduce generic flow API
This new API supersedes all the legacy filter types described in rte_eth_ctrl.h. It is slightly higher level and as a result relies more on PMDs to process and validate flow rules.
Benefits:
- A unified API is easier to program for, applications do not have to be written for a specific filter type which may or may not be supported by the underlying device.
- The behavior of a flow rule is the same regardless of the underlying device, applications do not need to be aware of hardware quirks.
- Extensible by design, API/ABI breakage should rarely occur if at all.
- Documentation is self-standing, no need to look up elsewhere.
Existing filter types will be deprecated and removed in the near future.
--- MAINTAINERS | 4 + doc/api/doxy-api-index.md | 2 + lib/librte_ether/Makefile | 3 + lib/librte_ether/rte_eth_ctrl.h | 1 + lib/librte_ether/rte_ether_version.map | 11 + lib/librte_ether/rte_flow.c | 159 +++++ lib/librte_ether/rte_flow.h | 947 ++++++++++++++++++++++++++++ lib/librte_ether/rte_flow_driver.h | 182 ++++++ 8 files changed, 1309 insertions(+)
MAINTAINERS +4 -0
@@ -243,6 +243,10 @@ M: Thomas Monjalon <[email protected]> F: lib/librte_ether/ F: scripts/test-null.sh +Generic flow API +M: Adrien Mazarguil <[email protected]> +F: lib/librte_ether/rte_flow* + Crypto API M: Declan Doherty <[email protected]> F: lib/librte_cryptodev/
doc/api/doxy-api-index.md +2 -0
@@ -39,6 +39,8 @@ There are many libraries, so their headers may be grouped by topics: [dev] (@ref rte_dev.h), [ethdev] (@ref rte_ethdev.h), [ethctrl] (@ref rte_eth_ctrl.h), + [rte_flow] (@ref rte_flow.h), + [rte_flow_driver] (@ref rte_flow_driver.h), [cryptodev] (@ref rte_cryptodev.h), [devargs] (@ref rte_devargs.h), [bond] (@ref rte_eth_bond.h),
lib/librte_ether/Makefile +3 -0
@@ -44,6 +44,7 @@ EXPORT_MAP := rte_ether_version.map LIBABIVER := 5 SRCS-y += rte_ethdev.c +SRCS-y += rte_flow.c # # Export include files
@@ -51,6 +52,8 @@ SRCS-y += rte_ethdev.c SYMLINK-y-include += rte_ethdev.h SYMLINK-y-include += rte_eth_ctrl.h SYMLINK-y-include += rte_dev_info.h +SYMLINK-y-include += rte_flow.h +SYMLINK-y-include += rte_flow_driver.h # this lib depends upon: DEPDIRS-y += lib/librte_net lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
lib/librte_ether/rte_eth_ctrl.h +1 -0
@@ -99,6 +99,7 @@ enum rte_filter_type {RTE_ETH_FILTER_FDIR ,RTE_ETH_FILTER_HASH ,RTE_ETH_FILTER_L2_TUNNEL , +RTE_ETH_FILTER_GENERIC , RTE_ETH_FILTER_MAX };
lib/librte_ether/rte_ether_version.map +11 -0
@@ -147,3 +147,14 @@ DPDK_16.11 { rte_eth_dev_pci_remove; } DPDK_16.07; + +DPDK_17.02 { + global: + + rte_flow_validate; + rte_flow_create; + rte_flow_destroy; + rte_flow_flush; + rte_flow_query; + +} DPDK_16.11;
lib/librte_ether/rte_flow.c new file +159 -0
159 lines not on this page · raw message
lib/librte_ether/rte_flow.h new file +947 -0
947 lines not on this page · raw message
lib/librte_ether/rte_flow_driver.h new file +182 -0
182 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v4 2/25 doc: add rte_flow prog guide
In reply to Adrien MazarguilThis documentation is based on the latest RFC submission, subsequently updated according to feedback from the community.
--- doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/rte_flow.rst | 2042 +++++++++++++++++++++++++++++++ 2 files changed, 2043 insertions(+)
doc/guides/prog_guide/index.rst +1 -0
@@ -42,6 +42,7 @@ Programmer's Guide mempool_lib mbuf_lib poll_mode_drv + rte_flow cryptodev_lib link_bonding_poll_mode_drv_lib timer_lib
doc/guides/prog_guide/rte_flow.rst new file +2042 -0
2,042 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH v4 02/25] doc: add rte_flow prog guide
Hi Adrien,
You missed out the changes I suggested to the table_rte_flow_migration_fdir which means that the pdf build is still broken. Also, the changes to table_rte_flow_migration_l2tunnel also break the PDF bulid.
You can test as follows:
make doc-guides-pdf -j
I'd suggest the following tables which retain the information and format that you are trying to achieve but which should compile:
.. _table_rte_flow_migration_fdir:
.. table:: FDIR conversion
+----------------------------------------+-----------------------+ | Pattern | Actions | +===+===================+==========+=====+=======================+ | 0 | ETH, RAW | ``spec`` | any | QUEUE, DROP, PASSTHRU | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+-----------------------+ | 1 | IPV4, IPv6 | ``spec`` | any | MARK | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+-----------------------+ | 2 | TCP, UDP, SCTP | ``spec`` | any | END | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+ | | 3 | VF, PF (optional) | ``spec`` | any | | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+ | | 4 | END | | +---+------------------------------------+-----------------------+
.. _table_rte_flow_migration_l2tunnel:
.. table:: L2_TUNNEL conversion
+---------------------------+--------------------+ | Pattern | Actions | +===+======+==========+=====+====================+ | 0 | VOID | ``spec`` | N/A | VXLAN, GENEVE, ... | | | | | | | | | | | | | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | N/A | | | | | | | | +---+------+----------+-----+--------------------+ | 1 | END | VF (optional) | +---+ +--------------------+ | 2 | | END | +---+-----------------------+--------------------+
Re: [PATCH v4 02/25] doc: add rte_flow prog guide
Hi John,
Quoted 9 lines · John
Hi Adrien,
You missed out the changes I suggested to the
table_rte_flow_migration_fdirwhich means that the pdf build is still broken. Also, the changes totable_rte_flow_migration_l2tunnelalso break the PDF bulid.You can test as follows:
make doc-guides-pdf -j
OK, I'm unable to generate pdf documentation on my setup even though I've installed the dependencies, I usually rely on HTML output only, that's why I did not see the remaining issue.
Quoted 42 lines
I'd suggest the following tables which retain the information and format that you are trying to achieve but which should compile:
..
_table_rte_flow_migration_fdir:.. table:: FDIR conversion
+----------------------------------------+-----------------------+ | Pattern | Actions | +===+===================+==========+=====+=======================+ | 0 | ETH, RAW | ``spec`` | any | QUEUE, DROP, PASSTHRU | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+-----------------------+ | 1 | IPV4, IPv6 | ``spec`` | any | MARK | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+-----------------------+ | 2 | TCP, UDP, SCTP | ``spec`` | any | END | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+ | | 3 | VF, PF (optional) | ``spec`` | any | | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | any | | +---+-------------------+----------+-----+ | | 4 | END | | +---+------------------------------------+-----------------------+..
_table_rte_flow_migration_l2tunnel:.. table::
L2_TUNNELconversion
Quoted 16 lines
+---------------------------+--------------------+ | Pattern | Actions | +===+======+==========+=====+====================+ | 0 | VOID | ``spec`` | N/A | VXLAN, GENEVE, ... | | | | | | | | | | | | | | | +----------+-----+ | | | | ``last`` | N/A | | | | +----------+-----+ | | | | ``mask`` | N/A | | | | | | | | +---+------+----------+-----+--------------------+ | 1 | END | VF (optional) | +---+ +--------------------+ | 2 | | END | +---+-----------------------+--------------------+
No problem, I'll include those changes along with a remaining bugfix and testpmd support for additional protocol fields (requested by several people). Brace yourself for v5!
Thanks for all the reviews.
Signature · 2 lines
Adrien Mazarguil 6WIND
PATCH v4 3/25 doc: announce deprecation of legacy filter types
In reply to Adrien MazarguilThey are superseded by the generic flow API (rte_flow). Target release is not defined yet.
--- doc/guides/rel_notes/deprecation.rst | 8 ++++++++ 1 file changed, 8 insertions(+)
doc/guides/rel_notes/deprecation.rst +8 -0
@@ -71,3 +71,11 @@ Deprecation Notices * mempool: The functions for single/multi producer/consumer are deprecated and will be removed in 17.02. It is replaced by ``rte_mempool_generic_get/put`` functions. + +* ethdev: the legacy filter API, including + ``rte_eth_dev_filter_supported()``, ``rte_eth_dev_filter_ctrl()`` as well + as filter types MACVLAN, ETHERTYPE, FLEXIBLE, SYN, NTUPLE, TUNNEL, FDIR, + HASH and L2_TUNNEL, is superseded by the generic flow API (rte_flow) in + PMDs that implement the latter. + Target release for removal of the legacy API will be defined once most + PMDs have switched to rte_flow.
Signature · 1 line
2.1.4
PATCH v4 4/25 cmdline: add support for dynamic tokens
In reply to Adrien MazarguilConsidering tokens must be hard-coded in a list part of the instruction structure, context-dependent tokens cannot be expressed.
This commit adds support for building dynamic token lists through a user-provided function, which is called when the static token list is empty (a single NULL entry).
Because no structures are modified (existing fields are reused), this commit has no impact on the current ABI.
--- lib/librte_cmdline/cmdline_parse.c | 60 +++++++++++++++++++++++++++++---- lib/librte_cmdline/cmdline_parse.h | 21 ++++++++++++ 2 files changed, 74 insertions(+), 7 deletions(-)
lib/librte_cmdline/cmdline_parse.c +53 -7
@@ -146,7 +146,9 @@ nb_common_chars(const char * s1, const char * s2)*/ static int match_inst (cmdline_parse_inst_t *inst,const char *buf, -unsigned int nb_match_token,void *resbuf,unsigned resbuf_size) +unsigned int nb_match_token,void *resbuf,unsigned resbuf_size, +cmdline_parse_token_hdr_t + *(*dyn_tokens)[CMDLINE_PARSE_DYNAMIC_TOKENS ]) {unsigned int token_num=0 ;cmdline_parse_token_hdr_t * token_p;
@@ -155,6 +157,11 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,struct cmdline_token_hdr token_hdr; token_p = inst->tokens[token_num]; +if (!token_p && dyn_tokens && inst->f) { +if (!(*dyn_tokens)[0 ]) + inst->f (&(*dyn_tokens)[0 ],NULL , dyn_tokens); + token_p = (*dyn_tokens)[0 ]; + }if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
@@ -196,7 +203,17 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf, buf += n; token_num ++; - token_p = inst->tokens[token_num]; +if (!inst->tokens[0 ]) { +if (token_num < (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!(*dyn_tokens)[token_num]) + inst->f (&(*dyn_tokens)[token_num], +NULL , + dyn_tokens); + token_p = (*dyn_tokens)[token_num]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[token_num];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr)); }
@@ -239,6 +256,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)cmdline_parse_inst_t *inst;const char *curbuf;char result_buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];void (*f)(void *,struct cmdline *,void *) =NULL ;void *data =NULL ;int comment =0 ;
@@ -255,6 +273,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)return CMDLINE_PARSE_BAD_ARGS ; ctx = cl->ctx; +memset (&dyn_tokens,0 ,sizeof (dyn_tokens));/* * - look if the buffer contains at least one line
@@ -299,7 +318,8 @@ cmdline_parse(struct cmdline *cl, const char * buf)debug_printf ("INST %d\n" , inst_num);/* fully parsed */ - tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf)); + tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf), + &dyn_tokens);if (tok >0 )/* we matched at least one token */ err =CMDLINE_PARSE_BAD_ARGS ;
@@ -355,6 +375,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,cmdline_parse_token_hdr_t *token_p;struct cmdline_token_hdr token_hdr;char tmpbuf[CMDLINE_BUFFER_SIZE ], comp_buf[CMDLINE_BUFFER_SIZE ]; +cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];unsigned int partial_tok_len;int comp_len =-1 ;int tmp_len =-1 ;
@@ -374,6 +395,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,debug_printf ("%s called\n" , __func__);memset (&token_hdr,0 ,sizeof (token_hdr)); +memset (&dyn_tokens,0 ,sizeof (dyn_tokens));/* count the number of complete token to parse */ for (i=0 ; buf[i] ; i++) {
@@ -396,11 +418,24 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state, inst = ctx[inst_num];while (inst) {/* parse the first tokens of the inst */ -if (nb_token &&match_inst (inst, buf, nb_token,NULL ,0 )) +if (nb_token && +match_inst (inst, buf, nb_token,NULL ,0 , + &dyn_tokens)) goto next;debug_printf ("instruction match\n" ); - token_p = inst->tokens[nb_token]; +if (!inst->tokens[0 ]) { +if (nb_token < + (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!dyn_tokens[nb_token]) + inst->f (&dyn_tokens[nb_token], +NULL , + &dyn_tokens); + token_p = dyn_tokens[nb_token]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[nb_token];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
@@ -490,10 +525,21 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,/* we need to redo it */ inst = ctx[inst_num]; -if (nb_token &&match_inst (inst, buf, nb_token,NULL ,0 )) +if (nb_token && +match_inst (inst, buf, nb_token,NULL ,0 , &dyn_tokens)) goto next2; - token_p = inst->tokens[nb_token]; +if (!inst->tokens[0 ]) { +if (nb_token < (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!dyn_tokens[nb_token]) + inst->f (&dyn_tokens[nb_token], +NULL , + &dyn_tokens); + token_p = dyn_tokens[nb_token]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[nb_token];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
lib/librte_cmdline/cmdline_parse.h +21 -0
@@ -83,6 +83,9 @@ extern "C" {/* maximum buffer size for parsed result */ #define CMDLINE_PARSE_RESULT_BUFSIZE 8192 +/* maximum number of dynamic tokens */ +#define CMDLINE_PARSE_DYNAMIC_TOKENS 128 +/** * Stores a pointer to the ops struct, and the offset: the place to * write the parsed result in the destination structure.
@@ -130,6 +133,24 @@ struct cmdline;* Store a instruction, which is a pointer to a callback function and * its parameter that is called when the instruction is parsed, a help * string, and a list of token composing this instruction. +* +* When no tokens are defined (tokens[0] == NULL), they are retrieved +* dynamically by calling f() as follows: +* +* f((struct cmdline_token_hdr **)&token_hdr, +* NULL, +* (struct cmdline_token_hdr *[])tokens)); +* +* The address of the resulting token is expected at the location pointed by +* the first argument. Can be set to NULL to end the list. +* +* The cmdline argument (struct cmdline *) is always NULL. +* +* The last argument points to the NULL-terminated list of dynamic tokens +* defined so far. Since token_hdr points to an index of that list, the +* current index can be derived as follows: +* +* int index = token_hdr - &(*tokens)[0]; */ struct cmdline_inst {/* f(parsed_struct, data) */
Signature · 1 line
2.1.4
PATCH v4 5/25 cmdline: add alignment constraint
In reply to Adrien MazarguilThis prevents sigbus errors on architectures that cannot handle unexpected unaligned accesses to the output buffer.
--- lib/librte_cmdline/cmdline_parse.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
lib/librte_cmdline/cmdline_parse.c +6 -3
@@ -255,7 +255,10 @@ cmdline_parse(struct cmdline *cl, const char * buf)unsigned int inst_num=0 ;cmdline_parse_inst_t *inst;const char *curbuf; -char result_buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +union { +char buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +long double align;/* strong alignment constraint for buf */ + } result;cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];void (*f)(void *,struct cmdline *,void *) =NULL ;void *data =NULL ;
@@ -318,7 +321,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)debug_printf ("INST %d\n" , inst_num);/* fully parsed */ - tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf), + tok =match_inst (inst, buf,0 , result.buf,sizeof (result.buf), &dyn_tokens);if (tok >0 )/* we matched at least one token */
@@ -353,7 +356,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)/* call func */ if (f) { -f (result_buf, cl, data); +f (result.buf, cl, data); }/* no match */
Signature · 1 line
2.1.4
PATCH v4 6/25 app/testpmd: implement basic support for rte_flow
In reply to Adrien MazarguilAdd basic management functions for the generic flow API (validate, create, destroy, flush, query and list). Flow rule objects and properties are arranged in lists associated with each port.
--- app/test-pmd/cmdline.c | 1 + app/test-pmd/config.c | 498 ++++++++++++++++++++++++++++++++++++++++ app/test-pmd/csumonly.c | 1 + app/test-pmd/flowgen.c | 1 + app/test-pmd/icmpecho.c | 1 + app/test-pmd/ieee1588fwd.c | 1 + app/test-pmd/iofwd.c | 1 + app/test-pmd/macfwd.c | 1 + app/test-pmd/macswap.c | 1 + app/test-pmd/parameters.c | 1 + app/test-pmd/rxonly.c | 1 + app/test-pmd/testpmd.c | 6 + app/test-pmd/testpmd.h | 27 +++ app/test-pmd/txonly.c | 1 + 14 files changed, 542 insertions(+)
app/test-pmd/cmdline.c +1 -0
@@ -75,6 +75,7 @@#include <rte_string_fns.h> #include <rte_devargs.h> #include <rte_eth_ctrl.h> +#include <rte_flow.h> #include <cmdline_rdline.h> #include <cmdline_parse.h>
app/test-pmd/config.c +498 -0
510 lines not on this page · raw message
app/test-pmd/csumonly.c +1 -0
@@ -70,6 +70,7 @@#include <rte_sctp.h> #include <rte_prefetch.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" #define IP_DEFTTL 64/* from RFC 1340. */
app/test-pmd/flowgen.c +1 -0
@@ -68,6 +68,7 @@#include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/icmpecho.c +1 -0
@@ -61,6 +61,7 @@#include <rte_ip.h> #include <rte_icmp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/ieee1588fwd.c +1 -0
@@ -34,6 +34,7 @@#include <rte_cycles.h> #include <rte_ethdev.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/iofwd.c +1 -0
@@ -64,6 +64,7 @@#include <rte_ether.h> #include <rte_ethdev.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/macfwd.c +1 -0
@@ -65,6 +65,7 @@#include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/macswap.c +1 -0
@@ -65,6 +65,7 @@#include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/parameters.c +1 -0
@@ -76,6 +76,7 @@#ifdef RTE_LIBRTE_PMD_BOND #include <rte_eth_bond.h> #endif +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/rxonly.c +1 -0
@@ -67,6 +67,7 @@#include <rte_ip.h> #include <rte_udp.h> #include <rte_net.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/testpmd.c +6 -0
@@ -78,6 +78,7 @@#ifdef RTE_LIBRTE_PDUMP #include <rte_pdump.h> #endif +#include <rte_flow.h> #include "testpmd.h"
@@ -1545,6 +1546,8 @@ close_port(portid_t pid)continue ; } +if (port->flow_list) +port_flow_flush (pi);rte_eth_dev_close (pi); if (rte_atomic16_cmpset(&(port->port_status),
@@ -1599,6 +1602,9 @@ detach_port(uint8_t port_id)return ; } +if (ports[port_id].flow_list) +port_flow_flush (port_id); +if (rte_eth_dev_detach (port_id, name))return ;
app/test-pmd/testpmd.h +27 -0
@@ -144,6 +144,19 @@ struct fwd_stream {/** Insert double VLAN header in forward engine */ #define TESTPMD_TX_OFFLOAD_INSERT_QINQ 0x0080 +/** Descriptor for a single flow. */ +struct port_flow { +size_t size;/**< Allocated space including data[]. */ +struct port_flow *next;/**< Next flow in list. */ +struct port_flow *tmp;/**< Temporary linking. */ +uint32_t id;/**< Flow rule ID. */ +struct rte_flow *flow;/**< Opaque flow object returned by PMD. */ +struct rte_flow_attr attr;/**< Attributes. */ +struct rte_flow_item *pattern;/**< Pattern. */ +struct rte_flow_action *actions;/**< Actions. */ +uint8_t data[];/**< Storage for pattern/actions. */ +}; +/** * The data structure associated with each port. */
@@ -177,6 +190,7 @@ struct rte_port {struct ether_addr *mc_addr_pool;/**< pool of multicast addrs */ uint32_t mc_addr_nb;/**< nb. of addr. in mc_addr_pool */ uint8_t slave_flag;/**< bonding slave port */ +struct port_flow *flow_list;/**< Associated flows. */ };extern portid_t __rte_unused
@@ -504,6 +518,19 @@ void port_reg_bit_field_set(portid_t port_id, uint32_t reg_off, uint8_t bit1_pos, uint8_t bit2_pos, uint32_t value);void port_reg_display (portid_t port_id,uint32_t reg_off);void port_reg_set (portid_t port_id,uint32_t reg_off,uint32_t value); +int port_flow_validate (portid_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item *pattern, +const struct rte_flow_action *actions); +int port_flow_create (portid_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item *pattern, +const struct rte_flow_action *actions); +int port_flow_destroy (portid_t port_id,uint32_t n,const uint32_t *rule); +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);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);
app/test-pmd/txonly.c +1 -0
@@ -68,6 +68,7 @@#include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
Signature · 1 line
2.1.4
PATCH v4 7/25 app/testpmd: add flow command
In reply to Adrien MazarguilManaging generic flow API functions from command line requires the use of dynamic tokens for convenience as flow rules are not fixed and cannot be defined statically.
This commit adds specific flexible parser code and object for a new "flow" command in separate file.
--- app/test-pmd/Makefile | 1 + app/test-pmd/cmdline.c | 4 + app/test-pmd/cmdline_flow.c | 439 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+)
app/test-pmd/Makefile +1 -0
@@ -47,6 +47,7 @@ CFLAGS += $(WERROR_FLAGS) SRCS-y := testpmd.c SRCS-y += parameters.c SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c SRCS-y += config.c SRCS-y += iofwd.c SRCS-y += macfwd.c
app/test-pmd/cmdline.c +4 -0
@@ -9567,6 +9567,9 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = { }, }; +/* Generic flow interface command. */ +extern cmdline_parse_inst_t cmd_flow; +/* *** Classification Filters Control *** */ /* *** Get symmetric hash enable per port *** */ struct cmd_get_sym_hash_ena_per_port_result {
@@ -11605,6 +11608,7 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_set_hash_global_config, (cmdline_parse_inst_t *)&cmd_set_hash_input_set, (cmdline_parse_inst_t *)&cmd_set_fdir_input_set, + (cmdline_parse_inst_t *)&cmd_flow, (cmdline_parse_inst_t *)&cmd_mcast_addr, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
app/test-pmd/cmdline_flow.c new file +439 -0
439 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v4 8/25 app/testpmd: add rte_flow integer support
In reply to Adrien MazarguilParse all integer types and handle conversion to network byte order in a single function.
--- app/test-pmd/cmdline_flow.c | 148 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+)
app/test-pmd/cmdline_flow.c +148 -0
@@ -34,11 +34,14 @@#include <stddef.h> #include <stdint.h> #include <stdio.h> +#include <inttypes.h> +#include <errno.h> #include <ctype.h> #include <string.h> #include <rte_common.h> #include <rte_ethdev.h> +#include <rte_byteorder.h> #include <cmdline_parse.h> #include <rte_flow.h>
@@ -50,6 +53,10 @@ enum index {ZERO =0 ,END , +/* Common tokens. */ +INTEGER , +UNSIGNED , +/* Top-level command. */ FLOW, };
@@ -61,12 +68,24 @@ enum index {struct context {/** Stack of subsequent token lists to process. */ const enum index *next[CTX_STACK_SIZE ]; +/** Arguments for stacked tokens. */ +const void *args[CTX_STACK_SIZE ];enum index curr;/**< Current token index. */ 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. */ +void *object;/**< Address of current object for relative offsets. */ +}; + +/** Token argument. */ +struct arg { +uint32_t hton:1 ;/**< Use network byte ordering. */ +uint32_t sign:1 ;/**< Value is signed. */ +uint32_t offset;/**< Relative offset from ctx->object. */ +uint32_t size;/**< Field size. */ };/** Parser token definition. */
@@ -80,6 +99,8 @@ struct token {* parser consumes the last entry of that stack. */ const enum index *const *next; +/** Arguments stack for subsequent tokens that need them. */ +const struct arg *const *args;/** * Token-processing callback, returns -1 in case of error, the * length of the matched string otherwise. If NULL, attempts to
@@ -112,6 +133,22 @@ struct token {/** Static initializer for a NEXT() entry. */ #define NEXT_ENTRY (...) (const enum index []){ __VA_ARGS__, ZERO, } +/** Static initializer for the args field. */ +#define ARGS (...) (const struct arg *const []){ __VA_ARGS__, NULL, } + +/** Static initializer for ARGS() to target a field. */ +#define ARGS_ENTRY (s, f) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + }) + +/** Static initializer for ARGS() to target a pointer. */ +#define ARGS_ENTRY_PTR (s, f) \ + (&(const struct arg){ \ + .size = sizeof(*((s *)0)->f), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -121,6 +158,11 @@ struct buffer {static int parse_init (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 ); +static int comp_none (struct context *,const struct token *, +unsigned int ,char *,unsigned int );/** Token definitions. */ static const struct token token_list[] = {
@@ -135,6 +177,21 @@ static const struct token token_list[] = { .type = "RETURN", .help = "command may end here", }, +/* Common tokens. */ + [INTEGER] = { + .name = "{int}", + .type = "INTEGER", + .help = "integer value", + .call = parse_int, + .comp = comp_none, + }, + [UNSIGNED] = { + .name = "{unsigned}", + .type = "UNSIGNED", + .help = "unsigned integer value", + .call = parse_int, + .comp = comp_none, + },/* Top-level command. */ [FLOW] = { .name = "flow",
@@ -144,6 +201,23 @@ static const struct token token_list[] = { }, }; +/** 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 ; +} +/** Default parsing function for token name matching. */ static int parse_default(struct context *ctx, const struct token *token,
@@ -178,9 +252,74 @@ parse_init(struct context *ctx, const struct token *token,/* Initialize buffer. */ memset (out,0x00 ,sizeof (*out));memset ((uint8_t *)out +sizeof (*out),0x22 , size -sizeof (*out)); + ctx->object = out;return len; } +/** +* Parse signed/unsigned integers 8 to 64-bit long. +* +* Last argument (ctx->args) is retrieved to determine integer type and +* storage location. +*/ +static int +parse_int (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); +uintmax_t u; +char *end; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + errno =0 ; + u = arg->sign ? + (uintmax_t )strtoimax (str, &end,0 ) : +strtoumax (str, &end,0 ); +if (errno || (size_t )(end - str) != len) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; + size = arg->size; +switch (size) { +case sizeof (uint8_t ): + *(uint8_t *)buf = u; +break ; +case sizeof (uint16_t ): + *(uint16_t *)buf = arg->hton ?rte_cpu_to_be_16 (u) : u; +break ; +case sizeof (uint32_t ): + *(uint32_t *)buf = arg->hton ?rte_cpu_to_be_32 (u) : u; +break ; +case sizeof (uint64_t ): + *(uint64_t *)buf = arg->hton ?rte_cpu_to_be_64 (u) : u; +break ; +default : + goto error; + } +return len; +error: +push_args (ctx, arg); +return -1 ; +} + +/** No completion. */ +static int +comp_none (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ + (void )ctx; + (void )token; + (void )ent; + (void )buf; + (void )size; +return 0 ; +} +/** Internal context. */ static struct context cmd_flow_context;
@@ -195,9 +334,11 @@ cmd_flow_context_init(struct context *ctx) ctx->curr =ZERO ; ctx->prev =ZERO ; ctx->next_num =0 ; + ctx->args_num =0 ; ctx->reparse =0 ; ctx->eol =0 ; ctx->last =0 ; + ctx->object =NULL ; }/** Parse a token (cmdline API). */
@@ -270,6 +411,13 @@ cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,return -1 ; ctx->next[ctx->next_num++] = token->next[i]; } +/* Push arguments if any. */ +if (token->args) +for (i =0 ; token->args[i]; ++i) { +if (ctx->args_num ==RTE_DIM (ctx->args)) +return -1 ; + ctx->args[ctx->args_num++] = token->args[i]; + }return len; }
Signature · 1 line
2.1.4
PATCH v4 9/25 app/testpmd: add flow list command
In reply to Adrien MazarguilSyntax:
flow list {port_id} [group {group_id}] [...]
List configured flow rules on a port. Output can optionally be limited to a given set of group identifiers.
--- app/test-pmd/cmdline.c | 4 ++ app/test-pmd/cmdline_flow.c | 141 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+)
app/test-pmd/cmdline.c +4 -0
@@ -810,6 +810,10 @@ static void cmd_help_long_parsed(void *parsed_result,"sctp-src-port|sctp-dst-port|sctp-veri-tag|none)" " (select|add)\n" " Set the input set for FDir.\n\n" + +"flow list {port_id} [group {group_id}] [...]\n" +" List existing flow rules sorted by priority," +" filtered by group identifiers.\n\n" ); } }
app/test-pmd/cmdline_flow.c +141 -0
215 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v4 10/25 app/testpmd: add flow flush command
In reply to Adrien MazarguilSyntax:
flow flush {port_id}
Destroy all flow rules on a port.
--- app/test-pmd/cmdline.c | 3 +++ app/test-pmd/cmdline_flow.c | 43 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow flush {port_id}\n" +" Destroy all flow rules.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," " filtered by group identifiers.\n\n"
app/test-pmd/cmdline_flow.c +42 -1
76 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v4 11/25 app/testpmd: add flow destroy command
In reply to Adrien MazarguilSyntax:
flow destroy {port_id} rule {rule_id} [...]
Destroy a given set of flow rules associated with a port.
--- app/test-pmd/cmdline.c | 3 ++ app/test-pmd/cmdline_flow.c | 106 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow destroy {port_id} rule {rule_id} [...]\n" +" Destroy specific flow rules.\n\n" +"flow flush {port_id}\n" " Destroy all flow rules.\n\n"
app/test-pmd/cmdline_flow.c +105 -1
185 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v4 12/25 app/testpmd: add flow validate/create commands
In reply to Adrien MazarguilSyntax:
flow (validate|create) {port_id}
[group {group_id}] [priority {level}] [ingress] [egress]
pattern {item} [/ {item} [...]] / end
actions {action} [/ {action} [...]] / endEither check the validity of a flow rule or create it. Any number of pattern items and actions can be provided in any order. Completion is available for convenience.
This commit only adds support for the most basic item and action types, namely:
- END: terminates pattern items and actions lists.
- VOID: item/action filler, no operation.
- INVERT: inverted pattern matching, process packets that do not match.
- PASSTHRU: action that leaves packets up for additional processing by subsequent flow rules.
--- app/test-pmd/cmdline.c | 14 ++ app/test-pmd/cmdline_flow.c | 314 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 327 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +14 -0
@@ -811,6 +811,20 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow validate {port_id}" +" [group {group_id}] [priority {level}]" +" [ingress] [egress]" +" pattern {item} [/ {item} [...]] / end" +" actions {action} [/ {action} [...]] / end\n" +" Check whether a flow rule can be created.\n\n" + +"flow create {port_id}" +" [group {group_id}] [priority {level}]" +" [ingress] [egress]" +" pattern {item} [/ {item} [...]] / end" +" actions {action} [/ {action} [...]] / end\n" +" Create a flow rule.\n\n" +"flow destroy {port_id} rule {rule_id} [...]\n" " Destroy specific flow rules.\n\n"
app/test-pmd/cmdline_flow.c +313 -1
445 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v4 13/25 app/testpmd: add flow query command
In reply to Adrien MazarguilSyntax:
flow query {port_id} {rule_id} {action}
Query a specific action of an existing flow rule.
--- app/test-pmd/cmdline.c | 3 + app/test-pmd/cmdline_flow.c | 121 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -831,6 +831,9 @@ static void cmd_help_long_parsed(void *parsed_result,"flow flush {port_id}\n" " Destroy all flow rules.\n\n" +"flow query {port_id} {rule_id} {action}\n" +" Query an existing flow rule.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," " filtered by group identifiers.\n\n"
app/test-pmd/cmdline_flow.c +120 -1
186 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v4 14/25 app/testpmd: add rte_flow item spec handler
In reply to Adrien MazarguilAdd parser code to fully set individual fields of pattern item specification structures, using the following operators:
- fix: sets field and applies full bit-mask for perfect matching.
- spec: sets field without modifying its bit-mask.
- last: sets upper value of the spec => last range.
- mask: sets bit-mask affecting both spec and last from arbitrary value.
--- app/test-pmd/cmdline_flow.c | 111 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
app/test-pmd/cmdline_flow.c +111 -0
@@ -89,6 +89,10 @@ enum index {/* Validate/create pattern. */ PATTERN , +ITEM_PARAM_IS , +ITEM_PARAM_SPEC , +ITEM_PARAM_LAST , +ITEM_PARAM_MASK ,ITEM_NEXT ,ITEM_END , ITEM_VOID,
@@ -121,6 +125,7 @@ struct context {uint16_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. */ };/** Token argument. */
@@ -267,6 +272,15 @@ static const enum index next_list_attr[] = { ZERO, }; +__rte_unused +static const enum index item_param[] = { +ITEM_PARAM_IS , +ITEM_PARAM_SPEC , +ITEM_PARAM_LAST , +ITEM_PARAM_MASK , +ZERO , +}; +static const enum index next_item[] = {ITEM_END ,ITEM_VOID ,
@@ -287,6 +301,8 @@ static int parse_init(struct context *, const struct token *,static int parse_vc (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_spec (struct context *,const struct token *, +const char *,unsigned int ,void *,unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -492,6 +508,26 @@ static const struct token token_list[] = { .next = NEXT(next_item), .call = parse_vc, }, + [ITEM_PARAM_IS] = { + .name = "is", + .help = "match value perfectly (with full bit-mask)", + .call = parse_vc_spec, + }, + [ITEM_PARAM_SPEC] = { + .name = "spec", + .help = "match value according to configured bit-mask", + .call = parse_vc_spec, + }, + [ITEM_PARAM_LAST] = { + .name = "last", + .help = "specify upper bound to establish a range", + .call = parse_vc_spec, + }, + [ITEM_PARAM_MASK] = { + .name = "mask", + .help = "specify bit-mask with relevant bits set to one", + .call = parse_vc_spec, + }, [ITEM_NEXT] = { .name = "/", .help = "specify next pattern item",
@@ -605,6 +641,7 @@ parse_init(struct context *ctx, const struct token *token,memset ((uint8_t *)out +sizeof (*out),0x22 , size -sizeof (*out)); ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ;return len; }
@@ -632,11 +669,13 @@ parse_vc(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.vc.data = (uint8_t *)out + size;return len; } ctx->objdata =0 ; ctx->object = &out->args.vc.attr; + ctx->objmask =NULL ;switch (ctx->curr) {case GROUP :case PRIORITY :
@@ -652,6 +691,7 @@ parse_vc(struct context *ctx, const struct token *token, (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double )); ctx->object = out->args.vc.pattern; + ctx->objmask =NULL ;return len;case ACTIONS : out->args.vc.actions =
@@ -660,6 +700,7 @@ parse_vc(struct context *ctx, const struct token *token, out->args.vc.pattern_n), sizeof(double)); ctx->object = out->args.vc.actions; + ctx->objmask =NULL ;return len;default :if (!token->priv)
@@ -682,6 +723,7 @@ parse_vc(struct context *ctx, const struct token *token, }; ++out->args.vc.pattern_n; ctx->object = item; + ctx->objmask =NULL ; }else {const struct parse_action_priv *priv = token->priv; struct rte_flow_action *action =
@@ -698,6 +740,7 @@ parse_vc(struct context *ctx, const struct token *token, }; ++out->args.vc.actions_n; ctx->object = action; + ctx->objmask =NULL ; }memset (data,0 , data_size); out->args.vc.data = data;
@@ -705,6 +748,60 @@ parse_vc(struct context *ctx, const struct token *token,return len; } +/** Parse pattern item parameter type. */ +static int +parse_vc_spec (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +struct buffer *out = buf; +struct rte_flow_item *item; +uint32_t data_size; +int index; +int objmask =0 ; + + (void )size; +/* Token name must match. */ +if (parse_default (ctx, token, str, len,NULL ,0 ) <0 ) +return -1 ; +/* Parse parameter types. */ +switch (ctx->curr) { +case ITEM_PARAM_IS : + index =0 ; + objmask =1 ; +break ; +case ITEM_PARAM_SPEC : + index =0 ; +break ; +case ITEM_PARAM_LAST : + index =1 ; +break ; +case ITEM_PARAM_MASK : + index =2 ; +break ; +default : +return -1 ; + } +/* Nothing else to do if there is no buffer. */ +if (!out) +return len; +if (!out->args.vc.pattern_n) +return -1 ; + item = &out->args.vc.pattern[out->args.vc.pattern_n -1 ]; + data_size = ctx->objdata /3 ;/* spec, last, mask */ +/* Point to selected object. */ + ctx->object = out->args.vc.data + (data_size * index); +if (objmask) { + ctx->objmask = out->args.vc.data + (data_size *2 );/* mask */ + item->mask = ctx->objmask; + }else + ctx->objmask =NULL ; +/* Update relevant item pointer. */ + *((const void **[]){ &item->spec, &item->last, &item->mask })[index] = + ctx->object; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
@@ -727,6 +824,7 @@ parse_destroy(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.destroy.rule = (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double ));
@@ -737,6 +835,7 @@ parse_destroy(struct context *ctx, const struct token *token,return -1 ; ctx->objdata =0 ; ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++; + ctx->objmask =NULL ;return len; }
@@ -762,6 +861,7 @@ parse_flush(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; }return len; }
@@ -788,6 +888,7 @@ parse_query(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; }return len; }
@@ -849,6 +950,7 @@ parse_list(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.list.group = (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double ));
@@ -859,6 +961,7 @@ parse_list(struct context *ctx, const struct token *token,return -1 ; ctx->objdata =0 ; ctx->object = out->args.list.group + out->args.list.group_n++; + ctx->objmask =NULL ;return len; }
@@ -891,6 +994,7 @@ parse_int(struct context *ctx, const struct token *token,return len; buf = (uint8_t *)ctx->object + arg->offset; size = arg->size; +objmask:switch (size) {case sizeof (uint8_t ): *(uint8_t *)buf = u;
@@ -907,6 +1011,11 @@ parse_int(struct context *ctx, const struct token *token,default : goto error; } +if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) { + u =-1 ; + buf = (uint8_t *)ctx->objmask + arg->offset; + goto objmask; + }return len; error:push_args (ctx, arg);
@@ -927,6 +1036,7 @@ parse_port(struct context *ctx, const struct token *token,else { ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; size =sizeof (*out); } ret =parse_int (ctx, token, str, len, out, size);
@@ -1033,6 +1143,7 @@ cmd_flow_context_init(struct context *ctx) ctx->port =0 ; ctx->objdata =0 ; ctx->object =NULL ; + ctx->objmask =NULL ; }/** Parse a token (cmdline API). */
Signature · 1 line
2.1.4
PATCH v4 15/25 app/testpmd: add rte_flow item spec prefix length
In reply to Adrien MazarguilGenerating bit-masks from prefix lengths is often more convenient than providing them entirely (e.g. to define IPv4 and IPv6 subnets).
This commit adds the "prefix" operator that assigns generated bit-masks to any pattern item specification field.
--- app/test-pmd/cmdline_flow.c | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
app/test-pmd/cmdline_flow.c +80 -0
@@ -56,6 +56,7 @@ enum index {/* Common tokens. */ INTEGER ,UNSIGNED , +PREFIX ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -93,6 +94,7 @@ enum index {ITEM_PARAM_SPEC ,ITEM_PARAM_LAST ,ITEM_PARAM_MASK , +ITEM_PARAM_PREFIX ,ITEM_NEXT ,ITEM_END , ITEM_VOID,
@@ -278,6 +280,7 @@ static const enum index item_param[] = {ITEM_PARAM_SPEC ,ITEM_PARAM_LAST ,ITEM_PARAM_MASK , +ITEM_PARAM_PREFIX , ZERO, };
@@ -321,6 +324,9 @@ static int parse_list(struct context *, const struct token *,static int parse_int (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_prefix (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -361,6 +367,13 @@ static const struct token token_list[] = { .call = parse_int, .comp = comp_none, }, + [PREFIX] = { + .name = "{prefix}", + .type = "PREFIX", + .help = "prefix length for bit-mask", + .call = parse_prefix, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -528,6 +541,11 @@ static const struct token token_list[] = { .help = "specify bit-mask with relevant bits set to one", .call = parse_vc_spec, }, + [ITEM_PARAM_PREFIX] = { + .name = "prefix", + .help = "generate bit-mask from a prefix length", + .call = parse_vc_spec, + }, [ITEM_NEXT] = { .name = "/", .help = "specify next pattern item",
@@ -605,6 +623,62 @@ push_args(struct context *ctx, const struct arg *arg)return 0 ; } +/** +* 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; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + errno =0 ; + u =strtoumax (str, &end,0 ); +if (errno || (size_t )(end - str) != len) + goto error; + bytes = u /8 ; + extra = u %8 ; + size = arg->size; +if (bytes > size || bytes + !!extra > size) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { +memset ((uint8_t *)buf + size - bytes,0xff , bytes); +memset (buf,0x00 , size - bytes); +if (extra) + ((uint8_t *)buf)[size - bytes -1 ] = conv[extra]; + } else +#endif + { +memset (buf,0xff , bytes); +memset ((uint8_t *)buf + bytes,0x00 , size - bytes); +if (extra) + ((uint8_t *)buf)[bytes] = conv[extra]; + } +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Default parsing function for token name matching. */ static int parse_default(struct context *ctx, const struct token *token,
@@ -776,6 +850,12 @@ parse_vc_spec(struct context *ctx, const struct token *token,case ITEM_PARAM_LAST : index =1 ;break ; +case ITEM_PARAM_PREFIX : +/* Modify next token to expect a prefix. */ +if (ctx->next_num <2 ) +return -1 ; + ctx->next[ctx->next_num -2 ] =NEXT_ENTRY (PREFIX ); +/* Fall through. */ case ITEM_PARAM_MASK : index =2 ;break ;
Signature · 1 line
2.1.4
PATCH v4 16/25 app/testpmd: add rte_flow bit-field support
In reply to Adrien MazarguilSeveral rte_flow structures expose bit-fields that cannot be set in a generic fashion at byte level. Add bit-mask support to handle them.
--- app/test-pmd/cmdline_flow.c | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+)
app/test-pmd/cmdline_flow.c +59 -0
@@ -136,6 +136,7 @@ struct arg { uint32_t sign:1; /**< Value is signed. */uint32_t offset;/**< Relative offset from ctx->object. */ uint32_t size;/**< Field size. */ +const uint8_t *mask;/**< Bit-mask to use instead of offset/size. */ };/** Parser token definition. */
@@ -195,6 +196,13 @@ struct token { .size = sizeof(((s *)0)->f), \ }) +/** Static initializer for ARGS() to target a bit-field. */ +#define ARGS_ENTRY_BF (s, f, b) \ + (&(const struct arg){ \ + .size = sizeof(s), \ + .mask = (const void *)&(const s){ .f = (1 << (b)) - 1 }, \ + }) +/** Static initializer for ARGS() to target a pointer. */ #define ARGS_ENTRY_PTR (s, f) \ (&(const struct arg){ \
@@ -623,6 +631,34 @@ push_args(struct context *ctx, const struct arg *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; +size_t len =0 ; + +/* Endian conversion is not supported on bit-fields. */ +if (!arg->mask || arg->hton) +return 0 ; +for (i =0 ; i != arg->size; ++i) { +unsigned int shift =0 ; +uint8_t *buf = (uint8_t *)dst + i; + +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 ; + } + } +return len; +} +/** * Parse a prefix length and generate a bit-mask. *
@@ -649,6 +685,23 @@ parse_prefix(struct context *ctx, const struct token *token, u =strtoumax (str, &end,0 );if (errno || (size_t )(end - str) != len) goto error; +if (arg->mask) { +uintmax_t v =0 ; + + extra =arg_entry_bf_fill (NULL ,0 , arg); +if (u > extra) + goto error; +if (!ctx->object) +return len; + extra -= u; +while (u--) + (v <<=1 , v |=1 ); + v <<= extra; +if (!arg_entry_bf_fill (ctx->object, v, arg) || + !arg_entry_bf_fill (ctx->objmask,-1 , arg)) + goto error; +return len; + } bytes = u /8 ; extra = u %8 ; size = arg->size;
@@ -1072,6 +1125,12 @@ parse_int(struct context *ctx, const struct token *token, goto error;if (!ctx->object)return len; +if (arg->mask) { +if (!arg_entry_bf_fill (ctx->object, u, arg) || + !arg_entry_bf_fill (ctx->objmask,-1 , arg)) + goto error; +return len; + } buf = (uint8_t *)ctx->object + arg->offset; size = arg->size; objmask:
Signature · 1 line
2.1.4
PATCH v4 17/25 app/testpmd: add item any to flow command
In reply to Adrien MazarguilThis pattern item matches any protocol in place of the current layer and has two properties:
- min: minimum number of layers covered (0 or more).
- max: maximum number of layers covered (0 means infinity).
--- app/test-pmd/cmdline_flow.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
app/test-pmd/cmdline_flow.c +22 -1
@@ -99,6 +99,8 @@ enum index {ITEM_END ,ITEM_VOID ,ITEM_INVERT , +ITEM_ANY , +ITEM_ANY_NUM ,/* Validate/create actions. */ ACTIONS,
@@ -282,7 +284,6 @@ static const enum index next_list_attr[] = { ZERO, }; -__rte_unused static const enum index item_param[] = {ITEM_PARAM_IS ,ITEM_PARAM_SPEC ,
@@ -296,6 +297,13 @@ static const enum index next_item[] = {ITEM_END ,ITEM_VOID ,ITEM_INVERT , +ITEM_ANY , + ZERO, +}; + +static const enum index item_any[] = { +ITEM_ANY_NUM , +ITEM_NEXT ,ZERO , };
@@ -580,6 +588,19 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), .call = parse_vc, }, + [ITEM_ANY] = { + .name = "any", + .help = "match any protocol for the current layer", + .priv = PRIV_ITEM(ANY, sizeof(struct rte_flow_item_any)), + .next = NEXT(item_any), + .call = parse_vc, + }, + [ITEM_ANY_NUM] = { + .name = "num", + .help = "number of layers covered", + .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
Signature · 1 line
2.1.4
PATCH v4 18/25 app/testpmd: add various items to flow command
In reply to Adrien Mazarguil- PF: match packets addressed to the physical function.
- VF: match packets addressed to a virtual function ID.
- PORT: device-specific physical port index to use.
--- app/test-pmd/cmdline_flow.c | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
app/test-pmd/cmdline_flow.c +53 -0
@@ -101,6 +101,11 @@ enum index {ITEM_INVERT ,ITEM_ANY ,ITEM_ANY_NUM , +ITEM_PF , +ITEM_VF , +ITEM_VF_ID , +ITEM_PORT , +ITEM_PORT_INDEX ,/* Validate/create actions. */ ACTIONS,
@@ -298,6 +303,9 @@ static const enum index next_item[] = {ITEM_VOID ,ITEM_INVERT ,ITEM_ANY , +ITEM_PF , +ITEM_VF , +ITEM_PORT , ZERO, };
@@ -307,6 +315,18 @@ static const enum index item_any[] = { ZERO, }; +static const enum index item_vf[] = { +ITEM_VF_ID , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_port[] = { +ITEM_PORT_INDEX , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -601,6 +621,39 @@ static const struct token token_list[] = { .next = NEXT(item_any, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY(struct rte_flow_item_any, num)), }, + [ITEM_PF] = { + .name = "pf", + .help = "match packets addressed to the physical function", + .priv = PRIV_ITEM(PF, 0), + .next = NEXT(NEXT_ENTRY(ITEM_NEXT)), + .call = parse_vc, + }, + [ITEM_VF] = { + .name = "vf", + .help = "match packets addressed to a virtual function ID", + .priv = PRIV_ITEM(VF, sizeof(struct rte_flow_item_vf)), + .next = NEXT(item_vf), + .call = parse_vc, + }, + [ITEM_VF_ID] = { + .name = "id", + .help = "destination VF ID", + .next = NEXT(item_vf, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_vf, id)), + }, + [ITEM_PORT] = { + .name = "port", + .help = "device-specific physical port index to use", + .priv = PRIV_ITEM(PORT, sizeof(struct rte_flow_item_port)), + .next = NEXT(item_port), + .call = parse_vc, + }, + [ITEM_PORT_INDEX] = { + .name = "index", + .help = "physical port index", + .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
Signature · 1 line
2.1.4
PATCH v4 19/25 app/testpmd: add item raw to flow command
In reply to Adrien MazarguilMatches arbitrary byte strings with properties:
- relative: look for pattern after the previous item.
- search: search pattern from offset (see also limit).
- offset: absolute or relative offset for pattern.
- limit: search area limit for start of pattern.
- length: pattern length.
- pattern: byte string to look for.
--- app/test-pmd/cmdline_flow.c | 208 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+)
app/test-pmd/cmdline_flow.c +208 -0
@@ -57,6 +57,8 @@ enum index {INTEGER ,UNSIGNED ,PREFIX , +BOOLEAN , +STRING ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -106,6 +108,12 @@ enum index {ITEM_VF_ID ,ITEM_PORT ,ITEM_PORT_INDEX , +ITEM_RAW , +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN ,/* Validate/create actions. */ ACTIONS,
@@ -115,6 +123,13 @@ enum index { ACTION_PASSTHRU, }; +/** Size of pattern[] field in struct rte_flow_item_raw. */ +#define ITEM_RAW_PATTERN_SIZE 36 + +/** Storage size for struct rte_flow_item_raw including pattern. */ +#define ITEM_RAW_SIZE \ + (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) +/** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16
@@ -216,6 +231,13 @@ struct token { .size = sizeof(*((s *)0)->f), \ }) +/** Static initializer for ARGS() with arbitrary size. */ +#define ARGS_ENTRY_USZ (s, f, sz) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = (sz), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -306,6 +328,7 @@ static const enum index next_item[] = {ITEM_PF ,ITEM_VF ,ITEM_PORT , +ITEM_RAW , ZERO, };
@@ -327,6 +350,16 @@ static const enum index item_port[] = { ZERO, }; +static const enum index item_raw[] = { +ITEM_RAW_RELATIVE , +ITEM_RAW_SEARCH , +ITEM_RAW_OFFSET , +ITEM_RAW_LIMIT , +ITEM_RAW_PATTERN , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -363,11 +396,19 @@ static int parse_int(struct context *, const struct token *,static int parse_prefix (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_boolean (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_string (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );static int comp_none (struct context *,const struct token *,unsigned int ,char *,unsigned int ); +static int comp_boolean (struct context *,const struct token *, +unsigned int ,char *,unsigned int );static int comp_action (struct context *,const struct token *,unsigned int ,char *,unsigned int ); static int comp_port(struct context *, const struct token *,
@@ -410,6 +451,20 @@ static const struct token token_list[] = { .call = parse_prefix, .comp = comp_none, }, + [BOOLEAN] = { + .name = "{boolean}", + .type = "BOOLEAN", + .help = "any boolean value", + .call = parse_boolean, + .comp = comp_boolean, + }, + [STRING] = { + .name = "{string}", + .type = "STRING", + .help = "fixed string", + .call = parse_string, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -654,6 +709,52 @@ static const struct token token_list[] = { .next = NEXT(item_port, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY(struct rte_flow_item_port, index)), }, + [ITEM_RAW] = { + .name = "raw", + .help = "match an arbitrary byte string", + .priv = PRIV_ITEM(RAW, ITEM_RAW_SIZE), + .next = NEXT(item_raw), + .call = parse_vc, + }, + [ITEM_RAW_RELATIVE] = { + .name = "relative", + .help = "look for pattern after the previous item", + .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + relative, 1)), + }, + [ITEM_RAW_SEARCH] = { + .name = "search", + .help = "search pattern from offset (see also limit)", + .next = NEXT(item_raw, NEXT_ENTRY(BOOLEAN), item_param), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_item_raw, + search, 1)), + }, + [ITEM_RAW_OFFSET] = { + .name = "offset", + .help = "absolute or relative offset for pattern", + .next = NEXT(item_raw, NEXT_ENTRY(INTEGER), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, offset)), + }, + [ITEM_RAW_LIMIT] = { + .name = "limit", + .help = "search area limit for start of pattern", + .next = NEXT(item_raw, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, limit)), + }, + [ITEM_RAW_PATTERN] = { + .name = "pattern", + .help = "byte string to look for", + .next =NEXT (item_raw, +NEXT_ENTRY (STRING ), +NEXT_ENTRY (ITEM_PARAM_IS , +ITEM_PARAM_SPEC , + ITEM_PARAM_MASK)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_item_raw, length), + ARGS_ENTRY_USZ(struct rte_flow_item_raw, + pattern, + ITEM_RAW_PATTERN_SIZE)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1235,6 +1336,96 @@ parse_int(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse a string. +* +* Two arguments (ctx->args) are retrieved from the stack to store data and +* its length (in that order). +*/ +static int +parse_string (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +const struct arg *arg_data =pop_args (ctx); +const struct arg *arg_len =pop_args (ctx); +char tmp[16 ];/* Ought to be enough. */ +int ret; + +/* Arguments are expected. */ +if (!arg_data) +return -1 ; +if (!arg_len) { +push_args (ctx, arg_data); +return -1 ; + } + size = arg_data->size; +/* Bit-mask fill is not supported. */ +if (arg_data->mask || size < len) + goto error; +if (!ctx->object) +return len; +/* Let parse_int() fill length information first. */ + ret =snprintf (tmp,sizeof (tmp),"%u" , len); +if (ret <0 ) + goto error; +push_args (ctx, arg_len); + ret =parse_int (ctx, token, tmp, ret,NULL ,0 ); +if (ret <0 ) { +pop_args (ctx); + goto error; + } + buf = (uint8_t *)ctx->object + arg_data->offset; +/* Output buffer is not necessarily NUL-terminated. */ +memcpy (buf, str, len); +memset ((uint8_t *)buf + len,0x55 , size - len); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg_data->offset,0xff , len); +return len; +error: +push_args (ctx, arg_len); +push_args (ctx, arg_data); +return -1 ; +} + +/** Boolean values (even indices stand for false). */ +static const char *const boolean_name[] = { +"0" ,"1" , +"false" ,"true" , +"no" ,"yes" , +"N" ,"Y" , +NULL , +}; + +/** +* Parse a boolean value. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_boolean (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); +unsigned int i; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; +for (i =0 ; boolean_name[i]; ++i) +if (!strncmp (str, boolean_name[i], len)) +break ; +/* Process token as integer. */ +if (boolean_name[i]) + str = i &1 ?"1" :"0" ; +push_args (ctx, arg); + ret =parse_int (ctx, token, str,strlen (str), buf, size); +return ret >0 ? (int )len : ret; +} +/** Parse port and update context. */ static int parse_port(struct context *ctx, const struct token *token,
@@ -1273,6 +1464,23 @@ comp_none(struct context *ctx, const struct token *token,return 0 ; } +/** Complete boolean values. */ +static int +comp_boolean (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ +unsigned int i; + + (void )ctx; + (void )token; +for (i =0 ; boolean_name[i]; ++i) +if (buf && i == ent) +return snprintf (buf, size,"%s" , boolean_name[i]); +if (buf) +return -1 ; +return i; +} +/** Complete action names. */ static int comp_action(struct context *ctx, const struct token *token,
Signature · 1 line
2.1.4
PATCH v4 20/25 app/testpmd: add items eth/vlan to flow command
In reply to Adrien MazarguilThese pattern items match basic Ethernet headers (source, destination and type) and related 802.1Q/ad VLAN headers.
--- app/test-pmd/cmdline_flow.c | 126 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+)
app/test-pmd/cmdline_flow.c +126 -0
@@ -43,6 +43,7 @@#include <rte_ethdev.h> #include <rte_byteorder.h> #include <cmdline_parse.h> +#include <cmdline_parse_etheraddr.h> #include <rte_flow.h> #include "testpmd.h"
@@ -59,6 +60,7 @@ enum index {PREFIX ,BOOLEAN ,STRING , +MAC_ADDR ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -114,6 +116,13 @@ enum index {ITEM_RAW_OFFSET ,ITEM_RAW_LIMIT ,ITEM_RAW_PATTERN , +ITEM_ETH , +ITEM_ETH_DST , +ITEM_ETH_SRC , +ITEM_ETH_TYPE , +ITEM_VLAN , +ITEM_VLAN_TPID , +ITEM_VLAN_TCI ,/* Validate/create actions. */ ACTIONS,
@@ -238,6 +247,14 @@ struct token { .size = (sz), \ }) +/** Same as ARGS_ENTRY() using network byte ordering. */ +#define ARGS_ENTRY_HTON (s, f) \ + (&(const struct arg){ \ + .hton = 1, \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -329,6 +346,8 @@ static const enum index next_item[] = {ITEM_VF ,ITEM_PORT ,ITEM_RAW , +ITEM_ETH , +ITEM_VLAN , ZERO, };
@@ -360,6 +379,21 @@ static const enum index item_raw[] = { ZERO, }; +static const enum index item_eth[] = { +ITEM_ETH_DST , +ITEM_ETH_SRC , +ITEM_ETH_TYPE , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_vlan[] = { +ITEM_VLAN_TPID , +ITEM_VLAN_TCI , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -402,6 +436,9 @@ static int parse_boolean(struct context *, const struct token *,static int parse_string (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_mac_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -465,6 +502,13 @@ static const struct token token_list[] = { .call = parse_string, .comp = comp_none, }, + [MAC_ADDR] = { + .name = "{MAC address}", + .type = "MAC-48", + .help = "standard MAC address notation", + .call = parse_mac_addr, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -755,6 +799,50 @@ static const struct token token_list[] = { pattern, ITEM_RAW_PATTERN_SIZE)), }, + [ITEM_ETH ] = { + .name ="eth" , + .help ="match Ethernet header" , + .priv =PRIV_ITEM (ETH ,sizeof (struct rte_flow_item_eth )), + .next =NEXT (item_eth), + .call = parse_vc, + }, + [ITEM_ETH_DST ] = { + .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)), + }, + [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)), + }, + [ITEM_ETH_TYPE ] = { + .name ="type" , + .help ="EtherType" , + .next =NEXT (item_eth,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_eth, type)), + }, + [ITEM_VLAN ] = { + .name ="vlan" , + .help ="match 802.1Q/ad VLAN tag" , + .priv =PRIV_ITEM (VLAN ,sizeof (struct rte_flow_item_vlan )), + .next =NEXT (item_vlan), + .call = parse_vc, + }, + [ITEM_VLAN_TPID ] = { + .name ="tpid" , + .help ="tag protocol identifier" , + .next =NEXT (item_vlan,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tpid)), + }, + [ITEM_VLAN_TCI ] = { + .name ="tci" , + .help ="tag control information" , + .next =NEXT (item_vlan,NEXT_ENTRY (UNSIGNED ), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), + }, /* Validate/create actions. */ [ACTIONS ] = { .name ="actions" ,
@@ -1388,6 +1476,44 @@ parse_string(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse a MAC address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_mac_addr (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); +struct ether_addr tmp; +int ret; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; + ret =cmdline_parse_etheraddr (NULL , str, &tmp, size); +if (ret <0 || (unsigned int )ret != len) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Boolean values (even indices stand for false). */ static const char *const boolean_name[] = {"0" ,"1" ,
Signature · 1 line
2.1.4
PATCH v4 21/25 app/testpmd: add items ipv4/ipv6 to flow command
In reply to Adrien MazarguilAdd the ability to match basic fields from IPv4 and IPv6 headers (source and destination addresses only).
--- app/test-pmd/cmdline_flow.c | 177 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+)
app/test-pmd/cmdline_flow.c +177 -0
@@ -38,6 +38,7 @@#include <errno.h> #include <ctype.h> #include <string.h> +#include <arpa/inet.h> #include <rte_common.h> #include <rte_ethdev.h>
@@ -61,6 +62,8 @@ enum index {BOOLEAN ,STRING ,MAC_ADDR , +IPV4_ADDR , +IPV6_ADDR ,RULE_ID ,PORT_ID , GROUP_ID,
@@ -123,6 +126,12 @@ enum index {ITEM_VLAN ,ITEM_VLAN_TPID ,ITEM_VLAN_TCI , +ITEM_IPV4 , +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_IPV6 , +ITEM_IPV6_SRC , +ITEM_IPV6_DST ,/* Validate/create actions. */ ACTIONS,
@@ -348,6 +357,8 @@ static const enum index next_item[] = {ITEM_RAW ,ITEM_ETH ,ITEM_VLAN , +ITEM_IPV4 , +ITEM_IPV6 , ZERO, };
@@ -394,6 +405,20 @@ static const enum index item_vlan[] = { ZERO, }; +static const enum index item_ipv4[] = { +ITEM_IPV4_SRC , +ITEM_IPV4_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_ipv6[] = { +ITEM_IPV6_SRC , +ITEM_IPV6_DST , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -439,6 +464,12 @@ static int parse_string(struct context *, const struct token *,static int parse_mac_addr (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_ipv4_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int ); +static int parse_ipv6_addr (struct context *,const struct token *, +const char *,unsigned int , +void *,unsigned int );static int parse_port (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -509,6 +540,20 @@ static const struct token token_list[] = { .call = parse_mac_addr, .comp = comp_none, }, + [IPV4_ADDR] = { + .name = "{IPv4 address}", + .type = "IPV4 ADDRESS", + .help = "standard IPv4 address notation", + .call = parse_ipv4_addr, + .comp = comp_none, + }, + [IPV6_ADDR] = { + .name = "{IPv6 address}", + .type = "IPV6 ADDRESS", + .help = "standard IPv6 address notation", + .call = parse_ipv6_addr, + .comp = comp_none, + }, [RULE_ID] = { .name = "{rule id}", .type = "RULE ID",
@@ -843,6 +888,48 @@ static const struct token token_list[] = { .next = NEXT(item_vlan, NEXT_ENTRY(UNSIGNED), item_param), .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, tci)), }, + [ITEM_IPV4] = { + .name = "ipv4", + .help = "match IPv4 header", + .priv = PRIV_ITEM(IPV4, sizeof(struct rte_flow_item_ipv4)), + .next = NEXT(item_ipv4), + .call = parse_vc, + }, + [ITEM_IPV4_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.src_addr)), + }, + [ITEM_IPV4_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv4, NEXT_ENTRY(IPV4_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv4, + hdr.dst_addr)), + }, + [ITEM_IPV6] = { + .name = "ipv6", + .help = "match IPv6 header", + .priv = PRIV_ITEM(IPV6, sizeof(struct rte_flow_item_ipv6)), + .next = NEXT(item_ipv6), + .call = parse_vc, + }, + [ITEM_IPV6_SRC] = { + .name = "src", + .help = "source address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.src_addr)), + }, + [ITEM_IPV6_DST] = { + .name = "dst", + .help = "destination address", + .next = NEXT(item_ipv6, NEXT_ENTRY(IPV6_ADDR), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, + hdr.dst_addr)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1514,6 +1601,96 @@ parse_mac_addr(struct context *ctx, const struct token *token,return -1 ; } +/** +* Parse an IPv4 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv4_addr (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); +char str2[len +1 ]; +struct in_addr tmp; +int ret; + +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET , str2, &tmp); +if (ret !=1 ) { +/* Attempt integer parsing. */ +push_args (ctx, arg); +return parse_int (ctx, token, str, len, buf, size); + } +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} + +/** +* Parse an IPv6 address. +* +* Last argument (ctx->args) is retrieved to determine storage size and +* location. +*/ +static int +parse_ipv6_addr (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); +char str2[len +1 ]; +struct in6_addr tmp; +int ret; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + size = arg->size; +/* Bit-mask fill is not supported. */ +if (arg->mask || size !=sizeof (tmp)) + goto error; +/* Only network endian is supported. */ +if (!arg->hton) + goto error; +memcpy (str2, str, len); + str2[len] ='\0' ; + ret =inet_pton (AF_INET6 , str2, &tmp); +if (ret !=1 ) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; +memcpy (buf, &tmp, size); +if (ctx->objmask) +memset ((uint8_t *)ctx->objmask + arg->offset,0xff , size); +return len; +error: +push_args (ctx, arg); +return -1 ; +} +/** Boolean values (even indices stand for false). */ static const char *const boolean_name[] = {"0" ,"1" ,
Signature · 1 line
2.1.4
PATCH v4 22/25 app/testpmd: add L4 items to flow command
In reply to Adrien MazarguilAdd the ability to match a few properties of common L4[.5] protocol headers:
- ICMP: type and code.
- UDP: source and destination ports.
- TCP: source and destination ports.
- SCTP: source and destination ports.
- VXLAN: network identifier.
--- app/test-pmd/cmdline_flow.c | 163 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+)
app/test-pmd/cmdline_flow.c +163 -0
@@ -132,6 +132,20 @@ enum index {ITEM_IPV6 ,ITEM_IPV6_SRC ,ITEM_IPV6_DST , +ITEM_ICMP , +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_UDP , +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_TCP , +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_SCTP , +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_VXLAN , +ITEM_VXLAN_VNI ,/* Validate/create actions. */ ACTIONS,
@@ -359,6 +373,11 @@ static const enum index next_item[] = {ITEM_VLAN ,ITEM_IPV4 ,ITEM_IPV6 , +ITEM_ICMP , +ITEM_UDP , +ITEM_TCP , +ITEM_SCTP , +ITEM_VXLAN , ZERO, };
@@ -419,6 +438,40 @@ static const enum index item_ipv6[] = { ZERO, }; +static const enum index item_icmp[] = { +ITEM_ICMP_TYPE , +ITEM_ICMP_CODE , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_udp[] = { +ITEM_UDP_SRC , +ITEM_UDP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_tcp[] = { +ITEM_TCP_SRC , +ITEM_TCP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_sctp[] = { +ITEM_SCTP_SRC , +ITEM_SCTP_DST , +ITEM_NEXT , +ZERO , +}; + +static const enum index item_vxlan[] = { +ITEM_VXLAN_VNI , +ITEM_NEXT , +ZERO , +}; +static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,
@@ -930,6 +983,103 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_ipv6, hdr.dst_addr)), }, + [ITEM_ICMP] = { + .name = "icmp", + .help = "match ICMP header", + .priv = PRIV_ITEM(ICMP, sizeof(struct rte_flow_item_icmp)), + .next = NEXT(item_icmp), + .call = parse_vc, + }, + [ITEM_ICMP_TYPE] = { + .name = "type", + .help = "ICMP packet type", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_type)), + }, + [ITEM_ICMP_CODE] = { + .name = "code", + .help = "ICMP packet code", + .next = NEXT(item_icmp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_icmp, + hdr.icmp_code)), + }, + [ITEM_UDP] = { + .name = "udp", + .help = "match UDP header", + .priv = PRIV_ITEM(UDP, sizeof(struct rte_flow_item_udp)), + .next = NEXT(item_udp), + .call = parse_vc, + }, + [ITEM_UDP_SRC] = { + .name = "src", + .help = "UDP source port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.src_port)), + }, + [ITEM_UDP_DST] = { + .name = "dst", + .help = "UDP destination port", + .next = NEXT(item_udp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_udp, + hdr.dst_port)), + }, + [ITEM_TCP] = { + .name = "tcp", + .help = "match TCP header", + .priv = PRIV_ITEM(TCP, sizeof(struct rte_flow_item_tcp)), + .next = NEXT(item_tcp), + .call = parse_vc, + }, + [ITEM_TCP_SRC] = { + .name = "src", + .help = "TCP source port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.src_port)), + }, + [ITEM_TCP_DST] = { + .name = "dst", + .help = "TCP destination port", + .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp, + hdr.dst_port)), + }, + [ITEM_SCTP] = { + .name = "sctp", + .help = "match SCTP header", + .priv = PRIV_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)), + .next = NEXT(item_sctp), + .call = parse_vc, + }, + [ITEM_SCTP_SRC] = { + .name = "src", + .help = "SCTP source port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.src_port)), + }, + [ITEM_SCTP_DST] = { + .name = "dst", + .help = "SCTP destination port", + .next = NEXT(item_sctp, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_sctp, + hdr.dst_port)), + }, + [ITEM_VXLAN] = { + .name = "vxlan", + .help = "match VXLAN header", + .priv = PRIV_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)), + .next = NEXT(item_vxlan), + .call = parse_vc, + }, + [ITEM_VXLAN_VNI] = { + .name = "vni", + .help = "VXLAN identifier", + .next = NEXT(item_vxlan, NEXT_ENTRY(UNSIGNED), item_param), + .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vxlan, vni)), + },/* Validate/create actions. */ [ACTIONS] = { .name = "actions",
@@ -1491,6 +1641,19 @@ parse_int(struct context *ctx, const struct token *token,case sizeof (uint16_t ): *(uint16_t *)buf = arg->hton ?rte_cpu_to_be_16 (u) : u;break ; +case sizeof (uint8_t [3 ]): +#if RTE_BYTE_ORDER ==RTE_LITTLE_ENDIAN +if (!arg->hton) { + ((uint8_t *)buf)[0 ] = u; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u >>16 ; +break ; + } +#endif + ((uint8_t *)buf)[0 ] = u >>16 ; + ((uint8_t *)buf)[1 ] = u >>8 ; + ((uint8_t *)buf)[2 ] = u; +break ;case sizeof (uint32_t ): *(uint32_t *)buf = arg->hton ?rte_cpu_to_be_32 (u) : u;break ;
Signature · 1 line
2.1.4
PATCH v4 23/25 app/testpmd: add various actions to flow command
In reply to Adrien Mazarguil- MARK: attach 32 bit value to packets.
- FLAG: flag packets.
- DROP: drop packets.
- COUNT: enable counters for a rule.
- PF: redirect packets to physical device function.
- VF: redirect packets to virtual device function.
--- app/test-pmd/cmdline_flow.c | 121 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+)
app/test-pmd/cmdline_flow.c +121 -0
@@ -153,6 +153,15 @@ enum index {ACTION_END ,ACTION_VOID ,ACTION_PASSTHRU , +ACTION_MARK , +ACTION_MARK_ID , +ACTION_FLAG , +ACTION_DROP , +ACTION_COUNT , +ACTION_PF , +ACTION_VF , +ACTION_VF_ORIGINAL , + ACTION_VF_ID, };/** Size of pattern[] field in struct rte_flow_item_raw. */
@@ -476,6 +485,25 @@ static const enum index next_action[] = {ACTION_END ,ACTION_VOID ,ACTION_PASSTHRU , +ACTION_MARK , +ACTION_FLAG , +ACTION_DROP , +ACTION_COUNT , +ACTION_PF , +ACTION_VF , + ZERO, +}; + +static const enum index action_mark[] = { +ACTION_MARK_ID , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_vf[] = { +ACTION_VF_ORIGINAL , +ACTION_VF_ID , +ACTION_NEXT ,ZERO , };
@@ -487,6 +515,8 @@ static int parse_vc(struct context *, const struct token *, void *, unsigned int);static int parse_vc_spec (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_conf (struct context *,const struct token *, +const char *,unsigned int ,void *,unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -1112,6 +1142,70 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_MARK] = { + .name = "mark", + .help = "attach 32 bit value to packets", + .priv = PRIV_ACTION(MARK, sizeof(struct rte_flow_action_mark)), + .next = NEXT(action_mark), + .call = parse_vc, + }, + [ACTION_MARK_ID] = { + .name = "id", + .help = "32 bit value to return with packets", + .next = NEXT(action_mark, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_mark, id)), + .call = parse_vc_conf, + }, + [ACTION_FLAG] = { + .name = "flag", + .help = "flag packets", + .priv = PRIV_ACTION(FLAG, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_DROP] = { + .name = "drop", + .help = "drop packets (note: passthru has priority)", + .priv = PRIV_ACTION(DROP, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_COUNT] = { + .name = "count", + .help = "enable counters for this rule", + .priv = PRIV_ACTION(COUNT, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_PF] = { + .name = "pf", + .help = "redirect packets to physical device function", + .priv = PRIV_ACTION(PF, 0), + .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), + .call = parse_vc, + }, + [ACTION_VF] = { + .name = "vf", + .help = "redirect packets to virtual device function", + .priv = PRIV_ACTION(VF, sizeof(struct rte_flow_action_vf)), + .next = NEXT(action_vf), + .call = parse_vc, + }, + [ACTION_VF_ORIGINAL] = { + .name = "original", + .help = "use original VF ID if possible", + .next = NEXT(action_vf, NEXT_ENTRY(BOOLEAN)), + .args = ARGS(ARGS_ENTRY_BF(struct rte_flow_action_vf, + original, 1)), + .call = parse_vc_conf, + }, + [ACTION_VF_ID] = { + .name = "id", + .help = "VF ID to redirect packets to", + .next = NEXT(action_vf, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)), + .call = parse_vc_conf, + }, };/** Remove and return last entry from argument stack. */
@@ -1435,6 +1529,33 @@ parse_vc_spec(struct context *ctx, const struct token *token,return len; } +/** Parse action configuration field. */ +static int +parse_vc_conf (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +struct buffer *out = buf; +struct rte_flow_action *action; + + (void )size; +/* 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->args.vc.actions_n) +return -1 ; + action = &out->args.vc.actions[out->args.vc.actions_n -1 ]; +/* Point to selected object. */ + ctx->object = out->args.vc.data; + ctx->objmask =NULL ; +/* Update configuration pointer. */ + action->conf = ctx->object; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
Signature · 1 line
2.1.4
PATCH v4 24/25 app/testpmd: add queue actions to flow command
In reply to Adrien Mazarguil- QUEUE: assign packets to a given queue index.
- DUP: duplicate packets to a given queue index.
- RSS: spread packets among several queues.
--- app/test-pmd/cmdline_flow.c | 152 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+)
app/test-pmd/cmdline_flow.c +152 -0
@@ -156,8 +156,15 @@ enum index {ACTION_MARK ,ACTION_MARK_ID ,ACTION_FLAG , +ACTION_QUEUE , +ACTION_QUEUE_INDEX ,ACTION_DROP ,ACTION_COUNT , +ACTION_DUP , +ACTION_DUP_INDEX , +ACTION_RSS , +ACTION_RSS_QUEUES , +ACTION_RSS_QUEUE ,ACTION_PF ,ACTION_VF , ACTION_VF_ORIGINAL,
@@ -171,6 +178,14 @@ enum index {#define ITEM_RAW_SIZE \ (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE) +/** Number of queue[] entries in struct rte_flow_action_rss. */ +#define ACTION_RSS_NUM 32 + +/** Storage size for struct rte_flow_action_rss including queues. */ +#define ACTION_RSS_SIZE \ + (offsetof(struct rte_flow_action_rss, queue) + \ + sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM) +/** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16
@@ -487,8 +502,11 @@ static const enum index next_action[] = {ACTION_PASSTHRU ,ACTION_MARK ,ACTION_FLAG , +ACTION_QUEUE ,ACTION_DROP ,ACTION_COUNT , +ACTION_DUP , +ACTION_RSS ,ACTION_PF ,ACTION_VF , ZERO,
@@ -500,6 +518,24 @@ static const enum index action_mark[] = { ZERO, }; +static const enum index action_queue[] = { +ACTION_QUEUE_INDEX , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_dup[] = { +ACTION_DUP_INDEX , +ACTION_NEXT , +ZERO , +}; + +static const enum index action_rss[] = { +ACTION_RSS_QUEUES , +ACTION_NEXT , +ZERO , +}; +static const enum index action_vf[] = {ACTION_VF_ORIGINAL ,ACTION_VF_ID ,
@@ -517,6 +553,9 @@ static int parse_vc_spec(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int);static int parse_vc_conf (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_action_rss_queue (struct context *,const struct token *, +const char *,unsigned int ,void *, +unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -566,6 +605,8 @@ static int comp_port(struct context *, const struct token *, unsigned int, char *, unsigned int);static int comp_rule_id (struct context *,const struct token *,unsigned int ,char *,unsigned int ); +static int comp_vc_action_rss_queue (struct context *,const struct token *, +unsigned int ,char *,unsigned int );/** Token definitions. */ static const struct token token_list[] = {
@@ -1163,6 +1204,21 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_QUEUE] = { + .name = "queue", + .help = "assign packets to a given queue index", + .priv =PRIV_ACTION (QUEUE , + sizeof(struct rte_flow_action_queue)), + .next = NEXT(action_queue), + .call = parse_vc, + }, + [ACTION_QUEUE_INDEX] = { + .name = "index", + .help = "queue index to use", + .next = NEXT(action_queue, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_queue, index)), + .call = parse_vc_conf, + }, [ACTION_DROP] = { .name = "drop", .help = "drop packets (note: passthru has priority)",
@@ -1177,6 +1233,39 @@ static const struct token token_list[] = { .next = NEXT(NEXT_ENTRY(ACTION_NEXT)), .call = parse_vc, }, + [ACTION_DUP] = { + .name = "dup", + .help = "duplicate packets to a given queue index", + .priv = PRIV_ACTION(DUP, sizeof(struct rte_flow_action_dup)), + .next = NEXT(action_dup), + .call = parse_vc, + }, + [ACTION_DUP_INDEX] = { + .name = "index", + .help = "queue index to duplicate packets to", + .next = NEXT(action_dup, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_dup, index)), + .call = parse_vc_conf, + }, + [ACTION_RSS] = { + .name = "rss", + .help = "spread packets among several queues", + .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE), + .next = NEXT(action_rss), + .call = parse_vc, + }, + [ACTION_RSS_QUEUES] = { + .name = "queues", + .help = "queue indices to use", + .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_QUEUE)), + .call = parse_vc_conf, + }, + [ACTION_RSS_QUEUE] = { + .name = "{queue}", + .help = "queue index", + .call = parse_vc_action_rss_queue, + .comp = comp_vc_action_rss_queue, + }, [ACTION_PF] = { .name = "pf", .help = "redirect packets to physical device function",
@@ -1556,6 +1645,51 @@ parse_vc_conf(struct context *ctx, const struct token *token,return len; } +/** +* Parse queue field for RSS action. +* +* Valid tokens are queue indices and the "end" token. +*/ +static int +parse_vc_action_rss_queue (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +static const enum index next[] =NEXT_ENTRY (ACTION_RSS_QUEUE ); +int ret; +int i; + + (void )token; + (void )buf; + (void )size; +if (ctx->curr !=ACTION_RSS_QUEUE ) +return -1 ; + i = ctx->objdata >>16 ; +if (!strncmp (str,"end" , len)) { + ctx->objdata &=0xffff ; +return len; + } +if (i >=ACTION_RSS_NUM ) +return -1 ; + if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i]))) +return -1 ; + ret =parse_int (ctx, token, str, len,NULL ,0 ); +if (ret <0 ) { +pop_args (ctx); +return -1 ; + } + ++i; + ctx->objdata = i <<16 | (ctx->objdata &0xffff ); +/* Repeat token. */ +if (ctx->next_num ==RTE_DIM (ctx->next)) +return -1 ; + ctx->next[ctx->next_num++] = next; +if (!ctx->object) +return len; + ((struct rte_flow_action_rss *)ctx->object)->num = i; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
@@ -2130,6 +2264,24 @@ comp_rule_id(struct context *ctx, const struct token *token,return i; } +/** Complete queue field for RSS action. */ +static int +comp_vc_action_rss_queue (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ +static const char *const str[] = {"" ,"end" ,NULL }; +unsigned int i; + + (void )ctx; + (void )token; +for (i =0 ; str[i] !=NULL ; ++i) +if (buf && i == ent) +return snprintf (buf, size,"%s" , str[i]); +if (buf) +return -1 ; +return i; +} +/** Internal context. */ static struct context cmd_flow_context;
Signature · 1 line
2.1.4
PATCH v4 25/25 doc: describe testpmd flow command
In reply to Adrien MazarguilDocument syntax, interaction with rte_flow and provide usage examples.
--- doc/guides/testpmd_app_ug/testpmd_funcs.rst | 612 +++++++++++++++++++++++ 1 file changed, 612 insertions(+)
doc/guides/testpmd_app_ug/testpmd_funcs.rst +612 -0
@@ -1631,6 +1631,9 @@ Filter Functions This section details the available filter functions that are available. +Note these functions interface the deprecated legacy filtering framework, +superseded by *rte_flow*. See `Flow rules management`_. + ethertype_filter ~~~~~~~~~~~~~~~~~~~~
@@ -2041,3 +2044,612 @@ Set different GRE key length for input set:: For example to set GRE key length for input set to 4 bytes on port 0:: testpmd> global_config 0 gre-key-len 4 + + +.. _testpmd_rte_flow: + +Flow rules management +--------------------- + +Control of the generic flow API (*rte_flow*) is fully exposed through the +``flow`` command (validation, creation, destruction and queries). + +Considering *rte_flow* overlaps with all `Filter Functions`_, using both +features simultaneously may cause undefined side-effects and is therefore +not recommended. + +``flow`` syntax +~~~~~~~~~~~~~~~ + +Because the ``flow`` command uses dynamic tokens to handle the large number +of possible flow rules combinations, its behavior differs slightly from +other commands, in particular: + +- Pressing *?* or the *<tab>* key displays contextual help for the current + token, not that of the entire command. + +- Optional and repeated parameters are supported (provided they are listed + in the contextual help). + +The first parameter stands for the operation mode. Possible operations and +their general syntax are described below. They are covered in detail in the +following sections. + +- Check whether a flow rule can be created:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Create a flow rule:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +- Destroy specific flow rules:: + + flow destroy {port_id} rule {rule_id} [...] + +- Destroy all flow rules:: + + flow flush {port_id} + +- Query an existing flow rule:: + + flow query {port_id} {rule_id} {action} + +- List existing flow rules sorted by priority, filtered by group + identifiers:: + + flow list {port_id} [group {group_id}] [...] + +Validating flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow validate`` reports whether a flow rule would be accepted by the +underlying device in its current state but stops short of creating it. It is +bound to ``rte_flow_validate()``:: + + flow validate {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will show:: + + Flow rule validated + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +This command uses the same parameters as ``flow create``, their format is +described in `Creating flow rules`_. + +Check whether redirecting any Ethernet packet received on port 0 to RX queue +index 6 is supported:: + + testpmd> flow validate 0 ingress pattern eth / end + actions queue index 6 / end + Flow rule validated + testpmd> + +Port 0 does not support TCPv6 rules:: + + testpmd> flow validate 0 ingress pattern eth / ipv6 / tcp / end + actions drop / end + Caught error type 9 (specific pattern item): Invalid argument. + testpmd> + +Creating flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow create`` validates and creates the specified flow rule. It is bound +to ``rte_flow_create()``:: + + flow create {port_id} + [group {group_id}] [priority {level}] [ingress] [egress] + pattern {item} [/ {item} [...]] / end + actions {action} [/ {action} [...]] / end + +If successful, it will return a flow rule ID usable with other commands:: + + Flow rule #[...] created + +Otherwise it will show an error message of the form:: + + Caught error type [...] ([...]): [...] + +Parameters describe in the following order: + +- Attributes (*group*, *priority*, *ingress*, *egress* tokens). +- A matching pattern, starting with the *pattern* token and terminated by an + *end* pattern item. +- Actions, starting with the *actions* token and terminated by an *end* + action. + +These translate directly to *rte_flow* objects provided as-is to the +underlying functions. + +The shortest valid definition only comprises mandatory tokens:: + + testpmd> flow create 0 pattern end actions end + +Note that PMDs may refuse rules that essentially do nothing such as this +one. + +**All unspecified object values are automatically initialized to 0.** + +Attributes +^^^^^^^^^^ + +These tokens affect flow rule attributes (``struct rte_flow_attr``) and are +specified before the ``pattern`` token. + +- ``group {group id}``: priority group. +- ``priority {level}``: priority level within group. +- ``ingress``: rule applies to ingress traffic. +- ``egress``: rule applies to egress traffic. + +Each instance of an attribute specified several times overrides the previous +value as shown below (group 4 is used):: + + testpmd> flow create 0 group 42 group 24 group 4 [...] + +Note that once enabled, ``ingress`` and ``egress`` cannot be disabled. + +While not specifying a direction is an error, some rules may allow both +simultaneously. + +Most rules affect RX therefore contain the ``ingress`` token:: + + testpmd> flow create 0 ingress pattern [...] + +Matching pattern +^^^^^^^^^^^^^^^^ + +A matching pattern starts after the ``pattern`` token. It is made of pattern +items and is terminated by a mandatory ``end`` item. + +Items are named after their type (*RTE_FLOW_ITEM_TYPE_* from ``enum +rte_flow_item_type``). + +The ``/`` token is used as a separator between pattern items as shown +below:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end [...] + +Note that protocol items like these must be stacked from lowest to highest +layer to make sense. For instance, the following rule is either invalid or +unlikely to match any packet:: + + testpmd> flow create 0 ingress pattern eth / udp / ipv4 / end [...] + +More information on these restrictions can be found in the *rte_flow* +documentation. + +Several items support additional specification structures, for example +``ipv4`` allows specifying source and destination addresses as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 src is 10.1.1.1 + dst is 10.2.0.0 / end [...] + +This rule matches all IPv4 traffic with the specified properties. + +In this example, ``src`` and ``dst`` are field names of the underlying +``struct rte_flow_item_ipv4`` object. All item properties can be specified +in a similar fashion. + +The ``is`` token means that the subsequent value must be matched exactly, +and assigns ``spec`` and ``mask`` fields in ``struct rte_flow_item`` +accordingly. Possible assignment tokens are: + +- ``is``: match value perfectly (with full bit-mask). +- ``spec``: match value according to configured bit-mask. +- ``last``: specify upper bound to establish a range. +- ``mask``: specify bit-mask with relevant bits set to one. +- ``prefix``: generate bit-mask from a prefix length. + +These yield identical results:: + + ipv4 src is 10.1.1.1 + +:: + + ipv4 src spec 10.1.1.1 src mask 255.255.255.255 + +:: + + ipv4 src spec 10.1.1.1 src prefix 32 + +:: + + ipv4 src is 10.1.1.1 src last 10.1.1.1 # range with a single value + +:: + + ipv4 src is 10.1.1.1 src last 0 # 0 disables range + +Inclusive ranges can be defined with ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 # 10.1.1.1 to 10.2.3.4 + +Note that ``mask`` affects both ``spec`` and ``last``:: + + ipv4 src is 10.1.1.1 src last 10.2.3.4 src mask 255.255.0.0 + # matches 10.1.0.0 to 10.2.255.255 + +Properties can be modified multiple times:: + + ipv4 src is 10.1.1.1 src is 10.1.2.3 src is 10.2.3.4 # matches 10.2.3.4 + +:: + + ipv4 src is 10.1.1.1 src prefix 24 src prefix 16 # matches 10.1.0.0/16 + +Pattern items +^^^^^^^^^^^^^ + +This section lists supported pattern items and their attributes, if any. + +- ``end``: end list of pattern items. + +- ``void``: no-op pattern item. + +- ``invert``: perform actions when pattern does not match. + +- ``any``: match any protocol for the current layer. + + - ``num {unsigned}``: number of layers covered. + +- ``pf``: match packets addressed to the physical function. + +- ``vf``: match packets addressed to a virtual function ID. + + - ``id {unsigned}``: destination VF ID. + +- ``port``: device-specific physical port index to use. + + - ``index {unsigned}``: physical port index. + +- ``raw``: match an arbitrary byte string. + + - ``relative {boolean}``: look for pattern after the previous item. + - ``search {boolean}``: search pattern from offset (see also limit). + - ``offset {integer}``: absolute or relative offset for pattern. + - ``limit {unsigned}``: search area limit for start of pattern. + - ``pattern {string}``: byte string to look for. + +- ``eth``: match Ethernet header. + + - ``dst {MAC-48}``: destination MAC. + - ``src {MAC-48}``: source MAC. + - ``type {unsigned}``: EtherType. + +- ``vlan``: match 802.1Q/ad VLAN tag. + + - ``tpid {unsigned}``: tag protocol identifier. + - ``tci {unsigned}``: tag control information. + +- ``ipv4``: match IPv4 header. + + - ``src {ipv4 address}``: source address. + - ``dst {ipv4 address}``: destination address. + +- ``ipv6``: match IPv6 header. + + - ``src {ipv6 address}``: source address. + - ``dst {ipv6 address}``: destination address. + +- ``icmp``: match ICMP header. + + - ``type {unsigned}``: ICMP packet type. + - ``code {unsigned}``: ICMP packet code. + +- ``udp``: match UDP header. + + - ``src {unsigned}``: UDP source port. + - ``dst {unsigned}``: UDP destination port. + +- ``tcp``: match TCP header. + + - ``src {unsigned}``: TCP source port. + - ``dst {unsigned}``: TCP destination port. + +- ``sctp``: match SCTP header. + + - ``src {unsigned}``: SCTP source port. + - ``dst {unsigned}``: SCTP destination port. + +- ``vxlan``: match VXLAN header. + + - ``vni {unsigned}``: VXLAN identifier. + +Actions list +^^^^^^^^^^^^ + +A list of actions starts after the ``actions`` token in the same fashion as +`Matching pattern`_; actions are separated by ``/`` tokens and the list is +terminated by a mandatory ``end`` action. + +Actions are named after their type (*RTE_FLOW_ACTION_TYPE_* from ``enum +rte_flow_action_type``). + +Dropping all incoming UDPv4 packets can be expressed as follows:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions drop / end + +Several actions have configurable properties which must be specified when +there is no valid default value. For example, ``queue`` requires a target +queue index. + +This rule redirects incoming UDPv4 traffic to queue index 6:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue index 6 / end + +While this one could be rejected by PMDs (unspecified queue index):: + + testpmd> flow create 0 ingress pattern eth / ipv4 / udp / end + actions queue / end + +As defined by *rte_flow*, the list is not ordered, all actions of a given +rule are performed simultaneously. These are equivalent:: + + queue index 6 / void / mark id 42 / end + +:: + + void / mark id 42 / queue index 6 / end + +All actions in a list should have different types, otherwise only the last +action of a given type is taken into account:: + + queue index 4 / queue index 5 / queue index 6 / end # will use queue 6 + +:: + + drop / drop / drop / end # drop is performed only once + +:: + + mark id 42 / queue index 3 / mark id 24 / end # mark will be 24 + +Considering they are performed simultaneously, opposite and overlapping +actions can sometimes be combined when the end result is unambiguous:: + + drop / queue index 6 / end # drop has no effect + +:: + + drop / dup index 6 / end # same as above + +:: + + queue index 6 / rss queues 6 7 8 / end # queue has no effect + +:: + + drop / passthru / end # drop has no effect + +Note that PMDs may still refuse such combinations. + +Actions +^^^^^^^ + +This section lists supported actions and their attributes, if any. + +- ``end``: end list of actions. + +- ``void``: no-op action. + +- ``passthru``: let subsequent rule process matched packets. + +- ``mark``: attach 32 bit value to packets. + + - ``id {unsigned}``: 32 bit value to return with packets. + +- ``flag``: flag packets. + +- ``queue``: assign packets to a given queue index. + + - ``index {unsigned}``: queue index to use. + +- ``drop``: drop packets (note: passthru has priority). + +- ``count``: enable counters for this rule. + +- ``dup``: duplicate packets to a given queue index. + + - ``index {unsigned}``: queue index to duplicate packets to. + +- ``rss``: spread packets among several queues. + + - ``queues [{unsigned} [...]] end``: queue indices to use. + +- ``pf``: redirect packets to physical device function. + +- ``vf``: redirect packets to virtual device function. + + - ``original {boolean}``: use original VF ID if possible. + - ``id {unsigned}``: VF ID to redirect packets to. + +Destroying flow rules +~~~~~~~~~~~~~~~~~~~~~ + +``flow destroy`` destroys one or more rules from their rule ID (as returned +by ``flow create``), this command calls ``rte_flow_destroy()`` as many +times as necessary:: + + flow destroy {port_id} rule {rule_id} [...] + +If successful, it will show:: + + Flow rule #[...] destroyed + +It does not report anything for rule IDs that do not exist. The usual error +message is shown when a rule cannot be destroyed:: + + Caught error type [...] ([...]): [...] + +``flow flush`` destroys all rules on a device and does not take extra +arguments. It is bound to ``rte_flow_flush()``:: + + flow flush {port_id} + +Any errors are reported as above. + +Creating several rules and destroying them:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 0 rule 1 + Flow rule #1 destroyed + Flow rule #0 destroyed + testpmd> + +The same result can be achieved using ``flow flush``:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow flush 0 + testpmd> + +Non-existent rule IDs are ignored:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 3 / end + Flow rule #1 created + testpmd> flow destroy 0 rule 42 rule 10 rule 2 + testpmd> + testpmd> flow destroy 0 rule 0 + Flow rule #0 destroyed + testpmd> + +Querying flow rules +~~~~~~~~~~~~~~~~~~~ + +``flow query`` queries a specific action of a flow rule having that +ability. Such actions collect information that can be reported using this +command. It is bound to ``rte_flow_query()``:: + + flow query {port_id} {rule_id} {action} + +If successful, it will display either the retrieved data for known actions +or the following message:: + + Cannot display result for action type [...] ([...]) + +Otherwise, it will complain either that the rule does not exist or that some +error occurred:: + + Flow rule #[...] not found + +:: + + Caught error type [...] ([...]): [...] + +Currently only the ``count`` action is supported. This action reports the +number of packets that hit the flow rule and the total number of bytes. Its +output has the following format:: + + count: + hits_set: [...] # whether "hits" contains a valid value + bytes_set: [...] # whether "bytes" contains a valid value + hits: [...] # number of packets + bytes: [...] # number of bytes + +Querying counters for TCPv6 packets redirected to queue 6:: + + testpmd> flow create 0 ingress pattern eth / ipv6 / tcp / end + actions queue index 6 / count / end + Flow rule #4 created + testpmd> flow query 0 4 count + count: + hits_set: 1 + bytes_set: 0 + hits: 386446 + bytes: 0 + testpmd> + +Listing flow rules +~~~~~~~~~~~~~~~~~~ + +``flow list`` lists existing flow rules sorted by priority and optionally +filtered by group identifiers:: + + flow list {port_id} [group {group_id}] [...] + +This command only fails with the following message if the device does not +exist:: + + Invalid port [...] + +Output consists of a header line followed by a short description of each +flow rule, one per line. There is no output at all when no flow rules are +configured on the device:: + + ID Group Prio Attr Rule + [...] [...] [...] [...] [...] + +``Attr`` column flags: + +- ``i`` for ``ingress``. +- ``e`` for ``egress``. + +Creating several flow rules and listing them:: + + testpmd> flow create 0 ingress pattern eth / ipv4 / end + actions queue index 6 / end + Flow rule #0 created + testpmd> flow create 0 ingress pattern eth / ipv6 / end + actions queue index 2 / end + Flow rule #1 created + testpmd> flow create 0 priority 5 ingress pattern eth / ipv4 / udp / end + actions rss queues 6 7 8 end / end + Flow rule #2 created + testpmd> flow list 0 + ID Group Prio Attr Rule + 0 0 0 i- ETH IPV4 => QUEUE + 1 0 0 i- ETH IPV6 => QUEUE + 2 0 5 i- ETH IPV4 UDP => RSS + testpmd> + +Rules are sorted by priority (i.e. group ID first, then priority level):: + + testpmd> flow list 1 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 1 24 0 i- ETH IPV4 UDP => QUEUE + 4 24 10 i- ETH IPV4 TCP => DROP + 3 24 20 i- ETH IPV4 => DROP + 2 24 42 i- ETH IPV4 UDP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd> + +Output can be limited to specific groups:: + + testpmd> flow list 1 group 0 group 63 + ID Group Prio Attr Rule + 0 0 0 i- ETH => COUNT + 6 0 500 i- ETH IPV6 TCP => DROP COUNT + 5 0 1000 i- ETH IPV6 ICMP => QUEUE + 7 63 0 i- ETH IPV6 UDP VXLAN => MARK QUEUE + testpmd>
Signature · 1 line
2.1.4
v5 cover Generic flow API (rte_flow)
In reply to Adrien MazarguilAs previously discussed in RFC v1 [1], RFC v2 [2], with changes described in [3] (also pasted below), here is the first non-draft series for this new API.
Its capabilities are so generic that its name had to be vague, it may be called "Generic flow API", "Generic flow interface" (possibly shortened as "GFI") to refer to the name of the new filter type, or "rte_flow" from the prefix used for its public symbols. I personally favor the latter.
While it is currently meant to supersede existing filter types in order for all PMDs to expose a common filtering/classification interface, it may eventually evolve to cover the following ideas as well:
- Rx/Tx offloads configuration through automatic offloads for specific packets, e.g. performing checksum on TCP packets could be expressed with an egress rule with a TCP pattern and a kind of checksum action.
- RSS configuration (already defined actually). Could be global or per rule depending on hardware capabilities.
- Switching configuration for devices with many physical ports; rules doing both ingress and egress could even be used to completely bypass software if supported by hardware.
[1] http://dpdk.org/ml/archives/dev/2016-July/043365.html
[2] http://dpdk.org/ml/archives/dev/2016-August/045383.html
[3] http://dpdk.org/ml/archives/dev/2016-November/050044.html
Changes since v4 series:
- Fixed compilation regression introduced in v2, caused by new #include directive (rte_flow_driver.h).
- Fixed remaining documentation tables that broke PDF generation (John Mcnamara / rte_flow.rst).
- Fixed testpmd flow command's bit-field handler that filled values in the wrong order on big-endian systems. This change also makes arg_entry_bf_fill() support endian conversion at no additional cost (cmdline_flow.c).
- Removed extra period from testpmd documentation example (testpmd_funcs.rst).
- Extra commit to handle additional protocol item fields (for VLAN, IPv4, IPv6 and SCTP) requested by several people (cmdline_flow.c).
Changes since v3 series:
- Fixed documentation tables that broke PDF generation (John Mcnamara / rte_flow.rst).
- Also properly aligned "Action" lines in several tables with their corresponding "Index" (rte_flow.rst).
- Fixed remaining ICC error #188 in testpmd (Ferruh / cmdline_flow.c).
- Indented testpmd examples properly (John / testpmd_funcs.rst).
- Fixed wrong port in example (Ferruh / testpmd_funcs.rst).
Changes since v2 series:
- Replaced ENOTSUP with ENOSYS in the code (although doing so triggers spurious checkpatch warnings) to tell apart unimplemented callbacks from unsupported flow rules and match the documented behavior.
- Fixed missing include seen by check-includes.sh in rte_flow_driver.h.
- Made clearer that PMDs must initialize rte_flow_error (if non-NULL) in case of error, added related memory poisoning in testpmd to catch missing initializations.
- Fixed rte_flow programmer's guide according to John Mcnamara's comments (tables, sections header and typos).
- Fixed deprecation notice as well.
Changes since v1 series:
- Added programmer's guide documentation for rte_flow.
- Added depreciation notice for the legacy API.
- Documented testpmd flow command.
- Fixed missing rte_flow_flush symbol in rte_ether_version.map.
- Cleaned up API documentation in rte_flow.h.
- Replaced "min/max" parameters with "num" in struct rte_flow_item_any, to align behavior with other item definitions.
- Fixed "type" (EtherType) size in struct rte_flow_item_eth.
- Renamed "queues" to "num" in struct rte_flow_action_rss.
- Fixed missing const in rte_flow_error_set() prototype definition.
- Fixed testpmd flow create command that did not save the rte_flow object pointer, causing crashes.
- Hopefully fixed all the remaining ICC/clang errors.
- Replaced testpmd flow command's "fix" token with "is" for clarity.
Changes since RFC v2:
- New separate VLAN pattern item (previously part of the ETH definition), found to be much more convenient.
- Removed useless "any" field from VF pattern item, the same effect can be achieved by not providing a specification structure.
- Replaced bit-fields from the VXLAN pattern item to avoid endianness conversion issues on 24-bit fields.
- Updated struct rte_flow_item with a new "last" field to create inclusive ranges. They are defined as the interval between (spec & mask) and (last & mask). All three parameters are optional.
- Renamed ID action MARK.
- Renamed "queue" fields in actions QUEUE and DUP to "index".
- "rss_conf" field in RSS action is now const.
- VF action now uses a 32 bit ID like its pattern item counterpart.
- Removed redundant struct rte_flow_pattern, API functions now expect struct
rte_flow_item lists terminated by END items.
- Replaced struct rte_flow_actions for the same reason, with struct rte_flow_action lists terminated by END actions.
- Error types (enum rte_flow_error_type) have been updated and the cause pointer in struct rte_flow_error is now const.
- Function prototypes (rte_flow_create, rte_flow_validate) have also been updated for clarity.
Additions:
- Public wrapper functions rte_flow_{validate|create|destroy|flush|query} are now implemented in rte_flow.c, with their symbols exported and versioned. Related filter type RTE_ETH_FILTER_GENERIC has been added.
- A separate header (rte_flow_driver.h) has been added for driver-side functionality, in particular struct rte_flow_ops which contains PMD callbacks returned by RTE_ETH_FILTER_GENERIC query.
- testpmd now exposes most of this API through the new "flow" command.
What remains to be done:
- Using endian-aware integer types (rte_beX_t) where necessary for clarity.
- API documentation (based on RFC).
- testpmd flow command documentation (although context-aware command completion should already help quite a bit in this regard).
- A few pattern item / action properties cannot be configured yet (e.g. rss_conf parameter for RSS action) and a few completions (e.g. possible queue IDs) should be added.
Adrien Mazarguil (26):
ethdev: introduce generic flow API
doc: add rte_flow prog guide
doc: announce deprecation of legacy filter types
cmdline: add support for dynamic tokens
cmdline: add alignment constraint app/testpmd: implement basic support for rte_flow app/testpmd: add flow command app/testpmd: add rte_flow integer support app/testpmd: add flow list command app/testpmd: add flow flush command app/testpmd: add flow destroy command app/testpmd: add flow validate/create commands app/testpmd: add flow query command app/testpmd: add rte_flow item spec handler app/testpmd: add rte_flow item spec prefix length app/testpmd: add rte_flow bit-field support app/testpmd: add item any to flow command app/testpmd: add various items to flow command app/testpmd: add item raw to flow command app/testpmd: add items eth/vlan to flow command app/testpmd: add items ipv4/ipv6 to flow command app/testpmd: add L4 items to flow command app/testpmd: add various actions to flow command app/testpmd: add queue actions to flow command
doc: describe testpmd flow command app/testpmd: add protocol fields to flow command
MAINTAINERS | 4 + app/test-pmd/Makefile | 1 + app/test-pmd/cmdline.c | 32 + app/test-pmd/cmdline_flow.c | 2713 ++++++++++++++++++++++ app/test-pmd/config.c | 498 ++++ app/test-pmd/csumonly.c | 1 + app/test-pmd/flowgen.c | 1 + app/test-pmd/icmpecho.c | 1 + app/test-pmd/ieee1588fwd.c | 1 + app/test-pmd/iofwd.c | 1 + app/test-pmd/macfwd.c | 1 + app/test-pmd/macswap.c | 1 + app/test-pmd/parameters.c | 1 + app/test-pmd/rxonly.c | 1 + app/test-pmd/testpmd.c | 6 + app/test-pmd/testpmd.h | 27 + app/test-pmd/txonly.c | 1 + doc/api/doxy-api-index.md | 2 + doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/rte_flow.rst | 2041 ++++++++++++++++ doc/guides/rel_notes/deprecation.rst | 8 + doc/guides/testpmd_app_ug/testpmd_funcs.rst | 624 +++++ lib/librte_cmdline/cmdline_parse.c | 67 +- lib/librte_cmdline/cmdline_parse.h | 21 + lib/librte_ether/Makefile | 3 + lib/librte_ether/rte_eth_ctrl.h | 1 + lib/librte_ether/rte_ether_version.map | 11 + lib/librte_ether/rte_flow.c | 159 ++ lib/librte_ether/rte_flow.h | 947 ++++++++ lib/librte_ether/rte_flow_driver.h | 182 ++ 30 files changed, 7349 insertions(+), 9 deletions(-) create mode 100644 app/test-pmd/cmdline_flow.c create mode 100644 doc/guides/prog_guide/rte_flow.rst create mode 100644 lib/librte_ether/rte_flow.c create mode 100644 lib/librte_ether/rte_flow.h create mode 100644 lib/librte_ether/rte_flow_driver.h
Signature · 1 line
2.1.4
PATCH v5 1/26 ethdev: introduce generic flow API
This new API supersedes all the legacy filter types described in rte_eth_ctrl.h. It is slightly higher level and as a result relies more on PMDs to process and validate flow rules.
Benefits:
- A unified API is easier to program for, applications do not have to be written for a specific filter type which may or may not be supported by the underlying device.
- The behavior of a flow rule is the same regardless of the underlying device, applications do not need to be aware of hardware quirks.
- Extensible by design, API/ABI breakage should rarely occur if at all.
- Documentation is self-standing, no need to look up elsewhere.
Existing filter types will be deprecated and removed in the near future.
--- MAINTAINERS | 4 + doc/api/doxy-api-index.md | 2 + lib/librte_ether/Makefile | 3 + lib/librte_ether/rte_eth_ctrl.h | 1 + lib/librte_ether/rte_ether_version.map | 11 + lib/librte_ether/rte_flow.c | 159 +++++ lib/librte_ether/rte_flow.h | 947 ++++++++++++++++++++++++++++ lib/librte_ether/rte_flow_driver.h | 182 ++++++ 8 files changed, 1309 insertions(+)
MAINTAINERS +4 -0
@@ -243,6 +243,10 @@ M: Thomas Monjalon <[email protected]> F: lib/librte_ether/ F: scripts/test-null.sh +Generic flow API +M: Adrien Mazarguil <[email protected]> +F: lib/librte_ether/rte_flow* + Crypto API M: Declan Doherty <[email protected]> F: lib/librte_cryptodev/
doc/api/doxy-api-index.md +2 -0
@@ -39,6 +39,8 @@ There are many libraries, so their headers may be grouped by topics: [dev] (@ref rte_dev.h), [ethdev] (@ref rte_ethdev.h), [ethctrl] (@ref rte_eth_ctrl.h), + [rte_flow] (@ref rte_flow.h), + [rte_flow_driver] (@ref rte_flow_driver.h), [cryptodev] (@ref rte_cryptodev.h), [devargs] (@ref rte_devargs.h), [bond] (@ref rte_eth_bond.h),
lib/librte_ether/Makefile +3 -0
@@ -44,6 +44,7 @@ EXPORT_MAP := rte_ether_version.map LIBABIVER := 5 SRCS-y += rte_ethdev.c +SRCS-y += rte_flow.c # # Export include files
@@ -51,6 +52,8 @@ SRCS-y += rte_ethdev.c SYMLINK-y-include += rte_ethdev.h SYMLINK-y-include += rte_eth_ctrl.h SYMLINK-y-include += rte_dev_info.h +SYMLINK-y-include += rte_flow.h +SYMLINK-y-include += rte_flow_driver.h # this lib depends upon: DEPDIRS-y += lib/librte_net lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
lib/librte_ether/rte_eth_ctrl.h +1 -0
@@ -99,6 +99,7 @@ enum rte_filter_type {RTE_ETH_FILTER_FDIR ,RTE_ETH_FILTER_HASH ,RTE_ETH_FILTER_L2_TUNNEL , +RTE_ETH_FILTER_GENERIC , RTE_ETH_FILTER_MAX };
lib/librte_ether/rte_ether_version.map +11 -0
@@ -147,3 +147,14 @@ DPDK_16.11 { rte_eth_dev_pci_remove; } DPDK_16.07; + +DPDK_17.02 { + global: + + rte_flow_validate; + rte_flow_create; + rte_flow_destroy; + rte_flow_flush; + rte_flow_query; + +} DPDK_16.11;
lib/librte_ether/rte_flow.c new file +159 -0
159 lines not on this page · raw message
lib/librte_ether/rte_flow.h new file +947 -0
947 lines not on this page · raw message
lib/librte_ether/rte_flow_driver.h new file +182 -0
182 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v5 2/26 doc: add rte_flow prog guide
In reply to Adrien MazarguilThis documentation is based on the latest RFC submission, subsequently updated according to feedback from the community.
--- doc/guides/prog_guide/index.rst | 1 + doc/guides/prog_guide/rte_flow.rst | 2041 +++++++++++++++++++++++++++++++ 2 files changed, 2042 insertions(+)
doc/guides/prog_guide/index.rst +1 -0
@@ -42,6 +42,7 @@ Programmer's Guide mempool_lib mbuf_lib poll_mode_drv + rte_flow cryptodev_lib link_bonding_poll_mode_drv_lib timer_lib
doc/guides/prog_guide/rte_flow.rst new file +2041 -0
2,041 lines not on this page · raw message
Signature · 1 line
2.1.4
Re: [PATCH v5 02/26] doc: add rte_flow prog guide
Quoted 8 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Adrien Mazarguil
Sent: Wednesday, December 21, 2016 2:51 PM
To: [email protected]
Subject: [dpdk-dev] [PATCH v5 02/26] doc: addrte_flowprog guide
Quoted 5 lines
This documentation is based on the latest RFC submission, subsequently updated according to feedback from the community.
Signed-off-by Adrien Mazarguil <[email protected]>Acked-by Olga Shern <[email protected]>
PATCH v5 3/26 doc: announce deprecation of legacy filter types
In reply to Adrien MazarguilThey are superseded by the generic flow API (rte_flow). Target release is not defined yet.
--- doc/guides/rel_notes/deprecation.rst | 8 ++++++++ 1 file changed, 8 insertions(+)
doc/guides/rel_notes/deprecation.rst +8 -0
@@ -71,3 +71,11 @@ Deprecation Notices * mempool: The functions for single/multi producer/consumer are deprecated and will be removed in 17.02. It is replaced by ``rte_mempool_generic_get/put`` functions. + +* ethdev: the legacy filter API, including + ``rte_eth_dev_filter_supported()``, ``rte_eth_dev_filter_ctrl()`` as well + as filter types MACVLAN, ETHERTYPE, FLEXIBLE, SYN, NTUPLE, TUNNEL, FDIR, + HASH and L2_TUNNEL, is superseded by the generic flow API (rte_flow) in + PMDs that implement the latter. + Target release for removal of the legacy API will be defined once most + PMDs have switched to rte_flow.
Signature · 1 line
2.1.4
PATCH v5 4/26 cmdline: add support for dynamic tokens
In reply to Adrien MazarguilConsidering tokens must be hard-coded in a list part of the instruction structure, context-dependent tokens cannot be expressed.
This commit adds support for building dynamic token lists through a user-provided function, which is called when the static token list is empty (a single NULL entry).
Because no structures are modified (existing fields are reused), this commit has no impact on the current ABI.
--- lib/librte_cmdline/cmdline_parse.c | 60 +++++++++++++++++++++++++++++---- lib/librte_cmdline/cmdline_parse.h | 21 ++++++++++++ 2 files changed, 74 insertions(+), 7 deletions(-)
lib/librte_cmdline/cmdline_parse.c +53 -7
@@ -146,7 +146,9 @@ nb_common_chars(const char * s1, const char * s2)*/ static int match_inst (cmdline_parse_inst_t *inst,const char *buf, -unsigned int nb_match_token,void *resbuf,unsigned resbuf_size) +unsigned int nb_match_token,void *resbuf,unsigned resbuf_size, +cmdline_parse_token_hdr_t + *(*dyn_tokens)[CMDLINE_PARSE_DYNAMIC_TOKENS ]) {unsigned int token_num=0 ;cmdline_parse_token_hdr_t * token_p;
@@ -155,6 +157,11 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf,struct cmdline_token_hdr token_hdr; token_p = inst->tokens[token_num]; +if (!token_p && dyn_tokens && inst->f) { +if (!(*dyn_tokens)[0 ]) + inst->f (&(*dyn_tokens)[0 ],NULL , dyn_tokens); + token_p = (*dyn_tokens)[0 ]; + }if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
@@ -196,7 +203,17 @@ match_inst(cmdline_parse_inst_t *inst, const char *buf, buf += n; token_num ++; - token_p = inst->tokens[token_num]; +if (!inst->tokens[0 ]) { +if (token_num < (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!(*dyn_tokens)[token_num]) + inst->f (&(*dyn_tokens)[token_num], +NULL , + dyn_tokens); + token_p = (*dyn_tokens)[token_num]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[token_num];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr)); }
@@ -239,6 +256,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)cmdline_parse_inst_t *inst;const char *curbuf;char result_buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];void (*f)(void *,struct cmdline *,void *) =NULL ;void *data =NULL ;int comment =0 ;
@@ -255,6 +273,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)return CMDLINE_PARSE_BAD_ARGS ; ctx = cl->ctx; +memset (&dyn_tokens,0 ,sizeof (dyn_tokens));/* * - look if the buffer contains at least one line
@@ -299,7 +318,8 @@ cmdline_parse(struct cmdline *cl, const char * buf)debug_printf ("INST %d\n" , inst_num);/* fully parsed */ - tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf)); + tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf), + &dyn_tokens);if (tok >0 )/* we matched at least one token */ err =CMDLINE_PARSE_BAD_ARGS ;
@@ -355,6 +375,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,cmdline_parse_token_hdr_t *token_p;struct cmdline_token_hdr token_hdr;char tmpbuf[CMDLINE_BUFFER_SIZE ], comp_buf[CMDLINE_BUFFER_SIZE ]; +cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];unsigned int partial_tok_len;int comp_len =-1 ;int tmp_len =-1 ;
@@ -374,6 +395,7 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,debug_printf ("%s called\n" , __func__);memset (&token_hdr,0 ,sizeof (token_hdr)); +memset (&dyn_tokens,0 ,sizeof (dyn_tokens));/* count the number of complete token to parse */ for (i=0 ; buf[i] ; i++) {
@@ -396,11 +418,24 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state, inst = ctx[inst_num];while (inst) {/* parse the first tokens of the inst */ -if (nb_token &&match_inst (inst, buf, nb_token,NULL ,0 )) +if (nb_token && +match_inst (inst, buf, nb_token,NULL ,0 , + &dyn_tokens)) goto next;debug_printf ("instruction match\n" ); - token_p = inst->tokens[nb_token]; +if (!inst->tokens[0 ]) { +if (nb_token < + (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!dyn_tokens[nb_token]) + inst->f (&dyn_tokens[nb_token], +NULL , + &dyn_tokens); + token_p = dyn_tokens[nb_token]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[nb_token];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
@@ -490,10 +525,21 @@ cmdline_complete(struct cmdline *cl, const char *buf, int *state,/* we need to redo it */ inst = ctx[inst_num]; -if (nb_token &&match_inst (inst, buf, nb_token,NULL ,0 )) +if (nb_token && +match_inst (inst, buf, nb_token,NULL ,0 , &dyn_tokens)) goto next2; - token_p = inst->tokens[nb_token]; +if (!inst->tokens[0 ]) { +if (nb_token < (CMDLINE_PARSE_DYNAMIC_TOKENS -1 )) { +if (!dyn_tokens[nb_token]) + inst->f (&dyn_tokens[nb_token], +NULL , + &dyn_tokens); + token_p = dyn_tokens[nb_token]; + }else + token_p =NULL ; + }else + token_p = inst->tokens[nb_token];if (token_p)memcpy (&token_hdr, token_p,sizeof (token_hdr));
lib/librte_cmdline/cmdline_parse.h +21 -0
@@ -83,6 +83,9 @@ extern "C" {/* maximum buffer size for parsed result */ #define CMDLINE_PARSE_RESULT_BUFSIZE 8192 +/* maximum number of dynamic tokens */ +#define CMDLINE_PARSE_DYNAMIC_TOKENS 128 +/** * Stores a pointer to the ops struct, and the offset: the place to * write the parsed result in the destination structure.
@@ -130,6 +133,24 @@ struct cmdline;* Store a instruction, which is a pointer to a callback function and * its parameter that is called when the instruction is parsed, a help * string, and a list of token composing this instruction. +* +* When no tokens are defined (tokens[0] == NULL), they are retrieved +* dynamically by calling f() as follows: +* +* f((struct cmdline_token_hdr **)&token_hdr, +* NULL, +* (struct cmdline_token_hdr *[])tokens)); +* +* The address of the resulting token is expected at the location pointed by +* the first argument. Can be set to NULL to end the list. +* +* The cmdline argument (struct cmdline *) is always NULL. +* +* The last argument points to the NULL-terminated list of dynamic tokens +* defined so far. Since token_hdr points to an index of that list, the +* current index can be derived as follows: +* +* int index = token_hdr - &(*tokens)[0]; */ struct cmdline_inst {/* f(parsed_struct, data) */
Signature · 1 line
2.1.4
PATCH v5 5/26 cmdline: add alignment constraint
In reply to Adrien MazarguilThis prevents sigbus errors on architectures that cannot handle unexpected unaligned accesses to the output buffer.
--- lib/librte_cmdline/cmdline_parse.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
lib/librte_cmdline/cmdline_parse.c +6 -3
@@ -255,7 +255,10 @@ cmdline_parse(struct cmdline *cl, const char * buf)unsigned int inst_num=0 ;cmdline_parse_inst_t *inst;const char *curbuf; -char result_buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +union { +char buf[CMDLINE_PARSE_RESULT_BUFSIZE ]; +long double align;/* strong alignment constraint for buf */ + } result;cmdline_parse_token_hdr_t *dyn_tokens[CMDLINE_PARSE_DYNAMIC_TOKENS ];void (*f)(void *,struct cmdline *,void *) =NULL ;void *data =NULL ;
@@ -318,7 +321,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)debug_printf ("INST %d\n" , inst_num);/* fully parsed */ - tok =match_inst (inst, buf,0 , result_buf,sizeof (result_buf), + tok =match_inst (inst, buf,0 , result.buf,sizeof (result.buf), &dyn_tokens);if (tok >0 )/* we matched at least one token */
@@ -353,7 +356,7 @@ cmdline_parse(struct cmdline *cl, const char * buf)/* call func */ if (f) { -f (result_buf, cl, data); +f (result.buf, cl, data); }/* no match */
Signature · 1 line
2.1.4
PATCH v5 6/26 app/testpmd: implement basic support for rte_flow
In reply to Adrien MazarguilAdd basic management functions for the generic flow API (validate, create, destroy, flush, query and list). Flow rule objects and properties are arranged in lists associated with each port.
--- app/test-pmd/cmdline.c | 1 + app/test-pmd/config.c | 498 ++++++++++++++++++++++++++++++++++++++++ app/test-pmd/csumonly.c | 1 + app/test-pmd/flowgen.c | 1 + app/test-pmd/icmpecho.c | 1 + app/test-pmd/ieee1588fwd.c | 1 + app/test-pmd/iofwd.c | 1 + app/test-pmd/macfwd.c | 1 + app/test-pmd/macswap.c | 1 + app/test-pmd/parameters.c | 1 + app/test-pmd/rxonly.c | 1 + app/test-pmd/testpmd.c | 6 + app/test-pmd/testpmd.h | 27 +++ app/test-pmd/txonly.c | 1 + 14 files changed, 542 insertions(+)
app/test-pmd/cmdline.c +1 -0
@@ -75,6 +75,7 @@#include <rte_string_fns.h> #include <rte_devargs.h> #include <rte_eth_ctrl.h> +#include <rte_flow.h> #include <cmdline_rdline.h> #include <cmdline_parse.h>
app/test-pmd/config.c +498 -0
510 lines not on this page · raw message
app/test-pmd/csumonly.c +1 -0
@@ -70,6 +70,7 @@#include <rte_sctp.h> #include <rte_prefetch.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h" #define IP_DEFTTL 64/* from RFC 1340. */
app/test-pmd/flowgen.c +1 -0
@@ -68,6 +68,7 @@#include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/icmpecho.c +1 -0
@@ -61,6 +61,7 @@#include <rte_ip.h> #include <rte_icmp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/ieee1588fwd.c +1 -0
@@ -34,6 +34,7 @@#include <rte_cycles.h> #include <rte_ethdev.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/iofwd.c +1 -0
@@ -64,6 +64,7 @@#include <rte_ether.h> #include <rte_ethdev.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/macfwd.c +1 -0
@@ -65,6 +65,7 @@#include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/macswap.c +1 -0
@@ -65,6 +65,7 @@#include <rte_ethdev.h> #include <rte_ip.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/parameters.c +1 -0
@@ -76,6 +76,7 @@#ifdef RTE_LIBRTE_PMD_BOND #include <rte_eth_bond.h> #endif +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/rxonly.c +1 -0
@@ -67,6 +67,7 @@#include <rte_ip.h> #include <rte_udp.h> #include <rte_net.h> +#include <rte_flow.h> #include "testpmd.h"
app/test-pmd/testpmd.c +6 -0
@@ -78,6 +78,7 @@#ifdef RTE_LIBRTE_PDUMP #include <rte_pdump.h> #endif +#include <rte_flow.h> #include "testpmd.h"
@@ -1545,6 +1546,8 @@ close_port(portid_t pid)continue ; } +if (port->flow_list) +port_flow_flush (pi);rte_eth_dev_close (pi); if (rte_atomic16_cmpset(&(port->port_status),
@@ -1599,6 +1602,9 @@ detach_port(uint8_t port_id)return ; } +if (ports[port_id].flow_list) +port_flow_flush (port_id); +if (rte_eth_dev_detach (port_id, name))return ;
app/test-pmd/testpmd.h +27 -0
@@ -144,6 +144,19 @@ struct fwd_stream {/** Insert double VLAN header in forward engine */ #define TESTPMD_TX_OFFLOAD_INSERT_QINQ 0x0080 +/** Descriptor for a single flow. */ +struct port_flow { +size_t size;/**< Allocated space including data[]. */ +struct port_flow *next;/**< Next flow in list. */ +struct port_flow *tmp;/**< Temporary linking. */ +uint32_t id;/**< Flow rule ID. */ +struct rte_flow *flow;/**< Opaque flow object returned by PMD. */ +struct rte_flow_attr attr;/**< Attributes. */ +struct rte_flow_item *pattern;/**< Pattern. */ +struct rte_flow_action *actions;/**< Actions. */ +uint8_t data[];/**< Storage for pattern/actions. */ +}; +/** * The data structure associated with each port. */
@@ -177,6 +190,7 @@ struct rte_port {struct ether_addr *mc_addr_pool;/**< pool of multicast addrs */ uint32_t mc_addr_nb;/**< nb. of addr. in mc_addr_pool */ uint8_t slave_flag;/**< bonding slave port */ +struct port_flow *flow_list;/**< Associated flows. */ };extern portid_t __rte_unused
@@ -504,6 +518,19 @@ void port_reg_bit_field_set(portid_t port_id, uint32_t reg_off, uint8_t bit1_pos, uint8_t bit2_pos, uint32_t value);void port_reg_display (portid_t port_id,uint32_t reg_off);void port_reg_set (portid_t port_id,uint32_t reg_off,uint32_t value); +int port_flow_validate (portid_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item *pattern, +const struct rte_flow_action *actions); +int port_flow_create (portid_t port_id, +const struct rte_flow_attr *attr, +const struct rte_flow_item *pattern, +const struct rte_flow_action *actions); +int port_flow_destroy (portid_t port_id,uint32_t n,const uint32_t *rule); +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);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);
app/test-pmd/txonly.c +1 -0
@@ -68,6 +68,7 @@#include <rte_tcp.h> #include <rte_udp.h> #include <rte_string_fns.h> +#include <rte_flow.h> #include "testpmd.h"
Signature · 1 line
2.1.4
PATCH v5 7/26 app/testpmd: add flow command
In reply to Adrien MazarguilManaging generic flow API functions from command line requires the use of dynamic tokens for convenience as flow rules are not fixed and cannot be defined statically.
This commit adds specific flexible parser code and object for a new "flow" command in separate file.
--- app/test-pmd/Makefile | 1 + app/test-pmd/cmdline.c | 4 + app/test-pmd/cmdline_flow.c | 439 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 444 insertions(+)
app/test-pmd/Makefile +1 -0
@@ -47,6 +47,7 @@ CFLAGS += $(WERROR_FLAGS) SRCS-y := testpmd.c SRCS-y += parameters.c SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c +SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c SRCS-y += config.c SRCS-y += iofwd.c SRCS-y += macfwd.c
app/test-pmd/cmdline.c +4 -0
@@ -9567,6 +9567,9 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = { }, }; +/* Generic flow interface command. */ +extern cmdline_parse_inst_t cmd_flow; +/* *** Classification Filters Control *** */ /* *** Get symmetric hash enable per port *** */ struct cmd_get_sym_hash_ena_per_port_result {
@@ -11605,6 +11608,7 @@ cmdline_parse_ctx_t main_ctx[] = { (cmdline_parse_inst_t *)&cmd_set_hash_global_config, (cmdline_parse_inst_t *)&cmd_set_hash_input_set, (cmdline_parse_inst_t *)&cmd_set_fdir_input_set, + (cmdline_parse_inst_t *)&cmd_flow, (cmdline_parse_inst_t *)&cmd_mcast_addr, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all, (cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
app/test-pmd/cmdline_flow.c new file +439 -0
439 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v5 8/26 app/testpmd: add rte_flow integer support
In reply to Adrien MazarguilParse all integer types and handle conversion to network byte order in a single function.
--- app/test-pmd/cmdline_flow.c | 148 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+)
app/test-pmd/cmdline_flow.c +148 -0
@@ -34,11 +34,14 @@#include <stddef.h> #include <stdint.h> #include <stdio.h> +#include <inttypes.h> +#include <errno.h> #include <ctype.h> #include <string.h> #include <rte_common.h> #include <rte_ethdev.h> +#include <rte_byteorder.h> #include <cmdline_parse.h> #include <rte_flow.h>
@@ -50,6 +53,10 @@ enum index {ZERO =0 ,END , +/* Common tokens. */ +INTEGER , +UNSIGNED , +/* Top-level command. */ FLOW, };
@@ -61,12 +68,24 @@ enum index {struct context {/** Stack of subsequent token lists to process. */ const enum index *next[CTX_STACK_SIZE ]; +/** Arguments for stacked tokens. */ +const void *args[CTX_STACK_SIZE ];enum index curr;/**< Current token index. */ 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. */ +void *object;/**< Address of current object for relative offsets. */ +}; + +/** Token argument. */ +struct arg { +uint32_t hton:1 ;/**< Use network byte ordering. */ +uint32_t sign:1 ;/**< Value is signed. */ +uint32_t offset;/**< Relative offset from ctx->object. */ +uint32_t size;/**< Field size. */ };/** Parser token definition. */
@@ -80,6 +99,8 @@ struct token {* parser consumes the last entry of that stack. */ const enum index *const *next; +/** Arguments stack for subsequent tokens that need them. */ +const struct arg *const *args;/** * Token-processing callback, returns -1 in case of error, the * length of the matched string otherwise. If NULL, attempts to
@@ -112,6 +133,22 @@ struct token {/** Static initializer for a NEXT() entry. */ #define NEXT_ENTRY (...) (const enum index []){ __VA_ARGS__, ZERO, } +/** Static initializer for the args field. */ +#define ARGS (...) (const struct arg *const []){ __VA_ARGS__, NULL, } + +/** Static initializer for ARGS() to target a field. */ +#define ARGS_ENTRY (s, f) \ + (&(const struct arg){ \ + .offset = offsetof(s, f), \ + .size = sizeof(((s *)0)->f), \ + }) + +/** Static initializer for ARGS() to target a pointer. */ +#define ARGS_ENTRY_PTR (s, f) \ + (&(const struct arg){ \ + .size = sizeof(*((s *)0)->f), \ + }) +/** Parser output buffer layout expected by cmd_flow_parsed(). */ struct buffer {enum index command;/**< Flow command. */
@@ -121,6 +158,11 @@ struct buffer {static int parse_init (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 ); +static int comp_none (struct context *,const struct token *, +unsigned int ,char *,unsigned int );/** Token definitions. */ static const struct token token_list[] = {
@@ -135,6 +177,21 @@ static const struct token token_list[] = { .type = "RETURN", .help = "command may end here", }, +/* Common tokens. */ + [INTEGER] = { + .name = "{int}", + .type = "INTEGER", + .help = "integer value", + .call = parse_int, + .comp = comp_none, + }, + [UNSIGNED] = { + .name = "{unsigned}", + .type = "UNSIGNED", + .help = "unsigned integer value", + .call = parse_int, + .comp = comp_none, + },/* Top-level command. */ [FLOW] = { .name = "flow",
@@ -144,6 +201,23 @@ static const struct token token_list[] = { }, }; +/** 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 ; +} +/** Default parsing function for token name matching. */ static int parse_default(struct context *ctx, const struct token *token,
@@ -178,9 +252,74 @@ parse_init(struct context *ctx, const struct token *token,/* Initialize buffer. */ memset (out,0x00 ,sizeof (*out));memset ((uint8_t *)out +sizeof (*out),0x22 , size -sizeof (*out)); + ctx->object = out;return len; } +/** +* Parse signed/unsigned integers 8 to 64-bit long. +* +* Last argument (ctx->args) is retrieved to determine integer type and +* storage location. +*/ +static int +parse_int (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); +uintmax_t u; +char *end; + + (void )token; +/* Argument is expected. */ +if (!arg) +return -1 ; + errno =0 ; + u = arg->sign ? + (uintmax_t )strtoimax (str, &end,0 ) : +strtoumax (str, &end,0 ); +if (errno || (size_t )(end - str) != len) + goto error; +if (!ctx->object) +return len; + buf = (uint8_t *)ctx->object + arg->offset; + size = arg->size; +switch (size) { +case sizeof (uint8_t ): + *(uint8_t *)buf = u; +break ; +case sizeof (uint16_t ): + *(uint16_t *)buf = arg->hton ?rte_cpu_to_be_16 (u) : u; +break ; +case sizeof (uint32_t ): + *(uint32_t *)buf = arg->hton ?rte_cpu_to_be_32 (u) : u; +break ; +case sizeof (uint64_t ): + *(uint64_t *)buf = arg->hton ?rte_cpu_to_be_64 (u) : u; +break ; +default : + goto error; + } +return len; +error: +push_args (ctx, arg); +return -1 ; +} + +/** No completion. */ +static int +comp_none (struct context *ctx,const struct token *token, +unsigned int ent,char *buf,unsigned int size) +{ + (void )ctx; + (void )token; + (void )ent; + (void )buf; + (void )size; +return 0 ; +} +/** Internal context. */ static struct context cmd_flow_context;
@@ -195,9 +334,11 @@ cmd_flow_context_init(struct context *ctx) ctx->curr =ZERO ; ctx->prev =ZERO ; ctx->next_num =0 ; + ctx->args_num =0 ; ctx->reparse =0 ; ctx->eol =0 ; ctx->last =0 ; + ctx->object =NULL ; }/** Parse a token (cmdline API). */
@@ -270,6 +411,13 @@ cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,return -1 ; ctx->next[ctx->next_num++] = token->next[i]; } +/* Push arguments if any. */ +if (token->args) +for (i =0 ; token->args[i]; ++i) { +if (ctx->args_num ==RTE_DIM (ctx->args)) +return -1 ; + ctx->args[ctx->args_num++] = token->args[i]; + }return len; }
Signature · 1 line
2.1.4
PATCH v5 9/26 app/testpmd: add flow list command
In reply to Adrien MazarguilSyntax:
flow list {port_id} [group {group_id}] [...]
List configured flow rules on a port. Output can optionally be limited to a given set of group identifiers.
--- app/test-pmd/cmdline.c | 4 ++ app/test-pmd/cmdline_flow.c | 141 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+)
app/test-pmd/cmdline.c +4 -0
@@ -810,6 +810,10 @@ static void cmd_help_long_parsed(void *parsed_result,"sctp-src-port|sctp-dst-port|sctp-veri-tag|none)" " (select|add)\n" " Set the input set for FDir.\n\n" + +"flow list {port_id} [group {group_id}] [...]\n" +" List existing flow rules sorted by priority," +" filtered by group identifiers.\n\n" ); } }
app/test-pmd/cmdline_flow.c +141 -0
215 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v5 10/26 app/testpmd: add flow flush command
In reply to Adrien MazarguilSyntax:
flow flush {port_id}
Destroy all flow rules on a port.
--- app/test-pmd/cmdline.c | 3 +++ app/test-pmd/cmdline_flow.c | 43 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow flush {port_id}\n" +" Destroy all flow rules.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," " filtered by group identifiers.\n\n"
app/test-pmd/cmdline_flow.c +42 -1
76 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v5 11/26 app/testpmd: add flow destroy command
In reply to Adrien MazarguilSyntax:
flow destroy {port_id} rule {rule_id} [...]
Destroy a given set of flow rules associated with a port.
--- app/test-pmd/cmdline.c | 3 ++ app/test-pmd/cmdline_flow.c | 106 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -811,6 +811,9 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow destroy {port_id} rule {rule_id} [...]\n" +" Destroy specific flow rules.\n\n" +"flow flush {port_id}\n" " Destroy all flow rules.\n\n"
app/test-pmd/cmdline_flow.c +105 -1
185 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v5 12/26 app/testpmd: add flow validate/create commands
In reply to Adrien MazarguilSyntax:
flow (validate|create) {port_id}
[group {group_id}] [priority {level}] [ingress] [egress]
pattern {item} [/ {item} [...]] / end
actions {action} [/ {action} [...]] / endEither check the validity of a flow rule or create it. Any number of pattern items and actions can be provided in any order. Completion is available for convenience.
This commit only adds support for the most basic item and action types, namely:
- END: terminates pattern items and actions lists.
- VOID: item/action filler, no operation.
- INVERT: inverted pattern matching, process packets that do not match.
- PASSTHRU: action that leaves packets up for additional processing by subsequent flow rules.
--- app/test-pmd/cmdline.c | 14 ++ app/test-pmd/cmdline_flow.c | 314 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 327 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +14 -0
@@ -811,6 +811,20 @@ static void cmd_help_long_parsed(void *parsed_result," (select|add)\n" " Set the input set for FDir.\n\n" +"flow validate {port_id}" +" [group {group_id}] [priority {level}]" +" [ingress] [egress]" +" pattern {item} [/ {item} [...]] / end" +" actions {action} [/ {action} [...]] / end\n" +" Check whether a flow rule can be created.\n\n" + +"flow create {port_id}" +" [group {group_id}] [priority {level}]" +" [ingress] [egress]" +" pattern {item} [/ {item} [...]] / end" +" actions {action} [/ {action} [...]] / end\n" +" Create a flow rule.\n\n" +"flow destroy {port_id} rule {rule_id} [...]\n" " Destroy specific flow rules.\n\n"
app/test-pmd/cmdline_flow.c +313 -1
445 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v5 13/26 app/testpmd: add flow query command
In reply to Adrien MazarguilSyntax:
flow query {port_id} {rule_id} {action}
Query a specific action of an existing flow rule.
--- app/test-pmd/cmdline.c | 3 + app/test-pmd/cmdline_flow.c | 121 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-)
app/test-pmd/cmdline.c +3 -0
@@ -831,6 +831,9 @@ static void cmd_help_long_parsed(void *parsed_result,"flow flush {port_id}\n" " Destroy all flow rules.\n\n" +"flow query {port_id} {rule_id} {action}\n" +" Query an existing flow rule.\n\n" +"flow list {port_id} [group {group_id}] [...]\n" " List existing flow rules sorted by priority," " filtered by group identifiers.\n\n"
app/test-pmd/cmdline_flow.c +120 -1
186 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v5 14/26 app/testpmd: add rte_flow item spec handler
In reply to Adrien MazarguilAdd parser code to fully set individual fields of pattern item specification structures, using the following operators:
- fix: sets field and applies full bit-mask for perfect matching.
- spec: sets field without modifying its bit-mask.
- last: sets upper value of the spec => last range.
- mask: sets bit-mask affecting both spec and last from arbitrary value.
--- app/test-pmd/cmdline_flow.c | 111 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
app/test-pmd/cmdline_flow.c +111 -0
@@ -89,6 +89,10 @@ enum index {/* Validate/create pattern. */ PATTERN , +ITEM_PARAM_IS , +ITEM_PARAM_SPEC , +ITEM_PARAM_LAST , +ITEM_PARAM_MASK ,ITEM_NEXT ,ITEM_END , ITEM_VOID,
@@ -121,6 +125,7 @@ struct context {uint16_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. */ };/** Token argument. */
@@ -267,6 +272,15 @@ static const enum index next_list_attr[] = { ZERO, }; +__rte_unused +static const enum index item_param[] = { +ITEM_PARAM_IS , +ITEM_PARAM_SPEC , +ITEM_PARAM_LAST , +ITEM_PARAM_MASK , +ZERO , +}; +static const enum index next_item[] = {ITEM_END ,ITEM_VOID ,
@@ -287,6 +301,8 @@ static int parse_init(struct context *, const struct token *,static int parse_vc (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int ); +static int parse_vc_spec (struct context *,const struct token *, +const char *,unsigned int ,void *,unsigned int );static int parse_destroy (struct context *,const struct token *,const char *,unsigned int ,void *,unsigned int );
@@ -492,6 +508,26 @@ static const struct token token_list[] = { .next = NEXT(next_item), .call = parse_vc, }, + [ITEM_PARAM_IS] = { + .name = "is", + .help = "match value perfectly (with full bit-mask)", + .call = parse_vc_spec, + }, + [ITEM_PARAM_SPEC] = { + .name = "spec", + .help = "match value according to configured bit-mask", + .call = parse_vc_spec, + }, + [ITEM_PARAM_LAST] = { + .name = "last", + .help = "specify upper bound to establish a range", + .call = parse_vc_spec, + }, + [ITEM_PARAM_MASK] = { + .name = "mask", + .help = "specify bit-mask with relevant bits set to one", + .call = parse_vc_spec, + }, [ITEM_NEXT] = { .name = "/", .help = "specify next pattern item",
@@ -605,6 +641,7 @@ parse_init(struct context *ctx, const struct token *token,memset ((uint8_t *)out +sizeof (*out),0x22 , size -sizeof (*out)); ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ;return len; }
@@ -632,11 +669,13 @@ parse_vc(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.vc.data = (uint8_t *)out + size;return len; } ctx->objdata =0 ; ctx->object = &out->args.vc.attr; + ctx->objmask =NULL ;switch (ctx->curr) {case GROUP :case PRIORITY :
@@ -652,6 +691,7 @@ parse_vc(struct context *ctx, const struct token *token, (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double )); ctx->object = out->args.vc.pattern; + ctx->objmask =NULL ;return len;case ACTIONS : out->args.vc.actions =
@@ -660,6 +700,7 @@ parse_vc(struct context *ctx, const struct token *token, out->args.vc.pattern_n), sizeof(double)); ctx->object = out->args.vc.actions; + ctx->objmask =NULL ;return len;default :if (!token->priv)
@@ -682,6 +723,7 @@ parse_vc(struct context *ctx, const struct token *token, }; ++out->args.vc.pattern_n; ctx->object = item; + ctx->objmask =NULL ; }else {const struct parse_action_priv *priv = token->priv; struct rte_flow_action *action =
@@ -698,6 +740,7 @@ parse_vc(struct context *ctx, const struct token *token, }; ++out->args.vc.actions_n; ctx->object = action; + ctx->objmask =NULL ; }memset (data,0 , data_size); out->args.vc.data = data;
@@ -705,6 +748,60 @@ parse_vc(struct context *ctx, const struct token *token,return len; } +/** Parse pattern item parameter type. */ +static int +parse_vc_spec (struct context *ctx,const struct token *token, +const char *str,unsigned int len, +void *buf,unsigned int size) +{ +struct buffer *out = buf; +struct rte_flow_item *item; +uint32_t data_size; +int index; +int objmask =0 ; + + (void )size; +/* Token name must match. */ +if (parse_default (ctx, token, str, len,NULL ,0 ) <0 ) +return -1 ; +/* Parse parameter types. */ +switch (ctx->curr) { +case ITEM_PARAM_IS : + index =0 ; + objmask =1 ; +break ; +case ITEM_PARAM_SPEC : + index =0 ; +break ; +case ITEM_PARAM_LAST : + index =1 ; +break ; +case ITEM_PARAM_MASK : + index =2 ; +break ; +default : +return -1 ; + } +/* Nothing else to do if there is no buffer. */ +if (!out) +return len; +if (!out->args.vc.pattern_n) +return -1 ; + item = &out->args.vc.pattern[out->args.vc.pattern_n -1 ]; + data_size = ctx->objdata /3 ;/* spec, last, mask */ +/* Point to selected object. */ + ctx->object = out->args.vc.data + (data_size * index); +if (objmask) { + ctx->objmask = out->args.vc.data + (data_size *2 );/* mask */ + item->mask = ctx->objmask; + }else + ctx->objmask =NULL ; +/* Update relevant item pointer. */ + *((const void **[]){ &item->spec, &item->last, &item->mask })[index] = + ctx->object; +return len; +} +/** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token,
@@ -727,6 +824,7 @@ parse_destroy(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.destroy.rule = (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double ));
@@ -737,6 +835,7 @@ parse_destroy(struct context *ctx, const struct token *token,return -1 ; ctx->objdata =0 ; ctx->object = out->args.destroy.rule + out->args.destroy.rule_n++; + ctx->objmask =NULL ;return len; }
@@ -762,6 +861,7 @@ parse_flush(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; }return len; }
@@ -788,6 +888,7 @@ parse_query(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; }return len; }
@@ -849,6 +950,7 @@ parse_list(struct context *ctx, const struct token *token, out->command = ctx->curr; ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; out->args.list.group = (void *)RTE_ALIGN_CEIL ((uintptr_t )(out +1 ),sizeof (double ));
@@ -859,6 +961,7 @@ parse_list(struct context *ctx, const struct token *token,return -1 ; ctx->objdata =0 ; ctx->object = out->args.list.group + out->args.list.group_n++; + ctx->objmask =NULL ;return len; }
@@ -891,6 +994,7 @@ parse_int(struct context *ctx, const struct token *token,return len; buf = (uint8_t *)ctx->object + arg->offset; size = arg->size; +objmask:switch (size) {case sizeof (uint8_t ): *(uint8_t *)buf = u;
@@ -907,6 +1011,11 @@ parse_int(struct context *ctx, const struct token *token,default : goto error; } +if (ctx->objmask && buf != (uint8_t *)ctx->objmask + arg->offset) { + u =-1 ; + buf = (uint8_t *)ctx->objmask + arg->offset; + goto objmask; + }return len; error:push_args (ctx, arg);
@@ -927,6 +1036,7 @@ parse_port(struct context *ctx, const struct token *token,else { ctx->objdata =0 ; ctx->object = out; + ctx->objmask =NULL ; size =sizeof (*out); } ret =parse_int (ctx, token, str, len, out, size);
@@ -1033,6 +1143,7 @@ cmd_flow_context_init(struct context *ctx) ctx->port =0 ; ctx->objdata =0 ; ctx->object =NULL ; + ctx->objmask =NULL ; }/** Parse a token (cmdline API). */
Signature · 1 line
2.1.4