diff mbox series

[v1,10/0010] Squash-to: "mptcp: add netlink based PM"

Message ID d92a9260aa37289dc44b3b3ffed93d7b8c3006dc.1583334096.git.pabeni@redhat.com
State Superseded, archived
Delegated to: Mat Martineau
Headers show
Series pm netlink: followup and fixes | expand

Commit Message

Paolo Abeni March 4, 2020, 3:02 p.m. UTC
Implement support for max subflow limits, updating the APIs.
Be sure to avoid any pending work if the subflows limit will
block that.

Fix an issue in local address lookup: we must traverse also
the join_list.

Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
 include/uapi/linux/mptcp.h |  5 +-
 net/mptcp/pm_netlink.c     | 93 +++++++++++++++++++++++++++-----------
 2 files changed, 69 insertions(+), 29 deletions(-)
diff mbox series

Patch

diff --git a/include/uapi/linux/mptcp.h b/include/uapi/linux/mptcp.h
index 92414f3d1463..d061c5a6ae05 100644
--- a/include/uapi/linux/mptcp.h
+++ b/include/uapi/linux/mptcp.h
@@ -45,6 +45,7 @@  enum mptcp_pm_attrs {
 
 	MPTCP_PM_ATTR_ADDR,				/* nested address */
 	MPTCP_PM_ATTR_RCV_ADD_ADDRS,			/* u32 */
+	MPTCP_PM_ATTR_SUBFLOWS,				/* u32 */
 
 	__MPTCP_PM_ATTR_MAX
 };
@@ -78,8 +79,8 @@  enum {
 	MPTCP_PM_CMD_DEL_ADDR,
 	MPTCP_PM_CMD_GET_ADDR,
 	MPTCP_PM_CMD_FLUSH_ADDRS,
-	MPTCP_PM_CMD_SET_RCV_ADD_ADDRS,
-	MPTCP_PM_CMD_GET_RCV_ADD_ADDRS,
+	MPTCP_PM_CMD_SET_LIMITS,
+	MPTCP_PM_CMD_GET_LIMITS,
 
 	__MPTCP_PM_CMD_AFTER_LAST
 };
diff --git a/net/mptcp/pm_netlink.c b/net/mptcp/pm_netlink.c
index 0887fae982fc..adfea3b85606 100644
--- a/net/mptcp/pm_netlink.c
+++ b/net/mptcp/pm_netlink.c
@@ -35,6 +35,7 @@  struct pm_nl_pernet {
 	unsigned int		add_addr_signal_max;
 	unsigned int		add_addr_accept_max;
 	unsigned int		local_addr_max;
+	unsigned int		subflows_max;
 	unsigned int		next_id;
 };
 
@@ -89,14 +90,14 @@  static void remote_address(const struct sock_common *skc,
 #endif
 }
 
-static bool lookup_subflow_by_saddr(const struct mptcp_sock *msk,
+static bool lookup_subflow_by_saddr(const struct list_head *list,
 				    struct mptcp_addr_info *saddr)
 {
 	struct mptcp_subflow_context *subflow;
 	struct mptcp_addr_info cur;
 	struct sock_common *skc;
 
-	list_for_each_entry(subflow, &msk->conn_list, node) {
+	list_for_each_entry(subflow, list, node) {
 		skc = (struct sock_common *)mptcp_subflow_tcp_sock(subflow);
 
 		local_address(skc, &cur);
@@ -109,20 +110,27 @@  static bool lookup_subflow_by_saddr(const struct mptcp_sock *msk,
 
 static struct mptcp_pm_addr_entry *
 select_local_address(const struct pm_nl_pernet *pernet,
-		     const struct mptcp_sock *msk)
+		     struct mptcp_sock *msk)
 {
 	struct mptcp_pm_addr_entry *entry, *ret = NULL;
 
 	rcu_read_lock();
+	spin_lock_bh(&msk->join_list_lock);
 	list_for_each_entry_rcu(entry, &pernet->local_addr_list, list) {
 		if (!(entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW))
 			continue;
+
+		/* avoid any address already in use by subflows and
+		 * pending join
+		 */
 		if (entry->addr.family == ((struct sock *)msk)->sk_family &&
-		    !lookup_subflow_by_saddr(msk, &entry->addr)) {
+		    !lookup_subflow_by_saddr(&msk->conn_list, &entry->addr) &&
+		    !lookup_subflow_by_saddr(&msk->join_list, &entry->addr)) {
 			ret = entry;
 			break;
 		}
 	}
+	spin_unlock_bh(&msk->join_list_lock);
 	rcu_read_unlock();
 	return ret;
 }
@@ -154,7 +162,8 @@  select_signal_address(struct pm_nl_pernet *pernet, unsigned int pos)
 static void check_work_pending(struct mptcp_sock *msk)
 {
 	if (msk->pm.add_addr_signaled == msk->pm.add_addr_signal_max &&
-	    msk->pm.local_addr_used == msk->pm.local_addr_max)
+	    (msk->pm.local_addr_used == msk->pm.local_addr_max ||
+	     (msk->pm.subflows == msk->pm.subflows_max)))
 		WRITE_ONCE(msk->pm.work_pending, false);
 }
 
@@ -192,12 +201,14 @@  static void mptcp_pm_create_subflow_or_signal_addr(struct mptcp_sock *msk)
 	}
 
 	/* check if should create a new subflow */
-	if (msk->pm.local_addr_used < msk->pm.local_addr_max) {
+	if (msk->pm.local_addr_used < msk->pm.local_addr_max &&
+	    msk->pm.subflows < msk->pm.subflows_max) {
 		remote_address((struct sock_common *)sk, &remote);
 
 		local = select_local_address(pernet, msk);
 		if (local) {
 			msk->pm.local_addr_used++;
+			msk->pm.subflows++;
 			check_work_pending(msk);
 			spin_unlock_bh(&msk->pm.lock);
 			__mptcp_subflow_connect(sk, local->ifindex,
@@ -239,7 +250,10 @@  void mptcp_pm_nl_add_addr_received(struct mptcp_sock *msk)
 	pr_debug("accepted %d:%d remote family %d",
 		 msk->pm.add_addr_accepted, msk->pm.add_addr_accept_max,
 		 msk->pm.remote.family);
-	if (++msk->pm.add_addr_accepted >= msk->pm.add_addr_accept_max)
+	msk->pm.add_addr_accepted++;
+	msk->pm.subflows++;
+	if (msk->pm.add_addr_accepted >= msk->pm.add_addr_accept_max ||
+	    msk->pm.subflows >= msk->pm.subflows_max)
 		WRITE_ONCE(msk->pm.accept_addr, false);
 
 	/* connect to the specified remote address, using whatever
@@ -352,16 +366,21 @@  int mptcp_pm_nl_get_local_id(struct mptcp_sock *msk, struct sock_common *skc)
 
 void mptcp_pm_nl_data_init(struct mptcp_sock *msk)
 {
+	struct mptcp_pm_data *pm = &msk->pm;
 	struct pm_nl_pernet *pernet;
+	bool subflows;
 
 	pernet = net_generic(sock_net((struct sock *)msk), pm_nl_pernet_id);
 
-	msk->pm.add_addr_signal_max = READ_ONCE(pernet->add_addr_signal_max);
-	msk->pm.add_addr_accept_max = READ_ONCE(pernet->add_addr_accept_max);
-	msk->pm.local_addr_max = READ_ONCE(pernet->local_addr_max);
-	WRITE_ONCE(msk->pm.work_pending,
-		   !!msk->pm.local_addr_max || !!msk->pm.add_addr_signal_max);
-	WRITE_ONCE(msk->pm.accept_addr, !!msk->pm.add_addr_accept_max);
+	pm->add_addr_signal_max = READ_ONCE(pernet->add_addr_signal_max);
+	pm->add_addr_accept_max = READ_ONCE(pernet->add_addr_accept_max);
+	pm->local_addr_max = READ_ONCE(pernet->local_addr_max);
+	pm->subflows_max = READ_ONCE(pernet->subflows_max);
+	subflows = !!pm->subflows_max;
+	WRITE_ONCE(pm->work_pending, (!!pm->local_addr_max && subflows) ||
+		   !!pm->add_addr_signal_max);
+	WRITE_ONCE(pm->accept_addr, !!pm->add_addr_accept_max && subflows);
+	WRITE_ONCE(pm->accept_subflow, subflows);
 }
 
 #define MPTCP_PM_CMD_GRP_OFFSET	0
@@ -386,6 +405,7 @@  static const struct nla_policy mptcp_pm_policy[MPTCP_PM_ATTR_MAX + 1] = {
 	[MPTCP_PM_ATTR_ADDR]		=
 					NLA_POLICY_NESTED(mptcp_pm_addr_policy),
 	[MPTCP_PM_ATTR_RCV_ADD_ADDRS]	= { .type	= NLA_U32,	},
+	[MPTCP_PM_ATTR_SUBFLOWS]	= { .type	= NLA_U32,	},
 };
 
 static int mptcp_pm_family_to_addr(int family)
@@ -690,31 +710,46 @@  static int mptcp_nl_cmd_dump_addrs(struct sk_buff *msg,
 	return msg->len;
 }
 
-static int
-mptcp_nl_cmd_set_rcv_add_addrs(struct sk_buff *skb, struct genl_info *info)
+static int parse_limit(struct genl_info *info, int id, unsigned int *limit)
 {
-	struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_RCV_ADD_ADDRS];
-	struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
-	int limit;
+	struct nlattr *attr = info->attrs[id];
 
 	if (!attr) {
 		GENL_SET_ERR_MSG(info, "missing announce accept limit");
 		return -EINVAL;
 	}
 
-	limit = nla_get_u32(attr);
-	if (limit > MPTCP_PM_ADDR_MAX) {
+	*limit = nla_get_u32(attr);
+	if (*limit > MPTCP_PM_ADDR_MAX) {
 		GENL_SET_ERR_MSG(info,
 				 "announce accept limit greater than maximum");
 		return -EINVAL;
 	}
+	return 0;
+}
 
-	WRITE_ONCE(pernet->add_addr_accept_max, limit);
+static int
+mptcp_nl_cmd_set_limits(struct sk_buff *skb, struct genl_info *info)
+{
+	struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
+	unsigned int rcv_addrs, subflows;
+	int ret;
+
+	ret = parse_limit(info, MPTCP_PM_ATTR_RCV_ADD_ADDRS, &rcv_addrs);
+	if (ret)
+		return ret;
+
+	ret = parse_limit(info, MPTCP_PM_ATTR_SUBFLOWS, &subflows);
+	if (ret)
+		return ret;
+
+	WRITE_ONCE(pernet->add_addr_accept_max, rcv_addrs);
+	WRITE_ONCE(pernet->subflows_max, subflows);
 	return 0;
 }
 
 static int
-mptcp_nl_cmd_get_rcv_add_addrs(struct sk_buff *skb, struct genl_info *info)
+mptcp_nl_cmd_get_limits(struct sk_buff *skb, struct genl_info *info)
 {
 	struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
 	struct sk_buff *msg;
@@ -725,7 +760,7 @@  mptcp_nl_cmd_get_rcv_add_addrs(struct sk_buff *skb, struct genl_info *info)
 		return -ENOMEM;
 
 	reply = genlmsg_put_reply(msg, info, &mptcp_genl_family, 0,
-				  MPTCP_PM_CMD_GET_RCV_ADD_ADDRS);
+				  MPTCP_PM_CMD_GET_LIMITS);
 	if (!reply)
 		goto fail;
 
@@ -733,6 +768,10 @@  mptcp_nl_cmd_get_rcv_add_addrs(struct sk_buff *skb, struct genl_info *info)
 			READ_ONCE(pernet->add_addr_accept_max)))
 		goto fail;
 
+	if (nla_put_u32(msg, MPTCP_PM_ATTR_SUBFLOWS,
+			READ_ONCE(pernet->subflows_max)))
+		goto fail;
+
 	genlmsg_end(msg, reply);
 	return genlmsg_reply(msg, info);
 
@@ -765,13 +804,13 @@  static struct genl_ops mptcp_pm_ops[] = {
 		.flags  = GENL_ADMIN_PERM,
 	},
 	{
-		.cmd    = MPTCP_PM_CMD_SET_RCV_ADD_ADDRS,
-		.doit   = mptcp_nl_cmd_set_rcv_add_addrs,
+		.cmd    = MPTCP_PM_CMD_SET_LIMITS,
+		.doit   = mptcp_nl_cmd_set_limits,
 		.flags  = GENL_ADMIN_PERM,
 	},
 	{
-		.cmd    = MPTCP_PM_CMD_GET_RCV_ADD_ADDRS,
-		.doit   = mptcp_nl_cmd_get_rcv_add_addrs,
+		.cmd    = MPTCP_PM_CMD_GET_LIMITS,
+		.doit   = mptcp_nl_cmd_get_limits,
 		.flags  = GENL_ADMIN_PERM,
 	},
 };