提交 5b0ec991 编写于 作者: S Sean Hefty 提交者: Roland Dreier

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: NSean Hefty <sean.hefty@intel.com>
Signed-off-by: NRoland Dreier <roland@purestorage.com>
上级 6887a413
...@@ -140,6 +140,7 @@ struct rdma_id_private { ...@@ -140,6 +140,7 @@ struct rdma_id_private {
u8 srq; u8 srq;
u8 tos; u8 tos;
u8 reuseaddr; u8 reuseaddr;
u8 afonly;
}; };
struct cma_multicast { struct cma_multicast {
...@@ -1573,6 +1574,7 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv, ...@@ -1573,6 +1574,7 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list); list_add_tail(&dev_id_priv->listen_list, &id_priv->listen_list);
atomic_inc(&id_priv->refcount); atomic_inc(&id_priv->refcount);
dev_id_priv->internal_id = 1; dev_id_priv->internal_id = 1;
dev_id_priv->afonly = id_priv->afonly;
ret = rdma_listen(id, id_priv->backlog); ret = rdma_listen(id, id_priv->backlog);
if (ret) if (ret)
...@@ -2187,22 +2189,24 @@ static int cma_check_port(struct rdma_bind_list *bind_list, ...@@ -2187,22 +2189,24 @@ static int cma_check_port(struct rdma_bind_list *bind_list,
struct hlist_node *node; struct hlist_node *node;
addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr; addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
if (cma_any_addr(addr) && !reuseaddr)
return -EADDRNOTAVAIL;
hlist_for_each_entry(cur_id, node, &bind_list->owners, node) { hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
if (id_priv == cur_id) if (id_priv == cur_id)
continue; continue;
if ((cur_id->state == RDMA_CM_LISTEN) || if ((cur_id->state != RDMA_CM_LISTEN) && reuseaddr &&
!reuseaddr || !cur_id->reuseaddr) { cur_id->reuseaddr)
cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr; continue;
if (cma_any_addr(cur_addr))
return -EADDRNOTAVAIL;
if (!cma_addr_cmp(addr, cur_addr)) cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
return -EADDRINUSE; if (id_priv->afonly && cur_id->afonly &&
} (addr->sa_family != cur_addr->sa_family))
continue;
if (cma_any_addr(addr) || cma_any_addr(cur_addr))
return -EADDRNOTAVAIL;
if (!cma_addr_cmp(addr, cur_addr))
return -EADDRINUSE;
} }
return 0; return 0;
} }
...@@ -2371,6 +2375,12 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) ...@@ -2371,6 +2375,12 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
} }
memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr)); memcpy(&id->route.addr.src_addr, addr, ip_addr_size(addr));
if (addr->sa_family == AF_INET)
id_priv->afonly = 1;
#if IS_ENABLED(CONFIG_IPV6)
else if (addr->sa_family == AF_INET6)
id_priv->afonly = init_net.ipv6.sysctl.bindv6only;
#endif
ret = cma_get_port(id_priv); ret = cma_get_port(id_priv);
if (ret) if (ret)
goto err2; goto err2;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册