linux/net/mptcp/mptcp_diag.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* MPTCP socket monitoring support
   3 *
   4 * Copyright (c) 2020 Red Hat
   5 *
   6 * Author: Paolo Abeni <pabeni@redhat.com>
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/net.h>
  11#include <linux/inet_diag.h>
  12#include <net/netlink.h>
  13#include <uapi/linux/mptcp.h>
  14#include "protocol.h"
  15
  16static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
  17                        struct netlink_callback *cb,
  18                        const struct inet_diag_req_v2 *req,
  19                        struct nlattr *bc, bool net_admin)
  20{
  21        if (!inet_diag_bc_sk(bc, sk))
  22                return 0;
  23
  24        return inet_sk_diag_fill(sk, inet_csk(sk), skb, cb, req, NLM_F_MULTI,
  25                                 net_admin);
  26}
  27
  28static int mptcp_diag_dump_one(struct netlink_callback *cb,
  29                               const struct inet_diag_req_v2 *req)
  30{
  31        struct sk_buff *in_skb = cb->skb;
  32        struct mptcp_sock *msk = NULL;
  33        struct sk_buff *rep;
  34        int err = -ENOENT;
  35        struct net *net;
  36        struct sock *sk;
  37
  38        net = sock_net(in_skb->sk);
  39        msk = mptcp_token_get_sock(req->id.idiag_cookie[0]);
  40        if (!msk)
  41                goto out_nosk;
  42
  43        err = -ENOMEM;
  44        sk = (struct sock *)msk;
  45        rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) +
  46                        inet_diag_msg_attrs_size() +
  47                        nla_total_size(sizeof(struct mptcp_info)) +
  48                        nla_total_size(sizeof(struct inet_diag_meminfo)) + 64,
  49                        GFP_KERNEL);
  50        if (!rep)
  51                goto out;
  52
  53        err = inet_sk_diag_fill(sk, inet_csk(sk), rep, cb, req, 0,
  54                                netlink_net_capable(in_skb, CAP_NET_ADMIN));
  55        if (err < 0) {
  56                WARN_ON(err == -EMSGSIZE);
  57                kfree_skb(rep);
  58                goto out;
  59        }
  60        err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid);
  61
  62out:
  63        sock_put(sk);
  64
  65out_nosk:
  66        return err;
  67}
  68
  69static void mptcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
  70                            const struct inet_diag_req_v2 *r)
  71{
  72        bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
  73        struct net *net = sock_net(skb->sk);
  74        struct inet_diag_dump_data *cb_data;
  75        struct mptcp_sock *msk;
  76        struct nlattr *bc;
  77
  78        cb_data = cb->data;
  79        bc = cb_data->inet_diag_nla_bc;
  80
  81        while ((msk = mptcp_token_iter_next(net, &cb->args[0], &cb->args[1])) !=
  82               NULL) {
  83                struct inet_sock *inet = (struct inet_sock *)msk;
  84                struct sock *sk = (struct sock *)msk;
  85                int ret = 0;
  86
  87                if (!(r->idiag_states & (1 << sk->sk_state)))
  88                        goto next;
  89                if (r->sdiag_family != AF_UNSPEC &&
  90                    sk->sk_family != r->sdiag_family)
  91                        goto next;
  92                if (r->id.idiag_sport != inet->inet_sport &&
  93                    r->id.idiag_sport)
  94                        goto next;
  95                if (r->id.idiag_dport != inet->inet_dport &&
  96                    r->id.idiag_dport)
  97                        goto next;
  98
  99                ret = sk_diag_dump(sk, skb, cb, r, bc, net_admin);
 100next:
 101                sock_put(sk);
 102                if (ret < 0) {
 103                        /* will retry on the same position */
 104                        cb->args[1]--;
 105                        break;
 106                }
 107                cond_resched();
 108        }
 109}
 110
 111static void mptcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 112                                void *_info)
 113{
 114        struct mptcp_sock *msk = mptcp_sk(sk);
 115        struct mptcp_info *info = _info;
 116        u32 flags = 0;
 117        bool slow;
 118        u8 val;
 119
 120        r->idiag_rqueue = sk_rmem_alloc_get(sk);
 121        r->idiag_wqueue = sk_wmem_alloc_get(sk);
 122        if (!info)
 123                return;
 124
 125        slow = lock_sock_fast(sk);
 126        info->mptcpi_subflows = READ_ONCE(msk->pm.subflows);
 127        info->mptcpi_add_addr_signal = READ_ONCE(msk->pm.add_addr_signaled);
 128        info->mptcpi_add_addr_accepted = READ_ONCE(msk->pm.add_addr_accepted);
 129        info->mptcpi_local_addr_used = READ_ONCE(msk->pm.local_addr_used);
 130        info->mptcpi_subflows_max = mptcp_pm_get_subflows_max(msk);
 131        val = mptcp_pm_get_add_addr_signal_max(msk);
 132        info->mptcpi_add_addr_signal_max = val;
 133        val = mptcp_pm_get_add_addr_accept_max(msk);
 134        info->mptcpi_add_addr_accepted_max = val;
 135        info->mptcpi_local_addr_max = mptcp_pm_get_local_addr_max(msk);
 136        if (test_bit(MPTCP_FALLBACK_DONE, &msk->flags))
 137                flags |= MPTCP_INFO_FLAG_FALLBACK;
 138        if (READ_ONCE(msk->can_ack))
 139                flags |= MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED;
 140        info->mptcpi_flags = flags;
 141        info->mptcpi_token = READ_ONCE(msk->token);
 142        info->mptcpi_write_seq = READ_ONCE(msk->write_seq);
 143        info->mptcpi_snd_una = READ_ONCE(msk->snd_una);
 144        info->mptcpi_rcv_nxt = READ_ONCE(msk->ack_seq);
 145        info->mptcpi_csum_enabled = READ_ONCE(msk->csum_enabled);
 146        unlock_sock_fast(sk, slow);
 147}
 148
 149static const struct inet_diag_handler mptcp_diag_handler = {
 150        .dump            = mptcp_diag_dump,
 151        .dump_one        = mptcp_diag_dump_one,
 152        .idiag_get_info  = mptcp_diag_get_info,
 153        .idiag_type      = IPPROTO_MPTCP,
 154        .idiag_info_size = sizeof(struct mptcp_info),
 155};
 156
 157static int __init mptcp_diag_init(void)
 158{
 159        return inet_diag_register(&mptcp_diag_handler);
 160}
 161
 162static void __exit mptcp_diag_exit(void)
 163{
 164        inet_diag_unregister(&mptcp_diag_handler);
 165}
 166
 167module_init(mptcp_diag_init);
 168module_exit(mptcp_diag_exit);
 169MODULE_LICENSE("GPL");
 170MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-262 /* AF_INET - IPPROTO_MPTCP */);
 171