#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>
}
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;
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);
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;
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;
}
#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 */
#include <net/arp.h>
#include <linux/jhash.h>
+#include <net/ipv6.h>
#include "ipoib.h"
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;
req_data.sz = list_count;
break;
case IPOIBACLGET:
+ case IPOIBACLNGET:
if (!strcmp(req_data.instance_name, DRIVER_ACL_NAME))
acl = &priv->acl;
else
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),
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) {
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);
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",
#define IB_CM_H
#include <linux/spinlock.h>
+#include <linux/in6.h>
#include <rdma/ib_mad.h>
#include <rdma/ib_sa.h>
struct rb_node node;
u64 guid;
u64 subnet_prefix;
- u32 ip;
+ struct in6_addr ip;
char uuid[UUID_SZ];
int ref_count;
};
};
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);
* 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));
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;
}
(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 */
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,