On Thu, Sep 13, 2018 at 12:16:20PM -0700, Steve Wise wrote: > Add support for new LINK messages to allow adding and deleting rdma > interfaces. This will be used initially for soft rdma drivers which > instantiate device instances dynamically by the admin specifying a netdev > device to use. The rdma_rxe module will be the first user of these > messages. > > The design is modeled after RTNL_NEWLINK/DELLINK: rdma drivers > register with the rdma core if they provide link add/delete functions. > Each driver registers with a unique "type" string, that is used to > dispatch messages coming from user space. A new RDMA_NLDEV_ATTR is > defined for the "type" string. User mode will pass 3 attributes in a > NEWLINK message: RDMA_NLDEV_ATTR_IBDEV_NAME for the desired rdma device > name to be created, RDMA_NLDEV_ATTR_LINK_TYPE for the "type" of link > being added, and RDMA_NLDEV_ATTR_NDEV_NAME for the net_device interface > to use for this link. The DELLINK message will contain the IBDEV_NAME > and LINK_TYPE attributes. > > Signed-off-by: Steve Wise <swise@xxxxxxxxxxxxxxxxxxxxx> > --- > drivers/infiniband/core/nldev.c | 113 +++++++++++++++++++++++++++++++++++++++ > include/rdma/rdma_netlink.h | 11 ++++ > include/uapi/rdma/rdma_netlink.h | 9 ++++ > 3 files changed, 133 insertions(+) > > diff --git a/drivers/infiniband/core/nldev.c b/drivers/infiniband/core/nldev.c > index 0385ab438320..d107b982c210 100644 > --- a/drivers/infiniband/core/nldev.c > +++ b/drivers/infiniband/core/nldev.c > @@ -33,6 +33,7 @@ > #include <linux/module.h> > #include <linux/pid.h> > #include <linux/pid_namespace.h> > +#include <linux/mutex.h> > #include <net/netlink.h> > #include <rdma/rdma_cm.h> > #include <rdma/rdma_netlink.h> > @@ -107,6 +108,8 @@ > [RDMA_NLDEV_ATTR_DRIVER_U32] = { .type = NLA_U32 }, > [RDMA_NLDEV_ATTR_DRIVER_S64] = { .type = NLA_S64 }, > [RDMA_NLDEV_ATTR_DRIVER_U64] = { .type = NLA_U64 }, > + [RDMA_NLDEV_ATTR_LINK_TYPE] = { .type = NLA_NUL_STRING, > + .len = IFNAMSIZ }, In case, we are continuing this path, better to use our define RDMA_NLDEV_ATTR_ENTRY_STRLEN. > }; > > static int put_driver_name_print_type(struct sk_buff *msg, const char *name, > @@ -1072,6 +1075,110 @@ static int nldev_res_get_pd_dumpit(struct sk_buff *skb, > return res_get_common_dumpit(skb, cb, RDMA_RESTRACK_PD); > } > > +static LIST_HEAD(link_ops); > +static DEFINE_MUTEX(link_ops_mutex); > + > +void rdma_link_register(struct rdma_link_ops *ops) > +{ > + mutex_lock(&link_ops_mutex); > + list_add(&ops->list, &link_ops); > + mutex_unlock(&link_ops_mutex); > +} > +EXPORT_SYMBOL(rdma_link_register); > + > +void rdma_link_unregister(struct rdma_link_ops *ops) > +{ > + mutex_lock(&link_ops_mutex); > + list_del_init(&ops->list); Why did you use list_del_init and not list_del? And in case we will use device_type, we won't need manage list at all :) > + mutex_unlock(&link_ops_mutex); > +} > +EXPORT_SYMBOL(rdma_link_unregister); > + > +static const struct rdma_link_ops *link_ops_get(const char *type) > +{ > + const struct rdma_link_ops *ops; > + > + mutex_lock(&link_ops_mutex); > + list_for_each_entry(ops, &link_ops, list) { > + if (!strncmp(ops->type, type, IFNAMSIZ)) > + goto out; > + } > + ops = NULL; > +out: > + mutex_unlock(&link_ops_mutex); > + return ops; > +} > + > +static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, > + struct netlink_ext_ack *extack) > +{ > + struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; > + char ibdev_name[IB_DEVICE_NAME_MAX]; > + const struct rdma_link_ops *ops; > + char ndev_name[IFNAMSIZ]; > + char type[IFNAMSIZ]; > + int err; > + > + err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, > + nldev_policy, extack); > + if (err || !tb[RDMA_NLDEV_ATTR_DEV_NAME] || > + !tb[RDMA_NLDEV_ATTR_LINK_TYPE] || !tb[RDMA_NLDEV_ATTR_NDEV_NAME]) { > + err = -EINVAL; > + goto err_out; > + } > + > + nla_strlcpy(ibdev_name, tb[RDMA_NLDEV_ATTR_DEV_NAME], > + sizeof(ibdev_name)); Query from userspace should be done RDMA_NLDEV_ATTR_DEV_INDEX, because it is our handle and not device name. > + nla_strlcpy(type, tb[RDMA_NLDEV_ATTR_LINK_TYPE], sizeof(type)); Will it mean that type should be unique? > + nla_strlcpy(ndev_name, tb[RDMA_NLDEV_ATTR_NDEV_NAME], > + sizeof(ndev_name)); > + pr_debug("ibdev_name |%s| type |%s| ndev_name |%s|\n", ibdev_name, > + type, ndev_name); > + > + ops = link_ops_get(type); > + if (!ops) { > + err = -ENODEV; > + goto err_out; > + } > + > + err = ops->newlink(ibdev_name, ndev_name); > +err_out: > + return err; > +} > + > +static int nldev_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, > + struct netlink_ext_ack *extack) > +{ > + struct nlattr *tb[RDMA_NLDEV_ATTR_MAX]; > + char ibdev_name[IB_DEVICE_NAME_MAX]; > + const struct rdma_link_ops *ops; > + char type[IFNAMSIZ]; > + int err; > + > + err = nlmsg_parse(nlh, 0, tb, RDMA_NLDEV_ATTR_MAX - 1, > + nldev_policy, extack); > + if (err || !tb[RDMA_NLDEV_ATTR_DEV_NAME] || > + !tb[RDMA_NLDEV_ATTR_LINK_TYPE]) { > + err = !err ? -EINVAL : err; > + goto err_out; > + } > + > + nla_strlcpy(ibdev_name, tb[RDMA_NLDEV_ATTR_DEV_NAME], > + sizeof(ibdev_name)); > + nla_strlcpy(type, tb[RDMA_NLDEV_ATTR_LINK_TYPE], sizeof(type)); > + pr_debug("ibdev_name |%s| type |%s|\n", ibdev_name, type); The same comments, > + > + ops = link_ops_get(type); > + if (!ops) { > + err = -ENODEV; > + goto err_out; > + } > + > + err = ops->dellink(ibdev_name); > +err_out: > + return err; > +} > + > static const struct rdma_nl_cbs nldev_cb_table[RDMA_NLDEV_NUM_OPS] = { > [RDMA_NLDEV_CMD_GET] = { > .doit = nldev_get_doit, > @@ -1110,6 +1217,12 @@ static int nldev_res_get_pd_dumpit(struct sk_buff *skb, > [RDMA_NLDEV_CMD_RES_PD_GET] = { > .dump = nldev_res_get_pd_dumpit, > }, > + [RDMA_NLDEV_CMD_NEWLINK] = { > + .doit = nldev_newlink, > + }, > + [RDMA_NLDEV_CMD_DELLINK] = { > + .doit = nldev_dellink, > + }, > }; > > void __init nldev_init(void) > diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h > index c369703fcd69..b5a5a1a7cddc 100644 > --- a/include/rdma/rdma_netlink.h > +++ b/include/rdma/rdma_netlink.h > @@ -99,4 +99,15 @@ int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, > * Returns 0 on success or a negative for no listeners. > */ > int rdma_nl_chk_listeners(unsigned int group); > + > +struct rdma_link_ops { > + struct list_head list; > + const char *type; > + int (*newlink)(char *ibdev_name, char *ndev_name); > + int (*dellink)(char *ibdev_name); > +}; > + > +void rdma_link_register(struct rdma_link_ops *ops); > +void rdma_link_unregister(struct rdma_link_ops *ops); > + > #endif /* _RDMA_NETLINK_H */ > diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h > index edba6351ac13..025172d41fa7 100644 > --- a/include/uapi/rdma/rdma_netlink.h > +++ b/include/uapi/rdma/rdma_netlink.h > @@ -246,6 +246,10 @@ enum rdma_nldev_command { > > RDMA_NLDEV_CMD_RES_PD_GET, /* can dump */ > > + RDMA_NLDEV_CMD_NEWLINK, > + > + RDMA_NLDEV_CMD_DELLINK, > + Let's reuse 3 and 4 indexes, which are not occupied. > RDMA_NLDEV_NUM_OPS > }; > > @@ -427,6 +431,11 @@ enum rdma_nldev_attr { > RDMA_NLDEV_ATTR_DRIVER_U64, /* u64 */ > > /* > + * Identifies the rdma driver. eg: "rxe" or "siw" > + */ > + RDMA_NLDEV_ATTR_LINK_TYPE, /* string */ > + > + /* > * Always the end > */ > RDMA_NLDEV_ATTR_MAX > -- > 1.8.3.1 >
Attachment:
signature.asc
Description: PGP signature