From: Yuval Shaia Date: Mon, 4 Apr 2016 13:40:56 +0000 (+0300) Subject: IB/ipoib: ioctl interface to manage ACL tables X-Git-Tag: v4.1.12-92~108^2~13 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=ac017ac257af02cccb4ef395f94175a19f54a65f;p=users%2Fjedix%2Flinux-maple.git IB/ipoib: ioctl interface to manage ACL tables Expose ioctl to manage ACL content by application layer. Orabug: 23222944 Signed-off-by: Yuval Shaia Reviewed-by: Santosh Shilimkar merge into IOCTL code --- diff --git a/drivers/infiniband/ulp/ipoib/Makefile b/drivers/infiniband/ulp/ipoib/Makefile index a4145f2b31d9..dab3dee987c7 100644 --- a/drivers/infiniband/ulp/ipoib/Makefile +++ b/drivers/infiniband/ulp/ipoib/Makefile @@ -6,6 +6,7 @@ ib_ipoib-y := ipoib_main.o \ ipoib_verbs.o \ ipoib_vlan.o \ ipoib_ethtool.o \ + ipoib_ioctl.o \ ipoib_acl.o \ ipoib_netlink.o ib_ipoib-$(CONFIG_INFINIBAND_IPOIB_CM) += ipoib_cm.o diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index bfdf3e4437b4..59f7b94e5ff4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -130,6 +130,19 @@ enum { #define IPOIB_QPN_MASK ((__force u32) cpu_to_be32(0xFFFFFF)) +/* AC ioctl commands */ +#define IPOIBACIOCTLSTART (SIOCDEVPRIVATE) +#define IPOIBSTATUSGET (IPOIBACIOCTLSTART + 0) +#define IPOIBSTATUSSET (IPOIBACIOCTLSTART + 1) +#define IPOIBACLINSTSZ (IPOIBACIOCTLSTART + 2) +#define IPOIBACLINSTGET (IPOIBACIOCTLSTART + 3) +#define IPOIBACLINSTADD (IPOIBACIOCTLSTART + 4) +#define IPOIBACLINSTDEL (IPOIBACIOCTLSTART + 5) +#define IPOIBACLSZ (IPOIBACIOCTLSTART + 6) +#define IPOIBACLGET (IPOIBACIOCTLSTART + 7) +#define IPOIBACLADD (IPOIBACIOCTLSTART + 8) +#define IPOIBACLDEL (IPOIBACIOCTLSTART + 9) + /* structs */ struct ipoib_header { @@ -481,6 +494,27 @@ struct ipoib_neigh { unsigned long alive; }; +/* ACL ioctl API */ +struct ipoib_ioctl_req_data { + char acl_enabled; + u32 sz; + u32 from_idx; + u64 *guids; + u64 *subnet_prefixes; + u32 *ips; + char *uuids; + char instance_name[INSTANCE_ACL_ID_SZ]; + char *instances_names; +}; + +struct ipoib_ioctl_req { + union { + char frn_name[IFNAMSIZ]; + } ifr_ifrn; + + struct ipoib_ioctl_req_data *req_data; +}; + #define IPOIB_UD_MTU(ib_mtu) (ib_mtu - IPOIB_ENCAP_LEN) #define IPOIB_UD_BUF_SIZE(ib_mtu) (ib_mtu + IB_GRH_BYTES) @@ -529,6 +563,7 @@ static inline void ipoib_put_ah(struct ipoib_ah *ah) int ipoib_open(struct net_device *dev); int ipoib_add_pkey_attr(struct net_device *dev); int ipoib_add_umcast_attr(struct net_device *dev); +int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); void ipoib_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_ah *address, u32 qpn); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c b/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c new file mode 100644 index 000000000000..993d990f1dd1 --- /dev/null +++ b/drivers/infiniband/ulp/ipoib/ipoib_ioctl.c @@ -0,0 +1,205 @@ +/* + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipoib.h" + +int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct ipoib_ioctl_req *rq = (struct ipoib_ioctl_req *)ifr; + struct ipoib_ioctl_req_data req_data; + struct ipoib_dev_priv *priv = netdev_priv(dev); + int rc = 0; + struct ib_cm_acl_elem *list; + ssize_t list_count, i; + u64 guid, subnet_prefix; + u32 ip; + char uuid[UUID_SZ]; + struct ib_cm_acl *acl; + char *buf; + + rc = copy_from_user(&req_data, rq->req_data, + sizeof(struct ipoib_ioctl_req_data)); + if (rc != 0) { + ipoib_warn(priv, "ioctl fail to copy request data\n"); + return -EINVAL; + } + + switch (cmd) { + case IPOIBSTATUSGET: + req_data.acl_enabled = priv->acl.enabled; + break; + case IPOIBSTATUSSET: + priv->acl.enabled = req_data.acl_enabled; + break; + case IPOIBACLINSTSZ: + req_data.sz = priv->instances_acls.list_count; + break; + case IPOIBACLINSTGET: + buf = kmalloc(req_data.sz, GFP_KERNEL); + print_acl_instances_to_buf(buf, req_data.sz, priv); + rc = copy_to_user(req_data.instances_names, buf, req_data.sz); + kfree(buf); + if (rc) { + ipoib_warn(priv, + "ioctl fail to copy instances names to userspace\n"); + return -EINVAL; + } + break; + case IPOIBACLINSTADD: + rc = ipoib_create_instance_acl(req_data.instance_name, dev); + if (rc != 0) + return -EINVAL; + break; + case IPOIBACLINSTDEL: + rc = ipoib_delete_instance_acl(req_data.instance_name, dev); + if (rc != 0) + return -EINVAL; + break; + case IPOIBACLSZ: + if (!strcmp(req_data.instance_name, DRIVER_ACL_NAME)) + acl = &priv->acl; + else + acl = ipoib_get_instance_acl(req_data.instance_name, + dev); + if (!acl) + return -EINVAL; + + ib_cm_acl_scan(acl, &list, &list_count); + kfree(list); + req_data.sz = list_count; + break; + case IPOIBACLGET: + if (!strcmp(req_data.instance_name, DRIVER_ACL_NAME)) + acl = &priv->acl; + else + acl = ipoib_get_instance_acl(req_data.instance_name, + dev); + if (!acl) + return -EINVAL; + + ib_cm_acl_scan(acl, &list, &list_count); + for (i = req_data.from_idx; (i < list_count) && + (i < req_data.sz) ; i++) { + rc = copy_to_user(&req_data.subnet_prefixes[i - + req_data.from_idx], + &(list[i].subnet_prefix), + sizeof(u64)); + rc |= copy_to_user(&req_data.guids[i - + req_data.from_idx], &(list[i].guid), + sizeof(u64)); + rc |= copy_to_user(&req_data.ips[i - + req_data.from_idx], &(list[i].ip), + sizeof(u32)); + rc |= copy_to_user((req_data.uuids + i * UUID_SZ), + list[i].uuid, UUID_SZ); + if (rc) { + ipoib_warn(priv, + "ioctl fail to copy index %ld to userspace\n", + i); + kfree(list); + return -EINVAL; + } + } + kfree(list); + req_data.sz = i - req_data.from_idx; + break; + case IPOIBACLADD: + acl = ipoib_get_instance_acl(req_data.instance_name, dev); + if (!acl) + return -EINVAL; + + for (i = 0; i < req_data.sz; i++) { + rc = copy_from_user(&subnet_prefix, + &req_data.subnet_prefixes[i], + sizeof(u64)); + rc |= copy_from_user(&guid, &req_data.guids[i], + sizeof(u64)); + rc |= copy_from_user(&ip, &req_data.ips[i], + sizeof(u32)); + rc |= copy_from_user(&uuid, + (req_data.uuids + i * UUID_SZ), + UUID_SZ); + if (rc) { + ipoib_warn(priv, + "ioctl fail to copy index %ld from userspace\n", + i); + return -EINVAL; + } + rc = ib_cm_acl_insert(acl, subnet_prefix, guid, ip, + uuid); + rc |= ib_cm_acl_insert(&priv->acl, subnet_prefix, guid, + ip, uuid); + if (rc) { + ipoib_warn(priv, + "ioctl fail to insert index %ld to ACL\n", + i); + return -EINVAL; + } + } + break; + case IPOIBACLDEL: + acl = ipoib_get_instance_acl(req_data.instance_name, dev); + if (!acl) + return -EINVAL; + + for (i = 0; i < req_data.sz; i++) { + rc = copy_from_user(&subnet_prefix, + &req_data.subnet_prefixes[i], + sizeof(u64)); + rc |= copy_from_user(&guid, &req_data.guids[i], + sizeof(u64)); + if (rc) { + ipoib_warn(priv, + "ioctl fail to copy index %ld from userspace\n", + i); + return -EINVAL; + } + ib_cm_acl_delete(acl, subnet_prefix, guid); + ib_cm_acl_delete(&priv->acl, subnet_prefix, guid); + } + break; + default: + ipoib_dbg(priv, "invalid ioctl opcode 0x%x\n", cmd); + rc = -EINVAL; + break; + } + + rc = copy_to_user(rq->req_data, &req_data, + sizeof(struct ipoib_ioctl_req_data)); + if (rc != 0) { + ipoib_warn(priv, "ioctl fail to copy back request data\n"); + return -EINVAL; + } + + return rc; +} diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 24f158418899..721a6eacad97 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1433,6 +1433,7 @@ static const struct net_device_ops ipoib_netdev_ops = { .ndo_tx_timeout = ipoib_timeout, .ndo_set_rx_mode = ipoib_set_mcast_list, .ndo_get_iflink = ipoib_get_iflink, + .ndo_do_ioctl = ipoib_do_ioctl, }; void ipoib_setup(struct net_device *dev)