Commit 1f4c3dce authored by James Chapman's avatar James Chapman Committed by David S. Miller
Browse files

l2tp: use get_next APIs for management requests and procfs/debugfs



l2tp netlink and procfs/debugfs iterate over tunnel and session lists
to obtain data. They currently use very inefficient get_nth functions
to do so. Replace these with get_next.

For netlink, use nl cb->ctx[] for passing state instead of the
obsolete cb->args[].

l2tp_tunnel_get_nth and l2tp_session_get_nth are no longer used so
they can be removed.

Signed-off-by: default avatarJames Chapman <jchapman@katalix.com>
Signed-off-by: default avatarTom Parkin <tparkin@katalix.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent aa92c1ce
Loading
Loading
Loading
Loading
+0 −40
Original line number Diff line number Diff line
@@ -241,27 +241,6 @@ struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
}
EXPORT_SYMBOL_GPL(l2tp_tunnel_get);

struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth)
{
	struct l2tp_net *pn = l2tp_pernet(net);
	unsigned long tunnel_id, tmp;
	struct l2tp_tunnel *tunnel;
	int count = 0;

	rcu_read_lock_bh();
	idr_for_each_entry_ul(&pn->l2tp_tunnel_idr, tunnel, tmp, tunnel_id) {
		if (tunnel && ++count > nth &&
		    refcount_inc_not_zero(&tunnel->ref_count)) {
			rcu_read_unlock_bh();
			return tunnel;
		}
	}
	rcu_read_unlock_bh();

	return NULL;
}
EXPORT_SYMBOL_GPL(l2tp_tunnel_get_nth);

struct l2tp_tunnel *l2tp_tunnel_get_next(const struct net *net, unsigned long *key)
{
	struct l2tp_net *pn = l2tp_pernet(net);
@@ -355,25 +334,6 @@ struct l2tp_session *l2tp_session_get(const struct net *net, struct sock *sk, in
}
EXPORT_SYMBOL_GPL(l2tp_session_get);

struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth)
{
	struct l2tp_session *session;
	int count = 0;

	rcu_read_lock_bh();
	list_for_each_entry_rcu(session, &tunnel->session_list, list) {
		if (++count > nth) {
			l2tp_session_inc_refcount(session);
			rcu_read_unlock_bh();
			return session;
		}
	}
	rcu_read_unlock_bh();

	return NULL;
}
EXPORT_SYMBOL_GPL(l2tp_session_get_nth);

static struct l2tp_session *l2tp_v2_session_get_next(const struct net *net,
						     u16 tid,
						     unsigned long *key)
+0 −2
Original line number Diff line number Diff line
@@ -219,14 +219,12 @@ void l2tp_session_dec_refcount(struct l2tp_session *session);
 * the caller must ensure that the reference is dropped appropriately.
 */
struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id);
struct l2tp_tunnel *l2tp_tunnel_get_nth(const struct net *net, int nth);
struct l2tp_tunnel *l2tp_tunnel_get_next(const struct net *net, unsigned long *key);

struct l2tp_session *l2tp_v3_session_get(const struct net *net, struct sock *sk, u32 session_id);
struct l2tp_session *l2tp_v2_session_get(const struct net *net, u16 tunnel_id, u16 session_id);
struct l2tp_session *l2tp_session_get(const struct net *net, struct sock *sk, int pver,
				      u32 tunnel_id, u32 session_id);
struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth);
struct l2tp_session *l2tp_session_get_next(const struct net *net, struct sock *sk, int pver,
					   u32 tunnel_id, unsigned long *key);
struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net,
+9 −7
Original line number Diff line number Diff line
@@ -34,8 +34,8 @@ static struct dentry *rootdir;
struct l2tp_dfs_seq_data {
	struct net	*net;
	netns_tracker	ns_tracker;
	int tunnel_idx;			/* current tunnel */
	int session_idx;		/* index of session within current tunnel */
	unsigned long tkey;		/* lookup key of current tunnel */
	unsigned long skey;		/* lookup key of current session */
	struct l2tp_tunnel *tunnel;
	struct l2tp_session *session;	/* NULL means get next tunnel */
};
@@ -46,8 +46,8 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd)
	if (pd->tunnel)
		l2tp_tunnel_dec_refcount(pd->tunnel);

	pd->tunnel = l2tp_tunnel_get_nth(pd->net, pd->tunnel_idx);
	pd->tunnel_idx++;
	pd->tunnel = l2tp_tunnel_get_next(pd->net, &pd->tkey);
	pd->tkey++;
}

static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
@@ -56,11 +56,13 @@ static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
	if (pd->session)
		l2tp_session_dec_refcount(pd->session);

	pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx);
	pd->session_idx++;
	pd->session = l2tp_session_get_next(pd->net, pd->tunnel->sock,
					    pd->tunnel->version,
					    pd->tunnel->tunnel_id, &pd->skey);
	pd->skey++;

	if (!pd->session) {
		pd->session_idx = 0;
		pd->skey = 0;
		l2tp_dfs_next_tunnel(pd);
	}
}
+21 −13
Original line number Diff line number Diff line
@@ -491,14 +491,20 @@ static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)
	return ret;
}

struct l2tp_nl_cb_data {
	unsigned long tkey;
	unsigned long skey;
};

static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
	int ti = cb->args[0];
	struct l2tp_nl_cb_data *cbd = (void *)&cb->ctx[0];
	unsigned long key = cbd->tkey;
	struct l2tp_tunnel *tunnel;
	struct net *net = sock_net(skb->sk);

	for (;;) {
		tunnel = l2tp_tunnel_get_nth(net, ti);
		tunnel = l2tp_tunnel_get_next(net, &key);
		if (!tunnel)
			goto out;

@@ -510,11 +516,11 @@ static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback
		}
		l2tp_tunnel_dec_refcount(tunnel);

		ti++;
		key++;
	}

out:
	cb->args[0] = ti;
	cbd->tkey = key;

	return skb->len;
}
@@ -832,25 +838,27 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)

static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct l2tp_nl_cb_data *cbd = (void *)&cb->ctx[0];
	struct net *net = sock_net(skb->sk);
	struct l2tp_session *session;
	struct l2tp_tunnel *tunnel = NULL;
	int ti = cb->args[0];
	int si = cb->args[1];
	unsigned long tkey = cbd->tkey;
	unsigned long skey = cbd->skey;

	for (;;) {
		if (!tunnel) {
			tunnel = l2tp_tunnel_get_nth(net, ti);
			tunnel = l2tp_tunnel_get_next(net, &tkey);
			if (!tunnel)
				goto out;
		}

		session = l2tp_session_get_nth(tunnel, si);
		session = l2tp_session_get_next(net, tunnel->sock, tunnel->version,
						tunnel->tunnel_id, &skey);
		if (!session) {
			ti++;
			tkey++;
			l2tp_tunnel_dec_refcount(tunnel);
			tunnel = NULL;
			si = 0;
			skey = 0;
			continue;
		}

@@ -863,12 +871,12 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback
		}
		l2tp_session_dec_refcount(session);

		si++;
		skey++;
	}

out:
	cb->args[0] = ti;
	cb->args[1] = si;
	cbd->tkey = tkey;
	cbd->skey = skey;

	return skb->len;
}
+9 −7
Original line number Diff line number Diff line
@@ -1397,8 +1397,8 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, int optname,

struct pppol2tp_seq_data {
	struct seq_net_private p;
	int tunnel_idx;			/* current tunnel */
	int session_idx;		/* index of session within current tunnel */
	unsigned long tkey;		/* lookup key of current tunnel */
	unsigned long skey;		/* lookup key of current session */
	struct l2tp_tunnel *tunnel;
	struct l2tp_session *session;	/* NULL means get next tunnel */
};
@@ -1410,8 +1410,8 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd)
		l2tp_tunnel_dec_refcount(pd->tunnel);

	for (;;) {
		pd->tunnel = l2tp_tunnel_get_nth(net, pd->tunnel_idx);
		pd->tunnel_idx++;
		pd->tunnel = l2tp_tunnel_get_next(net, &pd->tkey);
		pd->tkey++;

		/* Only accept L2TPv2 tunnels */
		if (!pd->tunnel || pd->tunnel->version == 2)
@@ -1427,11 +1427,13 @@ static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd)
	if (pd->session)
		l2tp_session_dec_refcount(pd->session);

	pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx);
	pd->session_idx++;
	pd->session = l2tp_session_get_next(net, pd->tunnel->sock,
					    pd->tunnel->version,
					    pd->tunnel->tunnel_id, &pd->skey);
	pd->skey++;

	if (!pd->session) {
		pd->session_idx = 0;
		pd->skey = 0;
		pppol2tp_next_tunnel(net, pd);
	}
}