diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 12711a638d079..299913377b228 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -3,6 +3,7 @@ #include #include +#include #include "en.h" #include "lib/mlx5.h" @@ -22,15 +23,22 @@ struct mlx5e_macsec_sa { struct rhash_head hash; u32 fs_id; - struct mlx5e_macsec_tx_rule *tx_rule; + union mlx5e_macsec_rule *macsec_rule; struct rcu_head rcu_head; }; +struct mlx5e_macsec_rx_sc; +struct mlx5e_macsec_rx_sc_xarray_element { + u32 fs_id; + struct mlx5e_macsec_rx_sc *rx_sc; +}; + struct mlx5e_macsec_rx_sc { bool active; sci_t sci; struct mlx5e_macsec_sa *rx_sa[MACSEC_NUM_AN]; struct list_head rx_sc_list_element; + struct mlx5e_macsec_rx_sc_xarray_element *sc_xarray_element; struct rcu_head rcu_head; }; @@ -54,6 +62,9 @@ struct mlx5e_macsec { /* Tx sci -> fs id mapping handling */ struct rhashtable sci_hash; /* sci -> mlx5e_macsec_sa */ + /* Rx fs_id -> rx_sc mapping */ + struct xarray sc_xarray; + struct mlx5_core_dev *mdev; }; @@ -120,21 +131,25 @@ static void mlx5e_macsec_destroy_object(struct mlx5_core_dev *mdev, u32 macsec_o mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out)); } -static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec, struct mlx5e_macsec_sa *sa) +static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec, + struct mlx5e_macsec_sa *sa, + bool is_tx) { - if (sa->fs_id) { + int action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT : + MLX5_ACCEL_MACSEC_ACTION_DECRYPT; + + if ((is_tx) && sa->fs_id) { /* Make sure ongoing datapath readers sees a valid SA */ rhashtable_remove_fast(&macsec->sci_hash, &sa->hash, rhash_sci); sa->fs_id = 0; } - if (!sa->tx_rule) + if (!sa->macsec_rule) return; - mlx5e_macsec_fs_del_rule(macsec->macsec_fs, sa->tx_rule, - MLX5_ACCEL_MACSEC_ACTION_ENCRYPT); + mlx5e_macsec_fs_del_rule(macsec->macsec_fs, sa->macsec_rule, action); mlx5e_macsec_destroy_object(macsec->mdev, sa->macsec_obj_id); - sa->tx_rule = NULL; + sa->macsec_rule = NULL; } static int mlx5e_macsec_init_sa(struct macsec_context *ctx, @@ -145,9 +160,9 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx, struct mlx5e_priv *priv = netdev_priv(ctx->netdev); struct mlx5e_macsec *macsec = priv->macsec; struct mlx5_macsec_rule_attrs rule_attrs; - struct mlx5e_macsec_tx_rule *tx_rule; struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_macsec_obj_attrs obj_attrs; + union mlx5e_macsec_rule *macsec_rule; int err; obj_attrs.next_pn = sa->next_pn; @@ -161,21 +176,27 @@ static int mlx5e_macsec_init_sa(struct macsec_context *ctx, return err; rule_attrs.macsec_obj_id = sa->macsec_obj_id; - rule_attrs.action = MLX5_ACCEL_MACSEC_ACTION_ENCRYPT; + rule_attrs.sci = sa->sci; + rule_attrs.assoc_num = sa->assoc_num; + rule_attrs.action = (is_tx) ? MLX5_ACCEL_MACSEC_ACTION_ENCRYPT : + MLX5_ACCEL_MACSEC_ACTION_DECRYPT; - tx_rule = mlx5e_macsec_fs_add_rule(macsec->macsec_fs, ctx, &rule_attrs, &sa->fs_id); - if (IS_ERR_OR_NULL(tx_rule)) + macsec_rule = mlx5e_macsec_fs_add_rule(macsec->macsec_fs, ctx, &rule_attrs, &sa->fs_id); + if (IS_ERR_OR_NULL(macsec_rule)) goto destroy_macsec_object; - err = rhashtable_insert_fast(&macsec->sci_hash, &sa->hash, rhash_sci); - if (err) - goto destroy_macsec_rule; + sa->macsec_rule = macsec_rule; + + if (is_tx) { + err = rhashtable_insert_fast(&macsec->sci_hash, &sa->hash, rhash_sci); + if (err) + goto destroy_macsec_object_and_rule; + } - sa->tx_rule = tx_rule; return 0; -destroy_macsec_rule: - mlx5e_macsec_fs_del_rule(macsec->macsec_fs, tx_rule, MLX5_ACCEL_MACSEC_ACTION_ENCRYPT); +destroy_macsec_object_and_rule: + mlx5e_macsec_cleanup_sa(macsec, sa, is_tx); destroy_macsec_object: mlx5e_macsec_destroy_object(mdev, sa->macsec_obj_id); @@ -208,7 +229,7 @@ static int mlx5e_macsec_update_rx_sa(struct mlx5e_macsec *macsec, rx_sa->active = active; if (!active) { - mlx5e_macsec_destroy_object(mdev, rx_sa->macsec_obj_id); + mlx5e_macsec_cleanup_sa(macsec, rx_sa, false); return 0; } @@ -334,10 +355,10 @@ static int mlx5e_macsec_upd_txsa(struct macsec_context *ctx) if (err) goto out; } else { - if (!tx_sa->tx_rule) + if (!tx_sa->macsec_rule) return -EINVAL; - mlx5e_macsec_cleanup_sa(macsec, tx_sa); + mlx5e_macsec_cleanup_sa(macsec, tx_sa, true); } tx_sa->active = ctx_tx_sa->active; @@ -369,7 +390,7 @@ static int mlx5e_macsec_del_txsa(struct macsec_context *ctx) goto out; } - mlx5e_macsec_cleanup_sa(macsec, tx_sa); + mlx5e_macsec_cleanup_sa(macsec, tx_sa, true); mlx5_destroy_encryption_key(macsec->mdev, tx_sa->enc_key_id); kfree_rcu(tx_sa); macsec->tx_sa[assoc_num] = NULL; @@ -396,6 +417,7 @@ static u32 mlx5e_macsec_get_sa_from_hashtable(struct rhashtable *sci_hash, sci_t static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx) { + struct mlx5e_macsec_rx_sc_xarray_element *sc_xarray_element; struct mlx5e_priv *priv = netdev_priv(ctx->netdev); const struct macsec_rx_sc *ctx_rx_sc = ctx->rx_sc; struct mlx5e_macsec_rx_sc *rx_sc; @@ -421,10 +443,33 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx) goto out; } + sc_xarray_element = kzalloc(sizeof(*sc_xarray_element), GFP_KERNEL); + if (!sc_xarray_element) { + err = -ENOMEM; + goto destroy_rx_sc; + } + + sc_xarray_element->rx_sc = rx_sc; + err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element, + XA_LIMIT(1, USHRT_MAX), GFP_KERNEL); + if (err) + goto destroy_sc_xarray_elemenet; + rx_sc->sci = ctx_rx_sc->sci; rx_sc->active = ctx_rx_sc->active; list_add_rcu(&rx_sc->rx_sc_list_element, &macsec->macsec_rx_sc_list_head); + rx_sc->sc_xarray_element = sc_xarray_element; + + mutex_unlock(&macsec->lock); + + return 0; + +destroy_sc_xarray_elemenet: + kfree(sc_xarray_element); +destroy_rx_sc: + kfree(rx_sc); + out: mutex_unlock(&macsec->lock); @@ -478,7 +523,6 @@ static int mlx5e_macsec_upd_rxsc(struct macsec_context *ctx) static int mlx5e_macsec_del_rxsc(struct macsec_context *ctx) { struct mlx5e_priv *priv = netdev_priv(ctx->netdev); - struct mlx5_core_dev *mdev = priv->mdev; struct mlx5e_macsec_rx_sc *rx_sc; struct mlx5e_macsec_sa *rx_sa; struct mlx5e_macsec *macsec; @@ -507,14 +551,16 @@ static int mlx5e_macsec_del_rxsc(struct macsec_context *ctx) if (!rx_sa) continue; - mlx5e_macsec_destroy_object(mdev, rx_sa->macsec_obj_id); - mlx5_destroy_encryption_key(mdev, rx_sa->enc_key_id); + mlx5e_macsec_cleanup_sa(macsec, rx_sa, false); + mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id); kfree(rx_sa); rx_sc->rx_sa[i] = NULL; } list_del_rcu(&rx_sc->rx_sc_list_element); + xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id); + kfree(rx_sc->sc_xarray_element); kfree_rcu(rx_sc); @@ -529,7 +575,6 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx) const struct macsec_rx_sa *ctx_rx_sa = ctx->sa.rx_sa; struct mlx5e_priv *priv = netdev_priv(ctx->netdev); struct mlx5_core_dev *mdev = priv->mdev; - struct mlx5_macsec_obj_attrs attrs; u8 assoc_num = ctx->sa.assoc_num; struct mlx5e_macsec_rx_sc *rx_sc; sci_t sci = ctx_rx_sa->sc->sci; @@ -572,6 +617,8 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx) rx_sa->next_pn = ctx_rx_sa->next_pn; rx_sa->sci = sci; rx_sa->assoc_num = assoc_num; + rx_sa->fs_id = rx_sc->sc_xarray_element->fs_id; + err = mlx5_create_encryption_key(mdev, ctx->sa.key, ctx->secy->key_len, MLX5_ACCEL_OBJ_MACSEC_KEY, &rx_sa->enc_key_id); @@ -582,11 +629,8 @@ static int mlx5e_macsec_add_rxsa(struct macsec_context *ctx) if (!rx_sa->active) goto out; - attrs.sci = rx_sa->sci; - attrs.enc_key_id = rx_sa->enc_key_id; - //TODO - add support for both authentication and encryption flows - err = mlx5e_macsec_create_object(mdev, &attrs, false, &rx_sa->macsec_obj_id); + err = mlx5e_macsec_init_sa(ctx, rx_sa, true, false); if (err) goto destroy_encryption_key; @@ -660,7 +704,6 @@ static int mlx5e_macsec_upd_rxsa(struct macsec_context *ctx) static int mlx5e_macsec_del_rxsa(struct macsec_context *ctx) { struct mlx5e_priv *priv = netdev_priv(ctx->netdev); - struct mlx5_core_dev *mdev = priv->mdev; sci_t sci = ctx->sa.rx_sa->sc->sci; struct mlx5e_macsec_rx_sc *rx_sc; u8 assoc_num = ctx->sa.assoc_num; @@ -694,9 +737,8 @@ static int mlx5e_macsec_del_rxsa(struct macsec_context *ctx) goto out; } - mlx5e_macsec_destroy_object(mdev, rx_sa->macsec_obj_id); - mlx5_destroy_encryption_key(mdev, rx_sa->enc_key_id); - + mlx5e_macsec_cleanup_sa(macsec, rx_sa, false); + mlx5_destroy_encryption_key(macsec->mdev, rx_sa->enc_key_id); kfree(rx_sa); rx_sc->rx_sa[assoc_num] = NULL; @@ -827,6 +869,8 @@ int mlx5e_macsec_init(struct mlx5e_priv *priv) goto err_out; } + xa_init_flags(&macsec->sc_xarray, XA_FLAGS_ALLOC1); + priv->macsec = macsec; macsec->mdev = mdev; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c index cb08877869e7c..d3d6802161152 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.c @@ -21,9 +21,25 @@ CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE)) #define TX_CHECK_TABLE_LEVEL 1 #define TX_CHECK_TABLE_NUM_FTE 2 +#define RX_CRYPTO_TABLE_LEVEL 0 +#define RX_CHECK_TABLE_LEVEL 1 +#define RX_CHECK_TABLE_NUM_FTE 3 +#define RX_CRYPTO_TABLE_NUM_GROUPS 3 +#define RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE \ + ((CRYPTO_NUM_MAXSEC_FTE - CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE) / 2) +#define RX_CRYPTO_TABLE_SA_RULE_WITHOUT_SCI_GROUP_SIZE \ + (CRYPTO_NUM_MAXSEC_FTE - RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE) +#define RX_NUM_OF_RULES_PER_SA 2 #define MLX5_MACSEC_TAG_LEN 8 /* SecTAG length with ethertype and without the optional SCI */ - +#define MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK 0x23 +#define MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET 0x8 +#define MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET 0x5 +#define MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT (0x1 << MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET) +#define MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI 0x8 +#define MLX5_SECTAG_HEADER_SIZE_WITH_SCI (MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI + MACSEC_SCI_LEN) + +/* MACsec RX flow steering */ #define MLX5_ETH_WQE_FT_META_MACSEC_MASK 0x3E struct mlx5_sectag_header { @@ -40,32 +56,58 @@ struct mlx5e_macsec_tx_rule { u32 fs_id; }; -struct mlx5e_macsec_tx { +struct mlx5e_macsec_tables { struct mlx5e_flow_table ft_crypto; struct mlx5_flow_handle *crypto_miss_rule; - struct mlx5_flow_handle *crypto_mke_rule; struct mlx5_flow_table *ft_check; struct mlx5_flow_group *ft_check_group; struct mlx5_fc *check_miss_rule_counter; struct mlx5_flow_handle *check_miss_rule; struct mlx5_fc *check_rule_counter; + + u32 refcnt; +}; + +struct mlx5e_macsec_tx { + struct mlx5_flow_handle *crypto_mke_rule; struct mlx5_flow_handle *check_rule; struct ida tx_halloc; - u32 refcnt; + struct mlx5e_macsec_tables tables; +}; + +struct mlx5e_macsec_rx_rule { + struct mlx5_flow_handle *rule[RX_NUM_OF_RULES_PER_SA]; + struct mlx5_modify_hdr *meta_modhdr; +}; + +struct mlx5e_macsec_rx { + struct mlx5_flow_handle *check_rule[2]; + struct mlx5_pkt_reformat *check_rule_pkt_reformat[2]; + + struct mlx5e_macsec_tables tables; +}; + +union mlx5e_macsec_rule { + struct mlx5e_macsec_tx_rule tx_rule; + struct mlx5e_macsec_rx_rule rx_rule; }; struct mlx5e_macsec_fs { struct mlx5_core_dev *mdev; struct net_device *netdev; struct mlx5e_macsec_tx *tx_fs; + struct mlx5e_macsec_rx *rx_fs; }; static void macsec_fs_tx_destroy(struct mlx5e_macsec_fs *macsec_fs) { struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs; + struct mlx5e_macsec_tables *tx_tables; + + tx_tables = &tx_fs->tables; /* Tx check table */ if (tx_fs->check_rule) { @@ -73,19 +115,19 @@ static void macsec_fs_tx_destroy(struct mlx5e_macsec_fs *macsec_fs) tx_fs->check_rule = NULL; } - if (tx_fs->check_miss_rule) { - mlx5_del_flow_rules(tx_fs->check_miss_rule); - tx_fs->check_miss_rule = NULL; + if (tx_tables->check_miss_rule) { + mlx5_del_flow_rules(tx_tables->check_miss_rule); + tx_tables->check_miss_rule = NULL; } - if (tx_fs->ft_check_group) { - mlx5_destroy_flow_group(tx_fs->ft_check_group); - tx_fs->ft_check_group = NULL; + if (tx_tables->ft_check_group) { + mlx5_destroy_flow_group(tx_tables->ft_check_group); + tx_tables->ft_check_group = NULL; } - if (tx_fs->ft_check) { - mlx5_destroy_flow_table(tx_fs->ft_check); - tx_fs->ft_check = NULL; + if (tx_tables->ft_check) { + mlx5_destroy_flow_table(tx_tables->ft_check); + tx_tables->ft_check = NULL; } /* Tx crypto table */ @@ -94,12 +136,12 @@ static void macsec_fs_tx_destroy(struct mlx5e_macsec_fs *macsec_fs) tx_fs->crypto_mke_rule = NULL; } - if (tx_fs->crypto_miss_rule) { - mlx5_del_flow_rules(tx_fs->crypto_miss_rule); - tx_fs->crypto_miss_rule = NULL; + if (tx_tables->crypto_miss_rule) { + mlx5_del_flow_rules(tx_tables->crypto_miss_rule); + tx_tables->crypto_miss_rule = NULL; } - mlx5e_destroy_flow_table(&tx_fs->ft_crypto); + mlx5e_destroy_flow_table(&tx_tables->ft_crypto); } static int macsec_fs_tx_create_crypto_table_groups(struct mlx5e_flow_table *ft) @@ -199,6 +241,7 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs) struct net_device *netdev = macsec_fs->netdev; struct mlx5_flow_table_attr ft_attr = {}; struct mlx5_flow_destination dest = {}; + struct mlx5e_macsec_tables *tx_tables; struct mlx5_flow_act flow_act = {}; struct mlx5e_flow_table *ft_crypto; struct mlx5_flow_table *flow_table; @@ -221,7 +264,8 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs) if (!flow_group_in) goto out_spec; - ft_crypto = &tx_fs->ft_crypto; + tx_tables = &tx_fs->tables; + ft_crypto = &tx_tables->ft_crypto; /* Tx crypto table */ ft_attr.flags = MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT; @@ -271,7 +315,7 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs) netdev_err(netdev, "Failed to add MACsec Tx table default miss rule %d\n", err); goto err; } - tx_fs->crypto_miss_rule = rule; + tx_tables->crypto_miss_rule = rule; /* Tx check table */ flow_table = macsec_fs_auto_group_table_create(ns, 0, TX_CHECK_TABLE_LEVEL, @@ -281,13 +325,13 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs) netdev_err(netdev, "fail to create MACsec TX check table, err(%d)\n", err); goto err; } - tx_fs->ft_check = flow_table; + tx_tables->ft_check = flow_table; /* Tx check table Default miss group/rule */ memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_table->max_fte - 1); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_table->max_fte - 1); - flow_group = mlx5_create_flow_group(tx_fs->ft_check, flow_group_in); + flow_group = mlx5_create_flow_group(tx_tables->ft_check, flow_group_in); if (IS_ERR(flow_group)) { err = PTR_ERR(flow_group); netdev_err(netdev, @@ -295,21 +339,21 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs) err); goto err; } - tx_fs->ft_check_group = flow_group; + tx_tables->ft_check_group = flow_group; /* Tx check table default drop rule */ memset(&dest, 0, sizeof(struct mlx5_flow_destination)); memset(&flow_act, 0, sizeof(flow_act)); dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - dest.counter_id = mlx5_fc_id(tx_fs->check_miss_rule_counter); + dest.counter_id = mlx5_fc_id(tx_tables->check_miss_rule_counter); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT; - rule = mlx5_add_flow_rules(tx_fs->ft_check, NULL, &flow_act, &dest, 1); + rule = mlx5_add_flow_rules(tx_tables->ft_check, NULL, &flow_act, &dest, 1); if (IS_ERR(rule)) { err = PTR_ERR(rule); netdev_err(netdev, "Failed to added MACsec tx check drop rule, err(%d)\n", err); goto err; } - tx_fs->check_miss_rule = rule; + tx_tables->check_miss_rule = rule; /* Tx check table rule */ memset(spec, 0, sizeof(struct mlx5_flow_spec)); @@ -323,8 +367,8 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs) flow_act.flags = FLOW_ACT_NO_APPEND; flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW | MLX5_FLOW_CONTEXT_ACTION_COUNT; dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; - dest.counter_id = mlx5_fc_id(tx_fs->check_rule_counter); - rule = mlx5_add_flow_rules(tx_fs->ft_check, spec, &flow_act, &dest, 1); + dest.counter_id = mlx5_fc_id(tx_tables->check_rule_counter); + rule = mlx5_add_flow_rules(tx_tables->ft_check, spec, &flow_act, &dest, 1); if (IS_ERR(rule)) { err = PTR_ERR(rule); netdev_err(netdev, "Failed to add MACsec check rule, err=%d\n", err); @@ -346,9 +390,11 @@ static int macsec_fs_tx_create(struct mlx5e_macsec_fs *macsec_fs) static int macsec_fs_tx_ft_get(struct mlx5e_macsec_fs *macsec_fs) { struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs; + struct mlx5e_macsec_tables *tx_tables; int err = 0; - if (tx_fs->refcnt) + tx_tables = &tx_fs->tables; + if (tx_tables->refcnt) goto out; err = macsec_fs_tx_create(macsec_fs); @@ -356,15 +402,15 @@ static int macsec_fs_tx_ft_get(struct mlx5e_macsec_fs *macsec_fs) return err; out: - tx_fs->refcnt++; + tx_tables->refcnt++; return err; } static void macsec_fs_tx_ft_put(struct mlx5e_macsec_fs *macsec_fs) { - struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs; + struct mlx5e_macsec_tables *tx_tables = &macsec_fs->tx_fs->tables; - if (--tx_fs->refcnt) + if (--tx_tables->refcnt) return; macsec_fs_tx_destroy(macsec_fs); @@ -380,7 +426,8 @@ static int macsec_fs_tx_setup_fte(struct mlx5e_macsec_fs *macsec_fs, int err = 0; u32 id; - err = ida_alloc_range(&tx_fs->tx_halloc, 1, MLX5_MACSEC_NUM_OF_SUPPORTED_INTERFACES, + err = ida_alloc_range(&tx_fs->tx_halloc, 1, + MLX5_MACSEC_NUM_OF_SUPPORTED_INTERFACES, GFP_KERNEL); if (err < 0) return err; @@ -461,7 +508,7 @@ static void macsec_fs_tx_del_rule(struct mlx5e_macsec_fs *macsec_fs, macsec_fs_tx_ft_put(macsec_fs); } -static struct mlx5e_macsec_tx_rule * +static union mlx5e_macsec_rule * macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs, const struct macsec_context *macsec_ctx, struct mlx5_macsec_rule_attrs *attrs, @@ -472,6 +519,8 @@ macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs, struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs; struct net_device *netdev = macsec_fs->netdev; struct mlx5_flow_destination dest = {}; + struct mlx5e_macsec_tables *tx_tables; + union mlx5e_macsec_rule *macsec_rule; struct mlx5e_macsec_tx_rule *tx_rule; struct mlx5_flow_act flow_act = {}; struct mlx5_flow_handle *rule; @@ -480,6 +529,8 @@ macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs, int err = 0; u32 fs_id; + tx_tables = &tx_fs->tables; + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return NULL; @@ -488,12 +539,14 @@ macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs, if (err) goto out_spec; - tx_rule = kzalloc(sizeof(*tx_rule), GFP_KERNEL); - if (!tx_rule) { + macsec_rule = kzalloc(sizeof(*macsec_rule), GFP_KERNEL); + if (!macsec_rule) { macsec_fs_tx_ft_put(macsec_fs); goto out_spec; } + tx_rule = &macsec_rule->tx_rule; + /* Tx crypto table crypto rule */ macsec_fs_tx_create_sectag_header(macsec_ctx, reformatbf, &reformat_size); @@ -525,8 +578,8 @@ macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs, MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT | MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT; dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; - dest.ft = tx_fs->ft_check; - rule = mlx5_add_flow_rules(tx_fs->ft_crypto.t, spec, &flow_act, &dest, 1); + dest.ft = tx_tables->ft_check; + rule = mlx5_add_flow_rules(tx_tables->ft_crypto.t, spec, &flow_act, &dest, 1); if (IS_ERR(rule)) { err = PTR_ERR(rule); netdev_err(netdev, "Failed to add MACsec TX crypto rule, err=%d\n", err); @@ -538,38 +591,40 @@ macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs, err: macsec_fs_tx_del_rule(macsec_fs, tx_rule); - tx_rule = NULL; + macsec_rule = NULL; out_spec: kvfree(spec); - return tx_rule; + return macsec_rule; } static void macsec_fs_tx_cleanup(struct mlx5e_macsec_fs *macsec_fs) { struct mlx5e_macsec_tx *tx_fs = macsec_fs->tx_fs; struct mlx5_core_dev *mdev = macsec_fs->mdev; + struct mlx5e_macsec_tables *tx_tables; if (!tx_fs) return; - if (tx_fs->refcnt) { + tx_tables = &tx_fs->tables; + if (tx_tables->refcnt) { netdev_err(macsec_fs->netdev, "Can't destroy MACsec offload tx_fs, refcnt(%u) isn't 0\n", - tx_fs->refcnt); + tx_tables->refcnt); return; } ida_destroy(&tx_fs->tx_halloc); - if (tx_fs->check_miss_rule_counter) { - mlx5_fc_destroy(mdev, tx_fs->check_miss_rule_counter); - tx_fs->check_miss_rule_counter = NULL; + if (tx_tables->check_miss_rule_counter) { + mlx5_fc_destroy(mdev, tx_tables->check_miss_rule_counter); + tx_tables->check_miss_rule_counter = NULL; } - if (tx_fs->check_rule_counter) { - mlx5_fc_destroy(mdev, tx_fs->check_rule_counter); - tx_fs->check_rule_counter = NULL; + if (tx_tables->check_rule_counter) { + mlx5_fc_destroy(mdev, tx_tables->check_rule_counter); + tx_tables->check_rule_counter = NULL; } kfree(tx_fs); @@ -580,6 +635,7 @@ static int macsec_fs_tx_init(struct mlx5e_macsec_fs *macsec_fs) { struct net_device *netdev = macsec_fs->netdev; struct mlx5_core_dev *mdev = macsec_fs->mdev; + struct mlx5e_macsec_tables *tx_tables; struct mlx5e_macsec_tx *tx_fs; struct mlx5_fc *flow_counter; int err; @@ -588,6 +644,8 @@ static int macsec_fs_tx_init(struct mlx5e_macsec_fs *macsec_fs) if (!tx_fs) return -ENOMEM; + tx_tables = &tx_fs->tables; + flow_counter = mlx5_fc_create(mdev, false); if (IS_ERR(flow_counter)) { err = PTR_ERR(flow_counter); @@ -596,7 +654,7 @@ static int macsec_fs_tx_init(struct mlx5e_macsec_fs *macsec_fs) err); goto err_encrypt_counter; } - tx_fs->check_rule_counter = flow_counter; + tx_tables->check_rule_counter = flow_counter; flow_counter = mlx5_fc_create(mdev, false); if (IS_ERR(flow_counter)) { @@ -606,7 +664,7 @@ static int macsec_fs_tx_init(struct mlx5e_macsec_fs *macsec_fs) err); goto err_drop_counter; } - tx_fs->check_miss_rule_counter = flow_counter; + tx_tables->check_miss_rule_counter = flow_counter; ida_init(&tx_fs->tx_halloc); @@ -615,8 +673,8 @@ static int macsec_fs_tx_init(struct mlx5e_macsec_fs *macsec_fs) return 0; err_drop_counter: - mlx5_fc_destroy(mdev, tx_fs->check_rule_counter); - tx_fs->check_rule_counter = NULL; + mlx5_fc_destroy(mdev, tx_tables->check_rule_counter); + tx_tables->check_rule_counter = NULL; err_encrypt_counter: kfree(tx_fs); @@ -625,28 +683,643 @@ static int macsec_fs_tx_init(struct mlx5e_macsec_fs *macsec_fs) return err; } -struct mlx5e_macsec_tx_rule * +static void macsec_fs_rx_destroy(struct mlx5e_macsec_fs *macsec_fs) +{ + struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs; + struct mlx5e_macsec_tables *rx_tables; + int i; + + /* Rx check table */ + for (i = 1; i >= 0; --i) { + if (rx_fs->check_rule[i]) { + mlx5_del_flow_rules(rx_fs->check_rule[i]); + rx_fs->check_rule[i] = NULL; + } + + if (rx_fs->check_rule_pkt_reformat[i]) { + mlx5_packet_reformat_dealloc(macsec_fs->mdev, + rx_fs->check_rule_pkt_reformat[i]); + rx_fs->check_rule_pkt_reformat[i] = NULL; + } + } + + rx_tables = &rx_fs->tables; + + if (rx_tables->check_miss_rule) { + mlx5_del_flow_rules(rx_tables->check_miss_rule); + rx_tables->check_miss_rule = NULL; + } + + if (rx_tables->ft_check_group) { + mlx5_destroy_flow_group(rx_tables->ft_check_group); + rx_tables->ft_check_group = NULL; + } + + if (rx_tables->ft_check) { + mlx5_destroy_flow_table(rx_tables->ft_check); + rx_tables->ft_check = NULL; + } + + /* Rx crypto table */ + if (rx_tables->crypto_miss_rule) { + mlx5_del_flow_rules(rx_tables->crypto_miss_rule); + rx_tables->crypto_miss_rule = NULL; + } + + mlx5e_destroy_flow_table(&rx_tables->ft_crypto); +} + +static int macsec_fs_rx_create_crypto_table_groups(struct mlx5e_flow_table *ft) +{ + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); + int mclen = MLX5_ST_SZ_BYTES(fte_match_param); + int ix = 0; + u32 *in; + int err; + u8 *mc; + + ft->g = kcalloc(RX_CRYPTO_TABLE_NUM_GROUPS, sizeof(*ft->g), GFP_KERNEL); + if (!ft->g) + return -ENOMEM; + + in = kvzalloc(inlen, GFP_KERNEL); + if (!in) { + kfree(ft->g); + return -ENOMEM; + } + + mc = MLX5_ADDR_OF(create_flow_group_in, in, match_criteria); + + /* Flow group for SA rule with SCI */ + MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS | + MLX5_MATCH_MISC_PARAMETERS_5); + MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype); + + MLX5_SET(fte_match_param, mc, misc_parameters_5.macsec_tag_0, + MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK << + MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET); + MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters_5.macsec_tag_2); + MLX5_SET_TO_ONES(fte_match_param, mc, misc_parameters_5.macsec_tag_3); + + MLX5_SET_CFG(in, start_flow_index, ix); + ix += RX_CRYPTO_TABLE_SA_RULE_WITH_SCI_GROUP_SIZE; + MLX5_SET_CFG(in, end_flow_index, ix - 1); + ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); + if (IS_ERR(ft->g[ft->num_groups])) + goto err; + ft->num_groups++; + + /* Flow group for SA rule without SCI */ + memset(in, 0, inlen); + memset(mc, 0, mclen); + MLX5_SET_CFG(in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS | + MLX5_MATCH_MISC_PARAMETERS_5); + MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.smac_47_16); + MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.smac_15_0); + MLX5_SET_TO_ONES(fte_match_param, mc, outer_headers.ethertype); + + MLX5_SET(fte_match_param, mc, misc_parameters_5.macsec_tag_0, + MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET); + + MLX5_SET_CFG(in, start_flow_index, ix); + ix += RX_CRYPTO_TABLE_SA_RULE_WITHOUT_SCI_GROUP_SIZE; + MLX5_SET_CFG(in, end_flow_index, ix - 1); + ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); + if (IS_ERR(ft->g[ft->num_groups])) + goto err; + ft->num_groups++; + + /* Flow Group for l2 traps */ + memset(in, 0, inlen); + memset(mc, 0, mclen); + MLX5_SET_CFG(in, start_flow_index, ix); + ix += CRYPTO_TABLE_DEFAULT_RULE_GROUP_SIZE; + MLX5_SET_CFG(in, end_flow_index, ix - 1); + ft->g[ft->num_groups] = mlx5_create_flow_group(ft->t, in); + if (IS_ERR(ft->g[ft->num_groups])) + goto err; + ft->num_groups++; + + kvfree(in); + return 0; + +err: + err = PTR_ERR(ft->g[ft->num_groups]); + ft->g[ft->num_groups] = NULL; + kvfree(in); + + return err; +} + +static int macsec_fs_rx_create_check_decap_rule(struct mlx5e_macsec_fs *macsec_fs, + struct mlx5_flow_destination *dest, + struct mlx5_flow_act *flow_act, + struct mlx5_flow_spec *spec, + int reformat_param_size) +{ + int rule_index = (reformat_param_size == MLX5_SECTAG_HEADER_SIZE_WITH_SCI) ? 0 : 1; + u8 mlx5_reformat_buf[MLX5_SECTAG_HEADER_SIZE_WITH_SCI]; + struct mlx5_pkt_reformat_params reformat_params = {}; + struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs; + struct net_device *netdev = macsec_fs->netdev; + struct mlx5e_macsec_tables *rx_tables; + struct mlx5_flow_handle *rule; + int err = 0; + + rx_tables = &rx_fs->tables; + + /* Rx check table decap 16B rule */ + memset(dest, 0, sizeof(*dest)); + memset(flow_act, 0, sizeof(*flow_act)); + memset(spec, 0, sizeof(*spec)); + + reformat_params.type = MLX5_REFORMAT_TYPE_DEL_MACSEC; + reformat_params.size = reformat_param_size; + reformat_params.data = mlx5_reformat_buf; + flow_act->pkt_reformat = mlx5_packet_reformat_alloc(macsec_fs->mdev, + &reformat_params, + MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC); + if (IS_ERR(flow_act->pkt_reformat)) { + err = PTR_ERR(flow_act->pkt_reformat); + netdev_err(netdev, "Failed to allocate MACsec Rx reformat context err=%d\n", err); + return err; + } + rx_fs->check_rule_pkt_reformat[rule_index] = flow_act->pkt_reformat; + + spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS_2; + /* MACsec syndrome match */ + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.macsec_syndrome); + MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.macsec_syndrome, 0); + /* ASO return reg syndrome match */ + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, misc_parameters_2.metadata_reg_c_4); + MLX5_SET(fte_match_param, spec->match_value, misc_parameters_2.metadata_reg_c_4, 0); + + spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5; + /* Sectag TCI SC present bit*/ + MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_5.macsec_tag_0, + MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET); + + if (reformat_param_size == MLX5_SECTAG_HEADER_SIZE_WITH_SCI) + MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_0, + MLX5_MACSEC_SECTAG_TCI_SC_FIELD_BIT << + MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET); + + flow_act->flags = FLOW_ACT_NO_APPEND; + flow_act->action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO | + MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT | + MLX5_FLOW_CONTEXT_ACTION_COUNT; + dest->type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; + dest->counter_id = mlx5_fc_id(rx_tables->check_rule_counter); + rule = mlx5_add_flow_rules(rx_tables->ft_check, spec, flow_act, dest, 1); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + netdev_err(netdev, "Failed to add MACsec Rx check rule, err=%d\n", err); + return err; + } + + rx_fs->check_rule[rule_index] = rule; + + return 0; +} + +static int macsec_fs_rx_create(struct mlx5e_macsec_fs *macsec_fs) +{ + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); + struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs; + struct net_device *netdev = macsec_fs->netdev; + struct mlx5_flow_table_attr ft_attr = {}; + struct mlx5_flow_destination dest = {}; + struct mlx5e_macsec_tables *rx_tables; + struct mlx5e_flow_table *ft_crypto; + struct mlx5_flow_table *flow_table; + struct mlx5_flow_group *flow_group; + struct mlx5_flow_act flow_act = {}; + struct mlx5_flow_namespace *ns; + struct mlx5_flow_handle *rule; + struct mlx5_flow_spec *spec; + u32 *flow_group_in; + int err = 0; + + ns = mlx5_get_flow_namespace(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC); + if (!ns) + return -ENOMEM; + + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + + flow_group_in = kvzalloc(inlen, GFP_KERNEL); + if (!flow_group_in) + goto free_spec; + + rx_tables = &rx_fs->tables; + ft_crypto = &rx_tables->ft_crypto; + + /* Rx crypto table */ + ft_attr.level = RX_CRYPTO_TABLE_LEVEL; + ft_attr.max_fte = CRYPTO_NUM_MAXSEC_FTE; + + flow_table = mlx5_create_flow_table(ns, &ft_attr); + if (IS_ERR(flow_table)) { + err = PTR_ERR(flow_table); + netdev_err(netdev, "Failed to create MACsec Rx crypto table err(%d)\n", err); + goto out_flow_group; + } + ft_crypto->t = flow_table; + + /* Rx crypto table groups */ + err = macsec_fs_rx_create_crypto_table_groups(ft_crypto); + if (err) { + netdev_err(netdev, + "Failed to create default flow group for MACsec Tx crypto table err(%d)\n", + err); + goto err; + } + + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_NEXT_PRIO; + rule = mlx5_add_flow_rules(ft_crypto->t, NULL, &flow_act, NULL, 0); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + netdev_err(netdev, + "Failed to add MACsec Rx crypto table default miss rule %d\n", + err); + goto err; + } + rx_tables->crypto_miss_rule = rule; + + /* Rx check table */ + flow_table = macsec_fs_auto_group_table_create(ns, + MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT, + RX_CHECK_TABLE_LEVEL, + RX_CHECK_TABLE_NUM_FTE); + if (IS_ERR(flow_table)) { + err = PTR_ERR(flow_table); + netdev_err(netdev, "fail to create MACsec RX check table, err(%d)\n", err); + goto err; + } + rx_tables->ft_check = flow_table; + + /* Rx check table Default miss group/rule */ + MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, flow_table->max_fte - 1); + MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, flow_table->max_fte - 1); + flow_group = mlx5_create_flow_group(rx_tables->ft_check, flow_group_in); + if (IS_ERR(flow_group)) { + err = PTR_ERR(flow_group); + netdev_err(netdev, + "Failed to create default flow group for MACsec Rx check table err(%d)\n", + err); + goto err; + } + rx_tables->ft_check_group = flow_group; + + /* Rx check table default drop rule */ + memset(&flow_act, 0, sizeof(flow_act)); + + dest.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; + dest.counter_id = mlx5_fc_id(rx_tables->check_miss_rule_counter); + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP | MLX5_FLOW_CONTEXT_ACTION_COUNT; + rule = mlx5_add_flow_rules(rx_tables->ft_check, NULL, &flow_act, &dest, 1); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + netdev_err(netdev, "Failed to added MACsec Rx check drop rule, err(%d)\n", err); + goto err; + } + rx_tables->check_miss_rule = rule; + + /* Rx check table decap rules */ + err = macsec_fs_rx_create_check_decap_rule(macsec_fs, &dest, &flow_act, spec, + MLX5_SECTAG_HEADER_SIZE_WITH_SCI); + if (err) + goto err; + + err = macsec_fs_rx_create_check_decap_rule(macsec_fs, &dest, &flow_act, spec, + MLX5_SECTAG_HEADER_SIZE_WITHOUT_SCI); + if (err) + goto err; + + goto out_flow_group; + +err: + macsec_fs_rx_destroy(macsec_fs); +out_flow_group: + kvfree(flow_group_in); +free_spec: + kvfree(spec); + return err; +} + +static int macsec_fs_rx_ft_get(struct mlx5e_macsec_fs *macsec_fs) +{ + struct mlx5e_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables; + int err = 0; + + if (rx_tables->refcnt) + goto out; + + err = macsec_fs_rx_create(macsec_fs); + if (err) + return err; + +out: + rx_tables->refcnt++; + return err; +} + +static void macsec_fs_rx_ft_put(struct mlx5e_macsec_fs *macsec_fs) +{ + struct mlx5e_macsec_tables *rx_tables = &macsec_fs->rx_fs->tables; + + if (--rx_tables->refcnt) + return; + + macsec_fs_rx_destroy(macsec_fs); +} + +static void macsec_fs_rx_del_rule(struct mlx5e_macsec_fs *macsec_fs, + struct mlx5e_macsec_rx_rule *rx_rule) +{ + int i; + + for (i = 0; i < RX_NUM_OF_RULES_PER_SA; ++i) { + if (rx_rule->rule[i]) { + mlx5_del_flow_rules(rx_rule->rule[i]); + rx_rule->rule[i] = NULL; + } + } + + if (rx_rule->meta_modhdr) { + mlx5_modify_header_dealloc(macsec_fs->mdev, rx_rule->meta_modhdr); + rx_rule->meta_modhdr = NULL; + } + + kfree(rx_rule); + + macsec_fs_rx_ft_put(macsec_fs); +} + +static void macsec_fs_rx_setup_fte(struct mlx5_flow_spec *spec, + struct mlx5_flow_act *flow_act, + struct mlx5_macsec_rule_attrs *attrs, + bool sci_present) +{ + u8 tci_an = (sci_present << MLX5_MACSEC_SECTAG_TCI_SC_FIELD_OFFSET) | attrs->assoc_num; + struct mlx5_flow_act_crypto_params *crypto_params = &flow_act->crypto; + __be32 *sci_p = (__be32 *)(&attrs->sci); + + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + + /* MACsec ethertype */ + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.ethertype); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.ethertype, ETH_P_MACSEC); + + spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_5; + + /* Sectag AN + TCI SC present bit*/ + MLX5_SET(fte_match_param, spec->match_criteria, misc_parameters_5.macsec_tag_0, + MLX5_MACSEC_SECTAG_TCI_AN_FIELD_BITMASK << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET); + MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_0, + tci_an << MLX5_MACSEC_SECTAG_TCI_AN_FIELD_OFFSET); + + if (sci_present) { + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, + misc_parameters_5.macsec_tag_2); + MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_2, + be32_to_cpu(sci_p[0])); + + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, + misc_parameters_5.macsec_tag_3); + MLX5_SET(fte_match_param, spec->match_value, misc_parameters_5.macsec_tag_3, + be32_to_cpu(sci_p[1])); + } else { + /* When SCI isn't present in the Sectag, need to match the source */ + /* MAC address only if the SCI contains the default MACsec PORT */ + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_47_16); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_15_0); + memcpy(MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers.smac_47_16), + sci_p, ETH_ALEN); + } + + crypto_params->type = MLX5_FLOW_CONTEXT_ENCRYPT_DECRYPT_TYPE_MACSEC; + crypto_params->obj_id = attrs->macsec_obj_id; +} + +static union mlx5e_macsec_rule * +macsec_fs_rx_add_rule(struct mlx5e_macsec_fs *macsec_fs, + const struct macsec_context *macsec_ctx, + struct mlx5_macsec_rule_attrs *attrs, + u32 fs_id) +{ + u8 action[MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto)] = {}; + struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs; + struct net_device *netdev = macsec_fs->netdev; + struct mlx5_modify_hdr *modify_hdr = NULL; + struct mlx5_flow_destination dest = {}; + struct mlx5e_macsec_tables *rx_tables; + union mlx5e_macsec_rule *macsec_rule; + struct mlx5e_macsec_rx_rule *rx_rule; + struct mlx5_flow_act flow_act = {}; + struct mlx5e_flow_table *ft_crypto; + struct mlx5_flow_handle *rule; + struct mlx5_flow_spec *spec; + int err = 0; + + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return NULL; + + err = macsec_fs_rx_ft_get(macsec_fs); + if (err) + goto out_spec; + + macsec_rule = kzalloc(sizeof(*macsec_rule), GFP_KERNEL); + if (!macsec_rule) { + macsec_fs_rx_ft_put(macsec_fs); + goto out_spec; + } + + rx_rule = &macsec_rule->rx_rule; + rx_tables = &rx_fs->tables; + ft_crypto = &rx_tables->ft_crypto; + + /* Set bit[31 - 30] macsec marker - 0x01 */ + /* Set bit[3-0] fs id */ + MLX5_SET(set_action_in, action, action_type, MLX5_ACTION_TYPE_SET); + MLX5_SET(set_action_in, action, field, MLX5_ACTION_IN_FIELD_METADATA_REG_B); + MLX5_SET(set_action_in, action, data, fs_id | BIT(30)); + MLX5_SET(set_action_in, action, offset, 0); + MLX5_SET(set_action_in, action, length, 32); + + modify_hdr = mlx5_modify_header_alloc(macsec_fs->mdev, MLX5_FLOW_NAMESPACE_KERNEL_RX_MACSEC, + 1, action); + if (IS_ERR(modify_hdr)) { + err = PTR_ERR(modify_hdr); + netdev_err(netdev, "fail to alloc MACsec set modify_header_id err=%d\n", err); + modify_hdr = NULL; + goto err; + } + rx_rule->meta_modhdr = modify_hdr; + + /* Rx crypto table with SCI rule */ + macsec_fs_rx_setup_fte(spec, &flow_act, attrs, true); + + flow_act.modify_hdr = modify_hdr; + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | + MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT | + MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; + + dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; + dest.ft = rx_tables->ft_check; + rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, &dest, 1); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + netdev_err(netdev, + "Failed to add SA with SCI rule to Rx crypto rule, err=%d\n", + err); + goto err; + } + rx_rule->rule[0] = rule; + + /* Rx crypto table without SCI rule */ + if (cpu_to_be64((__force u64)attrs->sci) & ntohs(MACSEC_PORT_ES)) { + memset(spec, 0, sizeof(struct mlx5_flow_spec)); + memset(&dest, 0, sizeof(struct mlx5_flow_destination)); + memset(&flow_act, 0, sizeof(flow_act)); + + macsec_fs_rx_setup_fte(spec, &flow_act, attrs, false); + + flow_act.modify_hdr = modify_hdr; + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | + MLX5_FLOW_CONTEXT_ACTION_CRYPTO_DECRYPT | + MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; + + dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE; + dest.ft = rx_tables->ft_check; + rule = mlx5_add_flow_rules(ft_crypto->t, spec, &flow_act, &dest, 1); + if (IS_ERR(rule)) { + err = PTR_ERR(rule); + netdev_err(netdev, + "Failed to add SA without SCI rule to Rx crypto rule, err=%d\n", + err); + goto err; + } + rx_rule->rule[1] = rule; + } + + return macsec_rule; + +err: + macsec_fs_rx_del_rule(macsec_fs, rx_rule); + macsec_rule = NULL; +out_spec: + kvfree(spec); + return macsec_rule; +} + +static int macsec_fs_rx_init(struct mlx5e_macsec_fs *macsec_fs) +{ + struct net_device *netdev = macsec_fs->netdev; + struct mlx5_core_dev *mdev = macsec_fs->mdev; + struct mlx5e_macsec_tables *rx_tables; + struct mlx5e_macsec_rx *rx_fs; + struct mlx5_fc *flow_counter; + int err; + + rx_fs = kzalloc(sizeof(*rx_fs), GFP_KERNEL); + if (!rx_fs) + return -ENOMEM; + + flow_counter = mlx5_fc_create(mdev, false); + if (IS_ERR(flow_counter)) { + err = PTR_ERR(flow_counter); + netdev_err(netdev, + "Failed to create MACsec Rx encrypt flow counter, err(%d)\n", + err); + goto err_encrypt_counter; + } + + rx_tables = &rx_fs->tables; + rx_tables->check_rule_counter = flow_counter; + + flow_counter = mlx5_fc_create(mdev, false); + if (IS_ERR(flow_counter)) { + err = PTR_ERR(flow_counter); + netdev_err(netdev, + "Failed to create MACsec Rx drop flow counter, err(%d)\n", + err); + goto err_drop_counter; + } + rx_tables->check_miss_rule_counter = flow_counter; + + macsec_fs->rx_fs = rx_fs; + + return 0; + +err_drop_counter: + mlx5_fc_destroy(mdev, rx_tables->check_rule_counter); + rx_tables->check_rule_counter = NULL; + +err_encrypt_counter: + kfree(rx_fs); + macsec_fs->rx_fs = NULL; + + return err; +} + +static void macsec_fs_rx_cleanup(struct mlx5e_macsec_fs *macsec_fs) +{ + struct mlx5e_macsec_rx *rx_fs = macsec_fs->rx_fs; + struct mlx5_core_dev *mdev = macsec_fs->mdev; + struct mlx5e_macsec_tables *rx_tables; + + if (!rx_fs) + return; + + rx_tables = &rx_fs->tables; + + if (rx_tables->refcnt) { + netdev_err(macsec_fs->netdev, + "Can't destroy MACsec offload rx_fs, refcnt(%u) isn't 0\n", + rx_tables->refcnt); + return; + } + + if (rx_tables->check_miss_rule_counter) { + mlx5_fc_destroy(mdev, rx_tables->check_miss_rule_counter); + rx_tables->check_miss_rule_counter = NULL; + } + + if (rx_tables->check_rule_counter) { + mlx5_fc_destroy(mdev, rx_tables->check_rule_counter); + rx_tables->check_rule_counter = NULL; + } + + kfree(rx_fs); + macsec_fs->rx_fs = NULL; +} + +union mlx5e_macsec_rule * mlx5e_macsec_fs_add_rule(struct mlx5e_macsec_fs *macsec_fs, const struct macsec_context *macsec_ctx, struct mlx5_macsec_rule_attrs *attrs, u32 *sa_fs_id) { - if (attrs->action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) - return macsec_fs_tx_add_rule(macsec_fs, macsec_ctx, attrs, sa_fs_id); - - return NULL; + return (attrs->action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) ? + macsec_fs_tx_add_rule(macsec_fs, macsec_ctx, attrs, sa_fs_id) : + macsec_fs_rx_add_rule(macsec_fs, macsec_ctx, attrs, *sa_fs_id); } void mlx5e_macsec_fs_del_rule(struct mlx5e_macsec_fs *macsec_fs, - struct mlx5e_macsec_tx_rule *tx_rule, + union mlx5e_macsec_rule *macsec_rule, int action) { - if (action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) - macsec_fs_tx_del_rule(macsec_fs, tx_rule); + (action == MLX5_ACCEL_MACSEC_ACTION_ENCRYPT) ? + macsec_fs_tx_del_rule(macsec_fs, &macsec_rule->tx_rule) : + macsec_fs_rx_del_rule(macsec_fs, &macsec_rule->rx_rule); } void mlx5e_macsec_fs_cleanup(struct mlx5e_macsec_fs *macsec_fs) { + macsec_fs_rx_cleanup(macsec_fs); macsec_fs_tx_cleanup(macsec_fs); kfree(macsec_fs); } @@ -671,8 +1344,16 @@ mlx5e_macsec_fs_init(struct mlx5_core_dev *mdev, goto err; } + err = macsec_fs_rx_init(macsec_fs); + if (err) { + netdev_err(netdev, "MACsec offload: Failed to init tx_fs, err=%d\n", err); + goto tx_cleanup; + } + return macsec_fs; +tx_cleanup: + macsec_fs_tx_cleanup(macsec_fs); err: kfree(macsec_fs); return NULL; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h index e911768ec0813..203240a993b63 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec_fs.h @@ -11,15 +11,18 @@ #define MLX5_MACSEC_NUM_OF_SUPPORTED_INTERFACES 16 struct mlx5e_macsec_fs; -struct mlx5e_macsec_tx_rule; +union mlx5e_macsec_rule; struct mlx5_macsec_rule_attrs { + sci_t sci; u32 macsec_obj_id; + u8 assoc_num; int action; }; enum mlx5_macsec_action { MLX5_ACCEL_MACSEC_ACTION_ENCRYPT, + MLX5_ACCEL_MACSEC_ACTION_DECRYPT, }; void mlx5e_macsec_fs_cleanup(struct mlx5e_macsec_fs *macsec_fs); @@ -27,14 +30,14 @@ void mlx5e_macsec_fs_cleanup(struct mlx5e_macsec_fs *macsec_fs); struct mlx5e_macsec_fs * mlx5e_macsec_fs_init(struct mlx5_core_dev *mdev, struct net_device *netdev); -struct mlx5e_macsec_tx_rule * +union mlx5e_macsec_rule * mlx5e_macsec_fs_add_rule(struct mlx5e_macsec_fs *macsec_fs, const struct macsec_context *ctx, struct mlx5_macsec_rule_attrs *attrs, u32 *sa_fs_id); void mlx5e_macsec_fs_del_rule(struct mlx5e_macsec_fs *macsec_fs, - struct mlx5e_macsec_tx_rule *macsec_rule, + union mlx5e_macsec_rule *macsec_rule, int action); #endif