]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: prestera: acl: add support for 'egress' rules
authorMaksym Glubokiy <maksym.glubokiy@plvision.eu>
Mon, 27 Jun 2022 09:50:18 +0000 (12:50 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 29 Jun 2022 13:02:37 +0000 (14:02 +0100)
The following is now supported:

  $ tc qdisc add PORT clsact
  $ tc filter add dev PORT egress ...

Signed-off-by: Maksym Glubokiy <maksym.glubokiy@plvision.eu>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/marvell/prestera/prestera.h
drivers/net/ethernet/marvell/prestera/prestera_acl.c
drivers/net/ethernet/marvell/prestera/prestera_acl.h
drivers/net/ethernet/marvell/prestera/prestera_flow.c
drivers/net/ethernet/marvell/prestera/prestera_flow.h
drivers/net/ethernet/marvell/prestera/prestera_flower.c
drivers/net/ethernet/marvell/prestera/prestera_hw.h

index 6f754ae2a5848ba7c840b475d3e60db158a50a11..0bb46eee46b4d8f51d363c44ffe1603aba1dc060 100644 (file)
@@ -107,7 +107,8 @@ struct prestera_port_phy_config {
 struct prestera_port {
        struct net_device *dev;
        struct prestera_switch *sw;
-       struct prestera_flow_block *flow_block;
+       struct prestera_flow_block *ingress_flow_block;
+       struct prestera_flow_block *egress_flow_block;
        struct devlink_port dl_port;
        struct list_head lag_member;
        struct prestera_lag *lag;
index 3a141f2db81269286d2b16d254b1d1555534a985..3d4b85f2d54147b3659091e54dee58f38c064e28 100644 (file)
@@ -61,6 +61,7 @@ struct prestera_acl_ruleset {
        u32 index;
        u16 pcl_id;
        bool offload;
+       bool ingress;
 };
 
 struct prestera_acl_vtcam {
@@ -70,6 +71,7 @@ struct prestera_acl_vtcam {
        u32 id;
        bool is_keymask_set;
        u8 lookup;
+       u8 direction;
 };
 
 static const struct rhashtable_params prestera_acl_ruleset_ht_params = {
@@ -93,23 +95,36 @@ static const struct rhashtable_params __prestera_acl_rule_entry_ht_params = {
        .automatic_shrinking = true,
 };
 
-int prestera_acl_chain_to_client(u32 chain_index, u32 *client)
+int prestera_acl_chain_to_client(u32 chain_index, bool ingress, u32 *client)
 {
-       static const u32 client_map[] = {
-               PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0,
-               PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1,
-               PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2
+       static const u32 ingress_client_map[] = {
+               PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_0,
+               PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_1,
+               PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_2
        };
 
-       if (chain_index >= ARRAY_SIZE(client_map))
+       if (!ingress) {
+               /* prestera supports only one chain on egress */
+               if (chain_index > 0)
+                       return -EINVAL;
+
+               *client = PRESTERA_HW_COUNTER_CLIENT_EGRESS_LOOKUP;
+               return 0;
+       }
+
+       if (chain_index >= ARRAY_SIZE(ingress_client_map))
                return -EINVAL;
 
-       *client = client_map[chain_index];
+       *client = ingress_client_map[chain_index];
        return 0;
 }
 
-static bool prestera_acl_chain_is_supported(u32 chain_index)
+static bool prestera_acl_chain_is_supported(u32 chain_index, bool ingress)
 {
+       if (!ingress)
+               /* prestera supports only one chain on egress */
+               return chain_index == 0;
+
        return (chain_index & ~PRESTERA_ACL_CHAIN_MASK) == 0;
 }
 
@@ -122,7 +137,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
        u32 uid = 0;
        int err;
 
-       if (!prestera_acl_chain_is_supported(chain_index))
+       if (!prestera_acl_chain_is_supported(chain_index, block->ingress))
                return ERR_PTR(-EINVAL);
 
        ruleset = kzalloc(sizeof(*ruleset), GFP_KERNEL);
@@ -130,6 +145,7 @@ prestera_acl_ruleset_create(struct prestera_acl *acl,
                return ERR_PTR(-ENOMEM);
 
        ruleset->acl = acl;
+       ruleset->ingress = block->ingress;
        ruleset->ht_key.block = block;
        ruleset->ht_key.chain_index = chain_index;
        refcount_set(&ruleset->refcount, 1);
@@ -172,13 +188,18 @@ int prestera_acl_ruleset_offload(struct prestera_acl_ruleset *ruleset)
 {
        struct prestera_acl_iface iface;
        u32 vtcam_id;
+       int dir;
        int err;
 
+       dir = ruleset->ingress ?
+               PRESTERA_HW_VTCAM_DIR_INGRESS : PRESTERA_HW_VTCAM_DIR_EGRESS;
+
        if (ruleset->offload)
                return -EEXIST;
 
        err = prestera_acl_vtcam_id_get(ruleset->acl,
                                        ruleset->ht_key.chain_index,
+                                       dir,
                                        ruleset->keymask, &vtcam_id);
        if (err)
                goto err_vtcam_create;
@@ -719,7 +740,7 @@ vtcam_found:
        return 0;
 }
 
-int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
+int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, u8 dir,
                              void *keymask, u32 *vtcam_id)
 {
        struct prestera_acl_vtcam *vtcam;
@@ -731,7 +752,8 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
         * fine for now
         */
        list_for_each_entry(vtcam, &acl->vtcam_list, list) {
-               if (lookup != vtcam->lookup)
+               if (lookup != vtcam->lookup ||
+                   dir != vtcam->direction)
                        continue;
 
                if (!keymask && !vtcam->is_keymask_set) {
@@ -752,7 +774,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
                return -ENOMEM;
 
        err = prestera_hw_vtcam_create(acl->sw, lookup, keymask, &new_vtcam_id,
-                                      PRESTERA_HW_VTCAM_DIR_INGRESS);
+                                      dir);
        if (err) {
                kfree(vtcam);
 
@@ -765,6 +787,7 @@ int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
                return 0;
        }
 
+       vtcam->direction = dir;
        vtcam->id = new_vtcam_id;
        vtcam->lookup = lookup;
        if (keymask) {
index f963e1e0c0f0b1f4ffd9baf0da83014bd33d4e45..03fc5b9dc9258686944d1fd41def03d59fb3e795 100644 (file)
@@ -199,9 +199,9 @@ void
 prestera_acl_rule_keymask_pcl_id_set(struct prestera_acl_rule *rule,
                                     u16 pcl_id);
 
-int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup,
+int prestera_acl_vtcam_id_get(struct prestera_acl *acl, u8 lookup, u8 dir,
                              void *keymask, u32 *vtcam_id);
 int prestera_acl_vtcam_id_put(struct prestera_acl *acl, u32 vtcam_id);
-int prestera_acl_chain_to_client(u32 chain_index, u32 *client);
+int prestera_acl_chain_to_client(u32 chain_index, bool ingress, u32 *client);
 
 #endif /* _PRESTERA_ACL_H_ */
index 05c3ad98eba9e088371170198a089358f075ec4a..2262693bd5cfb56cb051b94c5902072f89649a77 100644 (file)
@@ -75,7 +75,9 @@ static void prestera_flow_block_destroy(void *cb_priv)
 }
 
 static struct prestera_flow_block *
-prestera_flow_block_create(struct prestera_switch *sw, struct net *net)
+prestera_flow_block_create(struct prestera_switch *sw,
+                          struct net *net,
+                          bool ingress)
 {
        struct prestera_flow_block *block;
 
@@ -87,6 +89,7 @@ prestera_flow_block_create(struct prestera_switch *sw, struct net *net)
        INIT_LIST_HEAD(&block->template_list);
        block->net = net;
        block->sw = sw;
+       block->ingress = ingress;
 
        return block;
 }
@@ -165,7 +168,8 @@ static int prestera_flow_block_unbind(struct prestera_flow_block *block,
 static struct prestera_flow_block *
 prestera_flow_block_get(struct prestera_switch *sw,
                        struct flow_block_offload *f,
-                       bool *register_block)
+                       bool *register_block,
+                       bool ingress)
 {
        struct prestera_flow_block *block;
        struct flow_block_cb *block_cb;
@@ -173,7 +177,7 @@ prestera_flow_block_get(struct prestera_switch *sw,
        block_cb = flow_block_cb_lookup(f->block,
                                        prestera_flow_block_cb, sw);
        if (!block_cb) {
-               block = prestera_flow_block_create(sw, f->net);
+               block = prestera_flow_block_create(sw, f->net, ingress);
                if (!block)
                        return ERR_PTR(-ENOMEM);
 
@@ -209,7 +213,7 @@ static void prestera_flow_block_put(struct prestera_flow_block *block)
 }
 
 static int prestera_setup_flow_block_bind(struct prestera_port *port,
-                                         struct flow_block_offload *f)
+                                         struct flow_block_offload *f, bool ingress)
 {
        struct prestera_switch *sw = port->sw;
        struct prestera_flow_block *block;
@@ -217,7 +221,7 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
        bool register_block;
        int err;
 
-       block = prestera_flow_block_get(sw, f, &register_block);
+       block = prestera_flow_block_get(sw, f, &register_block, ingress);
        if (IS_ERR(block))
                return PTR_ERR(block);
 
@@ -232,7 +236,11 @@ static int prestera_setup_flow_block_bind(struct prestera_port *port,
                list_add_tail(&block_cb->driver_list, &prestera_block_cb_list);
        }
 
-       port->flow_block = block;
+       if (ingress)
+               port->ingress_flow_block = block;
+       else
+               port->egress_flow_block = block;
+
        return 0;
 
 err_block_bind:
@@ -242,7 +250,7 @@ err_block_bind:
 }
 
 static void prestera_setup_flow_block_unbind(struct prestera_port *port,
-                                            struct flow_block_offload *f)
+                                            struct flow_block_offload *f, bool ingress)
 {
        struct prestera_switch *sw = port->sw;
        struct prestera_flow_block *block;
@@ -266,24 +274,38 @@ static void prestera_setup_flow_block_unbind(struct prestera_port *port,
                list_del(&block_cb->driver_list);
        }
 error:
-       port->flow_block = NULL;
+       if (ingress)
+               port->ingress_flow_block = NULL;
+       else
+               port->egress_flow_block = NULL;
 }
 
-int prestera_flow_block_setup(struct prestera_port *port,
-                             struct flow_block_offload *f)
+static int prestera_setup_flow_block_clsact(struct prestera_port *port,
+                                           struct flow_block_offload *f,
+                                           bool ingress)
 {
-       if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
-               return -EOPNOTSUPP;
-
        f->driver_block_list = &prestera_block_cb_list;
 
        switch (f->command) {
        case FLOW_BLOCK_BIND:
-               return prestera_setup_flow_block_bind(port, f);
+               return prestera_setup_flow_block_bind(port, f, ingress);
        case FLOW_BLOCK_UNBIND:
-               prestera_setup_flow_block_unbind(port, f);
+               prestera_setup_flow_block_unbind(port, f, ingress);
                return 0;
        default:
                return -EOPNOTSUPP;
        }
 }
+
+int prestera_flow_block_setup(struct prestera_port *port,
+                             struct flow_block_offload *f)
+{
+       switch (f->binder_type) {
+       case FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS:
+               return prestera_setup_flow_block_clsact(port, f, true);
+       case FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS:
+               return prestera_setup_flow_block_clsact(port, f, false);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
index 6550278b166ad96f0099929c4221b6459a8ec507..0c9e13263261df73fe932811352e25a7370a82e7 100644 (file)
@@ -23,6 +23,7 @@ struct prestera_flow_block {
        struct flow_block_cb *block_cb;
        struct list_head template_list;
        unsigned int rule_count;
+       bool ingress;
 };
 
 int prestera_flow_block_setup(struct prestera_port *port,
index d43e503c644f85d496ff55761ca1b7e1d2633af5..a54748ac65412ec6c0bb4668b5f51af38728ef72 100644 (file)
@@ -79,7 +79,7 @@ static int prestera_flower_parse_actions(struct prestera_flow_block *block,
        } else if (act->hw_stats & FLOW_ACTION_HW_STATS_DELAYED) {
                /* setup counter first */
                rule->re_arg.count.valid = true;
-               err = prestera_acl_chain_to_client(chain_index,
+               err = prestera_acl_chain_to_client(chain_index, block->ingress,
                                                   &rule->re_arg.count.client);
                if (err)
                        return err;
index 579d9ba23ffcae8725cb93dc51d7c3485f0ebb85..aa74f668aa3ca7fd9e7047a50daf12a3a7aebc8d 100644 (file)
@@ -123,9 +123,10 @@ enum prestera_hw_vtcam_direction_t {
 };
 
 enum {
-       PRESTERA_HW_COUNTER_CLIENT_LOOKUP_0 = 0,
-       PRESTERA_HW_COUNTER_CLIENT_LOOKUP_1 = 1,
-       PRESTERA_HW_COUNTER_CLIENT_LOOKUP_2 = 2,
+       PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_0 = 0,
+       PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_1 = 1,
+       PRESTERA_HW_COUNTER_CLIENT_INGRESS_LOOKUP_2 = 2,
+       PRESTERA_HW_COUNTER_CLIENT_EGRESS_LOOKUP = 3,
 };
 
 struct prestera_switch;