#include "en_accel/ipsec_rxtx.h"
#include "en_accel/ktls.h"
#include "en_accel/ktls_txrx.h"
+#include <en_accel/macsec.h>
#include "en.h"
#include "en/txrx.h"
}
#endif
+#ifdef CONFIG_MLX5_EN_MACSEC
+ if (unlikely(mlx5e_macsec_skb_is_offload(skb))) {
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
+ if (unlikely(!mlx5e_macsec_handle_tx_skb(priv->macsec, skb)))
+ return false;
+ }
+#endif
+
return true;
}
mlx5e_ipsec_tx_build_eseg(priv, skb, eseg);
#endif
+#ifdef CONFIG_MLX5_EN_MACSEC
+ if (unlikely(mlx5e_macsec_skb_is_offload(skb)))
+ mlx5e_macsec_tx_build_eseg(priv->macsec, skb, eseg);
+#endif
+
#if IS_ENABLED(CONFIG_GENEVE)
if (skb->encapsulation && skb->ip_summed == CHECKSUM_PARTIAL)
mlx5e_tx_tunnel_accel(skb, eseg, ihs);
u32 next_pn;
sci_t sci;
+ struct rhash_head hash;
+ u32 fs_id;
struct mlx5e_macsec_tx_rule *tx_rule;
+ struct rcu_head rcu_head;
+};
+
+static const struct rhashtable_params rhash_sci = {
+ .key_len = sizeof_field(struct mlx5e_macsec_sa, sci),
+ .key_offset = offsetof(struct mlx5e_macsec_sa, sci),
+ .head_offset = offsetof(struct mlx5e_macsec_sa, hash),
+ .automatic_shrinking = true,
+ .min_size = 1,
};
struct mlx5e_macsec {
/* Global PD for MACsec object ASO context */
u32 aso_pdn;
+ /* Tx sci -> fs id mapping handling */
+ struct rhashtable sci_hash; /* sci -> mlx5e_macsec_sa */
+
struct mlx5_core_dev *mdev;
};
static void mlx5e_macsec_cleanup_sa(struct mlx5e_macsec *macsec, struct mlx5e_macsec_sa *sa)
{
+ if (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)
return;
rule_attrs.macsec_obj_id = sa->macsec_obj_id;
rule_attrs.action = MLX5_ACCEL_MACSEC_ACTION_ENCRYPT;
- tx_rule = mlx5e_macsec_fs_add_rule(macsec->macsec_fs, ctx, &rule_attrs);
+ tx_rule = mlx5e_macsec_fs_add_rule(macsec->macsec_fs, ctx, &rule_attrs, &sa->fs_id);
if (IS_ERR_OR_NULL(tx_rule))
goto destroy_macsec_object;
- sa->tx_rule = tx_rule;
+ err = rhashtable_insert_fast(&macsec->sci_hash, &sa->hash, rhash_sci);
+ if (err)
+ goto destroy_macsec_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:
mlx5e_macsec_destroy_object(mdev, sa->macsec_obj_id);
mlx5e_macsec_cleanup_sa(macsec, tx_sa);
mlx5_destroy_encryption_key(macsec->mdev, tx_sa->enc_key_id);
- kfree(tx_sa);
+ kfree_rcu(tx_sa);
macsec->tx_sa[assoc_num] = NULL;
out:
return err;
}
+static u32 mlx5e_macsec_get_sa_from_hashtable(struct rhashtable *sci_hash, sci_t *sci)
+{
+ struct mlx5e_macsec_sa *macsec_sa;
+ u32 fs_id = 0;
+
+ rcu_read_lock();
+ macsec_sa = rhashtable_lookup(sci_hash, sci, rhash_sci);
+ if (macsec_sa)
+ fs_id = macsec_sa->fs_id;
+ rcu_read_unlock();
+
+ return fs_id;
+}
+
static bool mlx5e_is_macsec_device(const struct mlx5_core_dev *mdev)
{
if (!(MLX5_CAP_GEN_64(mdev, general_obj_types) &
.mdo_del_txsa = mlx5e_macsec_del_txsa,
};
+bool mlx5e_macsec_handle_tx_skb(struct mlx5e_macsec *macsec, struct sk_buff *skb)
+{
+ struct metadata_dst *md_dst = skb_metadata_dst(skb);
+ u32 fs_id;
+
+ fs_id = mlx5e_macsec_get_sa_from_hashtable(&macsec->sci_hash, &md_dst->u.macsec_info.sci);
+ if (!fs_id)
+ goto err_out;
+
+ return true;
+
+err_out:
+ dev_kfree_skb_any(skb);
+ return false;
+}
+
+void mlx5e_macsec_tx_build_eseg(struct mlx5e_macsec *macsec,
+ struct sk_buff *skb,
+ struct mlx5_wqe_eth_seg *eseg)
+{
+ struct metadata_dst *md_dst = skb_metadata_dst(skb);
+ u32 fs_id;
+
+ fs_id = mlx5e_macsec_get_sa_from_hashtable(&macsec->sci_hash, &md_dst->u.macsec_info.sci);
+ if (!fs_id)
+ return;
+
+ eseg->flow_table_metadata = cpu_to_be32(MLX5_ETH_WQE_FT_META_MACSEC | fs_id << 2);
+}
+
void mlx5e_macsec_build_netdev(struct mlx5e_priv *priv)
{
struct net_device *netdev = priv->netdev;
goto err_pd;
}
+ err = rhashtable_init(&macsec->sci_hash, &rhash_sci);
+ if (err) {
+ mlx5_core_err(mdev, "MACsec offload: Failed to init SCI hash table, err=%d\n",
+ err);
+ goto err_out;
+ }
+
priv->macsec = macsec;
macsec->mdev = mdev;
mlx5_core_dealloc_pd(priv->mdev, macsec->aso_pdn);
+ rhashtable_destroy(&macsec->sci_hash);
+
mutex_destroy(&macsec->lock);
kfree(macsec);
#include <linux/mlx5/driver.h>
#include <net/macsec.h>
+#include <net/dst_metadata.h>
struct mlx5e_priv;
+struct mlx5e_macsec;
void mlx5e_macsec_build_netdev(struct mlx5e_priv *priv);
int mlx5e_macsec_init(struct mlx5e_priv *priv);
void mlx5e_macsec_cleanup(struct mlx5e_priv *priv);
+bool mlx5e_macsec_handle_tx_skb(struct mlx5e_macsec *macsec, struct sk_buff *skb);
+void mlx5e_macsec_tx_build_eseg(struct mlx5e_macsec *macsec,
+ struct sk_buff *skb,
+ struct mlx5_wqe_eth_seg *eseg);
+
+static inline bool mlx5e_macsec_skb_is_offload(struct sk_buff *skb)
+{
+ struct metadata_dst *md_dst = skb_metadata_dst(skb);
+
+ return md_dst && (md_dst->type == METADATA_MACSEC);
+}
#else
static inline void mlx5e_macsec_build_netdev(struct mlx5e_priv *priv) {}
static inline int mlx5e_macsec_init(struct mlx5e_priv *priv) { return 0; }
static inline void mlx5e_macsec_cleanup(struct mlx5e_priv *priv) {}
+static inline bool mlx5e_macsec_skb_is_offload(struct sk_buff *skb) { return false; }
#endif /* CONFIG_MLX5_EN_MACSEC */
static struct mlx5e_macsec_tx_rule *
macsec_fs_tx_add_rule(struct mlx5e_macsec_fs *macsec_fs,
const struct macsec_context *macsec_ctx,
- struct mlx5_macsec_rule_attrs *attrs)
+ struct mlx5_macsec_rule_attrs *attrs,
+ u32 *sa_fs_id)
{
char reformatbf[MLX5_MACSEC_TAG_LEN + MACSEC_SCI_LEN];
struct mlx5_pkt_reformat_params reformat_params = {};
}
tx_rule->fs_id = fs_id;
+ *sa_fs_id = fs_id;
flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
MLX5_FLOW_CONTEXT_ACTION_CRYPTO_ENCRYPT |
struct mlx5e_macsec_tx_rule *
mlx5e_macsec_fs_add_rule(struct mlx5e_macsec_fs *macsec_fs,
const struct macsec_context *macsec_ctx,
- struct mlx5_macsec_rule_attrs *attrs)
+ 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);
+ return macsec_fs_tx_add_rule(macsec_fs, macsec_ctx, attrs, sa_fs_id);
return NULL;
}