Parav Pandit
2021-Jun-16 19:11 UTC
[PATCH linux-next v3 0/6] vdpa: enable user to set mac, mtu
Currently user cannot set the mac address and mtu of the vdpa device. This patchset enables users to set the mac address and mtu of the vdpa device once the device is created. If a vendor driver supports such configuration user can set it otherwise user gets unsupported error. vdpa mac address and mtu are device configuration layout fields. To keep interface generic enough for multiple types of vdpa devices, mac address and mtu setting is implemented as configuration layout config knobs. This enables to use similar config layout for other virtio devices. An example of query & set of config layout fields for vdpa_sim_net driver: Configuration layout fields are set after device is created. This enables user to change such fields at later point without destroying and recreating the device for new config. $ vdpa mgmtdev show vdpasim_net: supported_classes net Add the device: $ vdpa dev add name bar mgmtdev vdpasim_net Configure mac address and mtu: $ vdpa dev config set bar mac 00:11:22:33:44:55 mtu 9000 In above command only mac address or only mtu can also be set. View the config after setting: $ vdpa dev config show bar: mac 00:11:22:33:44:55 link up link_announce false mtu 9000 speed 0 duplex 0 Patch summary: Patch-1 introduced and use helpers for get/set config area Patch-2 implement query device config layout Patch-3 enanble user to set mac and mtu in config space Patch-4 vdpa_sim_net implements get and set of config layout Patch-5 mlx5 vdpa driver supports user provided mac config Patch-6 mlx5 vdpa driver uses user provided mac during rx flow steering changelog: v2->v3: - dropped patches which are merged - simplified code to handle non transitional devices v1->v2: - new patches to fix kdoc comment to add new kdoc section - new patch to have synchronized access to features and config space - read whole net config layout instead of individual fields - added error extack for unmanaged vdpa device - fixed several endianness issues - introduced vdpa device ops for get config which is synchronized with other get/set features ops and config ops - fixed mtu range checking for max - using NLA_POLICY_ETH_ADDR - set config moved to device ops instead of mgmtdev ops - merged build and set to single routine - ensuring that user has NET_ADMIN capability for configuring network attributes - using updated interface and callbacks for get/set config - following new api for config get/set for mgmt tool in mlx5 vdpa driver - fixes for accessing right SF dma device and bar address - fix for mtu calculation - fix for bit access in features - fix for index restore with suspend/resume operation Eli Cohen (2): vdpa/mlx5: Support configuration of MAC vdpa/mlx5: Forward only packets with allowed MAC address Parav Pandit (4): vdpa: Introduce and use vdpa device get, set config helpers vdpa: Introduce query of device config layout vdpa: Enable user to set mac and mtu of vdpa device vdpa_sim_net: Enable user to set mac address and mtu drivers/vdpa/mlx5/net/mlx5_vnet.c | 101 ++++++-- drivers/vdpa/vdpa.c | 337 +++++++++++++++++++++++++++ drivers/vdpa/vdpa_sim/vdpa_sim.c | 13 ++ drivers/vdpa/vdpa_sim/vdpa_sim.h | 2 + drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 34 +-- drivers/vhost/vdpa.c | 3 +- include/linux/vdpa.h | 38 +-- include/uapi/linux/vdpa.h | 12 + 8 files changed, 490 insertions(+), 50 deletions(-) -- 2.26.2
Parav Pandit
2021-Jun-16 19:11 UTC
[PATCH linux-next v3 1/6] vdpa: Introduce and use vdpa device get, set config helpers
Subsequent patches enable get and set configuration either via management device or via vdpa device' config ops. This requires synchronization between multiple callers to get and set config callbacks. Features setting also influence the layout of the configuration fields endianness. To avoid exposing synchronization primitives to callers, introduce helper for setting the configuration and use it. Signed-off-by: Parav Pandit <parav at nvidia.com> Reviewed-by: Eli Cohen <elic at nvidia.com> --- changelog: v1->v2 - new patch to have synchronized access to features and config space --- drivers/vdpa/vdpa.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/vhost/vdpa.c | 3 +-- include/linux/vdpa.h | 18 ++++-------------- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c index bb3f1d1f0422..bc44cdc34114 100644 --- a/drivers/vdpa/vdpa.c +++ b/drivers/vdpa/vdpa.c @@ -284,6 +284,42 @@ void vdpa_mgmtdev_unregister(struct vdpa_mgmt_dev *mdev) } EXPORT_SYMBOL_GPL(vdpa_mgmtdev_unregister); +/** + * vdpa_get_config - Get one or more device configuration fields. + * @vdev: vdpa device to operate on + * @offset: starting byte offset of the field + * @buf: buffer pointer to read to + * @len: length of the configuration fields in bytes + */ +void vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, + void *buf, unsigned int len) +{ + const struct vdpa_config_ops *ops = vdev->config; + + /* + * Config accesses aren't supposed to trigger before features are set. + * If it does happen we assume a legacy guest. + */ + if (!vdev->features_valid) + vdpa_set_features(vdev, 0); + ops->get_config(vdev, offset, buf, len); +} +EXPORT_SYMBOL_GPL(vdpa_get_config); + +/** + * vdpa_set_config - Set one or more device configuration fields. + * @vdev: vdpa device to operate on + * @offset: starting byte offset of the field + * @buf: buffer pointer to read from + * @length: length of the configuration fields in bytes + */ +void vdpa_set_config(struct vdpa_device *vdev, unsigned int offset, + void *buf, unsigned int length) +{ + vdev->config->set_config(vdev, offset, buf, length); +} +EXPORT_SYMBOL_GPL(vdpa_set_config); + static bool mgmtdev_handle_match(const struct vdpa_mgmt_dev *mdev, const char *busname, const char *devname) { diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index fb41db3da611..908b4fb251b3 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -231,7 +231,6 @@ static long vhost_vdpa_set_config(struct vhost_vdpa *v, struct vhost_vdpa_config __user *c) { struct vdpa_device *vdpa = v->vdpa; - const struct vdpa_config_ops *ops = vdpa->config; struct vhost_vdpa_config config; unsigned long size = offsetof(struct vhost_vdpa_config, buf); u8 *buf; @@ -245,7 +244,7 @@ static long vhost_vdpa_set_config(struct vhost_vdpa *v, if (IS_ERR(buf)) return PTR_ERR(buf); - ops->set_config(vdpa, config.off, buf, config.len); + vdpa_set_config(vdpa, config.off, buf, config.len); kvfree(buf); return 0; diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index f311d227aa1b..993d99519452 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -332,20 +332,10 @@ static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features) return ops->set_features(vdev, features); } - -static inline void vdpa_get_config(struct vdpa_device *vdev, unsigned offset, - void *buf, unsigned int len) -{ - const struct vdpa_config_ops *ops = vdev->config; - - /* - * Config accesses aren't supposed to trigger before features are set. - * If it does happen we assume a legacy guest. - */ - if (!vdev->features_valid) - vdpa_set_features(vdev, 0); - ops->get_config(vdev, offset, buf, len); -} +void vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, + void *buf, unsigned int len); +void vdpa_set_config(struct vdpa_device *dev, unsigned int offset, + void *buf, unsigned int length); /** * struct vdpa_mgmtdev_ops - vdpa device ops -- 2.26.2
Parav Pandit
2021-Jun-16 19:11 UTC
[PATCH linux-next v3 2/6] vdpa: Introduce query of device config layout
Introduce a command to query a device config layout. An example query of network vdpa device: $ vdpa dev add name bar mgmtdev vdpasim_net $ vdpa dev config show bar: mac 00:35:09:19:48:05 link up link_announce false mtu 1500 speed 0 duplex 0 $ vdpa dev config show -jp { "config": { "bar": { "mac": "00:35:09:19:48:05", "link ": "up", "link_announce ": false, "mtu": 1500, "speed": 0, "duplex": 0 } } } Signed-off-by: Parav Pandit <parav at nvidia.com> Signed-off-by: Eli Cohen <elic at nvidia.com> --- drivers/vdpa/vdpa.c | 212 ++++++++++++++++++++++++++++++++++++++ include/linux/vdpa.h | 2 + include/uapi/linux/vdpa.h | 11 ++ 3 files changed, 225 insertions(+) diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c index bc44cdc34114..1295528244c3 100644 --- a/drivers/vdpa/vdpa.c +++ b/drivers/vdpa/vdpa.c @@ -14,6 +14,8 @@ #include <uapi/linux/vdpa.h> #include <net/genetlink.h> #include <linux/mod_devicetable.h> +#include <linux/virtio_net.h> +#include <linux/virtio_ids.h> static LIST_HEAD(mdev_head); /* A global mutex that protects vdpa management device and device level operations. */ @@ -60,6 +62,7 @@ static void vdpa_release_dev(struct device *d) ops->free(vdev); ida_simple_remove(&vdpa_index_ida, vdev->index); + mutex_destroy(&vdev->cf_mutex); kfree(vdev); } @@ -114,6 +117,7 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent, if (err) goto err_name; + mutex_init(&vdev->cf_mutex); device_initialize(&vdev->dev); return vdev; @@ -296,6 +300,7 @@ void vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, { const struct vdpa_config_ops *ops = vdev->config; + mutex_lock(&vdev->cf_mutex); /* * Config accesses aren't supposed to trigger before features are set. * If it does happen we assume a legacy guest. @@ -303,6 +308,7 @@ void vdpa_get_config(struct vdpa_device *vdev, unsigned int offset, if (!vdev->features_valid) vdpa_set_features(vdev, 0); ops->get_config(vdev, offset, buf, len); + mutex_unlock(&vdev->cf_mutex); } EXPORT_SYMBOL_GPL(vdpa_get_config); @@ -316,7 +322,9 @@ EXPORT_SYMBOL_GPL(vdpa_get_config); void vdpa_set_config(struct vdpa_device *vdev, unsigned int offset, void *buf, unsigned int length) { + mutex_lock(&vdev->cf_mutex); vdev->config->set_config(vdev, offset, buf, length); + mutex_unlock(&vdev->cf_mutex); } EXPORT_SYMBOL_GPL(vdpa_set_config); @@ -643,6 +651,204 @@ static int vdpa_nl_cmd_dev_get_dumpit(struct sk_buff *msg, struct netlink_callba return msg->len; } +static int vdpa_dev_net_mq_config_fill(struct vdpa_device *vdev, + struct sk_buff *msg, u64 features, + const struct virtio_net_config *config) +{ + u16 val_u16; + + if ((features & (1ULL << VIRTIO_NET_F_MQ)) == 0) + return 0; + + val_u16 = le16_to_cpu(config->max_virtqueue_pairs); + return nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MAX_VQP, val_u16); +} + +static int vdpa_dev_net_rss_config_fill(struct vdpa_device *vdev, + struct sk_buff *msg, u64 features, + const struct virtio_net_config *config) +{ + u16 val_u16; + u16 val_u32; + + if ((features & (1ULL << VIRTIO_NET_F_RSS)) == 0) + return 0; + + if (nla_put_u8(msg, VDPA_ATTR_DEV_NET_CFG_RSS_MAX_KEY_LEN, + config->rss_max_key_size)) + return -EMSGSIZE; + + val_u16 = le16_to_cpu(config->rss_max_key_size); + if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_RSS_MAX_IT_LEN, val_u16)) + return -EMSGSIZE; + + val_u32 = le32_to_cpu(config->supported_hash_types); + if (nla_put_u32(msg, VDPA_ATTR_DEV_NET_CFG_RSS_HASH_TYPES, val_u32)) + return -EMSGSIZE; + return 0; +} + +static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *msg) +{ + struct virtio_net_config config = {}; + u64 features; + u32 val_u32; + u16 val_u16; + int err; + + vdpa_get_config(vdev, 0, &config, sizeof(config)); + + if (nla_put(msg, VDPA_ATTR_DEV_NET_CFG_MACADDR, sizeof(config.mac), + config.mac)) + return -EMSGSIZE; + + val_u16 = le16_to_cpu(config.status); + if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16)) + return -EMSGSIZE; + + val_u16 = le16_to_cpu(config.mtu); + if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_CFG_MTU, val_u16)) + return -EMSGSIZE; + + val_u32 = le32_to_cpu(config.speed); + if (nla_put_u32(msg, VDPA_ATTR_DEV_NET_CFG_SPEED, val_u32)) + return -EMSGSIZE; + + if (nla_put_u8(msg, VDPA_ATTR_DEV_NET_CFG_DUPLEX, config.duplex)) + return -EMSGSIZE; + + features = vdev->config->get_features(vdev); + + err = vdpa_dev_net_mq_config_fill(vdev, msg, features, &config); + if (err) + return err; + return vdpa_dev_net_rss_config_fill(vdev, msg, features, &config); +} + +static int +vdpa_dev_config_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, u32 seq, + int flags, struct netlink_ext_ack *extack) +{ + u32 device_id; + void *hdr; + int err; + + hdr = genlmsg_put(msg, portid, seq, &vdpa_nl_family, flags, + VDPA_CMD_DEV_CONFIG_GET); + if (!hdr) + return -EMSGSIZE; + + if (nla_put_string(msg, VDPA_ATTR_DEV_NAME, dev_name(&vdev->dev))) { + err = -EMSGSIZE; + goto msg_err; + } + + device_id = vdev->config->get_device_id(vdev); + if (nla_put_u32(msg, VDPA_ATTR_DEV_ID, device_id)) { + err = -EMSGSIZE; + goto msg_err; + } + + switch (device_id) { + case VIRTIO_ID_NET: + err = vdpa_dev_net_config_fill(vdev, msg); + break; + default: + err = -EOPNOTSUPP; + break; + } + if (err) + goto msg_err; + + genlmsg_end(msg, hdr); + return 0; + +msg_err: + genlmsg_cancel(msg, hdr); + return err; +} + +static int vdpa_nl_cmd_dev_config_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct vdpa_device *vdev; + struct sk_buff *msg; + const char *devname; + struct device *dev; + int err; + + if (!info->attrs[VDPA_ATTR_DEV_NAME]) + return -EINVAL; + devname = nla_data(info->attrs[VDPA_ATTR_DEV_NAME]); + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + mutex_lock(&vdpa_dev_mutex); + dev = bus_find_device(&vdpa_bus, NULL, devname, vdpa_name_match); + if (!dev) { + NL_SET_ERR_MSG_MOD(info->extack, "device not found"); + err = -ENODEV; + goto dev_err; + } + vdev = container_of(dev, struct vdpa_device, dev); + if (!vdev->mdev) { + NL_SET_ERR_MSG_MOD(info->extack, "unmanaged vdpa device"); + err = -EINVAL; + goto mdev_err; + } + err = vdpa_dev_config_fill(vdev, msg, info->snd_portid, info->snd_seq, + 0, info->extack); + if (!err) + err = genlmsg_reply(msg, info); + +mdev_err: + put_device(dev); +dev_err: + mutex_unlock(&vdpa_dev_mutex); + if (err) + nlmsg_free(msg); + return err; +} + +static int vdpa_dev_config_dump(struct device *dev, void *data) +{ + struct vdpa_device *vdev = container_of(dev, struct vdpa_device, dev); + struct vdpa_dev_dump_info *info = data; + int err; + + if (!vdev->mdev) + return 0; + if (info->idx < info->start_idx) { + info->idx++; + return 0; + } + err = vdpa_dev_config_fill(vdev, info->msg, NETLINK_CB(info->cb->skb).portid, + info->cb->nlh->nlmsg_seq, NLM_F_MULTI, + info->cb->extack); + if (err) + return err; + + info->idx++; + return 0; +} + +static int +vdpa_nl_cmd_dev_config_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) +{ + struct vdpa_dev_dump_info info; + + info.msg = msg; + info.cb = cb; + info.start_idx = cb->args[0]; + info.idx = 0; + + mutex_lock(&vdpa_dev_mutex); + bus_for_each_dev(&vdpa_bus, NULL, &info, vdpa_dev_config_dump); + mutex_unlock(&vdpa_dev_mutex); + cb->args[0] = info.idx; + return msg->len; +} + static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = { [VDPA_ATTR_MGMTDEV_BUS_NAME] = { .type = NLA_NUL_STRING }, [VDPA_ATTR_MGMTDEV_DEV_NAME] = { .type = NLA_STRING }, @@ -674,6 +880,12 @@ static const struct genl_ops vdpa_nl_ops[] = { .doit = vdpa_nl_cmd_dev_get_doit, .dumpit = vdpa_nl_cmd_dev_get_dumpit, }, + { + .cmd = VDPA_CMD_DEV_CONFIG_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = vdpa_nl_cmd_dev_config_get_doit, + .dumpit = vdpa_nl_cmd_dev_config_get_dumpit, + }, }; static struct genl_family vdpa_nl_family __ro_after_init = { diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index 993d99519452..bf104f9f461a 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -42,6 +42,7 @@ struct vdpa_mgmt_dev; * @dev: underlying device * @dma_dev: the actual device that is performing DMA * @config: the configuration ops for this device. + * @cf_mutex: Protects get and set access to features and configuration layout. * @index: device index * @features_valid: were features initialized? for legacy guests * @nvqs: maximum number of supported virtqueues @@ -52,6 +53,7 @@ struct vdpa_device { struct device dev; struct device *dma_dev; const struct vdpa_config_ops *config; + struct mutex cf_mutex; /* Protects get/set config and features */ unsigned int index; bool features_valid; int nvqs; diff --git a/include/uapi/linux/vdpa.h b/include/uapi/linux/vdpa.h index 66a41e4ec163..5c31ecc3b956 100644 --- a/include/uapi/linux/vdpa.h +++ b/include/uapi/linux/vdpa.h @@ -17,6 +17,7 @@ enum vdpa_command { VDPA_CMD_DEV_NEW, VDPA_CMD_DEV_DEL, VDPA_CMD_DEV_GET, /* can dump */ + VDPA_CMD_DEV_CONFIG_GET, /* can dump */ }; enum vdpa_attr { @@ -33,6 +34,16 @@ enum vdpa_attr { VDPA_ATTR_DEV_MAX_VQS, /* u32 */ VDPA_ATTR_DEV_MAX_VQ_SIZE, /* u16 */ + VDPA_ATTR_DEV_NET_CFG_MACADDR, /* binary */ + VDPA_ATTR_DEV_NET_STATUS, /* u8 */ + VDPA_ATTR_DEV_NET_CFG_MAX_VQP, /* u16 */ + VDPA_ATTR_DEV_NET_CFG_MTU, /* u16 */ + VDPA_ATTR_DEV_NET_CFG_SPEED, /* u16 */ + VDPA_ATTR_DEV_NET_CFG_DUPLEX, /* u16 */ + VDPA_ATTR_DEV_NET_CFG_RSS_MAX_KEY_LEN, /* u8 */ + VDPA_ATTR_DEV_NET_CFG_RSS_MAX_IT_LEN, /* u16 */ + VDPA_ATTR_DEV_NET_CFG_RSS_HASH_TYPES, /* u32 */ + /* new attributes must be added above here */ VDPA_ATTR_MAX, }; -- 2.26.2
Parav Pandit
2021-Jun-16 19:11 UTC
[PATCH linux-next v3 3/6] vdpa: Enable user to set mac and mtu of vdpa device
$ vdpa dev add name bar mgmtdev vdpasim_net $ vdpa dev config set bar mac 00:11:22:33:44:55 mtu 9000 $ vdpa dev config show bar: mac 00:11:22:33:44:55 link up link_announce false mtu 9000 speed 0 duplex 0 $ vdpa dev config show -jp { "config": { "bar": { "mac": "00:11:22:33:44:55", "link ": "up", "link_announce ": false, "mtu": 9000, "speed": 0, "duplex": 0 } } } Signed-off-by: Parav Pandit <parav at nvidia.com> Reviewed-by: Eli Cohen <elic at nvidia.com> --- changelog: v2->v3: - using new setup_config callback to setup device params via mgmt tool to avoid mixing with existing set_config(). --- drivers/vdpa/vdpa.c | 91 ++++++++++++++++++++++++++++++++++++++- include/linux/vdpa.h | 18 ++++++++ include/uapi/linux/vdpa.h | 1 + 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c index 1295528244c3..40874bd92126 100644 --- a/drivers/vdpa/vdpa.c +++ b/drivers/vdpa/vdpa.c @@ -14,7 +14,6 @@ #include <uapi/linux/vdpa.h> #include <net/genetlink.h> #include <linux/mod_devicetable.h> -#include <linux/virtio_net.h> #include <linux/virtio_ids.h> static LIST_HEAD(mdev_head); @@ -849,10 +848,94 @@ vdpa_nl_cmd_dev_config_get_dumpit(struct sk_buff *msg, struct netlink_callback * return msg->len; } +static int vdpa_dev_net_config_set(struct vdpa_device *vdev, + struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr **nl_attrs = info->attrs; + struct vdpa_dev_set_config config = {}; + const u8 *macaddr; + int err; + + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + + if (!vdev->config->setup_config) + return -EOPNOTSUPP; + + if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR]) { + macaddr = nla_data(nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR]); + memcpy(config.net.mac, macaddr, sizeof(config.net.mac)); + config.net_mask.mac_valid = true; + } + if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU]) { + config.net.mtu + nla_get_u16(nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU]); + config.net_mask.mtu_valid = true; + } + + mutex_lock(&vdev->cf_mutex); + err = vdev->config->setup_config(vdev, &config); + mutex_unlock(&vdev->cf_mutex); + return err; +} + +static int vdpa_dev_config_set(struct vdpa_device *vdev, struct sk_buff *skb, + struct genl_info *info) +{ + int err = -EOPNOTSUPP; + u32 device_id; + + if (!vdev->mdev) + return -EOPNOTSUPP; + + device_id = vdev->config->get_device_id(vdev); + switch (device_id) { + case VIRTIO_ID_NET: + err = vdpa_dev_net_config_set(vdev, skb, info); + break; + default: + break; + } + return err; +} + +static int vdpa_nl_cmd_dev_config_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + struct vdpa_device *vdev; + const char *devname; + struct device *dev; + int err; + + if (!info->attrs[VDPA_ATTR_DEV_NAME]) + return -EINVAL; + devname = nla_data(info->attrs[VDPA_ATTR_DEV_NAME]); + + mutex_lock(&vdpa_dev_mutex); + dev = bus_find_device(&vdpa_bus, NULL, devname, vdpa_name_match); + if (!dev) { + mutex_unlock(&vdpa_dev_mutex); + NL_SET_ERR_MSG_MOD(info->extack, "device not found"); + return -ENODEV; + } + vdev = container_of(dev, struct vdpa_device, dev); + if (!vdev->mdev) { + mutex_unlock(&vdpa_dev_mutex); + put_device(dev); + return -EINVAL; + } + err = vdpa_dev_config_set(vdev, skb, info); + put_device(dev); + mutex_unlock(&vdpa_dev_mutex); + return err; +} + static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = { [VDPA_ATTR_MGMTDEV_BUS_NAME] = { .type = NLA_NUL_STRING }, [VDPA_ATTR_MGMTDEV_DEV_NAME] = { .type = NLA_STRING }, [VDPA_ATTR_DEV_NAME] = { .type = NLA_STRING }, + [VDPA_ATTR_DEV_NET_CFG_MACADDR] = NLA_POLICY_ETH_ADDR, + /* virtio spec 1.1 section 5.1.4.1 for valid MTU range */ + [VDPA_ATTR_DEV_NET_CFG_MTU] = NLA_POLICY_MIN(NLA_U16, 68), }; static const struct genl_ops vdpa_nl_ops[] = { @@ -886,6 +969,12 @@ static const struct genl_ops vdpa_nl_ops[] = { .doit = vdpa_nl_cmd_dev_config_get_doit, .dumpit = vdpa_nl_cmd_dev_config_get_dumpit, }, + { + .cmd = VDPA_CMD_DEV_CONFIG_SET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = vdpa_nl_cmd_dev_config_set_doit, + .flags = GENL_ADMIN_PERM, + }, }; static struct genl_family vdpa_nl_family __ro_after_init = { diff --git a/include/linux/vdpa.h b/include/linux/vdpa.h index bf104f9f461a..9b7238d5310e 100644 --- a/include/linux/vdpa.h +++ b/include/linux/vdpa.h @@ -6,6 +6,8 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/vhost_iotlb.h> +#include <linux/virtio_net.h> +#include <linux/if_ether.h> /** * struct vdpa_calllback - vDPA callback definition. @@ -70,6 +72,17 @@ struct vdpa_iova_range { u64 last; }; +struct vdpa_dev_set_config { + struct { + u8 mac[ETH_ALEN]; + u16 mtu; + } net; + struct { + u8 mac_valid: 1; + u8 mtu_valid: 1; + } net_mask; +}; + /** * struct vdpa_config_ops - operations for configuring a vDPA device. * Note: vDPA device drivers are required to implement all of the @@ -169,6 +182,9 @@ struct vdpa_iova_range { * @buf: buffer used to write from * @len: the length to write to * configuration space + * @setup_config: Setup configuration space + * @vdev: vdpa device + * #config: configuration to apply to device * @get_generation: Get device config generation (optional) * @vdev: vdpa device * Returns u32: device generation @@ -241,6 +257,8 @@ struct vdpa_config_ops { void *buf, unsigned int len); void (*set_config)(struct vdpa_device *vdev, unsigned int offset, const void *buf, unsigned int len); + int (*setup_config)(struct vdpa_device *vdev, + const struct vdpa_dev_set_config *config); u32 (*get_generation)(struct vdpa_device *vdev); struct vdpa_iova_range (*get_iova_range)(struct vdpa_device *vdev); diff --git a/include/uapi/linux/vdpa.h b/include/uapi/linux/vdpa.h index 5c31ecc3b956..ec349789b8d1 100644 --- a/include/uapi/linux/vdpa.h +++ b/include/uapi/linux/vdpa.h @@ -18,6 +18,7 @@ enum vdpa_command { VDPA_CMD_DEV_DEL, VDPA_CMD_DEV_GET, /* can dump */ VDPA_CMD_DEV_CONFIG_GET, /* can dump */ + VDPA_CMD_DEV_CONFIG_SET, }; enum vdpa_attr { -- 2.26.2
Parav Pandit
2021-Jun-16 19:11 UTC
[PATCH linux-next v3 4/6] vdpa_sim_net: Enable user to set mac address and mtu
Enable user to set the mac address and mtu so that each vdpa device can have its own user specified mac address and mtu. This is done by implementing the management device's configuration layout fields setting callback routine. Now that user is enabled to set the mac address, remove the module parameter for same. And example of setting mac addr and mtu: $ vdpa mgmtdev show $ vdpa dev add name bar mgmtdev vdpasim_net $ vdpa dev config set bar mac 00:11:22:33:44:55 mtu 9000 View the config after setting: $ vdpa dev config show bar: mac 00:11:22:33:44:55 link up link_announce false mtu 9000 speed 0 duplex 0 Signed-off-by: Parav Pandit <parav at nvidia.com> Reviewed-by: Eli Cohen <elic at nvidia.com> --- changelog: v1->v2: - using updated interface and callbacks for get/set config --- drivers/vdpa/vdpa_sim/vdpa_sim.c | 13 +++++++++++ drivers/vdpa/vdpa_sim/vdpa_sim.h | 2 ++ drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 34 +++++++++++++++------------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 98f793bc9376..e57cd1ff47e3 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -497,6 +497,17 @@ static void vdpasim_set_config(struct vdpa_device *vdpa, unsigned int offset, vdpasim->dev_attr.set_config(vdpasim, vdpasim->config); } +static int vdpasim_setup_config(struct vdpa_device *vdpa, + const struct vdpa_dev_set_config *config) +{ + struct vdpasim *vdpasim = vdpa_to_sim(vdpa); + + if (!vdpasim->dev_attr.setup_config) + return -EOPNOTSUPP; + + return vdpasim->dev_attr.setup_config(vdpasim, config); +} + static u32 vdpasim_get_generation(struct vdpa_device *vdpa) { struct vdpasim *vdpasim = vdpa_to_sim(vdpa); @@ -608,6 +619,7 @@ static const struct vdpa_config_ops vdpasim_config_ops = { .get_config_size = vdpasim_get_config_size, .get_config = vdpasim_get_config, .set_config = vdpasim_set_config, + .setup_config = vdpasim_setup_config, .get_generation = vdpasim_get_generation, .get_iova_range = vdpasim_get_iova_range, .dma_map = vdpasim_dma_map, @@ -636,6 +648,7 @@ static const struct vdpa_config_ops vdpasim_batch_config_ops = { .get_config_size = vdpasim_get_config_size, .get_config = vdpasim_get_config, .set_config = vdpasim_set_config, + .setup_config = vdpasim_setup_config, .get_generation = vdpasim_get_generation, .get_iova_range = vdpasim_get_iova_range, .set_map = vdpasim_set_map, diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.h b/drivers/vdpa/vdpa_sim/vdpa_sim.h index cd58e888bcf3..395894635010 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.h +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.h @@ -45,6 +45,8 @@ struct vdpasim_dev_attr { work_func_t work_fn; void (*get_config)(struct vdpasim *vdpasim, void *config); void (*set_config)(struct vdpasim *vdpasim, const void *config); + int (*setup_config)(struct vdpasim *vdpasim, + const struct vdpa_dev_set_config *config); }; /* State of each vdpasim device */ diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c index a1ab6163f7d1..5fcee88a89c5 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim_net.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim_net.c @@ -29,12 +29,6 @@ #define VDPASIM_NET_VQ_NUM 2 -static char *macaddr; -module_param(macaddr, charp, 0); -MODULE_PARM_DESC(macaddr, "Ethernet MAC address"); - -static u8 macaddr_buf[ETH_ALEN]; - static void vdpasim_net_work(struct work_struct *work) { struct vdpasim *vdpasim = container_of(work, struct vdpasim, work); @@ -112,9 +106,19 @@ static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config) { struct virtio_net_config *net_config = config; - net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500); net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP); - memcpy(net_config->mac, macaddr_buf, ETH_ALEN); +} + +static int vdpasim_net_setup_config(struct vdpasim *vdpasim, + const struct vdpa_dev_set_config *config) +{ + struct virtio_net_config *vio_config = vdpasim->config; + + if (config->net_mask.mac_valid) + memcpy(vio_config->mac, config->net.mac, ETH_ALEN); + if (config->net_mask.mtu_valid) + vio_config->mtu = cpu_to_vdpasim16(vdpasim, config->net.mtu); + return 0; } static void vdpasim_net_mgmtdev_release(struct device *dev) @@ -128,6 +132,7 @@ static struct device vdpasim_net_mgmtdev = { static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name) { + struct virtio_net_config *vio_config; struct vdpasim_dev_attr dev_attr = {}; struct vdpasim *simdev; int ret; @@ -139,6 +144,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name) dev_attr.nvqs = VDPASIM_NET_VQ_NUM; dev_attr.config_size = sizeof(struct virtio_net_config); dev_attr.get_config = vdpasim_net_get_config; + dev_attr.setup_config = vdpasim_net_setup_config; dev_attr.work_fn = vdpasim_net_work; dev_attr.buffer_size = PAGE_SIZE; @@ -146,6 +152,10 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name) if (IS_ERR(simdev)) return PTR_ERR(simdev); + vio_config = simdev->config; + /* Setup default MTU to be 1500 */ + vio_config->mtu = cpu_to_le16(1500); + ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM); if (ret) goto reg_err; @@ -185,14 +195,6 @@ static int __init vdpasim_net_init(void) { int ret; - if (macaddr) { - mac_pton(macaddr, macaddr_buf); - if (!is_valid_ether_addr(macaddr_buf)) - return -EADDRNOTAVAIL; - } else { - eth_random_addr(macaddr_buf); - } - ret = device_register(&vdpasim_net_mgmtdev); if (ret) return ret; -- 2.26.2
Parav Pandit
2021-Jun-16 19:11 UTC
[PATCH linux-next v3 5/6] vdpa/mlx5: Support configuration of MAC
From: Eli Cohen <elic at nvidia.com> Add code to accept MAC configuration through vdpa tool. The MAC is written into the config struct and later can be retrieved through get_config(). Examples: 1. Configure MAC: $ vdpa dev config set vdpa0 mac 00:11:22:33:44:55 2. Show configured params: $ vdpa dev config show vdpa0: mac 00:11:22:33:44:55 link down link_announce false mtu 0 speed 0 duplex 0 Signed-off-by: Eli Cohen <elic at nvidia.com> Reviewed-by: Parav Pandit <parav at nvidia.com> --- changelog: v2->v3: - following new api for config space setup for mgmt tool v1->v2: - following new api for config get/set for mgmt tool --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index dda5dc6f7737..7f3d09f201fc 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -1831,6 +1831,30 @@ static void mlx5_vdpa_set_config(struct vdpa_device *vdev, unsigned int offset, /* not supported */ } +static int mlx5_vdpa_setup_config(struct vdpa_device *vdev, + const struct vdpa_dev_set_config *config) +{ + struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); + struct mlx5_vdpa_net *ndev = to_mlx5_vdpa_ndev(mvdev); + int err = 0; + + mutex_lock(&ndev->reslock); + if (ndev->setup) + err = -EBUSY; + mutex_unlock(&ndev->reslock); + + if (err) + return err; + + if (config->net_mask.mtu_valid) + return -EOPNOTSUPP; + + if (config->net_mask.mac_valid) + memcpy(ndev->config.mac, config->net.mac, ETH_ALEN); + + return 0; +} + static u32 mlx5_vdpa_get_generation(struct vdpa_device *vdev) { struct mlx5_vdpa_dev *mvdev = to_mvdev(vdev); @@ -1909,6 +1933,7 @@ static const struct vdpa_config_ops mlx5_vdpa_ops = { .get_config_size = mlx5_vdpa_get_config_size, .get_config = mlx5_vdpa_get_config, .set_config = mlx5_vdpa_set_config, + .setup_config = mlx5_vdpa_setup_config, .get_generation = mlx5_vdpa_get_generation, .set_map = mlx5_vdpa_set_map, .free = mlx5_vdpa_free, -- 2.26.2
Parav Pandit
2021-Jun-16 19:11 UTC
[PATCH linux-next v3 6/6] vdpa/mlx5: Forward only packets with allowed MAC address
From: Eli Cohen <elic at nvidia.com> Add rules to forward packets to the net device's TIR only if the destination MAC is equal to the configured MAC. This is required to prevent the netdevice from receiving traffic not destined to its configured MAC. Signed-off-by: Eli Cohen <elic at nvidia.com> Reviewed-by: Parav Pandit <parav at nvidia.com> --- drivers/vdpa/mlx5/net/mlx5_vnet.c | 76 +++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 7f3d09f201fc..f7c8c34e76e9 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -148,7 +148,8 @@ struct mlx5_vdpa_net { struct mutex reslock; struct mlx5_flow_table *rxft; struct mlx5_fc *rx_counter; - struct mlx5_flow_handle *rx_rule; + struct mlx5_flow_handle *rx_rule_ucast; + struct mlx5_flow_handle *rx_rule_mcast; bool setup; u16 mtu; }; @@ -1296,21 +1297,33 @@ static int add_fwd_to_tir(struct mlx5_vdpa_net *ndev) struct mlx5_flow_table_attr ft_attr = {}; struct mlx5_flow_act flow_act = {}; struct mlx5_flow_namespace *ns; + struct mlx5_flow_spec *spec; + void *headers_c; + void *headers_v; + u8 *dmac_c; + u8 *dmac_v; int err; - /* for now, one entry, match all, forward to tir */ - ft_attr.max_fte = 1; - ft_attr.autogroup.max_num_groups = 1; + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + ft_attr.max_fte = 2; + ft_attr.autogroup.max_num_groups = 2; ns = mlx5_get_flow_namespace(ndev->mvdev.mdev, MLX5_FLOW_NAMESPACE_BYPASS); if (!ns) { - mlx5_vdpa_warn(&ndev->mvdev, "get flow namespace\n"); - return -EOPNOTSUPP; + mlx5_vdpa_warn(&ndev->mvdev, "failed to get flow namespace\n"); + err = -EOPNOTSUPP; + goto err_ns; } ndev->rxft = mlx5_create_auto_grouped_flow_table(ns, &ft_attr); - if (IS_ERR(ndev->rxft)) - return PTR_ERR(ndev->rxft); + if (IS_ERR(ndev->rxft)) { + err = PTR_ERR(ndev->rxft); + goto err_ns; + } ndev->rx_counter = mlx5_fc_create(ndev->mvdev.mdev, false); if (IS_ERR(ndev->rx_counter)) { @@ -1318,37 +1331,64 @@ static int add_fwd_to_tir(struct mlx5_vdpa_net *ndev) goto err_fc; } + headers_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, outer_headers); + dmac_c = MLX5_ADDR_OF(fte_match_param, headers_c, outer_headers.dmac_47_16); + memset(dmac_c, 0xff, ETH_ALEN); + headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers); + dmac_v = MLX5_ADDR_OF(fte_match_param, headers_v, outer_headers.dmac_47_16); + ether_addr_copy(dmac_v, ndev->config.mac); + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_COUNT; dest[0].type = MLX5_FLOW_DESTINATION_TYPE_TIR; dest[0].tir_num = ndev->res.tirn; dest[1].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; dest[1].counter_id = mlx5_fc_id(ndev->rx_counter); - ndev->rx_rule = mlx5_add_flow_rules(ndev->rxft, NULL, &flow_act, dest, 2); - if (IS_ERR(ndev->rx_rule)) { - err = PTR_ERR(ndev->rx_rule); - ndev->rx_rule = NULL; - goto err_rule; + ndev->rx_rule_ucast = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dest, 2); + + if (IS_ERR(ndev->rx_rule_ucast)) { + err = PTR_ERR(ndev->rx_rule_ucast); + ndev->rx_rule_ucast = NULL; + goto err_rule_ucast; + } + + memset(dmac_c, 0, ETH_ALEN); + memset(dmac_v, 0, ETH_ALEN); + dmac_c[0] = 1; + dmac_v[0] = 1; + flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; + ndev->rx_rule_mcast = mlx5_add_flow_rules(ndev->rxft, spec, &flow_act, dest, 1); + if (IS_ERR(ndev->rx_rule_mcast)) { + err = PTR_ERR(ndev->rx_rule_mcast); + ndev->rx_rule_mcast = NULL; + goto err_rule_mcast; } + kvfree(spec); return 0; -err_rule: +err_rule_mcast: + mlx5_del_flow_rules(ndev->rx_rule_ucast); + ndev->rx_rule_ucast = NULL; +err_rule_ucast: mlx5_fc_destroy(ndev->mvdev.mdev, ndev->rx_counter); err_fc: mlx5_destroy_flow_table(ndev->rxft); +err_ns: + kvfree(spec); return err; } static void remove_fwd_to_tir(struct mlx5_vdpa_net *ndev) { - if (!ndev->rx_rule) + if (!ndev->rx_rule_ucast) return; - mlx5_del_flow_rules(ndev->rx_rule); + mlx5_del_flow_rules(ndev->rx_rule_mcast); + ndev->rx_rule_mcast = NULL; + mlx5_del_flow_rules(ndev->rx_rule_ucast); + ndev->rx_rule_ucast = NULL; mlx5_fc_destroy(ndev->mvdev.mdev, ndev->rx_counter); mlx5_destroy_flow_table(ndev->rxft); - - ndev->rx_rule = NULL; } static void mlx5_vdpa_kick_vq(struct vdpa_device *vdev, u16 idx) -- 2.26.2
Michael S. Tsirkin
2021-Aug-05 09:57 UTC
[PATCH linux-next v3 0/6] vdpa: enable user to set mac, mtu
On Wed, Jun 16, 2021 at 10:11:49PM +0300, Parav Pandit wrote:> Currently user cannot set the mac address and mtu of the vdpa device. > This patchset enables users to set the mac address and mtu of the vdpa > device once the device is created. > If a vendor driver supports such configuration user can set it otherwise > user gets unsupported error.This makes sense to me overall. People are used to use netlink to set these parameters, and virtio does not necessarily have a way to set all device parameters - they can be RO in the config space.> vdpa mac address and mtu are device configuration layout fields. > To keep interface generic enough for multiple types of vdpa devices, mac > address and mtu setting is implemented as configuration layout config > knobs. > This enables to use similar config layout for other virtio devices. > > An example of query & set of config layout fields for vdpa_sim_net > driver: > > Configuration layout fields are set after device is created. > This enables user to change such fields at later point without destroying and > recreating the device for new config. > > $ vdpa mgmtdev show > vdpasim_net: > supported_classes net > > Add the device: > $ vdpa dev add name bar mgmtdev vdpasim_net > > Configure mac address and mtu: > $ vdpa dev config set bar mac 00:11:22:33:44:55 mtu 9000 > > In above command only mac address or only mtu can also be set. > > View the config after setting: > $ vdpa dev config show > bar: mac 00:11:22:33:44:55 link up link_announce false mtu 9000 speed 0 duplex 0 > > Patch summary: > Patch-1 introduced and use helpers for get/set config area > Patch-2 implement query device config layout > Patch-3 enanble user to set mac and mtu in config space > Patch-4 vdpa_sim_net implements get and set of config layout > Patch-5 mlx5 vdpa driver supports user provided mac config > Patch-6 mlx5 vdpa driver uses user provided mac during rx flow steering > > changelog: > v2->v3: > - dropped patches which are merged > - simplified code to handle non transitional devices > > v1->v2: > - new patches to fix kdoc comment to add new kdoc section > - new patch to have synchronized access to features and config space > - read whole net config layout instead of individual fields > - added error extack for unmanaged vdpa device > - fixed several endianness issues > - introduced vdpa device ops for get config which is synchronized > with other get/set features ops and config ops > - fixed mtu range checking for max > - using NLA_POLICY_ETH_ADDR > - set config moved to device ops instead of mgmtdev ops > - merged build and set to single routine > - ensuring that user has NET_ADMIN capability for configuring network > attributes > - using updated interface and callbacks for get/set config > - following new api for config get/set for mgmt tool in mlx5 vdpa > driver > - fixes for accessing right SF dma device and bar address > - fix for mtu calculation > - fix for bit access in features > - fix for index restore with suspend/resume operation > > > Eli Cohen (2): > vdpa/mlx5: Support configuration of MAC > vdpa/mlx5: Forward only packets with allowed MAC address > > Parav Pandit (4): > vdpa: Introduce and use vdpa device get, set config helpers > vdpa: Introduce query of device config layout > vdpa: Enable user to set mac and mtu of vdpa device > vdpa_sim_net: Enable user to set mac address and mtu > > drivers/vdpa/mlx5/net/mlx5_vnet.c | 101 ++++++-- > drivers/vdpa/vdpa.c | 337 +++++++++++++++++++++++++++ > drivers/vdpa/vdpa_sim/vdpa_sim.c | 13 ++ > drivers/vdpa/vdpa_sim/vdpa_sim.h | 2 + > drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 34 +-- > drivers/vhost/vdpa.c | 3 +- > include/linux/vdpa.h | 38 +-- > include/uapi/linux/vdpa.h | 12 + > 8 files changed, 490 insertions(+), 50 deletions(-) > > -- > 2.26.2