Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d7220e8 authored by Tetsuo Handa's avatar Tetsuo Handa Committed by Roland Dreier
Browse files

RDMA/cma: Randomize local port allocation



Randomize local port allocation in the way sctp_get_port_local() does.
Update rover at the end of loop since we're likely to pick a valid port
on the first try.

Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reviewed-by: default avatarSean Hefty <sean.hefty@intel.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 0eddb519
Loading
Loading
Loading
Loading
+25 −45
Original line number Diff line number Diff line
@@ -79,7 +79,6 @@ static DEFINE_IDR(sdp_ps);
static DEFINE_IDR(tcp_ps);
static DEFINE_IDR(udp_ps);
static DEFINE_IDR(ipoib_ps);
static int next_port;

struct cma_device {
	struct list_head	list;
@@ -1970,47 +1969,33 @@ err1:

static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
{
	struct rdma_bind_list *bind_list;
	int port, ret, low, high;

	bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
	if (!bind_list)
		return -ENOMEM;

retry:
	/* FIXME: add proper port randomization per like inet_csk_get_port */
	do {
		ret = idr_get_new_above(ps, bind_list, next_port, &port);
	} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));

	if (ret)
		goto err1;
	static unsigned int last_used_port;
	int low, high, remaining;
	unsigned int rover;

	inet_get_local_port_range(&low, &high);
	if (port > high) {
		if (next_port != low) {
			idr_remove(ps, port);
			next_port = low;
			goto retry;
	remaining = (high - low) + 1;
	rover = net_random() % remaining + low;
retry:
	if (last_used_port != rover &&
	    !idr_find(ps, (unsigned short) rover)) {
		int ret = cma_alloc_port(ps, id_priv, rover);
		/*
		 * Remember previously used port number in order to avoid
		 * re-using same port immediately after it is closed.
		 */
		if (!ret)
			last_used_port = rover;
		if (ret != -EADDRNOTAVAIL)
			return ret;
	}
		ret = -EADDRNOTAVAIL;
		goto err2;
	if (--remaining) {
		rover++;
		if ((rover < low) || (rover > high))
			rover = low;
		goto retry;
	}

	if (port == high)
		next_port = low;
	else
		next_port = port + 1;

	bind_list->ps = ps;
	bind_list->port = (unsigned short) port;
	cma_bind_port(bind_list, id_priv);
	return 0;
err2:
	idr_remove(ps, port);
err1:
	kfree(bind_list);
	return ret;
	return -EADDRNOTAVAIL;
}

static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
@@ -2995,12 +2980,7 @@ static void cma_remove_one(struct ib_device *device)

static int __init cma_init(void)
{
	int ret, low, high, remaining;

	get_random_bytes(&next_port, sizeof next_port);
	inet_get_local_port_range(&low, &high);
	remaining = (high - low) + 1;
	next_port = ((unsigned int) next_port % remaining) + low;
	int ret;

	cma_wq = create_singlethread_workqueue("rdma_cm");
	if (!cma_wq)