Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-14 Thread Simon Horman
On Thu, Sep 14, 2017 at 10:35:10AM +0800, Yuanhan Liu wrote:
> On Wed, Sep 13, 2017 at 11:45:30AM +0200, Simon Horman wrote:
> > > > > +rte_memcpy(ð_spec.dst, &match->flow.dl_dst, 
> > > sizeof(eth_spec.dst));
> > > > > +rte_memcpy(ð_spec.src, &match->flow.dl_src, 
> > > sizeof(eth_spec.src));
> > > > > +eth_spec.type = match->flow.dl_type;
> > > > > +
> > > > > +rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
> > > > > +   sizeof(eth_mask.dst));
> > > > > +rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
> > > > > +   sizeof(eth_mask.src));
> > > > > +eth_mask.type = match->wc.masks.dl_type;
> > > > > +
> > > > > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
> > > > > + ð_spec, ð_mask);
> > > > > +} else {
> > > > > +/*
> > > > > + * If user specifies a flow (like UDP flow) without L2 
> > > patterns,
> > > > > + * OVS will at least set the dl_type. Normally, it's 
> > > enough to
> > > > > + * create an eth pattern just with it. Unluckily, some 
> > > Intel's
> > > > > + * NIC (such as XL710) doesn't support that. Below is a 
> > > workaround,
> > > > > + * which simply matches any L2 pkts.
> > > > > + */
> > > > > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, 
> > > NULL, NULL);
> > > > > +}
> > > > 
> > > > This feels a lot like a layer violation - making the core aware
> > > > of specific implementation details of lower layers.
> > > 
> > > I agree with you, but unlickily, without it, Intel NIC simply won't 
> > > work
> > > (according to Finn), unless you have mac addr being provided.
> > 
> > I think its reasonable to provide hardware-workarounds. But is it
> > appropriate to enable it for all hardware
> 
> Without the underlaying hardware info/cap given, yes, I'm afraid that
> is what we can get best now.

Agreed.

> > and is this the most appropriate
> > place for a hardware work-around?
> 
> Maybe not. Maybe this should be workarounded inside the DPDK PMD driver.

Pushing it lower down sounds better to me.
But I'm not really in a position to judge how practical
it is to handle this in the DPDK PMD driver.
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-13 Thread Yuanhan Liu
On Wed, Sep 13, 2017 at 05:18:03AM +, Darrell Ball wrote:
> +/* IP v4 */
> +uint8_t proto = 0;
> +struct rte_flow_item_ipv4 ipv4_spec;
> +struct rte_flow_item_ipv4 ipv4_mask;
> +memset(&ipv4_mask, 0, sizeof(ipv4_mask));
> +if ((match->flow.dl_type == ntohs(ETH_TYPE_IP)) &&
> +(match->wc.masks.nw_src || match->wc.masks.nw_dst ||
> + match->wc.masks.nw_tos || match->wc.masks.nw_ttl ||
> + match->wc.masks.nw_proto)) {
> +ipv4_spec.hdr.type_of_service = match->flow.nw_tos;
> +ipv4_spec.hdr.time_to_live= match->flow.nw_tos;
> 
> [Darrell] should be TTL; lots of e-mails but I don’t remember seeing this 
> mentioned

That's really a good catch! And actually, I have also noticed it few days,
that I have fixed in my local v3 branch.

> +
> +CHECK_NONZERO_BYTES(&match_zero_wc.flow.tunnel,
> +sizeof(match_zero_wc.flow.tunnel));
> +CHECK_NONZERO(match->wc.masks.metadata);
> +CHECK_NONZERO(match->wc.masks.skb_priority);
> +CHECK_NONZERO(match->wc.masks.pkt_mark);
> +CHECK_NONZERO(match->wc.masks.dp_hash);
> +
> +/* recirc id must be zero */
> +CHECK_NONZERO(match_zero_wc.flow.recirc_id);
> +
> +CHECK_NONZERO(match->wc.masks.ct_state);
> +CHECK_NONZERO(match->wc.masks.ct_zone);
> +CHECK_NONZERO(match->wc.masks.ct_mark);
> 
> [Darrell]
> check the other pkt_metadata fields; some are missing here.

I will give it a try.

--yliu
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-13 Thread Yuanhan Liu
On Wed, Sep 13, 2017 at 11:45:30AM +0200, Simon Horman wrote:
> > > > +rte_memcpy(ð_spec.dst, &match->flow.dl_dst, 
> > sizeof(eth_spec.dst));
> > > > +rte_memcpy(ð_spec.src, &match->flow.dl_src, 
> > sizeof(eth_spec.src));
> > > > +eth_spec.type = match->flow.dl_type;
> > > > +
> > > > +rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
> > > > +   sizeof(eth_mask.dst));
> > > > +rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
> > > > +   sizeof(eth_mask.src));
> > > > +eth_mask.type = match->wc.masks.dl_type;
> > > > +
> > > > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
> > > > + ð_spec, ð_mask);
> > > > +} else {
> > > > +/*
> > > > + * If user specifies a flow (like UDP flow) without L2 
> > patterns,
> > > > + * OVS will at least set the dl_type. Normally, it's 
> > enough to
> > > > + * create an eth pattern just with it. Unluckily, some 
> > Intel's
> > > > + * NIC (such as XL710) doesn't support that. Below is a 
> > workaround,
> > > > + * which simply matches any L2 pkts.
> > > > + */
> > > > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, 
> > NULL);
> > > > +}
> > > 
> > > This feels a lot like a layer violation - making the core aware
> > > of specific implementation details of lower layers.
> > 
> > I agree with you, but unlickily, without it, Intel NIC simply won't work
> > (according to Finn), unless you have mac addr being provided.
> 
> I think its reasonable to provide hardware-workarounds. But is it
> appropriate to enable it for all hardware

Without the underlaying hardware info/cap given, yes, I'm afraid that
is what we can get best now.

> and is this the most appropriate
> place for a hardware work-around?

Maybe not. Maybe this should be workarounded inside the DPDK PMD driver.

--yliu
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-13 Thread Simon Horman
On Tue, Sep 12, 2017 at 08:34:44AM +, Darrell Ball wrote:
> 
> 
> On 9/10/17, 11:11 PM, "ovs-dev-boun...@openvswitch.org on behalf of Yuanhan 
> Liu"  
> wrote:
> 
> On Fri, Sep 08, 2017 at 06:47:55PM +0200, Simon Horman wrote:
> > On Tue, Sep 05, 2017 at 05:22:57PM +0800, Yuanhan Liu wrote:
> > > From: Finn Christensen 
> > > 
> > > The basic yet the major part of this patch is to translate the "match"
> > > to rte flow patterns. And then, we create a rte flow with a MARK 
> action.
> > > Afterwards, all pkts matches the flow will have the mark id in the 
> mbuf.
> > > 
> > > For any unsupported flows, such as MPLS, -1 is returned, meaning the
> > > flow offload is failed and then skipped.
> > 
> > ...
> > 
> > > +static int
> > > +netdev_dpdk_add_rte_flow_offload(struct netdev *netdev,
> > > + const struct match *match,
> > > + struct nlattr *nl_actions 
> OVS_UNUSED,
> > > + size_t actions_len,
> > > + const ovs_u128 *ufid,
> > > + struct offload_info *info)
> > > +{
> > > +struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
> > > +const struct rte_flow_attr flow_attr = {
> > > +.group = 0,
> > > +.priority = 0,
> > > +.ingress = 1,
> > > +.egress = 0
> > > +};
> > > +struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
> > > +struct flow_actions actions = { .actions = NULL, .cnt = 0 };
> > 
> > I believe the following will give the same result as the above,
> > less verbosely.
> > 
> > +const struct rte_flow_attr flow_attr = { .ingress = 1 };
> > +struct flow_patterns patterns = { .cnt = 0 };
> > +struct flow_actions actions = { .cnt = 0 };
> 
> I'm not quite sure on that. If the compiler doesn't do zero assigment
> correctly, something deadly wrong could happen. They all are short
> structs, that I think it's fine, IMO. If they are big, I'd prefer an
> explicit memset.

I'm pretty sure that the compiler will zero all other fields when the
scheme I described above is used. However, its a moot point if the approach
you used is preferred. So I think what you have is fine.

> 
> > > +struct rte_flow *flow;
> > > +struct rte_flow_error error;
> > > +uint8_t *ipv4_next_proto_mask = NULL;
> > > +int ret = 0;
> > > +
> > > +/* Eth */
> > > +struct rte_flow_item_eth eth_spec;
> > > +struct rte_flow_item_eth eth_mask;
> > 
> > Empty line here please.
> 
> I actually want to bind the two declartions with the following code piece,
> to show that they are tightly related.

As I think Darrell pointed out elsewhere it is common practice to
put declarations close to code that uses them. This is different from
my assumption that they should be grouped at the top of a context.
With this in mind what you already have makes sense to me.

> 
> > > +memset(ð_mask, 0, sizeof(eth_mask));
> > > +if (match->wc.masks.dl_src.be16[0] ||
> > > +match->wc.masks.dl_src.be16[1] ||
> > > +match->wc.masks.dl_src.be16[2] ||
> > > +match->wc.masks.dl_dst.be16[0] ||
> > > +match->wc.masks.dl_dst.be16[1] ||
> > > +match->wc.masks.dl_dst.be16[2]) {
> > 
> > It looks like eth_addr_is_zero() can be used in the above.
> 
> Yes, we could. Thanks for the tip.
> 
> > > +rte_memcpy(ð_spec.dst, &match->flow.dl_dst, 
> sizeof(eth_spec.dst));
> > > +rte_memcpy(ð_spec.src, &match->flow.dl_src, 
> sizeof(eth_spec.src));
> > > +eth_spec.type = match->flow.dl_type;
> > > +
> > > +rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
> > > +   sizeof(eth_mask.dst));
> > > +rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
> > > +   sizeof(eth_mask.src));
> > > +eth_mask.type = match->wc.masks.dl_type;
> > > +
> > > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
> > > + ð_spec, ð_mask);
> > > +} else {
> > > +/*
> > > + * If user specifies a flow (like UDP flow) without L2 
> patterns,
> > > + * OVS will at least set the dl_type. Normally, it's enough 
> to
> > > + * create an eth pattern just with it. Unluckily, some 
> Intel's
> > > + * NIC (such as XL710) doesn't support that. Below is a 
> workaround,
> > > + * which simply matches any L2 pkts.
> > > + */
> > > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, 
> NULL);
> > > +}
> > 
> > This feels a lot like a layer violation - making the core

Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-12 Thread Darrell Ball
More comments

On 9/12/17, 9:15 PM, "Darrell Ball"  wrote:

Still working my way through this patch, but I had a couple comments inline

On 9/5/17, 2:23 AM, "Yuanhan Liu"  wrote:

From: Finn Christensen 

The basic yet the major part of this patch is to translate the "match"
to rte flow patterns. And then, we create a rte flow with a MARK action.
Afterwards, all pkts matches the flow will have the mark id in the mbuf.

For any unsupported flows, such as MPLS, -1 is returned, meaning the
flow offload is failed and then skipped.

Co-authored-by: Yuanhan Liu 
Signed-off-by: Finn Christensen 
Signed-off-by: Yuanhan Liu 
---

v2: - convert some macros to functions
- do not hardcode the max number of flow/action
- fix L2 patterns for Intel nic
- add comments for not implemented offload methods
---
 lib/netdev-dpdk.c | 421 
+-
 1 file changed, 420 insertions(+), 1 deletion(-)

diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 46f9885..37b0f99 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -58,6 +58,7 @@
 #include "smap.h"
 #include "sset.h"
 #include "unaligned.h"
+#include "uuid.h"
 #include "timeval.h"
 #include "unixctl.h"
 
@@ -3400,6 +3401,424 @@ get_rte_flow_by_ufid(const ovs_u128 *ufid)
 }
 
 
+struct flow_patterns {
+struct rte_flow_item *items;
+int cnt;
+int max;
+};
+
+struct flow_actions {
+struct rte_flow_action *actions;
+int cnt;
+int max;
+};
+
+static void
+add_flow_pattern(struct flow_patterns *patterns, enum 
rte_flow_item_type type,
+ const void *spec, const void *mask)
+{
+int cnt = patterns->cnt;
+
+if (cnt == 0) {
+patterns->max = 8;
+patterns->items = xcalloc(patterns->max, sizeof(struct 
rte_flow_item));
+} else if (cnt == patterns->max) {
+patterns->max *= 2;
+patterns->items = xrealloc(patterns->items, patterns->max *
+   sizeof(struct rte_flow_item));
+}
+
+patterns->items[cnt].type = type;
+patterns->items[cnt].spec = spec;
+patterns->items[cnt].mask = mask;
+patterns->items[cnt].last = NULL;
+patterns->cnt++;
+}
+
+static void
+add_flow_action(struct flow_actions *actions, enum 
rte_flow_action_type type,
+const void *conf)
+{
+int cnt = actions->cnt;
+
+if (cnt == 0) {
+actions->max = 8;
+actions->actions = xcalloc(actions->max,
+   sizeof(struct rte_flow_action));
+} else if (cnt == actions->max) {
+actions->max *= 2;
+actions->actions = xrealloc(actions->actions, actions->max *
+sizeof(struct rte_flow_action));
+}
+
+actions->actions[cnt].type = type;
+actions->actions[cnt].conf = conf;
+actions->cnt++;
+}
+
+static int
+netdev_dpdk_add_rte_flow_offload(struct netdev *netdev,
+ const struct match *match,
+ struct nlattr *nl_actions OVS_UNUSED,
+ size_t actions_len,
+ const ovs_u128 *ufid,
+ struct offload_info *info)
+{
+struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+const struct rte_flow_attr flow_attr = {
+.group = 0,
+.priority = 0,
+.ingress = 1,
+.egress = 0
+};
+struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
+struct flow_actions actions = { .actions = NULL, .cnt = 0 };
+struct rte_flow *flow;
+struct rte_flow_error error;
+uint8_t *ipv4_next_proto_mask = NULL;
+int ret = 0;
+
+/* Eth */
+struct rte_flow_item_eth eth_spec;
+struct rte_flow_item_eth eth_mask;
+memset(ð_mask, 0, sizeof(eth_mask));
+if (match->wc.masks.dl_src.be16[0] ||
+match->wc.masks.dl_src.be16[1] ||
+match->wc.masks.dl_src.be16[2] ||
+match->wc.masks.dl_dst.be16[0] ||
+

Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-12 Thread Darrell Ball
Still working my way through this patch, but I had a couple comments inline

On 9/5/17, 2:23 AM, "Yuanhan Liu"  wrote:

From: Finn Christensen 

The basic yet the major part of this patch is to translate the "match"
to rte flow patterns. And then, we create a rte flow with a MARK action.
Afterwards, all pkts matches the flow will have the mark id in the mbuf.

For any unsupported flows, such as MPLS, -1 is returned, meaning the
flow offload is failed and then skipped.

Co-authored-by: Yuanhan Liu 
Signed-off-by: Finn Christensen 
Signed-off-by: Yuanhan Liu 
---

v2: - convert some macros to functions
- do not hardcode the max number of flow/action
- fix L2 patterns for Intel nic
- add comments for not implemented offload methods
---
 lib/netdev-dpdk.c | 421 
+-
 1 file changed, 420 insertions(+), 1 deletion(-)

diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 46f9885..37b0f99 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -58,6 +58,7 @@
 #include "smap.h"
 #include "sset.h"
 #include "unaligned.h"
+#include "uuid.h"
 #include "timeval.h"
 #include "unixctl.h"
 
@@ -3400,6 +3401,424 @@ get_rte_flow_by_ufid(const ovs_u128 *ufid)
 }
 
 
+struct flow_patterns {
+struct rte_flow_item *items;
+int cnt;
+int max;
+};
+
+struct flow_actions {
+struct rte_flow_action *actions;
+int cnt;
+int max;
+};
+
+static void
+add_flow_pattern(struct flow_patterns *patterns, enum rte_flow_item_type 
type,
+ const void *spec, const void *mask)
+{
+int cnt = patterns->cnt;
+
+if (cnt == 0) {
+patterns->max = 8;
+patterns->items = xcalloc(patterns->max, sizeof(struct 
rte_flow_item));
+} else if (cnt == patterns->max) {
+patterns->max *= 2;
+patterns->items = xrealloc(patterns->items, patterns->max *
+   sizeof(struct rte_flow_item));
+}
+
+patterns->items[cnt].type = type;
+patterns->items[cnt].spec = spec;
+patterns->items[cnt].mask = mask;
+patterns->items[cnt].last = NULL;
+patterns->cnt++;
+}
+
+static void
+add_flow_action(struct flow_actions *actions, enum rte_flow_action_type 
type,
+const void *conf)
+{
+int cnt = actions->cnt;
+
+if (cnt == 0) {
+actions->max = 8;
+actions->actions = xcalloc(actions->max,
+   sizeof(struct rte_flow_action));
+} else if (cnt == actions->max) {
+actions->max *= 2;
+actions->actions = xrealloc(actions->actions, actions->max *
+sizeof(struct rte_flow_action));
+}
+
+actions->actions[cnt].type = type;
+actions->actions[cnt].conf = conf;
+actions->cnt++;
+}
+
+static int
+netdev_dpdk_add_rte_flow_offload(struct netdev *netdev,
+ const struct match *match,
+ struct nlattr *nl_actions OVS_UNUSED,
+ size_t actions_len,
+ const ovs_u128 *ufid,
+ struct offload_info *info)
+{
+struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+const struct rte_flow_attr flow_attr = {
+.group = 0,
+.priority = 0,
+.ingress = 1,
+.egress = 0
+};
+struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
+struct flow_actions actions = { .actions = NULL, .cnt = 0 };
+struct rte_flow *flow;
+struct rte_flow_error error;
+uint8_t *ipv4_next_proto_mask = NULL;
+int ret = 0;
+
+/* Eth */
+struct rte_flow_item_eth eth_spec;
+struct rte_flow_item_eth eth_mask;
+memset(ð_mask, 0, sizeof(eth_mask));
+if (match->wc.masks.dl_src.be16[0] ||
+match->wc.masks.dl_src.be16[1] ||
+match->wc.masks.dl_src.be16[2] ||
+match->wc.masks.dl_dst.be16[0] ||
+match->wc.masks.dl_dst.be16[1] ||
+match->wc.masks.dl_dst.be16[2]) {
+rte_memcpy(ð_spec.dst, &match->flow.dl_dst, 
sizeof(eth_spec.dst));
+rte_memcpy(ð_spec.src, &match->flow.dl_src, 
sizeof(eth_spec.src));
+eth_spec.type = match->flow.dl_type;
+
+rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
+   sizeof(eth_mask.dst));
+rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
+   sizeof(eth_mask.src));
+eth_mask.type = match->wc.masks.dl_type;

Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-12 Thread Darrell Ball


On 9/11/17, 3:02 AM, "ovs-dev-boun...@openvswitch.org on behalf of Yuanhan Liu" 
 wrote:

On Sun, Sep 10, 2017 at 04:32:19PM +, Chandran, Sugesh wrote:
> As mentioned earlier in the cover letter we also have a similar 
implementation to do the flow translate.
> I feel its good to make bit more modular for this translation.  The 
reason being its easy to extend and add more protocols in the future.

Honestly, I don't see a strong need to make it that complex first. Yes,
it's a big function with a chunk of codes. And yes, I'm also a fun of
splitting big monsters to many small functions. However, if you look
at it closer, you will see it's nicely organized: the function is split
nicely with chunks: something like one chunk for one protocol.

Extending is also not that hard: just adding another chunk of the code.

Besides, if you see tc offloads, they do it in a same way.

[...]
> > +
> > +/*
> > + * Validate for later rte flow offload creation. If any unsupported
> > + * flow are specified, return -1.
> > + */
> [Sugesh] I feel this is very hardware centric. There are chances hardware 
can support
> Ipv6 or other fields in a packet. This has to be based on what flow 
fields a hardware can support.

Yes, you are right. Again, we need capabilities feedback from DPDK.

[Darrell] There have been several mentions of capability queries in version 1 
and version 2 of the patchset.

1/ We asked for HW scaling checks to better support manageability and 
predictability.

2/ We asked for a ‘queue action workaround requirement’ query, which would be a 
nice enhancement,
to avoid an unnecessary first failed attempt at flow create for nics that 
don’t allow the mark action in isolation.

3/ Here we ask for flow matching capability checking, with fallback to what we 
already support today.
 Similar kinds of queries were also mentioned in regard to the patchset 
“prioritizing latency sensitive traffic”.
 TCP flags matching mentioned in Patch 2 also falls into this category.



--yliu
___
dev mailing list
d...@openvswitch.org

https://urldefense.proofpoint.com/v2/url?u=https-3A__mail.openvswitch.org_mailman_listinfo_ovs-2Ddev&d=DwICAg&c=uilaK90D4TOVoH58JNXRgQ&r=BVhFA09CGX7JQ5Ih-uZnsw&m=SbdNOA5djgzhAIm49EWuBLui1KsaSl-tOsvhgb685Js&s=oKRfV8aE2G8A_Te761VR9n29SJuhr4-SJshaFetgICw&e=
 






___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-12 Thread Darrell Ball


On 9/10/17, 11:11 PM, "ovs-dev-boun...@openvswitch.org on behalf of Yuanhan 
Liu"  wrote:

On Fri, Sep 08, 2017 at 06:47:55PM +0200, Simon Horman wrote:
> On Tue, Sep 05, 2017 at 05:22:57PM +0800, Yuanhan Liu wrote:
> > From: Finn Christensen 
> > 
> > The basic yet the major part of this patch is to translate the "match"
> > to rte flow patterns. And then, we create a rte flow with a MARK action.
> > Afterwards, all pkts matches the flow will have the mark id in the mbuf.
> > 
> > For any unsupported flows, such as MPLS, -1 is returned, meaning the
> > flow offload is failed and then skipped.
> 
> ...
> 
> > +static int
> > +netdev_dpdk_add_rte_flow_offload(struct netdev *netdev,
> > + const struct match *match,
> > + struct nlattr *nl_actions OVS_UNUSED,
> > + size_t actions_len,
> > + const ovs_u128 *ufid,
> > + struct offload_info *info)
> > +{
> > +struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
> > +const struct rte_flow_attr flow_attr = {
> > +.group = 0,
> > +.priority = 0,
> > +.ingress = 1,
> > +.egress = 0
> > +};
> > +struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
> > +struct flow_actions actions = { .actions = NULL, .cnt = 0 };
> 
> I believe the following will give the same result as the above,
> less verbosely.
> 
> +const struct rte_flow_attr flow_attr = { .ingress = 1 };
> +struct flow_patterns patterns = { .cnt = 0 };
> +struct flow_actions actions = { .cnt = 0 };

I'm not quite sure on that. If the compiler doesn't do zero assigment
correctly, something deadly wrong could happen. They all are short
structs, that I think it's fine, IMO. If they are big, I'd prefer an
explicit memset.

> > +struct rte_flow *flow;
> > +struct rte_flow_error error;
> > +uint8_t *ipv4_next_proto_mask = NULL;
> > +int ret = 0;
> > +
> > +/* Eth */
> > +struct rte_flow_item_eth eth_spec;
> > +struct rte_flow_item_eth eth_mask;
> 
> Empty line here please.

I actually want to bind the two declartions with the following code piece,
to show that they are tightly related.

> > +memset(ð_mask, 0, sizeof(eth_mask));
> > +if (match->wc.masks.dl_src.be16[0] ||
> > +match->wc.masks.dl_src.be16[1] ||
> > +match->wc.masks.dl_src.be16[2] ||
> > +match->wc.masks.dl_dst.be16[0] ||
> > +match->wc.masks.dl_dst.be16[1] ||
> > +match->wc.masks.dl_dst.be16[2]) {
> 
> It looks like eth_addr_is_zero() can be used in the above.

Yes, we could. Thanks for the tip.

> > +rte_memcpy(ð_spec.dst, &match->flow.dl_dst, 
sizeof(eth_spec.dst));
> > +rte_memcpy(ð_spec.src, &match->flow.dl_src, 
sizeof(eth_spec.src));
> > +eth_spec.type = match->flow.dl_type;
> > +
> > +rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
> > +   sizeof(eth_mask.dst));
> > +rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
> > +   sizeof(eth_mask.src));
> > +eth_mask.type = match->wc.masks.dl_type;
> > +
> > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
> > + ð_spec, ð_mask);
> > +} else {
> > +/*
> > + * If user specifies a flow (like UDP flow) without L2 
patterns,
> > + * OVS will at least set the dl_type. Normally, it's enough to
> > + * create an eth pattern just with it. Unluckily, some Intel's
> > + * NIC (such as XL710) doesn't support that. Below is a 
workaround,
> > + * which simply matches any L2 pkts.
> > + */
> > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, 
NULL);
> > +}
> 
> This feels a lot like a layer violation - making the core aware
> of specific implementation details of lower layers.

I agree with you, but unlickily, without it, Intel NIC simply won't work
(according to Finn), unless you have mac addr being provided.

> >From a functional point of view, is the idea that
> a eth_type+5-tuple match is converted to a 5-tuple match?

Unluckily, yes.

> > +/* VLAN */
> > +struct rte_flow_item_vlan vlan_spec;
> > +struct rte_flow_item_vlan vlan_mask;
> 
> Please declare all local variables at the top of the context
> (in this case function).
> 
> ...
> 
> > +struct rte_flow_item_udp udp_spec;
> > +struct rte_flow_item_udp udp_mask;
> > +memset(&udp_mask, 0, siz

Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-11 Thread Yuanhan Liu
On Mon, Sep 11, 2017 at 10:04:21AM +, Chandran, Sugesh wrote:
> 
> 
> Regards
> _Sugesh
> 
> 
> > -Original Message-
> > From: Yuanhan Liu [mailto:y...@fridaylinux.org]
> > Sent: Monday, September 11, 2017 10:58 AM
> > To: Chandran, Sugesh 
> > Cc: d...@openvswitch.org
> > Subject: Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with
> > rte flow
> > 
> > On Sun, Sep 10, 2017 at 04:32:19PM +, Chandran, Sugesh wrote:
> > > As mentioned earlier in the cover letter we also have a similar
> > implementation to do the flow translate.
> > > I feel its good to make bit more modular for this translation.  The reason
> > being its easy to extend and add more protocols in the future.
> > 
> > Honestly, I don't see a strong need to make it that complex first. Yes, 
> > it's a big
> > function with a chunk of codes. And yes, I'm also a fun of splitting big
> > monsters to many small functions. However, if you look at it closer, you 
> > will
> > see it's nicely organized: the function is split nicely with chunks: 
> > something
> > like one chunk for one protocol.
> > 
> > Extending is also not that hard: just adding another chunk of the code.
> [Sugesh] Sure, I just wanted to share our proposal which works fine for our 
> usecase. :)

Thanks for sharing!

--yliu
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-11 Thread Chandran, Sugesh


Regards
_Sugesh


> -Original Message-
> From: Yuanhan Liu [mailto:y...@fridaylinux.org]
> Sent: Monday, September 11, 2017 10:58 AM
> To: Chandran, Sugesh 
> Cc: d...@openvswitch.org
> Subject: Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with
> rte flow
> 
> On Sun, Sep 10, 2017 at 04:32:19PM +, Chandran, Sugesh wrote:
> > As mentioned earlier in the cover letter we also have a similar
> implementation to do the flow translate.
> > I feel its good to make bit more modular for this translation.  The reason
> being its easy to extend and add more protocols in the future.
> 
> Honestly, I don't see a strong need to make it that complex first. Yes, it's 
> a big
> function with a chunk of codes. And yes, I'm also a fun of splitting big
> monsters to many small functions. However, if you look at it closer, you will
> see it's nicely organized: the function is split nicely with chunks: something
> like one chunk for one protocol.
> 
> Extending is also not that hard: just adding another chunk of the code.
[Sugesh] Sure, I just wanted to share our proposal which works fine for our 
usecase. :)
> 
> Besides, if you see tc offloads, they do it in a same way.
[Sugesh] yes. 
> 
> [...]
> > > +
> > > +/*
> > > + * Validate for later rte flow offload creation. If any unsupported
> > > + * flow are specified, return -1.
> > > + */
> > [Sugesh] I feel this is very hardware centric. There are chances
> > hardware can support
> > Ipv6 or other fields in a packet. This has to be based on what flow fields a
> hardware can support.
> 
> Yes, you are right. Again, we need capabilities feedback from DPDK.
[Sugesh] Ok.
> 
>   --yliu
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-11 Thread Yuanhan Liu
On Sun, Sep 10, 2017 at 04:32:19PM +, Chandran, Sugesh wrote:
> As mentioned earlier in the cover letter we also have a similar 
> implementation to do the flow translate.
> I feel its good to make bit more modular for this translation.  The reason 
> being its easy to extend and add more protocols in the future.

Honestly, I don't see a strong need to make it that complex first. Yes,
it's a big function with a chunk of codes. And yes, I'm also a fun of
splitting big monsters to many small functions. However, if you look
at it closer, you will see it's nicely organized: the function is split
nicely with chunks: something like one chunk for one protocol.

Extending is also not that hard: just adding another chunk of the code.

Besides, if you see tc offloads, they do it in a same way.

[...]
> > +
> > +/*
> > + * Validate for later rte flow offload creation. If any unsupported
> > + * flow are specified, return -1.
> > + */
> [Sugesh] I feel this is very hardware centric. There are chances hardware can 
> support
> Ipv6 or other fields in a packet. This has to be based on what flow fields a 
> hardware can support.

Yes, you are right. Again, we need capabilities feedback from DPDK.

--yliu
___
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev


Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-10 Thread Yuanhan Liu
On Fri, Sep 08, 2017 at 06:47:55PM +0200, Simon Horman wrote:
> On Tue, Sep 05, 2017 at 05:22:57PM +0800, Yuanhan Liu wrote:
> > From: Finn Christensen 
> > 
> > The basic yet the major part of this patch is to translate the "match"
> > to rte flow patterns. And then, we create a rte flow with a MARK action.
> > Afterwards, all pkts matches the flow will have the mark id in the mbuf.
> > 
> > For any unsupported flows, such as MPLS, -1 is returned, meaning the
> > flow offload is failed and then skipped.
> 
> ...
> 
> > +static int
> > +netdev_dpdk_add_rte_flow_offload(struct netdev *netdev,
> > + const struct match *match,
> > + struct nlattr *nl_actions OVS_UNUSED,
> > + size_t actions_len,
> > + const ovs_u128 *ufid,
> > + struct offload_info *info)
> > +{
> > +struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
> > +const struct rte_flow_attr flow_attr = {
> > +.group = 0,
> > +.priority = 0,
> > +.ingress = 1,
> > +.egress = 0
> > +};
> > +struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
> > +struct flow_actions actions = { .actions = NULL, .cnt = 0 };
> 
> I believe the following will give the same result as the above,
> less verbosely.
> 
> +const struct rte_flow_attr flow_attr = { .ingress = 1 };
> +struct flow_patterns patterns = { .cnt = 0 };
> +struct flow_actions actions = { .cnt = 0 };

I'm not quite sure on that. If the compiler doesn't do zero assigment
correctly, something deadly wrong could happen. They all are short
structs, that I think it's fine, IMO. If they are big, I'd prefer an
explicit memset.

> > +struct rte_flow *flow;
> > +struct rte_flow_error error;
> > +uint8_t *ipv4_next_proto_mask = NULL;
> > +int ret = 0;
> > +
> > +/* Eth */
> > +struct rte_flow_item_eth eth_spec;
> > +struct rte_flow_item_eth eth_mask;
> 
> Empty line here please.

I actually want to bind the two declartions with the following code piece,
to show that they are tightly related.

> > +memset(ð_mask, 0, sizeof(eth_mask));
> > +if (match->wc.masks.dl_src.be16[0] ||
> > +match->wc.masks.dl_src.be16[1] ||
> > +match->wc.masks.dl_src.be16[2] ||
> > +match->wc.masks.dl_dst.be16[0] ||
> > +match->wc.masks.dl_dst.be16[1] ||
> > +match->wc.masks.dl_dst.be16[2]) {
> 
> It looks like eth_addr_is_zero() can be used in the above.

Yes, we could. Thanks for the tip.

> > +rte_memcpy(ð_spec.dst, &match->flow.dl_dst, 
> > sizeof(eth_spec.dst));
> > +rte_memcpy(ð_spec.src, &match->flow.dl_src, 
> > sizeof(eth_spec.src));
> > +eth_spec.type = match->flow.dl_type;
> > +
> > +rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
> > +   sizeof(eth_mask.dst));
> > +rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
> > +   sizeof(eth_mask.src));
> > +eth_mask.type = match->wc.masks.dl_type;
> > +
> > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
> > + ð_spec, ð_mask);
> > +} else {
> > +/*
> > + * If user specifies a flow (like UDP flow) without L2 patterns,
> > + * OVS will at least set the dl_type. Normally, it's enough to
> > + * create an eth pattern just with it. Unluckily, some Intel's
> > + * NIC (such as XL710) doesn't support that. Below is a workaround,
> > + * which simply matches any L2 pkts.
> > + */
> > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL);
> > +}
> 
> This feels a lot like a layer violation - making the core aware
> of specific implementation details of lower layers.

I agree with you, but unlickily, without it, Intel NIC simply won't work
(according to Finn), unless you have mac addr being provided.

> >From a functional point of view, is the idea that
> a eth_type+5-tuple match is converted to a 5-tuple match?

Unluckily, yes.

> > +/* VLAN */
> > +struct rte_flow_item_vlan vlan_spec;
> > +struct rte_flow_item_vlan vlan_mask;
> 
> Please declare all local variables at the top of the context
> (in this case function).
> 
> ...
> 
> > +struct rte_flow_item_udp udp_spec;
> > +struct rte_flow_item_udp udp_mask;
> > +memset(&udp_mask, 0, sizeof(udp_mask));
> > +if ((proto == IPPROTO_UDP) &&
> > +(match->wc.masks.tp_src || match->wc.masks.tp_dst)) {
> > +udp_spec.hdr.src_port = match->flow.tp_src;
> > +udp_spec.hdr.dst_port = match->flow.tp_dst;
> > +
> > +udp_mask.hdr.src_port = match->wc.masks.tp_src;
> > +udp_mask.hdr.dst_port = match->wc.masks.tp_dst;
> > +
> > +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_UDP,
> > + &udp_spec, &udp_mask);
> > +
> > +/* proto == UDP and ITEM_TYPE_UDP, thus n

Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-10 Thread Chandran, Sugesh
As mentioned earlier in the cover letter we also have a similar implementation 
to do the flow translate.
I feel its good to make bit more modular for this translation.  The reason 
being its easy to extend and add more protocols in the future.

 Please find below our similar implementation. We have started with single 
function implementation as in patch series, and eventually moved
to this approach. 
 I can share the code as a patch if you are interested.  Again the approach 
below work well for our use case. Feel free to
discard if it doesn't make any sense/it's an overhead.


The flow and actions translate were invoked from dpdkhw_rte_flow_xlate  and ' 
dpdkhw_rte_action_xlate'.
struct flow_xlate_dic {
enum rte_flow_item_type rte_flow_type;
/*
 * Flow xlate function to translate specific header match into rtl format.
 * Each rte_flow_item_type, it is necessary to define a corresponding
 * xlate function in this structure. Return 0 if the flow is being 
translated
 * successfully and error code otherwise.
 */
int (*flow_xlate)(struct match *match, struct rte_flow_item *hw_flow_item,
   const void *md);
};

static int do_inport_flow_xlate(struct match *match,
   struct rte_flow_item *hw_flow_item, const void *md);
static int do_l2_flow_xlate(struct match *match,
struct rte_flow_item *hw_flow_item, const void *md);
static int do_l3_flow_xlate(struct match *match,
  struct rte_flow_item *hw_flow_item, const void *md);
static int do_l4_flow_xlate(struct match *match,
   struct rte_flow_item *hw_flow_item, const void *md);
static int do_end_flow_xlate(struct match *match,
   struct rte_flow_item *hw_flow_item, const void *md);

struct flow_xlate_dic PORT_FLOW_XLATE = {
RTE_FLOW_ITEM_TYPE_PORT,
do_inport_flow_xlate
};

struct flow_xlate_dic L2_FLOW_XLATE = {
RTE_FLOW_ITEM_TYPE_ETH,
do_l2_flow_xlate
};

struct flow_xlate_dic L3_FLOW_XLATE = {
RTE_FLOW_ITEM_TYPE_VOID, /* L3 flow item can be different */
do_l3_flow_xlate
};


struct flow_xlate_dic L4_FLOW_XLATE = {
RTE_FLOW_ITEM_TYPE_VOID, /* Can be UDP/TCP */
do_l4_flow_xlate
};

struct flow_xlate_dic END_FLOW_XLATE = {
RTE_FLOW_ITEM_TYPE_END,
do_end_flow_xlate
};

/*
 * Convert the mac address to little endian for flow programming
 */
static void
ntoh_mac(struct eth_addr *src, struct eth_addr *dst)
{
int i;
for (i = 0; i < 6; i++) {
dst->ea[6 - i - 1] = src->ea[i];
}
}

static int
do_inport_flow_xlate(struct match *match, struct rte_flow_item *hw_flow_item,
  const void *md)
{
struct flow *flow;
struct rte_flow_item_port *port_flow_item;
struct rte_flow_item_port *port_flow_item_mask;
struct netdev *netdev;
uint16_t hw_portno;
struct offload_info *ofld_info = (struct offload_info *)md;

flow = &match->flow;
port_flow_item = xzalloc (sizeof *port_flow_item);
port_flow_item_mask = xzalloc(sizeof *port_flow_item_mask);
if(!port_flow_item) {
VLOG_ERR("Failed to allocate the memory for hardware flow item");
return ENOMEM;
}

netdev = get_hw_netdev(flow->in_port.odp_port, ofld_info->port_hmap_obj);
if (!netdev) {
VLOG_WARN("Inport %u is not a valid hardware accelerated port.",
odp_to_u32(flow->in_port.odp_port));
return EOPNOTSUPP;
}
/* The inport should be the hardware port number, not the ovs portno */
hw_portno = netdev_get_hw_portno(netdev);
port_flow_item->index = hw_portno;

hw_flow_item->type = PORT_FLOW_XLATE.rte_flow_type;
hw_flow_item->spec = port_flow_item;
hw_flow_item->last = NULL;

/* Set the mask for the rte port flow */
port_flow_item_mask->index = 0x;
hw_flow_item->mask = port_flow_item_mask;
return 0;
}

static int
do_l2_flow_xlate(struct match *match, struct rte_flow_item *hw_flow_item,
  const void *md)
{
struct flow *flow, *mask;
struct rte_flow_item_eth *eth_flow_item;
struct rte_flow_item_eth *eth_flow_mask;
struct eth_addr mac_le;
flow = &match->flow;
mask = &match->wc.masks;
bool is_l2_zero  = 0;
is_l2_zero = eth_addr_is_zero(mask->dl_dst);
is_l2_zero &= eth_addr_is_zero(mask->dl_src);
if(is_l2_zero) {
VLOG_INFO("Cannot install flow with zero eth addr");
return EOPNOTSUPP;
}
eth_flow_item = xzalloc(sizeof *eth_flow_item);
eth_flow_mask = xzalloc(sizeof *eth_flow_mask);
if(!eth_flow_item || !eth_flow_mask) {
VLOG_ERR("Failed to allocate the memory for flow item");
return ENOMEM;
}
ntoh_mac(&flow->dl_dst, &mac_le);
memcpy(ð_flow_item->dst, &mac_le, sizeof(eth_flow_item->dst));

ntoh_mac(&flow->dl

Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-08 Thread Darrell Ball


On 9/8/17, 9:47 AM, "ovs-dev-boun...@openvswitch.org on behalf of Simon Horman" 
 wrote:

On Tue, Sep 05, 2017 at 05:22:57PM +0800, Yuanhan Liu wrote:
> From: Finn Christensen 
> 
> The basic yet the major part of this patch is to translate the "match"
> to rte flow patterns. And then, we create a rte flow with a MARK action.
> Afterwards, all pkts matches the flow will have the mark id in the mbuf.
> 
> For any unsupported flows, such as MPLS, -1 is returned, meaning the
> flow offload is failed and then skipped.

...

> +static int
> +netdev_dpdk_add_rte_flow_offload(struct netdev *netdev,
> + const struct match *match,
> + struct nlattr *nl_actions OVS_UNUSED,
> + size_t actions_len,
> + const ovs_u128 *ufid,
> + struct offload_info *info)
> +{
> +struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
> +const struct rte_flow_attr flow_attr = {
> +.group = 0,
> +.priority = 0,
> +.ingress = 1,
> +.egress = 0
> +};
> +struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
> +struct flow_actions actions = { .actions = NULL, .cnt = 0 };

I believe the following will give the same result as the above,
less verbosely.

+const struct rte_flow_attr flow_attr = { .ingress = 1 };
+struct flow_patterns patterns = { .cnt = 0 };
+struct flow_actions actions = { .cnt = 0 };

[Darrell] I understand your good point about succinctness.
 Prior art seems to be towards showing all used members because
 it makes it clear nothing was missed and initializing to zero 
was intentional.


> +struct rte_flow *flow;
> +struct rte_flow_error error;
> +uint8_t *ipv4_next_proto_mask = NULL;
> +int ret = 0;
> +
> +/* Eth */
> +struct rte_flow_item_eth eth_spec;
> +struct rte_flow_item_eth eth_mask;

Empty line here please.

> +memset(ð_mask, 0, sizeof(eth_mask));
> +if (match->wc.masks.dl_src.be16[0] ||
> +match->wc.masks.dl_src.be16[1] ||
> +match->wc.masks.dl_src.be16[2] ||
> +match->wc.masks.dl_dst.be16[0] ||
> +match->wc.masks.dl_dst.be16[1] ||
> +match->wc.masks.dl_dst.be16[2]) {

It looks like eth_addr_is_zero() can be used in the above.

> +rte_memcpy(ð_spec.dst, &match->flow.dl_dst, 
sizeof(eth_spec.dst));
> +rte_memcpy(ð_spec.src, &match->flow.dl_src, 
sizeof(eth_spec.src));
> +eth_spec.type = match->flow.dl_type;
> +
> +rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
> +   sizeof(eth_mask.dst));
> +rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
> +   sizeof(eth_mask.src));
> +eth_mask.type = match->wc.masks.dl_type;
> +
> +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
> + ð_spec, ð_mask);
> +} else {
> +/*
> + * If user specifies a flow (like UDP flow) without L2 patterns,
> + * OVS will at least set the dl_type. Normally, it's enough to
> + * create an eth pattern just with it. Unluckily, some Intel's
> + * NIC (such as XL710) doesn't support that. Below is a 
workaround,
> + * which simply matches any L2 pkts.
> + */
> +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL);
> +}

This feels a lot like a layer violation - making the core aware
of specific implementation details of lower layers.

From a functional point of view, is the idea that
a eth_type+5-tuple match is converted to a 5-tuple match?

> +
> +/* VLAN */
> +struct rte_flow_item_vlan vlan_spec;
> +struct rte_flow_item_vlan vlan_mask;

Please declare all local variables at the top of the context
(in this case function).

[Darrell] In OVS, we try to keep the variable declarations as close to their 
usage as possible, including inside condition checks when 
appropriate.
This is easily forgotten and sometimes missed in review.

...

> +struct rte_flow_item_udp udp_spec;
> +struct rte_flow_item_udp udp_mask;
> +memset(&udp_mask, 0, sizeof(udp_mask));
> +if ((proto == IPPROTO_UDP) &&
> +(match->wc.masks.tp_src || match->wc.masks.tp_dst)) {
> +udp_spec.hdr.src_port = match->flow.tp_src;
> +udp_spec.hdr.dst_port = match->flow.tp_dst;
> +
> +udp_mask.hdr.src_port = match->wc.masks.tp_src;
> +udp_mask.hdr.dst_port = match-

Re: [ovs-dev] [PATCH v2 4/8] netdev-dpdk: implement flow put with rte flow

2017-09-08 Thread Simon Horman
On Tue, Sep 05, 2017 at 05:22:57PM +0800, Yuanhan Liu wrote:
> From: Finn Christensen 
> 
> The basic yet the major part of this patch is to translate the "match"
> to rte flow patterns. And then, we create a rte flow with a MARK action.
> Afterwards, all pkts matches the flow will have the mark id in the mbuf.
> 
> For any unsupported flows, such as MPLS, -1 is returned, meaning the
> flow offload is failed and then skipped.

...

> +static int
> +netdev_dpdk_add_rte_flow_offload(struct netdev *netdev,
> + const struct match *match,
> + struct nlattr *nl_actions OVS_UNUSED,
> + size_t actions_len,
> + const ovs_u128 *ufid,
> + struct offload_info *info)
> +{
> +struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
> +const struct rte_flow_attr flow_attr = {
> +.group = 0,
> +.priority = 0,
> +.ingress = 1,
> +.egress = 0
> +};
> +struct flow_patterns patterns = { .items = NULL, .cnt = 0 };
> +struct flow_actions actions = { .actions = NULL, .cnt = 0 };

I believe the following will give the same result as the above,
less verbosely.

+const struct rte_flow_attr flow_attr = { .ingress = 1 };
+struct flow_patterns patterns = { .cnt = 0 };
+struct flow_actions actions = { .cnt = 0 };

> +struct rte_flow *flow;
> +struct rte_flow_error error;
> +uint8_t *ipv4_next_proto_mask = NULL;
> +int ret = 0;
> +
> +/* Eth */
> +struct rte_flow_item_eth eth_spec;
> +struct rte_flow_item_eth eth_mask;

Empty line here please.

> +memset(ð_mask, 0, sizeof(eth_mask));
> +if (match->wc.masks.dl_src.be16[0] ||
> +match->wc.masks.dl_src.be16[1] ||
> +match->wc.masks.dl_src.be16[2] ||
> +match->wc.masks.dl_dst.be16[0] ||
> +match->wc.masks.dl_dst.be16[1] ||
> +match->wc.masks.dl_dst.be16[2]) {

It looks like eth_addr_is_zero() can be used in the above.

> +rte_memcpy(ð_spec.dst, &match->flow.dl_dst, sizeof(eth_spec.dst));
> +rte_memcpy(ð_spec.src, &match->flow.dl_src, sizeof(eth_spec.src));
> +eth_spec.type = match->flow.dl_type;
> +
> +rte_memcpy(ð_mask.dst, &match->wc.masks.dl_dst,
> +   sizeof(eth_mask.dst));
> +rte_memcpy(ð_mask.src, &match->wc.masks.dl_src,
> +   sizeof(eth_mask.src));
> +eth_mask.type = match->wc.masks.dl_type;
> +
> +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH,
> + ð_spec, ð_mask);
> +} else {
> +/*
> + * If user specifies a flow (like UDP flow) without L2 patterns,
> + * OVS will at least set the dl_type. Normally, it's enough to
> + * create an eth pattern just with it. Unluckily, some Intel's
> + * NIC (such as XL710) doesn't support that. Below is a workaround,
> + * which simply matches any L2 pkts.
> + */
> +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_ETH, NULL, NULL);
> +}

This feels a lot like a layer violation - making the core aware
of specific implementation details of lower layers.

>From a functional point of view, is the idea that
a eth_type+5-tuple match is converted to a 5-tuple match?

> +
> +/* VLAN */
> +struct rte_flow_item_vlan vlan_spec;
> +struct rte_flow_item_vlan vlan_mask;

Please declare all local variables at the top of the context
(in this case function).

...

> +struct rte_flow_item_udp udp_spec;
> +struct rte_flow_item_udp udp_mask;
> +memset(&udp_mask, 0, sizeof(udp_mask));
> +if ((proto == IPPROTO_UDP) &&
> +(match->wc.masks.tp_src || match->wc.masks.tp_dst)) {
> +udp_spec.hdr.src_port = match->flow.tp_src;
> +udp_spec.hdr.dst_port = match->flow.tp_dst;
> +
> +udp_mask.hdr.src_port = match->wc.masks.tp_src;
> +udp_mask.hdr.dst_port = match->wc.masks.tp_dst;
> +
> +add_flow_pattern(&patterns, RTE_FLOW_ITEM_TYPE_UDP,
> + &udp_spec, &udp_mask);
> +
> +/* proto == UDP and ITEM_TYPE_UDP, thus no need for proto match */
> +if (ipv4_next_proto_mask) {
> +*ipv4_next_proto_mask = 0;

I think this should be:

+*ipv4_next_proto_mask = NULL;

> +}
> +}
> +
> +struct rte_flow_item_sctp sctp_spec;
> +struct rte_flow_item_sctp sctp_mask;
> +memset(&sctp_mask, 0, sizeof(sctp_mask));
> +if ((proto == IPPROTO_SCTP) &&

It seems there are unnecessary () in the line above.

...

> +/*
> + * Validate for later rte flow offload creation. If any unsupported
> + * flow are specified, return -1.
> + */
> +static int
> +netdev_dpdk_validate_flow(const struct match *match)
> +{
> +struct match match_zero_wc;
> +
> +/* Create a wc-zeroed version of flow */
> +match_init(&match_zero_wc, &match->flow, &match->wc);
> +
> +#define CHECK_NONZE