Re: [PATCH net-next V2] cls_flower: Support multiple masks per priority

2018-05-01 Thread David Miller
From: Paul Blakey 
Date: Mon, 30 Apr 2018 14:28:30 +0300

> Currently flower doesn't support inserting filters with different masks
> on a single priority, even if the actual flows (key + mask) inserted
> aren't overlapping, as with the use case of offloading openvswitch
> datapath flows. Instead one must go up one level, and assign different
> priorities for each mask, which will create a different flower
> instances.
> 
> This patch opens flower to support more than one mask per priority,
> and a single flower instance. It does so by adding another hash table
> on top of the existing one which will store the different masks,
> and the filters that share it.
> 
> The user is left with the responsibility of ensuring non overlapping
> flows, otherwise precedence is not guaranteed.
> 
> Signed-off-by: Paul Blakey 
> Signed-off-by: Jiri Pirko 
> ---
> 
> Changes:
> V1 -> V2: in fl_init, removed unnessecry err variable, just return direct 
> result instead.
>   in fl_mask_range, removed extra new line.
>   commit msg, spelling.

Applied, thanks.


[PATCH net-next V2] cls_flower: Support multiple masks per priority

2018-04-30 Thread Paul Blakey
Currently flower doesn't support inserting filters with different masks
on a single priority, even if the actual flows (key + mask) inserted
aren't overlapping, as with the use case of offloading openvswitch
datapath flows. Instead one must go up one level, and assign different
priorities for each mask, which will create a different flower
instances.

This patch opens flower to support more than one mask per priority,
and a single flower instance. It does so by adding another hash table
on top of the existing one which will store the different masks,
and the filters that share it.

The user is left with the responsibility of ensuring non overlapping
flows, otherwise precedence is not guaranteed.

Signed-off-by: Paul Blakey 
Signed-off-by: Jiri Pirko 
---

Changes:
V1 -> V2: in fl_init, removed unnessecry err variable, just return direct 
result instead.
  in fl_mask_range, removed extra new line.
  commit msg, spelling.

 net/sched/cls_flower.c | 275 +++--
 1 file changed, 174 insertions(+), 101 deletions(-)

diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c
index d964e60..eacaaf8 100644
--- a/net/sched/cls_flower.c
+++ b/net/sched/cls_flower.c
@@ -61,16 +61,18 @@ struct fl_flow_mask_range {
 struct fl_flow_mask {
struct fl_flow_key key;
struct fl_flow_mask_range range;
-   struct rcu_head rcu;
+   struct rhash_head ht_node;
+   struct rhashtable ht;
+   struct rhashtable_params filter_ht_params;
+   struct flow_dissector dissector;
+   struct list_head filters;
+   struct rcu_head rcu;
+   struct list_head list;
 };
 
 struct cls_fl_head {
struct rhashtable ht;
-   struct fl_flow_mask mask;
-   struct flow_dissector dissector;
-   bool mask_assigned;
-   struct list_head filters;
-   struct rhashtable_params ht_params;
+   struct list_head masks;
union {
struct work_struct work;
struct rcu_head rcu;
@@ -79,6 +81,7 @@ struct cls_fl_head {
 };
 
 struct cls_fl_filter {
+   struct fl_flow_mask *mask;
struct rhash_head ht_node;
struct fl_flow_key mkey;
struct tcf_exts exts;
@@ -94,6 +97,13 @@ struct cls_fl_filter {
struct net_device *hw_dev;
 };
 
+static const struct rhashtable_params mask_ht_params = {
+   .key_offset = offsetof(struct fl_flow_mask, key),
+   .key_len = sizeof(struct fl_flow_key),
+   .head_offset = offsetof(struct fl_flow_mask, ht_node),
+   .automatic_shrinking = true,
+};
+
 static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
 {
return mask->range.end - mask->range.start;
@@ -103,13 +113,19 @@ static void fl_mask_update_range(struct fl_flow_mask 
*mask)
 {
const u8 *bytes = (const u8 *) &mask->key;
size_t size = sizeof(mask->key);
-   size_t i, first = 0, last = size - 1;
+   size_t i, first = 0, last;
 
-   for (i = 0; i < sizeof(mask->key); i++) {
+   for (i = 0; i < size; i++) {
+   if (bytes[i]) {
+   first = i;
+   break;
+   }
+   }
+   last = first;
+   for (i = size - 1; i != first; i--) {
if (bytes[i]) {
-   if (!first && i)
-   first = i;
last = i;
+   break;
}
}
mask->range.start = rounddown(first, sizeof(long));
@@ -140,12 +156,11 @@ static void fl_clear_masked_range(struct fl_flow_key *key,
memset(fl_key_get_start(key, mask), 0, fl_mask_range(mask));
 }
 
-static struct cls_fl_filter *fl_lookup(struct cls_fl_head *head,
+static struct cls_fl_filter *fl_lookup(struct fl_flow_mask *mask,
   struct fl_flow_key *mkey)
 {
-   return rhashtable_lookup_fast(&head->ht,
- fl_key_get_start(mkey, &head->mask),
- head->ht_params);
+   return rhashtable_lookup_fast(&mask->ht, fl_key_get_start(mkey, mask),
+ mask->filter_ht_params);
 }
 
 static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp,
@@ -153,28 +168,28 @@ static int fl_classify(struct sk_buff *skb, const struct 
tcf_proto *tp,
 {
struct cls_fl_head *head = rcu_dereference_bh(tp->root);
struct cls_fl_filter *f;
+   struct fl_flow_mask *mask;
struct fl_flow_key skb_key;
struct fl_flow_key skb_mkey;
 
-   if (!atomic_read(&head->ht.nelems))
-   return -1;
-
-   fl_clear_masked_range(&skb_key, &head->mask);
+   list_for_each_entry_rcu(mask, &head->masks, list) {
+   fl_clear_masked_range(&skb_key, mask);
 
-   skb_key.indev_ifindex = skb->skb_iif;
-   /* skb_flow_dissect() does not set n_proto in case an unknown protocol,
-* so do it rather here.
-*/
-