Skip to content

Commit e95a33b

Browse files
kcp-gitLinuxMinion
authored andcommitted
{IB/{core,ipoib},net/rds}: IPv6 support for ACL
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 <[email protected]> Reviewed-by: Yuval Shaia <[email protected]> Reviewed-by: Håkon Bugge <[email protected]>
1 parent 160bb96 commit e95a33b

File tree

5 files changed

+98
-53
lines changed

5 files changed

+98
-53
lines changed

drivers/infiniband/core/cm.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <linux/workqueue.h>
4949
#include <linux/kdev_t.h>
5050
#include <linux/etherdevice.h>
51+
#include <net/ipv6.h>
5152

5253
#include <rdma/ib_cache.h>
5354
#include <rdma/ib_cm.h>
@@ -767,8 +768,8 @@ void ib_cm_acl_init(struct ib_cm_acl *acl)
767768
}
768769
EXPORT_SYMBOL(ib_cm_acl_init);
769770

770-
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
771-
const char *uuid)
771+
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid,
772+
struct in6_addr *ip, const char *uuid)
772773
{
773774
struct ib_cm_acl_elem *elem;
774775
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,
805806
goto err_nomem;
806807
elem->guid = guid;
807808
elem->subnet_prefix = subnet_prefix;
808-
elem->ip = ip;
809+
elem->ip = *ip;
809810
memcpy(elem->uuid, uuid, UUID_SZ);
810811
elem->ref_count = 1;
811812
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,
868869
EXPORT_SYMBOL(ib_cm_acl_lookup);
869870

870871
struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
871-
char *uuid, u32 ip)
872+
char *uuid,
873+
const struct in6_addr *ip)
872874
{
873875
struct ib_cm_acl_elem *elem, *ret = NULL;
874876
struct rb_node *node;
@@ -878,7 +880,8 @@ struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
878880
node = rb_first(&acl->allowed_list);
879881
while (node) {
880882
elem = container_of(node, struct ib_cm_acl_elem, node);
881-
if ((ip == elem->ip) && (!memcmp(uuid, elem->uuid, UUID_SZ))) {
883+
if (ipv6_addr_equal(ip, &elem->ip) &&
884+
(!memcmp(uuid, elem->uuid, UUID_SZ))) {
882885
ret = elem;
883886
goto out;
884887
}

drivers/infiniband/ulp/ipoib/ipoib.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,22 @@ enum {
133133
#define IPOIB_QPN_MASK ((__force u32) cpu_to_be32(0xFFFFFF))
134134

135135
/* AC ioctl commands */
136-
#define IPOIBACIOCTLSTART (SIOCDEVPRIVATE)
137-
#define IPOIBSTATUSGET (IPOIBACIOCTLSTART + 0)
138-
#define IPOIBSTATUSSET (IPOIBACIOCTLSTART + 1)
139-
#define IPOIBACLINSTSZ (IPOIBACIOCTLSTART + 2)
140-
#define IPOIBACLINSTGET (IPOIBACIOCTLSTART + 3)
141-
#define IPOIBACLINSTADD (IPOIBACIOCTLSTART + 4)
142-
#define IPOIBACLINSTDEL (IPOIBACIOCTLSTART + 5)
143-
#define IPOIBACLSZ (IPOIBACIOCTLSTART + 6)
144-
#define IPOIBACLGET (IPOIBACIOCTLSTART + 7)
145-
#define IPOIBACLADD (IPOIBACIOCTLSTART + 8)
146-
#define IPOIBACLDEL (IPOIBACIOCTLSTART + 9)
136+
#define IPOIBACLIOCTLSTART (SIOCDEVPRIVATE)
137+
#define IPOIBSTATUSGET (IPOIBACLIOCTLSTART + 0)
138+
#define IPOIBSTATUSSET (IPOIBACLIOCTLSTART + 1)
139+
#define IPOIBACLINSTSZ (IPOIBACLIOCTLSTART + 2)
140+
#define IPOIBACLINSTGET (IPOIBACLIOCTLSTART + 3)
141+
#define IPOIBACLINSTADD (IPOIBACLIOCTLSTART + 4)
142+
#define IPOIBACLINSTDEL (IPOIBACLIOCTLSTART + 5)
143+
#define IPOIBACLSZ (IPOIBACLIOCTLSTART + 6)
144+
#define IPOIBACLGET (IPOIBACLIOCTLSTART + 7)
145+
#define IPOIBACLADD (IPOIBACLIOCTLSTART + 8)
146+
#define IPOIBACLDEL (IPOIBACLIOCTLSTART + 9)
147+
/* Commands which can handle IPv6 address. */
148+
#define IPOIBACLNGET (IPOIBACLIOCTLSTART + 10)
149+
#define IPOIBACLNADD (IPOIBACLIOCTLSTART + 11)
150+
/* Value of IPOIBACIOCTLEND should be updated when new commands are added. */
151+
#define IPOIBACLIOCTLEND (IPOIBACLIOCTLSTART + 11)
147152

148153
/* structs */
149154

drivers/infiniband/ulp/ipoib/ipoib_ioctl.c

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include <net/arp.h>
3232
#include <linux/jhash.h>
33+
#include <net/ipv6.h>
3334

3435
#include "ipoib.h"
3536

@@ -42,18 +43,19 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4243
struct ib_cm_acl_elem *list;
4344
ssize_t list_count, i;
4445
u64 guid, subnet_prefix;
45-
u32 ip;
46+
struct in6_addr addr6;
4647
char uuid[UUID_SZ];
4748
struct ib_cm_acl *acl;
4849
char *buf;
4950

50-
if (cmd < IPOIBSTATUSGET || cmd > IPOIBACLDEL) {
51+
if (cmd < IPOIBACLIOCTLSTART || cmd > IPOIBACLIOCTLEND) {
5152
ipoib_dbg(priv, "invalid ioctl opcode 0x%x\n", cmd);
5253
return -EOPNOTSUPP;
5354
}
5455

5556
rc = copy_from_user(&req_data, rq->req_data,
5657
sizeof(struct ipoib_ioctl_req_data));
58+
5759
if (rc != 0) {
5860
ipoib_warn(priv, "ioctl fail to copy request data\n");
5961
return -EINVAL;
@@ -104,6 +106,7 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
104106
req_data.sz = list_count;
105107
break;
106108
case IPOIBACLGET:
109+
case IPOIBACLNGET:
107110
if (!strcmp(req_data.instance_name, DRIVER_ACL_NAME))
108111
acl = &priv->acl;
109112
else
@@ -113,18 +116,40 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
113116
return -EINVAL;
114117

115118
ib_cm_acl_scan(acl, &list, &list_count);
119+
116120
for (i = req_data.from_idx; (i < list_count) &&
117121
(i < req_data.sz) ; i++) {
122+
/* Need to skip entries with IPv6 address for old
123+
* IPOIBACLGET command.
124+
*/
125+
if (cmd == IPOIBACLGET &&
126+
!ipv6_addr_v4mapped(&list[i].ip))
127+
continue;
118128
rc = copy_to_user(&req_data.subnet_prefixes[i -
119129
req_data.from_idx],
120130
&(list[i].subnet_prefix),
121131
sizeof(u64));
122132
rc |= copy_to_user(&req_data.guids[i -
123133
req_data.from_idx], &(list[i].guid),
124134
sizeof(u64));
125-
rc |= copy_to_user(&req_data.ips[i -
126-
req_data.from_idx], &(list[i].ip),
127-
sizeof(u32));
135+
if (cmd == IPOIBACLGET)
136+
rc |= copy_to_user(&req_data.ips[i -
137+
req_data.from_idx],
138+
&(list[i].ip.s6_addr32[3]),
139+
sizeof(u32));
140+
else
141+
/* The IPOIBACLNGET command re-uses the same
142+
* ipoib_ioctl_req_data, except that the
143+
* ips should actually be a pointer to a list
144+
* of struct in6_addr. Here we assume that
145+
* the pointer size to an u32 and in6_addr are
146+
* the same.
147+
*/
148+
rc |= copy_to_user((struct in6_addr *)
149+
&req_data.ips[i -
150+
req_data.from_idx],
151+
&list[i].ip,
152+
sizeof(list[i].ip));
128153
rc |= copy_to_user((req_data.uuids + i * UUID_SZ),
129154
list[i].uuid, UUID_SZ);
130155
if (rc) {
@@ -139,18 +164,41 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
139164
req_data.sz = i - req_data.from_idx;
140165
break;
141166
case IPOIBACLADD:
167+
case IPOIBACLNADD:
142168
acl = ipoib_get_instance_acl(req_data.instance_name, dev);
143169
if (!acl)
144170
return -EINVAL;
145171

172+
if (cmd == IPOIBACLADD) {
173+
/* IPOIBACLADD command contains a list of IPv4
174+
* addresses. Need to convert them to IPv4 mapped
175+
* IPv6 addresses. Pre-initialize the IPv6 address
176+
* to be an IPv4 mapped address.
177+
*/
178+
addr6.s6_addr32[0] = 0;
179+
addr6.s6_addr32[1] = 0;
180+
addr6.s6_addr32[2] = htonl(0xFFFF);
181+
}
182+
146183
for (i = 0; i < req_data.sz; i++) {
147184
rc = copy_from_user(&subnet_prefix,
148185
&req_data.subnet_prefixes[i],
149186
sizeof(u64));
150187
rc |= copy_from_user(&guid, &req_data.guids[i],
151188
sizeof(u64));
152-
rc |= copy_from_user(&ip, &req_data.ips[i],
153-
sizeof(u32));
189+
if (cmd == IPOIBACLADD)
190+
rc |= copy_from_user(&addr6.s6_addr32[3],
191+
&req_data.ips[i],
192+
sizeof(u32));
193+
else
194+
/* The IPOIBACLNADD command re-uses the same
195+
* ipoib_ioctl_req_data, except that the
196+
* ips should actually be a pointer to a list
197+
* of struct in6_addr.
198+
*/
199+
rc |= copy_from_user(&addr6,
200+
&req_data.ips[i],
201+
sizeof(addr6));
154202
rc |= copy_from_user(&uuid,
155203
(req_data.uuids + i * UUID_SZ),
156204
UUID_SZ);
@@ -160,10 +208,10 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
160208
i);
161209
return -EINVAL;
162210
}
163-
rc = ib_cm_acl_insert(acl, subnet_prefix, guid, ip,
211+
rc = ib_cm_acl_insert(acl, subnet_prefix, guid, &addr6,
164212
uuid);
165213
rc |= ib_cm_acl_insert(&priv->acl, subnet_prefix, guid,
166-
ip, uuid);
214+
&addr6, uuid);
167215
if (rc) {
168216
ipoib_warn(priv,
169217
"ioctl fail to insert index %ld to ACL\n",

include/rdma/ib_cm.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#define IB_CM_H
3737

3838
#include <linux/spinlock.h>
39+
#include <linux/in6.h>
3940

4041
#include <rdma/ib_mad.h>
4142
#include <rdma/ib_sa.h>
@@ -320,7 +321,7 @@ struct ib_cm_acl_elem {
320321
struct rb_node node;
321322
u64 guid;
322323
u64 subnet_prefix;
323-
u32 ip;
324+
struct in6_addr ip;
324325
char uuid[UUID_SZ];
325326
int ref_count;
326327
};
@@ -333,12 +334,13 @@ struct ib_cm_acl {
333334
};
334335

335336
void ib_cm_acl_init(struct ib_cm_acl *acl);
336-
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
337-
const char *uuid);
337+
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid,
338+
struct in6_addr *ip, const char *uuid);
338339
struct ib_cm_acl_elem *ib_cm_acl_lookup(struct ib_cm_acl *acl,
339340
u64 subnet_prefix, u64 guid);
340341
struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
341-
char *uuid, u32 ip);
342+
char *uuid,
343+
const struct in6_addr *ip);
342344
int ib_cm_acl_delete(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid);
343345
void ib_cm_acl_scan(struct ib_cm_acl *acl, struct ib_cm_acl_elem **list,
344346
ssize_t *list_count);

net/rds/ib_cm.c

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,14 @@ static inline void rds_ib_init_ic_frag(struct rds_ib_connection *ic)
202202
* 1 - acl is not enabled
203203
* -1 - acl match failed
204204
*/
205-
static int rds_ib_match_acl(struct rdma_cm_id *cm_id, __be32 saddr)
205+
static int rds_ib_match_acl(struct rdma_cm_id *cm_id,
206+
const struct in6_addr *saddr)
206207
{
207208
struct ib_cm_acl *acl = 0;
208209
struct ib_cm_acl_elem *acl_elem = 0;
209210
__be64 fguid = cm_id->route.path_rec->dgid.global.interface_id;
210211
__be64 fsubnet = cm_id->route.path_rec->dgid.global.subnet_prefix;
211212
struct ib_cm_dpp dpp;
212-
u32 addr;
213213

214214
ib_cm_dpp_init(&dpp, cm_id->device, cm_id->port_num,
215215
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)
227227
goto out;
228228
}
229229

230-
addr = be32_to_cpu(saddr);
231-
if (!addr)
232-
goto out;
233-
234-
acl_elem = ib_cm_acl_lookup_uuid_ip(acl, acl_elem->uuid, addr);
230+
acl_elem = ib_cm_acl_lookup_uuid_ip(acl, acl_elem->uuid, saddr);
235231
if (!acl_elem) {
236-
pr_err_ratelimited("RDS/IB: IP %pI4 ib_cm_acl_lookup_uuid_ip() failed\n",
237-
&saddr);
232+
pr_err_ratelimited("RDS/IB: IP %pI6c ib_cm_acl_lookup_uuid_ip() failed\n",
233+
saddr);
238234
goto out;
239235
}
240236

@@ -1028,16 +1024,11 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
10281024
(unsigned long long)be64_to_cpu(fguid),
10291025
dp_cmn->ricpc_tos);
10301026

1031-
/* IPoIB ACL only supports IPv4. Let all IPv6 traffic pass. */
1032-
if (ipv6_addr_v4mapped(saddr6)) {
1033-
acl_ret = rds_ib_match_acl(cm_id, saddr6->s6_addr32[3]);
1034-
if (acl_ret < 0) {
1035-
err = RDS_ACL_FAILURE;
1036-
rdsdebug("RDS: IB: passive: rds_ib_match_acl failed\n");
1037-
goto out;
1038-
}
1039-
} else {
1040-
acl_ret = 0;
1027+
acl_ret = rds_ib_match_acl(cm_id, saddr6);
1028+
if (acl_ret < 0) {
1029+
err = RDS_ACL_FAILURE;
1030+
rdsdebug("RDS: IB: passive: rds_ib_match_acl failed\n");
1031+
goto out;
10411032
}
10421033

10431034
/* 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)
12031194
u16 frag;
12041195
int ret;
12051196

1206-
/* IPoIB ACL only supports IPv4. Let all IPv6 traffic pass. */
1207-
if (ipv6_addr_v4mapped(&conn->c_faddr))
1208-
ret = rds_ib_match_acl(ic->i_cm_id, conn->c_faddr.s6_addr32[3]);
1209-
else
1210-
ret = 0;
1197+
ret = rds_ib_match_acl(ic->i_cm_id, &conn->c_faddr);
12111198
if (ret < 0) {
12121199
pr_err("RDS: IB: active conn=%p, <%pI6c,%pI6c,%d> destroyed due ACL violation\n",
12131200
conn, &conn->c_laddr, &conn->c_faddr,

0 commit comments

Comments
 (0)