Commit 0ccc171e authored by Yevgeny Kliteynik's avatar Yevgeny Kliteynik Committed by Saeed Mahameed

net/mlx5: Geneve, Manage Geneve TLV options

Use Geneve TLV Options object to manage the flex parser matching
on the 32-bit options data.

When the first flow with a certain class/type values is requested to
be offloaded, create a FW object with FW command (Geneve TLV Options
general object) and start counting the number of flows using this object.

During this time, any request with a different class/type values will
fail to be offloaded.
Once the refcount reaches 0, destroy the TLV options general object,
and can now offload a flow with any class/type parameters.

Geneve TLV Options object is added to core device.
It is currently used to manage Geneve TLV options general
object allocation in FW and its reference counting only.
In the future it will also be used for managing geneve ports
by registering callbacks for ndo_udp_tunnel_add/del.
Reviewed-by: default avatarOz Shlomo <ozsh@mellanox.com>
Signed-off-by: default avatarYevgeny Kliteynik <kliteyn@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
parent d4a18e16
......@@ -31,7 +31,8 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
mlx5_core-$(CONFIG_MLX5_EN_ARFS) += en_arfs.o
mlx5_core-$(CONFIG_MLX5_EN_RXNFC) += en_fs_ethtool.o
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o
mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
lib/geneve.o
#
# Core extra
......
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2019 Mellanox Technologies. */
#include <linux/kernel.h>
#include "mlx5_core.h"
#include "geneve.h"
struct mlx5_geneve {
struct mlx5_core_dev *mdev;
__be16 opt_class;
u8 opt_type;
u32 obj_id;
struct mutex sync_lock; /* protect GENEVE obj operations */
u32 refcount;
};
static int mlx5_geneve_tlv_option_create(struct mlx5_core_dev *mdev,
__be16 class,
u8 type,
u8 len)
{
u32 in[MLX5_ST_SZ_DW(create_geneve_tlv_option_in)] = {};
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
u64 general_obj_types;
void *hdr, *opt;
u16 obj_id;
int err;
general_obj_types = MLX5_CAP_GEN_64(mdev, general_obj_types);
if (!(general_obj_types & MLX5_GENERAL_OBJ_TYPES_CAP_GENEVE_TLV_OPT))
return -EINVAL;
hdr = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, hdr);
opt = MLX5_ADDR_OF(create_geneve_tlv_option_in, in, geneve_tlv_opt);
MLX5_SET(general_obj_in_cmd_hdr, hdr, opcode, MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr, hdr, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
MLX5_SET(geneve_tlv_option, opt, option_class, be16_to_cpu(class));
MLX5_SET(geneve_tlv_option, opt, option_type, type);
MLX5_SET(geneve_tlv_option, opt, option_data_length, len);
err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
if (err)
return err;
obj_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
return obj_id;
}
static void mlx5_geneve_tlv_option_destroy(struct mlx5_core_dev *mdev, u16 obj_id)
{
u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_GENEVE_TLV_OPT);
MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, obj_id);
mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
}
int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt)
{
int res = 0;
if (IS_ERR_OR_NULL(geneve))
return -EOPNOTSUPP;
mutex_lock(&geneve->sync_lock);
if (geneve->refcount) {
if (geneve->opt_class == opt->opt_class &&
geneve->opt_type == opt->type) {
/* We already have TLV options obj allocated */
geneve->refcount++;
} else {
/* TLV options obj allocated, but its params
* do not match the new request.
* We support only one such object.
*/
mlx5_core_warn(geneve->mdev,
"Won't create Geneve TLV opt object with class:type:len = 0x%x:0x%x:%d (another class:type already exists)\n",
be16_to_cpu(opt->opt_class),
opt->type,
opt->length);
res = -EOPNOTSUPP;
goto unlock;
}
} else {
/* We don't have any TLV options obj allocated */
res = mlx5_geneve_tlv_option_create(geneve->mdev,
opt->opt_class,
opt->type,
opt->length);
if (res < 0) {
mlx5_core_warn(geneve->mdev,
"Failed creating Geneve TLV opt object class:type:len = 0x%x:0x%x:%d (err=%d)\n",
be16_to_cpu(opt->opt_class),
opt->type, opt->length, res);
goto unlock;
}
geneve->opt_class = opt->opt_class;
geneve->opt_type = opt->type;
geneve->obj_id = res;
geneve->refcount++;
}
unlock:
mutex_unlock(&geneve->sync_lock);
return res;
}
void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve)
{
if (IS_ERR_OR_NULL(geneve))
return;
mutex_lock(&geneve->sync_lock);
if (--geneve->refcount == 0) {
/* We've just removed the last user of Geneve option.
* Now delete the object in FW.
*/
mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
geneve->opt_class = 0;
geneve->opt_type = 0;
geneve->obj_id = 0;
}
mutex_unlock(&geneve->sync_lock);
}
struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev)
{
struct mlx5_geneve *geneve =
kzalloc(sizeof(*geneve), GFP_KERNEL);
if (!geneve)
return ERR_PTR(-ENOMEM);
geneve->mdev = mdev;
mutex_init(&geneve->sync_lock);
return geneve;
}
void mlx5_geneve_destroy(struct mlx5_geneve *geneve)
{
if (IS_ERR_OR_NULL(geneve))
return;
/* Lockless since we are unloading */
if (geneve->refcount)
mlx5_geneve_tlv_option_destroy(geneve->mdev, geneve->obj_id);
kfree(geneve);
}
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2019 Mellanox Technologies. */
#ifndef __MLX5_GENEVE_H__
#define __MLX5_GENEVE_H__
#include <net/geneve.h>
#include <linux/mlx5/driver.h>
struct mlx5_geneve;
#ifdef CONFIG_MLX5_ESWITCH
struct mlx5_geneve *mlx5_geneve_create(struct mlx5_core_dev *mdev);
void mlx5_geneve_destroy(struct mlx5_geneve *geneve);
int mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt);
void mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve);
#else /* CONFIG_MLX5_ESWITCH */
static inline struct mlx5_geneve
*mlx5_geneve_create(struct mlx5_core_dev *mdev) { return NULL; }
static inline void
mlx5_geneve_destroy(struct mlx5_geneve *geneve) {}
static inline int
mlx5_geneve_tlv_option_add(struct mlx5_geneve *geneve, struct geneve_opt *opt) { return 0; }
static inline void
mlx5_geneve_tlv_option_del(struct mlx5_geneve *geneve) {}
#endif /* CONFIG_MLX5_ESWITCH */
#endif /* __MLX5_GENEVE_H__ */
......@@ -63,6 +63,7 @@
#include "accel/tls.h"
#include "lib/clock.h"
#include "lib/vxlan.h"
#include "lib/geneve.h"
#include "lib/devcom.h"
#include "diag/fw_tracer.h"
#include "ecpf.h"
......@@ -821,6 +822,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
mlx5_init_clock(dev);
dev->vxlan = mlx5_vxlan_create(dev);
dev->geneve = mlx5_geneve_create(dev);
err = mlx5_init_rl_table(dev);
if (err) {
......@@ -865,6 +867,7 @@ static int mlx5_init_once(struct mlx5_core_dev *dev)
err_rl_cleanup:
mlx5_cleanup_rl_table(dev);
err_tables_cleanup:
mlx5_geneve_destroy(dev->geneve);
mlx5_vxlan_destroy(dev->vxlan);
mlx5_cleanup_mkey_table(dev);
mlx5_cleanup_qp_table(dev);
......@@ -887,6 +890,7 @@ static void mlx5_cleanup_once(struct mlx5_core_dev *dev)
mlx5_eswitch_cleanup(dev->priv.eswitch);
mlx5_mpfs_cleanup(dev);
mlx5_cleanup_rl_table(dev);
mlx5_geneve_destroy(dev->geneve);
mlx5_vxlan_destroy(dev->vxlan);
mlx5_cleanup_clock(dev);
mlx5_cleanup_reserved_gids(dev);
......
......@@ -647,6 +647,7 @@ struct mlx5_clock {
struct mlx5_fw_tracer;
struct mlx5_vxlan;
struct mlx5_geneve;
struct mlx5_core_dev {
struct device *device;
......@@ -681,6 +682,7 @@ struct mlx5_core_dev {
u32 issi;
struct mlx5e_resources mlx5e_res;
struct mlx5_vxlan *vxlan;
struct mlx5_geneve *geneve;
struct {
struct mlx5_rsvd_gids reserved_gids;
u32 roce_en;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment