diff options
author | Sean Hefty <sean.hefty@intel.com> | 2012-06-14 16:31:39 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2012-07-08 21:02:23 -0400 |
commit | 5b0ec991c0576c54db75803fbcb0ef5bebfa0828 (patch) | |
tree | 7d1abd89f59d77b596056df3c2c2bb97a113c301 | |
parent | 6887a4131da3adaab011613776d865f4bcfb5678 (diff) |
RDMA/cma: Bind to a specific address family
The RDMA CM uses a single port space for all associated (tcp, udp,
etc.) port bindings, regardless of the address family that the user
binds to. The result is that if a user binds to AF_INET, but does not
specify an IP address, the bind will occur for AF_INET6. This causes
an attempt to bind to the same port using AF_INET6 to fail, and
connection requests to AF_INET6 will match with the AF_INET listener.
Align the behavior with sockets and restrict the bind to AF_INET only.
If a user binds to AF_INET6, we bind the port to AF_INET6 and
AF_INET depending on the value of bindv6only.
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
-rw-r--r-- | drivers/infiniband/core/cma.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 2e826f9702c6..c10c45a07162 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c | |||
@@ -140,6 +140,7 @@ struct rdma_id_private { | |||
140 | u8 srq; | 140 | u8 srq; |
141 | u8 tos; | 141 | u8 tos; |
142 | u8 reuseaddr; | 142 | u8 reuseaddr; |
143 | u8 afonly; | ||
143 | }; | 144 | }; |
144 | 145 | ||
145 | struct cma_multicast { | 146 | struct cma_multicast { |
@@ -1573,6 +1574,7 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv, | |||
1573 | list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); | 1574 | list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); |
1574 | atomic_inc(&id_priv->refcount); | 1575 | atomic_inc(&id_priv->refcount); |
1575 | dev_id_priv->internal_id = 1; | 1576 | dev_id_priv->internal_id = 1; |
1577 | dev_id_priv->afonly = id_priv->afonly; | ||
1576 | 1578 | ||
1577 | ret = rdma_listen(id, id_priv->backlog); | 1579 | ret = rdma_listen(id, id_priv->backlog); |
1578 | if (ret) | 1580 | if (ret) |
@@ -2187,22 +2189,24 @@ static int cma_check_port(struct rdma_bind_list *bind_list, | |||
2187 | struct hlist_node *node; | 2189 | struct hlist_node *node; |
2188 | 2190 | ||
2189 | addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; | 2191 | addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; |
2190 | if (cma_any_addr(addr) && !reuseaddr) | ||
2191 | return -EADDRNOTAVAIL; | ||
2192 | |||
2193 | hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { | 2192 | hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { |
2194 | if (id_priv == cur_id) | 2193 | if (id_priv == cur_id) |
2195 | continue; | 2194 | continue; |
2196 | 2195 | ||
2197 | if ((cur_id->state == RDMA_CM_LISTEN) || | 2196 | if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr && |
2198 | !reuseaddr || !cur_id->reuseaddr) { | 2197 | cur_id->reuseaddr) |
2199 | cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; | 2198 | continue; |
2200 | if (cma_any_addr(cur_addr)) | ||
2201 | return -EADDRNOTAVAIL; | ||
2202 | 2199 | ||
2203 | if (!cma_addr_cmp(addr, cur_addr)) | 2200 | cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; |
2204 | return -EADDRINUSE; | 2201 | if (id_priv->afonly && cur_id->afonly && |
2205 | } | 2202 | (addr->sa_family != cur_addr->sa_family)) |
2203 | continue; | ||
2204 | |||
2205 | if (cma_any_addr(addr) || cma_any_addr(cur_addr)) | ||
2206 | return -EADDRNOTAVAIL; | ||
2207 | |||
2208 | if (!cma_addr_cmp(addr, cur_addr)) | ||
2209 | return -EADDRINUSE; | ||
2206 | } | 2210 | } |
2207 | return 0; | 2211 | return 0; |
2208 | } | 2212 | } |
@@ -2371,6 +2375,12 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) | |||
2371 | } | 2375 | } |
2372 | 2376 | ||
2373 | memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); | 2377 | memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); |
2378 | if (addr->sa_family == AF_INET) | ||
2379 | id_priv->afonly = 1; | ||
2380 | #if IS_ENABLED(CONFIG_IPV6) | ||
2381 | else if (addr->sa_family == AF_INET6) | ||
2382 | id_priv->afonly = init_net.ipv6.sysctl.bindv6only; | ||
2383 | #endif | ||
2374 | ret = cma_get_port(id_priv); | 2384 | ret = cma_get_port(id_priv); |
2375 | if (ret) | 2385 | if (ret) |
2376 | goto err2; | 2386 | goto err2; |