]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
{IB/{core,ipoib},net/rds}: IPv6 support for ACL
authorKa-Cheong Poon <ka-cheong.poon@oracle.com>
Tue, 24 Oct 2017 14:59:30 +0000 (07:59 -0700)
committerChuck Anderson <chuck.anderson@oracle.com>
Mon, 11 Dec 2017 04:20:22 +0000 (20:20 -0800)
The IB ACL components are extended to support IPv6 address.  Some
of the ACL ioctls use a 32 bit integer to represent an IP address.  To
support IPv6, struct in6_addr needs to be used. To ensure backward
compatibility, a new ioctl will be introduced for each of those ioctls
that take a 32 bit integer as address. The original ioctls are kept
and can still be used. The new ioctls can take IPv4 mapped IPv6
address so new apps only need to use the new ioctls.

The IPOIBACLNGET and IPOIBACLNADD commands re-use the same
ipoib_ioctl_req_data, except that the ips field should actually be a
pointer to a list of struct in6_addr.  Here we assume that the pointer
size to an u32 and in6_addr are the same.

Orabug: 25410192

Signed-off-by: Ka-Cheong Poon <ka-cheong.poon@oracle.com>
Reviewed-by: Yuval Shaia <yuval.shaia@oracle.com>
Reviewed-by: HÃ¥kon Bugge <haakon.bugge@oracle.com>
drivers/infiniband/core/cm.c
drivers/infiniband/ulp/ipoib/ipoib.h
drivers/infiniband/ulp/ipoib/ipoib_ioctl.c
include/rdma/ib_cm.h
net/rds/ib_cm.c

index 46c7659bf69a9fe9ec1991bb80cb75504274f607..e8bb4a92cbd6079dec3330376f68463b0a61e5f5 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/workqueue.h>
 #include <linux/kdev_t.h>
 #include <linux/etherdevice.h>
+#include <net/ipv6.h>
 
 #include <rdma/ib_cache.h>
 #include <rdma/ib_cm.h>
@@ -767,8 +768,8 @@ void ib_cm_acl_init(struct ib_cm_acl *acl)
 }
 EXPORT_SYMBOL(ib_cm_acl_init);
 
-int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
-                    const char *uuid)
+int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid,
+                    struct in6_addr *ip, const char *uuid)
 {
        struct ib_cm_acl_elem *elem;
        struct rb_node **new, *parent = NULL;
@@ -805,7 +806,7 @@ int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
                goto err_nomem;
        elem->guid = guid;
        elem->subnet_prefix = subnet_prefix;
-       elem->ip = ip;
+       elem->ip = *ip;
        memcpy(elem->uuid, uuid, UUID_SZ);
        elem->ref_count = 1;
        rb_link_node(&elem->node, parent, new);
@@ -868,7 +869,8 @@ struct ib_cm_acl_elem *ib_cm_acl_lookup(struct ib_cm_acl *acl,
 EXPORT_SYMBOL(ib_cm_acl_lookup);
 
 struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
-                                               char *uuid, u32 ip)
+                                               char *uuid,
+                                               const struct in6_addr *ip)
 {
        struct ib_cm_acl_elem *elem, *ret = NULL;
        struct rb_node *node;
@@ -878,7 +880,8 @@ struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
        node = rb_first(&acl->allowed_list);
        while (node) {
                elem = container_of(node, struct ib_cm_acl_elem, node);
-               if ((ip == elem->ip) && (!memcmp(uuid, elem->uuid, UUID_SZ))) {
+               if (ipv6_addr_equal(ip, &elem->ip) &&
+                   (!memcmp(uuid, elem->uuid, UUID_SZ))) {
                        ret = elem;
                        goto out;
                }
index bb977b906f5fb37f5b4036e072d80b5889e73646..24fbd6341825bf69559ed4cf0c8ac2444870219c 100644 (file)
@@ -133,17 +133,22 @@ 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)
+#define IPOIBACLIOCTLSTART     (SIOCDEVPRIVATE)
+#define IPOIBSTATUSGET         (IPOIBACLIOCTLSTART + 0)
+#define IPOIBSTATUSSET         (IPOIBACLIOCTLSTART + 1)
+#define IPOIBACLINSTSZ         (IPOIBACLIOCTLSTART + 2)
+#define IPOIBACLINSTGET                (IPOIBACLIOCTLSTART + 3)
+#define IPOIBACLINSTADD                (IPOIBACLIOCTLSTART + 4)
+#define IPOIBACLINSTDEL                (IPOIBACLIOCTLSTART + 5)
+#define IPOIBACLSZ             (IPOIBACLIOCTLSTART + 6)
+#define IPOIBACLGET            (IPOIBACLIOCTLSTART + 7)
+#define IPOIBACLADD            (IPOIBACLIOCTLSTART + 8)
+#define IPOIBACLDEL            (IPOIBACLIOCTLSTART + 9)
+/* Commands which can handle IPv6 address. */
+#define IPOIBACLNGET           (IPOIBACLIOCTLSTART + 10)
+#define IPOIBACLNADD           (IPOIBACLIOCTLSTART + 11)
+/* Value of IPOIBACIOCTLEND should be updated when new commands are added. */
+#define IPOIBACLIOCTLEND       (IPOIBACLIOCTLSTART + 11)
 
 /* structs */
 
index 1b08d2d6ad764b4b785547f261d0b4fb2da79340..9e417b1fb358fb452e51d2feb59d5896239429a1 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <net/arp.h>
 #include <linux/jhash.h>
+#include <net/ipv6.h>
 
 #include "ipoib.h"
 
@@ -42,18 +43,19 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        struct ib_cm_acl_elem *list;
        ssize_t list_count, i;
        u64 guid, subnet_prefix;
-       u32 ip;
+       struct in6_addr addr6;
        char uuid[UUID_SZ];
        struct ib_cm_acl *acl;
        char *buf;
 
-       if (cmd < IPOIBSTATUSGET || cmd > IPOIBACLDEL) {
+       if (cmd < IPOIBACLIOCTLSTART || cmd > IPOIBACLIOCTLEND) {
                ipoib_dbg(priv, "invalid ioctl opcode 0x%x\n", cmd);
                return -EOPNOTSUPP;
        }
 
        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;
@@ -104,6 +106,7 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                req_data.sz = list_count;
                break;
        case IPOIBACLGET:
+       case IPOIBACLNGET:
                if (!strcmp(req_data.instance_name, DRIVER_ACL_NAME))
                        acl = &priv->acl;
                else
@@ -113,8 +116,15 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        return -EINVAL;
 
                ib_cm_acl_scan(acl, &list, &list_count);
+
                for (i = req_data.from_idx; (i < list_count) &&
                     (i < req_data.sz) ; i++) {
+                       /* Need to skip entries with IPv6 address for old
+                        * IPOIBACLGET command.
+                        */
+                       if (cmd == IPOIBACLGET &&
+                           !ipv6_addr_v4mapped(&list[i].ip))
+                               continue;
                        rc = copy_to_user(&req_data.subnet_prefixes[i -
                                          req_data.from_idx],
                                          &(list[i].subnet_prefix),
@@ -122,9 +132,24 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        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));
+                       if (cmd == IPOIBACLGET)
+                               rc |= copy_to_user(&req_data.ips[i -
+                                                  req_data.from_idx],
+                                                  &(list[i].ip.s6_addr32[3]),
+                                                  sizeof(u32));
+                       else
+                               /* The IPOIBACLNGET command re-uses the same
+                                * ipoib_ioctl_req_data, except that the
+                                * ips should actually be a pointer to a list
+                                * of struct in6_addr.  Here we assume that
+                                * the pointer size to an u32 and in6_addr are
+                                * the same.
+                                */
+                               rc |= copy_to_user((struct in6_addr *)
+                                                  &req_data.ips[i -
+                                                  req_data.from_idx],
+                                                  &list[i].ip,
+                                                  sizeof(list[i].ip));
                        rc |= copy_to_user((req_data.uuids + i * UUID_SZ),
                                           list[i].uuid, UUID_SZ);
                        if (rc) {
@@ -139,18 +164,41 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                req_data.sz = i - req_data.from_idx;
                break;
        case IPOIBACLADD:
+       case IPOIBACLNADD:
                acl = ipoib_get_instance_acl(req_data.instance_name, dev);
                if (!acl)
                        return -EINVAL;
 
+               if (cmd == IPOIBACLADD) {
+                       /* IPOIBACLADD command contains a list of IPv4
+                        * addresses.  Need to convert them to IPv4 mapped
+                        * IPv6 addresses.  Pre-initialize the IPv6 address
+                        * to be an IPv4 mapped address.
+                        */
+                       addr6.s6_addr32[0] = 0;
+                       addr6.s6_addr32[1] = 0;
+                       addr6.s6_addr32[2] = htonl(0xFFFF);
+               }
+
                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));
+                       if (cmd == IPOIBACLADD)
+                               rc |= copy_from_user(&addr6.s6_addr32[3],
+                                                    &req_data.ips[i],
+                                                    sizeof(u32));
+                       else
+                               /* The IPOIBACLNADD command re-uses the same
+                                * ipoib_ioctl_req_data, except that the
+                                * ips should actually be a pointer to a list
+                                * of struct in6_addr.
+                                */
+                               rc |= copy_from_user(&addr6,
+                                                    &req_data.ips[i],
+                                                    sizeof(addr6));
                        rc |= copy_from_user(&uuid,
                                             (req_data.uuids + i * UUID_SZ),
                                             UUID_SZ);
@@ -160,10 +208,10 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                                           i);
                                return -EINVAL;
                        }
-                       rc = ib_cm_acl_insert(acl, subnet_prefix, guid, ip,
+                       rc = ib_cm_acl_insert(acl, subnet_prefix, guid, &addr6,
                                              uuid);
                        rc |= ib_cm_acl_insert(&priv->acl, subnet_prefix, guid,
-                                              ip, uuid);
+                                              &addr6, uuid);
                        if (rc) {
                                ipoib_warn(priv,
                                           "ioctl fail to insert index %ld to ACL\n",
index 7c06afdd01bfba51390448774591c6be7165dd8b..bc620bd98b62f2e0d988b96880275df111ff26d5 100644 (file)
@@ -36,6 +36,7 @@
 #define IB_CM_H
 
 #include <linux/spinlock.h>
+#include <linux/in6.h>
 
 #include <rdma/ib_mad.h>
 #include <rdma/ib_sa.h>
@@ -320,7 +321,7 @@ struct ib_cm_acl_elem {
        struct rb_node  node;
        u64             guid;
        u64             subnet_prefix;
-       u32             ip;
+       struct in6_addr ip;
        char            uuid[UUID_SZ];
        int             ref_count;
 };
@@ -333,12 +334,13 @@ struct ib_cm_acl {
 };
 
 void ib_cm_acl_init(struct ib_cm_acl *acl);
-int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
-                    const char *uuid);
+int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid,
+                    struct in6_addr *ip, const char *uuid);
 struct ib_cm_acl_elem *ib_cm_acl_lookup(struct ib_cm_acl *acl,
                                        u64 subnet_prefix, u64 guid);
 struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
-                                               char *uuid, u32 ip);
+                                               char *uuid,
+                                               const struct in6_addr *ip);
 int ib_cm_acl_delete(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid);
 void ib_cm_acl_scan(struct ib_cm_acl *acl, struct ib_cm_acl_elem **list,
                    ssize_t *list_count);
index 2445f161cbfab31b92f028154276387f58594b01..00244bf5e37c3a0dd7fa8380dceb489c071f18c0 100644 (file)
@@ -202,14 +202,14 @@ static inline void rds_ib_init_ic_frag(struct rds_ib_connection *ic)
 *  1 - acl is not enabled
 * -1 - acl match failed
 */
-static int rds_ib_match_acl(struct rdma_cm_id *cm_id, __be32 saddr)
+static int rds_ib_match_acl(struct rdma_cm_id *cm_id,
+                           const struct in6_addr *saddr)
 {
        struct ib_cm_acl *acl = 0;
        struct ib_cm_acl_elem *acl_elem = 0;
        __be64 fguid = cm_id->route.path_rec->dgid.global.interface_id;
        __be64 fsubnet = cm_id->route.path_rec->dgid.global.subnet_prefix;
        struct ib_cm_dpp dpp;
-       u32 addr;
 
        ib_cm_dpp_init(&dpp, cm_id->device, cm_id->port_num,
                       ntohs(cm_id->route.path_rec->pkey));
@@ -227,14 +227,10 @@ static int rds_ib_match_acl(struct rdma_cm_id *cm_id, __be32 saddr)
                goto out;
        }
 
-       addr = be32_to_cpu(saddr);
-       if (!addr)
-               goto out;
-
-       acl_elem = ib_cm_acl_lookup_uuid_ip(acl, acl_elem->uuid, addr);
+       acl_elem = ib_cm_acl_lookup_uuid_ip(acl, acl_elem->uuid, saddr);
        if (!acl_elem) {
-               pr_err_ratelimited("RDS/IB: IP %pI4 ib_cm_acl_lookup_uuid_ip() failed\n",
-                                  &saddr);
+               pr_err_ratelimited("RDS/IB: IP %pI6c ib_cm_acl_lookup_uuid_ip() failed\n",
+                                  saddr);
                goto out;
        }
 
@@ -1028,16 +1024,11 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
                (unsigned long long)be64_to_cpu(fguid),
                dp_cmn->ricpc_tos);
 
-       /* IPoIB ACL only supports IPv4.  Let all IPv6 traffic pass. */
-       if (ipv6_addr_v4mapped(saddr6)) {
-               acl_ret = rds_ib_match_acl(cm_id, saddr6->s6_addr32[3]);
-               if (acl_ret < 0) {
-                       err = RDS_ACL_FAILURE;
-                       rdsdebug("RDS: IB: passive: rds_ib_match_acl failed\n");
-                       goto out;
-               }
-       } else {
-               acl_ret = 0;
+       acl_ret = rds_ib_match_acl(cm_id, saddr6);
+       if (acl_ret < 0) {
+               err = RDS_ACL_FAILURE;
+               rdsdebug("RDS: IB: passive: rds_ib_match_acl failed\n");
+               goto out;
        }
 
        /* RDS/IB is not currently netns aware, thus init_net */
@@ -1203,11 +1194,7 @@ int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id, bool isv6)
        u16 frag;
        int ret;
 
-       /* IPoIB ACL only supports IPv4.  Let all IPv6 traffic pass. */
-       if (ipv6_addr_v4mapped(&conn->c_faddr))
-               ret = rds_ib_match_acl(ic->i_cm_id, conn->c_faddr.s6_addr32[3]);
-       else
-               ret = 0;
+       ret = rds_ib_match_acl(ic->i_cm_id, &conn->c_faddr);
        if (ret < 0) {
                pr_err("RDS: IB: active conn=%p, <%pI6c,%pI6c,%d> destroyed due ACL violation\n",
                       conn, &conn->c_laddr, &conn->c_faddr,