mlxsw: spectrum_acl: Add multicast router profile operations
authorNir Dotan <nird@mellanox.com>
Mon, 10 Dec 2018 07:11:40 +0000 (07:11 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 12 Dec 2018 07:01:33 +0000 (23:01 -0800)
Add specific ACL operations needed for programming multicast routing ACL
groups and routes.

Signed-off-by: Nir Dotan <nird@mellanox.com>
Reviewed-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.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c

index 2d8f369..fa60c74 100644 (file)
@@ -572,6 +572,7 @@ struct mlxsw_sp_acl_ruleset;
 /* spectrum_acl.c */
 enum mlxsw_sp_acl_profile {
        MLXSW_SP_ACL_PROFILE_FLOWER,
+       MLXSW_SP_ACL_PROFILE_MR,
 };
 
 struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl);
index e171513..015cf9a 100644 (file)
@@ -848,6 +848,15 @@ struct mlxsw_sp_acl_tcam_flower_rule {
        struct mlxsw_sp_acl_tcam_entry entry;
 };
 
+struct mlxsw_sp_acl_tcam_mr_ruleset {
+       struct mlxsw_sp_acl_tcam_chunk *chunk;
+       struct mlxsw_sp_acl_tcam_group group;
+};
+
+struct mlxsw_sp_acl_tcam_mr_rule {
+       struct mlxsw_sp_acl_tcam_entry entry;
+};
+
 static int
 mlxsw_sp_acl_tcam_flower_ruleset_add(struct mlxsw_sp *mlxsw_sp,
                                     struct mlxsw_sp_acl_tcam *tcam,
@@ -952,9 +961,129 @@ static const struct mlxsw_sp_acl_profile_ops mlxsw_sp_acl_tcam_flower_ops = {
        .rule_activity_get      = mlxsw_sp_acl_tcam_flower_rule_activity_get,
 };
 
+static int
+mlxsw_sp_acl_tcam_mr_ruleset_add(struct mlxsw_sp *mlxsw_sp,
+                                struct mlxsw_sp_acl_tcam *tcam,
+                                void *ruleset_priv,
+                                struct mlxsw_afk_element_usage *tmplt_elusage)
+{
+       struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
+       int err;
+
+       err = mlxsw_sp_acl_tcam_group_add(mlxsw_sp, tcam, &ruleset->group,
+                                         mlxsw_sp_acl_tcam_patterns,
+                                         MLXSW_SP_ACL_TCAM_PATTERNS_COUNT,
+                                         tmplt_elusage);
+       if (err)
+               return err;
+
+       /* For most of the TCAM clients it would make sense to take a tcam chunk
+        * only when the first rule is written. This is not the case for
+        * multicast router as it is required to bind the multicast router to a
+        * specific ACL Group ID which must exist in HW before multicast router
+        * is initialized.
+        */
+       ruleset->chunk = mlxsw_sp_acl_tcam_chunk_get(mlxsw_sp, &ruleset->group,
+                                                    1, tmplt_elusage);
+       if (IS_ERR(ruleset->chunk)) {
+               err = PTR_ERR(ruleset->chunk);
+               goto err_chunk_get;
+       }
+
+       return 0;
+
+err_chunk_get:
+       mlxsw_sp_acl_tcam_group_del(mlxsw_sp, &ruleset->group);
+       return err;
+}
+
+static void
+mlxsw_sp_acl_tcam_mr_ruleset_del(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv)
+{
+       struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
+
+       mlxsw_sp_acl_tcam_chunk_put(mlxsw_sp, ruleset->chunk);
+       mlxsw_sp_acl_tcam_group_del(mlxsw_sp, &ruleset->group);
+}
+
+static int
+mlxsw_sp_acl_tcam_mr_ruleset_bind(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
+                                 struct mlxsw_sp_port *mlxsw_sp_port,
+                                 bool ingress)
+{
+       /* Binding is done when initializing multicast router */
+       return 0;
+}
+
+static void
+mlxsw_sp_acl_tcam_mr_ruleset_unbind(struct mlxsw_sp *mlxsw_sp,
+                                   void *ruleset_priv,
+                                   struct mlxsw_sp_port *mlxsw_sp_port,
+                                   bool ingress)
+{
+}
+
+static u16
+mlxsw_sp_acl_tcam_mr_ruleset_group_id(void *ruleset_priv)
+{
+       struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
+
+       return mlxsw_sp_acl_tcam_group_id(&ruleset->group);
+}
+
+static size_t mlxsw_sp_acl_tcam_mr_rule_priv_size(struct mlxsw_sp *mlxsw_sp)
+{
+       return sizeof(struct mlxsw_sp_acl_tcam_mr_rule) +
+              mlxsw_sp_acl_tcam_entry_priv_size(mlxsw_sp);
+}
+
+static int
+mlxsw_sp_acl_tcam_mr_rule_add(struct mlxsw_sp *mlxsw_sp, void *ruleset_priv,
+                             void *rule_priv,
+                             struct mlxsw_sp_acl_rule_info *rulei)
+{
+       struct mlxsw_sp_acl_tcam_mr_ruleset *ruleset = ruleset_priv;
+       struct mlxsw_sp_acl_tcam_mr_rule *rule = rule_priv;
+
+       return mlxsw_sp_acl_tcam_entry_add(mlxsw_sp, &ruleset->group,
+                                          &rule->entry, rulei);
+}
+
+static void
+mlxsw_sp_acl_tcam_mr_rule_del(struct mlxsw_sp *mlxsw_sp, void *rule_priv)
+{
+       struct mlxsw_sp_acl_tcam_mr_rule *rule = rule_priv;
+
+       mlxsw_sp_acl_tcam_entry_del(mlxsw_sp, &rule->entry);
+}
+
+static int
+mlxsw_sp_acl_tcam_mr_rule_activity_get(struct mlxsw_sp *mlxsw_sp,
+                                      void *rule_priv, bool *activity)
+{
+       struct mlxsw_sp_acl_tcam_mr_rule *rule = rule_priv;
+
+       return mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp, &rule->entry,
+                                                   activity);
+}
+
+static const struct mlxsw_sp_acl_profile_ops mlxsw_sp_acl_tcam_mr_ops = {
+       .ruleset_priv_size      = sizeof(struct mlxsw_sp_acl_tcam_mr_ruleset),
+       .ruleset_add            = mlxsw_sp_acl_tcam_mr_ruleset_add,
+       .ruleset_del            = mlxsw_sp_acl_tcam_mr_ruleset_del,
+       .ruleset_bind           = mlxsw_sp_acl_tcam_mr_ruleset_bind,
+       .ruleset_unbind         = mlxsw_sp_acl_tcam_mr_ruleset_unbind,
+       .ruleset_group_id       = mlxsw_sp_acl_tcam_mr_ruleset_group_id,
+       .rule_priv_size         = mlxsw_sp_acl_tcam_mr_rule_priv_size,
+       .rule_add               = mlxsw_sp_acl_tcam_mr_rule_add,
+       .rule_del               = mlxsw_sp_acl_tcam_mr_rule_del,
+       .rule_activity_get      = mlxsw_sp_acl_tcam_mr_rule_activity_get,
+};
+
 static const struct mlxsw_sp_acl_profile_ops *
 mlxsw_sp_acl_tcam_profile_ops_arr[] = {
        [MLXSW_SP_ACL_PROFILE_FLOWER] = &mlxsw_sp_acl_tcam_flower_ops,
+       [MLXSW_SP_ACL_PROFILE_MR] = &mlxsw_sp_acl_tcam_mr_ops,
 };
 
 const struct mlxsw_sp_acl_profile_ops *