From: Stephen Hemminger <stephen@networkplumber.org>
To: Asaf Penso <asafp@mellanox.com>
Cc: Adrien Mazarguil <adrien.mazarguil@6wind.com>,
"dev@dpdk.org" <dev@dpdk.org>,
Shahaf Shuler <shahafs@mellanox.com>,
Ori Kam <orika@mellanox.com>,
Thomas Monjalon <thomas@monjalon.net>
Subject: Re: [PATCH] ethdev: add function to print a flow
Date: Thu, 6 Dec 2018 13:44:18 -0800 [thread overview]
Message-ID: <20181206134418.475b8d06@xeon-e3> (raw)
In-Reply-To: <1543418758-23748-1-git-send-email-asafp@mellanox.com>
On Wed, 28 Nov 2018 15:26:06 +0000
Asaf Penso <asafp@mellanox.com> wrote:
> Flow contains the following information: port id, attributes,
> patterns and actions.
> The function rte_flow_print prints all above information.
>
> It can be used for debugging purposes to validate the
> behavior of different dpdk applications.
>
> Example: running testpmd with the following flow create:
> flow create 1 transfer ingress
> pattern eth src is 52:54:00:15:b1:b1 dst is 24:8A:07:8D:AE:C6 /
> end
> actions of_push_vlan ethertype 0x8100 /
> of_set_vlan_vid vlan_vid 0x888 /
> of_set_vlan_pcp vlan_pcp 7 /
> port_id id 0 /
> end
> Will result in this output:
> Print flow info
> port_id =1
> group =0
> priority =0
> ingress =1
> egress =0
> transfer =1
> group =0
> reserved =0
> pattern type =9
> name=RTE_FLOW_ITEM_TYPE_ETH
> spec type=0x0, src=52:54:00:15:b1:b1, dst=24:8a:07:8d:ae:c6
> mask type=0x0, src=ff:ff:ff:ff:ff:ff, dst=ff:ff:ff:ff:ff:ff
> actions type =23
> name=RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN
> ethertype=0x81
> actions type =24
> name=RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID
> vlan_vid=0x8808
> actions type =25
> name=RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP
> vlan_pcp=7
> actions type =13
> name=RTE_FLOW_ACTION_TYPE_PORT_ID
> id=0
> reserved=0
>
> Signed-off-by: Asaf Penso <asafp@mellanox.com>
> ---
> lib/librte_ethdev/rte_ethdev_version.map | 1 +
> lib/librte_ethdev/rte_flow.c | 226 ++++++++++++++++++++++++++++++
> lib/librte_ethdev/rte_flow.h | 31 ++++
> 3 files changed, 258 insertions(+), 0 deletions(-)
>
> diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map
> index 92ac3de..7676983 100644
> --- a/lib/librte_ethdev/rte_ethdev_version.map
> +++ b/lib/librte_ethdev/rte_ethdev_version.map
> @@ -249,6 +249,7 @@ EXPERIMENTAL {
> rte_eth_switch_domain_free;
> rte_flow_conv;
> rte_flow_expand_rss;
> + rte_flow_print;
> rte_mtr_capabilities_get;
> rte_mtr_create;
> rte_mtr_destroy;
> diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> index 3277be1..742d892 100644
> --- a/lib/librte_ethdev/rte_flow.c
> +++ b/lib/librte_ethdev/rte_flow.c
> @@ -16,6 +16,8 @@
> #include "rte_flow_driver.h"
> #include "rte_flow.h"
>
> +int rte_flow_logtype;
> +
> /**
> * Flow elements description tables.
> */
> @@ -202,6 +204,222 @@ struct rte_flow_desc_data {
> NULL, rte_strerror(ENOSYS));
> }
>
> +/* Example:
> + *
> + * struct eth_addr mac;
> + * [...]
> + * printf("The Ethernet address is "RTE_ETH_ADDR_FMT"\n",
> + * RTE_ETH_ADDR_ARGS(mac));
> + *
> + */
> +#define RTE_ETH_ADDR_FMT \
> + "%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8":%02"PRIx8
> +#define RTE_ETH_ADDR_ARGS(addr) RTE_ETH_ADDR_BYTES_ARGS((addr).ea)
> +#define RTE_ETH_ADDR_BYTES_ARGS(bytes) \
> + (bytes)[0], (bytes)[1], (bytes)[2], (bytes)[3], (bytes)[4], (bytes)[5]
> +
> +/* Print the flow fields. */
> +void __rte_experimental
> +rte_flow_print(uint16_t port_id,
> + const struct rte_flow_attr *attr,
> + const struct rte_flow_item pattern[],
> + const struct rte_flow_action actions[])
> +{
> + RTE_FLOW_LOG(INFO, "Print flow info\n");
> + RTE_FLOW_LOG(INFO, "port_id =%u\n", port_id);
> + RTE_FLOW_LOG(INFO, "group =%u\n", attr->group);
> + RTE_FLOW_LOG(INFO, "priority =%u\n", attr->priority);
> + RTE_FLOW_LOG(INFO, "ingress =%u\n", attr->ingress);
> + RTE_FLOW_LOG(INFO, "egress =%u\n", attr->egress);
> + RTE_FLOW_LOG(INFO, "transfer =%u\n", attr->transfer);
> + RTE_FLOW_LOG(INFO, "group =%u\n", attr->group);
> + RTE_FLOW_LOG(INFO, "reserved =%u\n", attr->reserved);
> +
> + for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
> + RTE_FLOW_LOG(INFO, "pattern type =%u\n", pattern->type);
> + switch (pattern->type) {
> + case RTE_FLOW_ITEM_TYPE_ETH: {
> + RTE_FLOW_LOG(INFO, " name=RTE_FLOW_ITEM_TYPE_ETH\n");
> + if (pattern->spec) {
> + const struct rte_flow_item_eth *spec =
> + pattern->spec;
> + RTE_FLOW_LOG(INFO, " spec type=0x%x, "
> + "src="RTE_ETH_ADDR_FMT", dst="RTE_ETH_ADDR_FMT
> + "\n",
> + spec->type,
> + RTE_ETH_ADDR_BYTES_ARGS(spec->src.addr_bytes),
> + RTE_ETH_ADDR_BYTES_ARGS(spec->dst.addr_bytes));
> + }
> +
> + if (pattern->mask) {
> + const struct rte_flow_item_eth *mask =
> + pattern->mask;
> + RTE_FLOW_LOG(INFO, " mask type=0x%x, "
> + "src="RTE_ETH_ADDR_FMT", dst="RTE_ETH_ADDR_FMT
> + "\n",
> + mask->type,
> + RTE_ETH_ADDR_BYTES_ARGS(mask->src.addr_bytes),
> + RTE_ETH_ADDR_BYTES_ARGS(mask->dst.addr_bytes));
> + }
> + break;
> + }
> + case RTE_FLOW_ITEM_TYPE_VLAN: {
> + RTE_FLOW_LOG(INFO, " name=RTE_FLOW_ITEM_TYPE_VLAN\n");
> + if (pattern->spec) {
> + const struct rte_flow_item_vlan *spec =
> + pattern->spec;
> + RTE_FLOW_LOG(INFO, " spec tci=0x%x\n",
> + spec->tci);
> + RTE_FLOW_LOG(INFO, " spec inner_type=%u\n",
> + spec->inner_type);
> + }
> + if (pattern->mask) {
> + const struct rte_flow_item_vlan *mask =
> + pattern->mask;
> + RTE_FLOW_LOG(INFO, " mask tci=0x%x\n",
> + mask->tci);
> + RTE_FLOW_LOG(INFO, " mask inner_type=%u\n",
> + mask->inner_type);
> + }
> + break;
> + }
> + case RTE_FLOW_ITEM_TYPE_IPV4: {
> + RTE_FLOW_LOG(INFO, " name=RTE_FLOW_ITEM_TYPE_IPV4\n");
> + if (pattern->spec) {
> + const struct rte_flow_item_ipv4 *spec =
> + pattern->spec;
> + RTE_FLOW_LOG(INFO, " spec version_ihl=%u\n",
> + spec->hdr.version_ihl);
> + RTE_FLOW_LOG(INFO, " spec type_of_service=%u\n",
> + spec->hdr.type_of_service);
> + RTE_FLOW_LOG(INFO, " spec total_length=%u\n",
> + spec->hdr.total_length);
> + RTE_FLOW_LOG(INFO, " spec packet_id=%u\n",
> + spec->hdr.packet_id);
> + RTE_FLOW_LOG(INFO, " spec fragment_offset=%u\n",
> + spec->hdr.fragment_offset);
> + RTE_FLOW_LOG(INFO, " spec time_to_live=%u\n",
> + spec->hdr.time_to_live);
> + RTE_FLOW_LOG(INFO, " spec next_proto_id=%u\n",
> + spec->hdr.next_proto_id);
> + RTE_FLOW_LOG(INFO, " spec hdr_checksum=0x%x\n",
> + spec->hdr.hdr_checksum);
> + RTE_FLOW_LOG(INFO,
> + " spec src_addr=%d.%d.%d.%d\n",
> + (spec->hdr.src_addr & 0x000000FF),
> + (spec->hdr.src_addr & 0x0000FF00) >> 8,
> + (spec->hdr.src_addr & 0x00FF0000) >> 16,
> + (spec->hdr.src_addr & 0xFF000000)
> + >> 24);
> + RTE_FLOW_LOG(INFO,
> + " spec dst_addr=%d.%d.%d.%d\n",
> + (spec->hdr.dst_addr & 0x000000FF),
> + (spec->hdr.dst_addr & 0x0000FF00) >> 8,
> + (spec->hdr.dst_addr & 0x00FF0000) >> 16,
> + (spec->hdr.dst_addr & 0xFF000000)
> + >> 24);
> + }
> +
> + if (pattern->mask) {
> + const struct rte_flow_item_ipv4 *mask =
> + pattern->mask;
> + RTE_FLOW_LOG(INFO, " mask version_ihl=%u\n",
> + mask->hdr.version_ihl);
> + RTE_FLOW_LOG(INFO, " mask type_of_service=%u\n",
> + mask->hdr.type_of_service);
> + RTE_FLOW_LOG(INFO, " mask total_length=%u\n",
> + mask->hdr.total_length);
> + RTE_FLOW_LOG(INFO, " mask packet_id=%u\n",
> + mask->hdr.packet_id);
> + RTE_FLOW_LOG(INFO, " mask fragment_offset=%u\n",
> + mask->hdr.fragment_offset);
> + RTE_FLOW_LOG(INFO, " mask time_to_live=%u\n",
> + mask->hdr.time_to_live);
> + RTE_FLOW_LOG(INFO, " mask next_proto_id=%u\n",
> + mask->hdr.next_proto_id);
> + RTE_FLOW_LOG(INFO, " mask hdr_checksum=0x%x\n",
> + mask->hdr.hdr_checksum);
> + RTE_FLOW_LOG(INFO,
> + " mask src_addr=%d.%d.%d.%d\n",
> + (mask->hdr.src_addr & 0x000000FF),
> + (mask->hdr.src_addr & 0x0000FF00) >> 8,
> + (mask->hdr.src_addr & 0x00FF0000) >> 16,
> + (mask->hdr.src_addr & 0xFF000000)
> + >> 24);
> + RTE_FLOW_LOG(INFO,
> + " mask dst_addr=%d.%d.%d.%d\n",
> + (mask->hdr.dst_addr & 0x000000FF),
> + (mask->hdr.dst_addr & 0x0000FF00) >> 8,
> + (mask->hdr.dst_addr & 0x00FF0000) >> 16,
> + (mask->hdr.dst_addr & 0xFF000000)
> + >> 24);
> + }
> + break;
> + }
> + default:
> + RTE_FLOW_LOG(INFO, "unfamiliar pattern item\n");
> + }
> + }
> +
> + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
> + RTE_FLOW_LOG(INFO, "actions type =%u\n", actions->type);
> + switch (actions->type) {
> + case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: {
> + RTE_FLOW_LOG(INFO,
> + " name=RTE_FLOW_ACTION_TYPE_OF_POP_VLAN\n");
> + break;
> + }
> + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: {
> + RTE_FLOW_LOG(INFO,
> + " name=RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN\n");
> + if (actions->conf) {
> + const struct rte_flow_action_of_push_vlan
> + *conf = actions->conf;
> + RTE_FLOW_LOG(INFO, " ethertype=0x%x\n",
> + conf->ethertype);
> + }
> + break;
> + }
> + case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: {
> + RTE_FLOW_LOG(INFO,
> + " name=RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID\n");
> + if (actions->conf) {
> + const struct rte_flow_action_of_set_vlan_vid
> + *conf = actions->conf;
> + RTE_FLOW_LOG(INFO, " vlan_vid=0x%x\n",
> + conf->vlan_vid);
> + }
> + break;
> + }
> + case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP: {
> + RTE_FLOW_LOG(INFO,
> + " name=RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP\n");
> + if (actions->conf) {
> + const struct rte_flow_action_of_set_vlan_pcp
> + *conf = actions->conf;
> + RTE_FLOW_LOG(INFO, " vlan_pcp=%u\n",
> + conf->vlan_pcp);
> + }
> + break;
> + }
> + case RTE_FLOW_ACTION_TYPE_PORT_ID: {
> + RTE_FLOW_LOG(INFO,
> + " name=RTE_FLOW_ACTION_TYPE_PORT_ID\n");
> + if (actions->conf) {
> + const struct rte_flow_action_port_id
> + *conf = actions->conf;
> + RTE_FLOW_LOG(INFO, " id=%u\n", conf->id);
> + RTE_FLOW_LOG(INFO, " reserved=%u\n",
> + conf->reserved);
> + }
> + break;
> + }
> + default:
> + RTE_FLOW_LOG(INFO, "unfamiliar action item\n");
> + }
> + }
> +}
> +
> /* Create a flow rule on a given port. */
> struct rte_flow *
> rte_flow_create(uint16_t port_id,
> @@ -1001,3 +1219,11 @@ enum rte_flow_conv_item_spec_type {
> };
> return lsize;
> }
> +
> +RTE_INIT(flow_init_log)
> +{
> + rte_flow_logtype = rte_log_register("lib.flow");
> + if (rte_flow_logtype >= 0)
> + rte_log_set_level(rte_flow_logtype, RTE_LOG_INFO);
> +}
> +
> diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
> index c0fe879..0a7e70b 100644
> --- a/lib/librte_ethdev/rte_flow.h
> +++ b/lib/librte_ethdev/rte_flow.h
> @@ -28,6 +28,12 @@
> #include <rte_udp.h>
> #include <rte_byteorder.h>
> #include <rte_esp.h>
> +#include <rte_log.h>
> +
> +extern int rte_flow_logtype;
> +
> +#define RTE_FLOW_LOG(level, ...) \
> + rte_log(RTE_LOG_ ## level, rte_flow_logtype, "" __VA_ARGS__)
>
> #ifdef __cplusplus
> extern "C" {
> @@ -2414,6 +2420,31 @@ enum rte_flow_conv_op {
> struct rte_flow_error *error);
>
> /**
> + * Print the flow fields.
> + *
> + * The flow contains the port id, different attributes, the pattern's
> + * items and the action's items, which are all being printed.
> + *
> + * @b EXPERIMENTAL: this API may change without prior notice
> + *
> + * @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).
> + *
> + * @note not all enum values of patterns and actions are printed.
> + */
> +void __rte_experimental
> +rte_flow_print(uint16_t port_id,
> + const struct rte_flow_attr *attr,
> + const struct rte_flow_item pattern[],
> + const struct rte_flow_action actions[]);
> +
> +/**
> * Create a flow rule on a given port.
> *
> * @param port_id
Since this is a debug function, it would make more sense for it to take a 'FILE *'
for output like the other debug functions do. That would make it consistent
with rte_pktmbuf_dump rte_event_dev_dump, rte_mempool_dump, etc.
Why not name it rte_flow_dump?
next prev parent reply other threads:[~2018-12-06 21:44 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-28 15:26 [PATCH] ethdev: add function to print a flow Asaf Penso
2018-12-06 7:23 ` Asaf Penso
2018-12-06 21:44 ` Stephen Hemminger [this message]
2018-12-11 7:24 ` Asaf Penso
2018-12-11 7:29 ` Ori Kam
2018-12-11 9:15 ` Asaf Penso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181206134418.475b8d06@xeon-e3 \
--to=stephen@networkplumber.org \
--cc=adrien.mazarguil@6wind.com \
--cc=asafp@mellanox.com \
--cc=dev@dpdk.org \
--cc=orika@mellanox.com \
--cc=shahafs@mellanox.com \
--cc=thomas@monjalon.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.