mptcp: add pm listener events
authorGeliang Tang <geliang.tang@suse.com>
Wed, 30 Nov 2022 14:06:28 +0000 (15:06 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 2 Dec 2022 04:06:06 +0000 (20:06 -0800)
This patch adds two new MPTCP netlink event types for PM listening
socket create and close, named MPTCP_EVENT_LISTENER_CREATED and
MPTCP_EVENT_LISTENER_CLOSED.

Add a new function mptcp_event_pm_listener() to push the new events
with family, port and addr to userspace.

Invoke mptcp_event_pm_listener() with MPTCP_EVENT_LISTENER_CREATED in
mptcp_listen() and mptcp_pm_nl_create_listen_socket(), invoke it with
MPTCP_EVENT_LISTENER_CLOSED in __mptcp_close_ssk().

Signed-off-by: Geliang Tang <geliang.tang@suse.com>
Reviewed-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/uapi/linux/mptcp.h
net/mptcp/pm_netlink.c
net/mptcp/protocol.c
net/mptcp/protocol.h

index dfe19bf..32af2d2 100644 (file)
@@ -160,6 +160,12 @@ struct mptcp_info {
  *                           daddr4 | daddr6, sport, dport, backup, if_idx
  *                           [, error]
  * The priority of a subflow has changed. 'error' should not be set.
+ *
+ * MPTCP_EVENT_LISTENER_CREATED: family, sport, saddr4 | saddr6
+ * A new PM listener is created.
+ *
+ * MPTCP_EVENT_LISTENER_CLOSED: family, sport, saddr4 | saddr6
+ * A PM listener is closed.
  */
 enum mptcp_event_type {
        MPTCP_EVENT_UNSPEC = 0,
@@ -174,6 +180,9 @@ enum mptcp_event_type {
        MPTCP_EVENT_SUB_CLOSED = 11,
 
        MPTCP_EVENT_SUB_PRIORITY = 13,
+
+       MPTCP_EVENT_LISTENER_CREATED = 15,
+       MPTCP_EVENT_LISTENER_CLOSED = 16,
 };
 
 enum mptcp_event_attr {
index d66fbd5..eef69d0 100644 (file)
@@ -1029,6 +1029,8 @@ static int mptcp_pm_nl_create_listen_socket(struct sock *sk,
        if (err)
                return err;
 
+       mptcp_event_pm_listener(ssock->sk, MPTCP_EVENT_LISTENER_CREATED);
+
        return 0;
 }
 
@@ -2152,6 +2154,58 @@ nla_put_failure:
        kfree_skb(skb);
 }
 
+void mptcp_event_pm_listener(const struct sock *ssk,
+                            enum mptcp_event_type event)
+{
+       const struct inet_sock *issk = inet_sk(ssk);
+       struct net *net = sock_net(ssk);
+       struct nlmsghdr *nlh;
+       struct sk_buff *skb;
+
+       if (!genl_has_listeners(&mptcp_genl_family, net, MPTCP_PM_EV_GRP_OFFSET))
+               return;
+
+       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!skb)
+               return;
+
+       nlh = genlmsg_put(skb, 0, 0, &mptcp_genl_family, 0, event);
+       if (!nlh)
+               goto nla_put_failure;
+
+       if (nla_put_u16(skb, MPTCP_ATTR_FAMILY, ssk->sk_family))
+               goto nla_put_failure;
+
+       if (nla_put_be16(skb, MPTCP_ATTR_SPORT, issk->inet_sport))
+               goto nla_put_failure;
+
+       switch (ssk->sk_family) {
+       case AF_INET:
+               if (nla_put_in_addr(skb, MPTCP_ATTR_SADDR4, issk->inet_saddr))
+                       goto nla_put_failure;
+               break;
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+       case AF_INET6: {
+               const struct ipv6_pinfo *np = inet6_sk(ssk);
+
+               if (nla_put_in6_addr(skb, MPTCP_ATTR_SADDR6, &np->saddr))
+                       goto nla_put_failure;
+               break;
+       }
+#endif
+       default:
+               WARN_ON_ONCE(1);
+               goto nla_put_failure;
+       }
+
+       genlmsg_end(skb, nlh);
+       mptcp_nl_mcast_send(net, skb, GFP_KERNEL);
+       return;
+
+nla_put_failure:
+       kfree_skb(skb);
+}
+
 void mptcp_event(enum mptcp_event_type type, const struct mptcp_sock *msk,
                 const struct sock *ssk, gfp_t gfp)
 {
@@ -2197,6 +2251,9 @@ void mptcp_event(enum mptcp_event_type type, const struct mptcp_sock *msk,
                if (mptcp_event_sub_closed(skb, msk, ssk) < 0)
                        goto nla_put_failure;
                break;
+       case MPTCP_EVENT_LISTENER_CREATED:
+       case MPTCP_EVENT_LISTENER_CLOSED:
+               break;
        }
 
        genlmsg_end(skb, nlh);
index b0d387b..f6f9395 100644 (file)
@@ -2355,6 +2355,7 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
                        tcp_set_state(ssk, TCP_CLOSE);
                        mptcp_subflow_queue_clean(ssk);
                        inet_csk_listen_stop(ssk);
+                       mptcp_event_pm_listener(ssk, MPTCP_EVENT_LISTENER_CLOSED);
                }
                __tcp_close(ssk, 0);
 
@@ -3647,6 +3648,8 @@ static int mptcp_listen(struct socket *sock, int backlog)
        if (!err)
                mptcp_copy_inaddrs(sock->sk, ssock->sk);
 
+       mptcp_event_pm_listener(ssock->sk, MPTCP_EVENT_LISTENER_CREATED);
+
 unlock:
        release_sock(sock->sk);
        return err;
index 8b4379a..955fb3d 100644 (file)
@@ -839,6 +839,8 @@ void mptcp_event(enum mptcp_event_type type, const struct mptcp_sock *msk,
                 const struct sock *ssk, gfp_t gfp);
 void mptcp_event_addr_announced(const struct sock *ssk, const struct mptcp_addr_info *info);
 void mptcp_event_addr_removed(const struct mptcp_sock *msk, u8 id);
+void mptcp_event_pm_listener(const struct sock *ssk,
+                            enum mptcp_event_type event);
 bool mptcp_userspace_pm_active(const struct mptcp_sock *msk);
 
 void mptcp_fastopen_gen_msk_ackseq(struct mptcp_sock *msk, struct mptcp_subflow_context *subflow,