mlxsw: spectrum_acl: Track rules that forbid egress block bind
authorJiri Pirko <jiri@mellanox.com>
Sat, 27 Jul 2019 17:32:56 +0000 (20:32 +0300)
committerDavid S. Miller <davem@davemloft.net>
Sat, 27 Jul 2019 21:32:31 +0000 (14:32 -0700)
Some matches and actions are not supported on egress. Track such rules
and forbid a bind of block which contains them to egress.

With this patch, the kernel tells the user he cannot do that:
$ tc qdisc add dev ens16np1 ingress_block 22 clsact
$ tc filter add block 22 protocol 802.1q pref 2 handle 101 flower vlan_id 100 skip_sw action pass
$ tc qdisc add dev ens16np2 egress_block 22 clsact
Error: mlxsw_spectrum: Block cannot be bound to egress because it contains unsupported rules.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c

index 7e8a54068d922c59d1c1bb4fb1df1d2f14a8e398..9277b3f125e8fee75a429f9f71a4aa1a7d2238bb 100644 (file)
@@ -1625,7 +1625,7 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
        }
        flow_block_cb_incref(block_cb);
        err = mlxsw_sp_acl_block_bind(mlxsw_sp, acl_block,
-                                     mlxsw_sp_port, ingress);
+                                     mlxsw_sp_port, ingress, f->extack);
        if (err)
                goto err_block_bind;
 
index 131f62ce9297a05e0ba5406995beb1a16c14bdfa..c78d93afbb9deb5e40d8d3b612d0232c78672b22 100644 (file)
@@ -623,7 +623,8 @@ struct mlxsw_sp_acl_rule_info {
        unsigned int priority;
        struct mlxsw_afk_element_values values;
        struct mlxsw_afa_block *act_block;
-       u8 action_created:1;
+       u8 action_created:1,
+          egress_bind_blocker:1;
        unsigned int counter_index;
 };
 
@@ -642,6 +643,7 @@ struct mlxsw_sp_acl_block {
        struct mlxsw_sp *mlxsw_sp;
        unsigned int rule_count;
        unsigned int disable_count;
+       unsigned int egress_blocker_rule_count;
        struct net *net;
 };
 
@@ -657,7 +659,8 @@ void mlxsw_sp_acl_block_destroy(struct mlxsw_sp_acl_block *block);
 int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp,
                            struct mlxsw_sp_acl_block *block,
                            struct mlxsw_sp_port *mlxsw_sp_port,
-                           bool ingress);
+                           bool ingress,
+                           struct netlink_ext_ack *extack);
 int mlxsw_sp_acl_block_unbind(struct mlxsw_sp *mlxsw_sp,
                              struct mlxsw_sp_acl_block *block,
                              struct mlxsw_sp_port *mlxsw_sp_port,
index e8ac90564dbe5ee36d3206542fa06145b51bfb3b..1aaab84462708ca43a99ef029db7e8a21c94f1f7 100644 (file)
@@ -239,7 +239,8 @@ mlxsw_sp_acl_block_lookup(struct mlxsw_sp_acl_block *block,
 int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp,
                            struct mlxsw_sp_acl_block *block,
                            struct mlxsw_sp_port *mlxsw_sp_port,
-                           bool ingress)
+                           bool ingress,
+                           struct netlink_ext_ack *extack)
 {
        struct mlxsw_sp_acl_block_binding *binding;
        int err;
@@ -247,6 +248,11 @@ int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp,
        if (WARN_ON(mlxsw_sp_acl_block_lookup(block, mlxsw_sp_port, ingress)))
                return -EEXIST;
 
+       if (!ingress && block->egress_blocker_rule_count) {
+               NL_SET_ERR_MSG_MOD(extack, "Block cannot be bound to egress because it contains unsupported rules");
+               return -EOPNOTSUPP;
+       }
+
        binding = kzalloc(sizeof(*binding), GFP_KERNEL);
        if (!binding)
                return -ENOMEM;
@@ -672,6 +678,7 @@ int mlxsw_sp_acl_rule_add(struct mlxsw_sp *mlxsw_sp,
 {
        struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
        const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
+       struct mlxsw_sp_acl_block *block = ruleset->ht_key.block;
        int err;
 
        err = ops->rule_add(mlxsw_sp, ruleset->priv, rule->priv, rule->rulei);
@@ -689,14 +696,14 @@ int mlxsw_sp_acl_rule_add(struct mlxsw_sp *mlxsw_sp,
                 * one, to be directly bound to device. The rest of the
                 * rulesets are bound by "Goto action set".
                 */
-               err = mlxsw_sp_acl_ruleset_block_bind(mlxsw_sp, ruleset,
-                                                     ruleset->ht_key.block);
+               err = mlxsw_sp_acl_ruleset_block_bind(mlxsw_sp, ruleset, block);
                if (err)
                        goto err_ruleset_block_bind;
        }
 
        list_add_tail(&rule->list, &mlxsw_sp->acl->rules);
-       ruleset->ht_key.block->rule_count++;
+       block->rule_count++;
+       block->egress_blocker_rule_count += rule->rulei->egress_bind_blocker;
        return 0;
 
 err_ruleset_block_bind:
@@ -712,7 +719,9 @@ void mlxsw_sp_acl_rule_del(struct mlxsw_sp *mlxsw_sp,
 {
        struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
        const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
+       struct mlxsw_sp_acl_block *block = ruleset->ht_key.block;
 
+       block->egress_blocker_rule_count -= rule->rulei->egress_bind_blocker;
        ruleset->ht_key.block->rule_count--;
        list_del(&rule->list);
        if (!ruleset->ht_key.chain_index &&
index 1eeac8a36ead4983bdafbb641859ba4447ee18cd..c86d582dafbebf90758e7a198d475e7e8b20a5ba 100644 (file)
@@ -83,6 +83,11 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
                                return -EOPNOTSUPP;
                        }
 
+                       /* Forbid block with this rulei to be bound
+                        * to egress in future.
+                        */
+                       rulei->egress_bind_blocker = 1;
+
                        fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp);
                        fid_index = mlxsw_sp_fid_index(fid);
                        err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei,
@@ -395,6 +400,12 @@ static int mlxsw_sp_flower_parse(struct mlxsw_sp *mlxsw_sp,
                        NL_SET_ERR_MSG_MOD(f->common.extack, "vlan_id key is not supported on egress");
                        return -EOPNOTSUPP;
                }
+
+               /* Forbid block with this rulei to be bound
+                * to egress in future.
+                */
+               rulei->egress_bind_blocker = 1;
+
                if (match.mask->vlan_id != 0)
                        mlxsw_sp_acl_rulei_keymask_u32(rulei,
                                                       MLXSW_AFK_ELEMENT_VID,