Commit 4be74b42 authored by Haggai Eran's avatar Haggai Eran Committed by Doug Ledford

IB/cma: Separate port allocation to network namespaces

Keep a struct for each network namespace containing the IDRs for the RDMA
CM port spaces. The struct is created dynamically using the generic_net
mechanism.

This patch is internal infrastructure work for the following patches. In
this patch, init_net is statically used as the network namespace for
the new port-space API.
Signed-off-by: default avatarHaggai Eran <haggaie@mellanox.com>
Signed-off-by: default avatarYotam Kenneth <yotamke@mellanox.com>
Signed-off-by: default avatarShachar Raindel <raindel@mellanox.com>
Signed-off-by: default avatarGuy Shapiro <guysh@mellanox.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 565edd1d
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <net/route.h> #include <net/route.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/ip_fib.h> #include <net/ip_fib.h>
...@@ -110,22 +112,33 @@ static LIST_HEAD(dev_list); ...@@ -110,22 +112,33 @@ static LIST_HEAD(dev_list);
static LIST_HEAD(listen_any_list); static LIST_HEAD(listen_any_list);
static DEFINE_MUTEX(lock); static DEFINE_MUTEX(lock);
static struct workqueue_struct *cma_wq; static struct workqueue_struct *cma_wq;
static DEFINE_IDR(tcp_ps); static int cma_pernet_id;
static DEFINE_IDR(udp_ps);
static DEFINE_IDR(ipoib_ps);
static DEFINE_IDR(ib_ps);
static struct idr *cma_idr(enum rdma_port_space ps) struct cma_pernet {
struct idr tcp_ps;
struct idr udp_ps;
struct idr ipoib_ps;
struct idr ib_ps;
};
static struct cma_pernet *cma_pernet(struct net *net)
{
return net_generic(net, cma_pernet_id);
}
static struct idr *cma_pernet_idr(struct net *net, enum rdma_port_space ps)
{ {
struct cma_pernet *pernet = cma_pernet(net);
switch (ps) { switch (ps) {
case RDMA_PS_TCP: case RDMA_PS_TCP:
return &tcp_ps; return &pernet->tcp_ps;
case RDMA_PS_UDP: case RDMA_PS_UDP:
return &udp_ps; return &pernet->udp_ps;
case RDMA_PS_IPOIB: case RDMA_PS_IPOIB:
return &ipoib_ps; return &pernet->ipoib_ps;
case RDMA_PS_IB: case RDMA_PS_IB:
return &ib_ps; return &pernet->ib_ps;
default: default:
return NULL; return NULL;
} }
...@@ -145,24 +158,25 @@ struct rdma_bind_list { ...@@ -145,24 +158,25 @@ struct rdma_bind_list {
unsigned short port; unsigned short port;
}; };
static int cma_ps_alloc(enum rdma_port_space ps, static int cma_ps_alloc(struct net *net, enum rdma_port_space ps,
struct rdma_bind_list *bind_list, int snum) struct rdma_bind_list *bind_list, int snum)
{ {
struct idr *idr = cma_idr(ps); struct idr *idr = cma_pernet_idr(net, ps);
return idr_alloc(idr, bind_list, snum, snum + 1, GFP_KERNEL); return idr_alloc(idr, bind_list, snum, snum + 1, GFP_KERNEL);
} }
static struct rdma_bind_list *cma_ps_find(enum rdma_port_space ps, int snum) static struct rdma_bind_list *cma_ps_find(struct net *net,
enum rdma_port_space ps, int snum)
{ {
struct idr *idr = cma_idr(ps); struct idr *idr = cma_pernet_idr(net, ps);
return idr_find(idr, snum); return idr_find(idr, snum);
} }
static void cma_ps_remove(enum rdma_port_space ps, int snum) static void cma_ps_remove(struct net *net, enum rdma_port_space ps, int snum)
{ {
struct idr *idr = cma_idr(ps); struct idr *idr = cma_pernet_idr(net, ps);
idr_remove(idr, snum); idr_remove(idr, snum);
} }
...@@ -1325,7 +1339,8 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id, ...@@ -1325,7 +1339,8 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id,
} }
} }
bind_list = cma_ps_find(rdma_ps_from_service_id(req.service_id), bind_list = cma_ps_find(&init_net,
rdma_ps_from_service_id(req.service_id),
cma_port_from_service_id(req.service_id)); cma_port_from_service_id(req.service_id));
id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev); id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev);
if (IS_ERR(id_priv) && *net_dev) { if (IS_ERR(id_priv) && *net_dev) {
...@@ -1403,7 +1418,7 @@ static void cma_release_port(struct rdma_id_private *id_priv) ...@@ -1403,7 +1418,7 @@ static void cma_release_port(struct rdma_id_private *id_priv)
mutex_lock(&lock); mutex_lock(&lock);
hlist_del(&id_priv->node); hlist_del(&id_priv->node);
if (hlist_empty(&bind_list->owners)) { if (hlist_empty(&bind_list->owners)) {
cma_ps_remove(bind_list->ps, bind_list->port); cma_ps_remove(&init_net, bind_list->ps, bind_list->port);
kfree(bind_list); kfree(bind_list);
} }
mutex_unlock(&lock); mutex_unlock(&lock);
...@@ -2693,7 +2708,7 @@ static int cma_alloc_port(enum rdma_port_space ps, ...@@ -2693,7 +2708,7 @@ static int cma_alloc_port(enum rdma_port_space ps,
if (!bind_list) if (!bind_list)
return -ENOMEM; return -ENOMEM;
ret = cma_ps_alloc(ps, bind_list, snum); ret = cma_ps_alloc(&init_net, ps, bind_list, snum);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -2718,7 +2733,7 @@ static int cma_alloc_any_port(enum rdma_port_space ps, ...@@ -2718,7 +2733,7 @@ static int cma_alloc_any_port(enum rdma_port_space ps,
rover = prandom_u32() % remaining + low; rover = prandom_u32() % remaining + low;
retry: retry:
if (last_used_port != rover && if (last_used_port != rover &&
!cma_ps_find(ps, (unsigned short)rover)) { !cma_ps_find(&init_net, ps, (unsigned short)rover)) {
int ret = cma_alloc_port(ps, id_priv, rover); int ret = cma_alloc_port(ps, id_priv, rover);
/* /*
* Remember previously used port number in order to avoid * Remember previously used port number in order to avoid
...@@ -2784,7 +2799,7 @@ static int cma_use_port(enum rdma_port_space ps, ...@@ -2784,7 +2799,7 @@ static int cma_use_port(enum rdma_port_space ps,
if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES; return -EACCES;
bind_list = cma_ps_find(ps, snum); bind_list = cma_ps_find(&init_net, ps, snum);
if (!bind_list) { if (!bind_list) {
ret = cma_alloc_port(ps, id_priv, snum); ret = cma_alloc_port(ps, id_priv, snum);
} else { } else {
...@@ -4004,6 +4019,35 @@ static const struct ibnl_client_cbs cma_cb_table[] = { ...@@ -4004,6 +4019,35 @@ static const struct ibnl_client_cbs cma_cb_table[] = {
.module = THIS_MODULE }, .module = THIS_MODULE },
}; };
static int cma_init_net(struct net *net)
{
struct cma_pernet *pernet = cma_pernet(net);
idr_init(&pernet->tcp_ps);
idr_init(&pernet->udp_ps);
idr_init(&pernet->ipoib_ps);
idr_init(&pernet->ib_ps);
return 0;
}
static void cma_exit_net(struct net *net)
{
struct cma_pernet *pernet = cma_pernet(net);
idr_destroy(&pernet->tcp_ps);
idr_destroy(&pernet->udp_ps);
idr_destroy(&pernet->ipoib_ps);
idr_destroy(&pernet->ib_ps);
}
static struct pernet_operations cma_pernet_operations = {
.init = cma_init_net,
.exit = cma_exit_net,
.id = &cma_pernet_id,
.size = sizeof(struct cma_pernet),
};
static int __init cma_init(void) static int __init cma_init(void)
{ {
int ret; int ret;
...@@ -4012,6 +4056,10 @@ static int __init cma_init(void) ...@@ -4012,6 +4056,10 @@ static int __init cma_init(void)
if (!cma_wq) if (!cma_wq)
return -ENOMEM; return -ENOMEM;
ret = register_pernet_subsys(&cma_pernet_operations);
if (ret)
goto err_wq;
ib_sa_register_client(&sa_client); ib_sa_register_client(&sa_client);
rdma_addr_register_client(&addr_client); rdma_addr_register_client(&addr_client);
register_netdevice_notifier(&cma_nb); register_netdevice_notifier(&cma_nb);
...@@ -4029,6 +4077,7 @@ static int __init cma_init(void) ...@@ -4029,6 +4077,7 @@ static int __init cma_init(void)
unregister_netdevice_notifier(&cma_nb); unregister_netdevice_notifier(&cma_nb);
rdma_addr_unregister_client(&addr_client); rdma_addr_unregister_client(&addr_client);
ib_sa_unregister_client(&sa_client); ib_sa_unregister_client(&sa_client);
err_wq:
destroy_workqueue(cma_wq); destroy_workqueue(cma_wq);
return ret; return ret;
} }
...@@ -4040,11 +4089,8 @@ static void __exit cma_cleanup(void) ...@@ -4040,11 +4089,8 @@ static void __exit cma_cleanup(void)
unregister_netdevice_notifier(&cma_nb); unregister_netdevice_notifier(&cma_nb);
rdma_addr_unregister_client(&addr_client); rdma_addr_unregister_client(&addr_client);
ib_sa_unregister_client(&sa_client); ib_sa_unregister_client(&sa_client);
unregister_pernet_subsys(&cma_pernet_operations);
destroy_workqueue(cma_wq); destroy_workqueue(cma_wq);
idr_destroy(&tcp_ps);
idr_destroy(&udp_ps);
idr_destroy(&ipoib_ps);
idr_destroy(&ib_ps);
} }
module_init(cma_init); module_init(cma_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment