Skip to content

Commit 8223387

Browse files
kcp-gitSomasundaram Krishnasamy
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]> Orabug: 27487515 (cherry picked from commit e95a33b) cherry-pick-repo=linux-uek.git Signed-off-by: Gerd Rausch <[email protected]> Reviewed-by: Sudhakar Didnukurti <[email protected]> Signed-off-by: Aron Silverton <[email protected]> Signed-off-by: Somasundaram Krishnasamy <[email protected]>
1 parent 0301870 commit 8223387

File tree

5 files changed

+99
-56
lines changed

5 files changed

+99
-56
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>
@@ -839,8 +840,8 @@ void ib_cm_acl_init(struct ib_cm_acl *acl)
839840
}
840841
EXPORT_SYMBOL(ib_cm_acl_init);
841842

842-
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
843-
const char *uuid)
843+
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid,
844+
struct in6_addr *ip, const char *uuid)
844845
{
845846
struct ib_cm_acl_elem *elem;
846847
struct rb_node **new, *parent = NULL;
@@ -879,7 +880,7 @@ int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
879880
goto err_nomem;
880881
elem->guid = guid;
881882
elem->subnet_prefix = subnet_prefix;
882-
elem->ip = ip;
883+
elem->ip = *ip;
883884
memcpy(elem->uuid, uuid, UUID_SZ);
884885
elem->ref_count = 1;
885886
rb_link_node(&elem->node, parent, new);
@@ -944,7 +945,8 @@ struct ib_cm_acl_elem *ib_cm_acl_lookup(struct ib_cm_acl *acl,
944945
EXPORT_SYMBOL(ib_cm_acl_lookup);
945946

946947
struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
947-
char *uuid, u32 ip)
948+
char *uuid,
949+
const struct in6_addr *ip)
948950
{
949951
struct ib_cm_acl_elem *elem, *ret = NULL;
950952
struct rb_node *node;
@@ -954,7 +956,8 @@ struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
954956
node = rb_first(&acl->allowed_list);
955957
while (node) {
956958
elem = container_of(node, struct ib_cm_acl_elem, node);
957-
if ((ip == elem->ip) && (!memcmp(uuid, elem->uuid, UUID_SZ))) {
959+
if (ipv6_addr_equal(ip, &elem->ip) &&
960+
(!memcmp(uuid, elem->uuid, UUID_SZ))) {
958961
ret = elem;
959962
goto out;
960963
}

drivers/infiniband/ulp/ipoib/ipoib.h

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,22 @@ enum {
134134
#define IPOIB_QPN_MASK ((__force u32) cpu_to_be32(0xFFFFFF))
135135

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

151154
/* structs */
152155

drivers/infiniband/ulp/ipoib/ipoib_ioctl.c

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include <net/arp.h>
3434
#include <linux/jhash.h>
35+
#include <net/ipv6.h>
3536

3637
#include "ipoib.h"
3738

@@ -44,19 +45,20 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
4445
struct ib_cm_acl_elem *list;
4546
ssize_t list_count, i;
4647
u64 guid, subnet_prefix;
47-
u32 ip;
48+
struct in6_addr addr6;
4849
char uuid[UUID_SZ];
4950
struct ib_cm_acl *acl;
5051
char *buf;
5152

52-
if (cmd < IPOIBACIOCTLSTART || cmd > IPOIBACIOCTLEND) {
53+
if (cmd < IPOIBACLIOCTLSTART || cmd > IPOIBACLIOCTLEND) {
5354
ipoib_dbg(priv, "invalid ioctl opcode 0x%x\n", cmd);
5455
return -EOPNOTSUPP;
5556
}
5657

5758
rc = copy_from_user(&req_data, rq->req_data,
5859
sizeof(struct ipoib_ioctl_req_data));
59-
if (rc) {
60+
61+
if (rc != 0) {
6062
ipoib_warn(priv, "ioctl fail to copy request data\n");
6163
return -EINVAL;
6264
}
@@ -104,6 +106,7 @@ int ipoib_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
104106
req_data.sz = ib_cm_acl_size(acl);
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>
@@ -325,7 +326,7 @@ struct ib_cm_acl_elem {
325326
struct rb_node node;
326327
u64 guid;
327328
u64 subnet_prefix;
328-
u32 ip;
329+
struct in6_addr ip;
329330
char uuid[UUID_SZ];
330331
int ref_count;
331332
};
@@ -338,12 +339,13 @@ struct ib_cm_acl {
338339
};
339340

340341
void ib_cm_acl_init(struct ib_cm_acl *acl);
341-
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid, u32 ip,
342-
const char *uuid);
342+
int ib_cm_acl_insert(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid,
343+
struct in6_addr *ip, const char *uuid);
343344
struct ib_cm_acl_elem *ib_cm_acl_lookup(struct ib_cm_acl *acl,
344345
u64 subnet_prefix, u64 guid);
345346
struct ib_cm_acl_elem *ib_cm_acl_lookup_uuid_ip(struct ib_cm_acl *acl,
346-
char *uuid, u32 ip);
347+
char *uuid,
348+
const struct in6_addr *ip);
347349
int ib_cm_acl_delete(struct ib_cm_acl *acl, u64 subnet_prefix, u64 guid);
348350
ssize_t ib_cm_acl_size(struct ib_cm_acl *acl);
349351
void ib_cm_acl_scan(struct ib_cm_acl *acl, struct ib_cm_acl_elem **list,

net/rds/ib_cm.c

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -206,14 +206,14 @@ static inline void rds_ib_init_ic_frag(struct rds_ib_connection *ic)
206206
* 1 - acl is not enabled
207207
* -1 - acl match failed
208208
*/
209-
static int rds_ib_match_acl(struct rdma_cm_id *cm_id, __be32 saddr)
209+
static int rds_ib_match_acl(struct rdma_cm_id *cm_id,
210+
const struct in6_addr *saddr)
210211
{
211212
struct ib_cm_acl *acl = 0;
212213
struct ib_cm_acl_elem *acl_elem = 0;
213214
__be64 fguid = cm_id->route.path_rec->dgid.global.interface_id;
214215
__be64 fsubnet = cm_id->route.path_rec->dgid.global.subnet_prefix;
215216
struct ib_cm_dpp dpp;
216-
u32 addr;
217217

218218
ib_cm_dpp_init(&dpp, cm_id->device, cm_id->port_num,
219219
ntohs(cm_id->route.path_rec->pkey));
@@ -231,14 +231,10 @@ static int rds_ib_match_acl(struct rdma_cm_id *cm_id, __be32 saddr)
231231
goto out;
232232
}
233233

234-
addr = be32_to_cpu(saddr);
235-
if (!addr)
236-
goto out;
237-
238-
acl_elem = ib_cm_acl_lookup_uuid_ip(acl, acl_elem->uuid, addr);
234+
acl_elem = ib_cm_acl_lookup_uuid_ip(acl, acl_elem->uuid, saddr);
239235
if (!acl_elem) {
240-
pr_err_ratelimited("RDS/IB: IP %pI4 ib_cm_acl_lookup_uuid_ip() failed\n",
241-
&saddr);
236+
pr_err_ratelimited("RDS/IB: IP %pI6c ib_cm_acl_lookup_uuid_ip() failed\n",
237+
saddr);
242238
goto out;
243239
}
244240

@@ -1043,16 +1039,11 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
10431039

10441040
#ifdef CONFIG_RDS_ACL
10451041

1046-
/* IPoIB ACL only supports IPv4. Let all IPv6 traffic pass. */
1047-
if (ipv6_addr_v4mapped(saddr6)) {
1048-
acl_ret = rds_ib_match_acl(cm_id, saddr6->s6_addr32[3]);
1049-
if (acl_ret < 0) {
1050-
err = RDS_ACL_FAILURE;
1051-
rdsdebug("RDS: IB: passive: rds_ib_match_acl failed\n");
1052-
goto out;
1053-
}
1054-
} else {
1055-
acl_ret = 0;
1042+
acl_ret = rds_ib_match_acl(cm_id, saddr6);
1043+
if (acl_ret < 0) {
1044+
err = RDS_ACL_FAILURE;
1045+
rdsdebug("RDS: IB: passive: rds_ib_match_acl failed\n");
1046+
goto out;
10561047
}
10571048

10581049
#else /* !CONFIG_RDS_ACL */
@@ -1226,11 +1217,7 @@ int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id, bool isv6)
12261217

12271218
#ifdef CONFIG_RDS_ACL
12281219

1229-
/* IPoIB ACL only supports IPv4. Let all IPv6 traffic pass. */
1230-
if (ipv6_addr_v4mapped(&conn->c_faddr))
1231-
ret = rds_ib_match_acl(ic->i_cm_id, conn->c_faddr.s6_addr32[3]);
1232-
else
1233-
ret = 0;
1220+
ret = rds_ib_match_acl(ic->i_cm_id, &conn->c_faddr);
12341221
if (ret < 0) {
12351222
pr_err("RDS: IB: active conn=%p, <%pI6c,%pI6c,%d> destroyed due ACL violation\n",
12361223
conn, &conn->c_laddr, &conn->c_faddr,

0 commit comments

Comments
 (0)