1 // SPDX-License-Identifier: GPL-2.0
2 /* MPTCP socket monitoring support
4 * Copyright (c) 2020 Red Hat
6 * Author: Paolo Abeni <pabeni@redhat.com>
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>
16 static 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
)
21 if (!inet_diag_bc_sk(bc
, sk
))
24 return inet_sk_diag_fill(sk
, inet_csk(sk
), skb
, cb
, req
, NLM_F_MULTI
,
28 static int mptcp_diag_dump_one(struct netlink_callback
*cb
,
29 const struct inet_diag_req_v2
*req
)
31 struct sk_buff
*in_skb
= cb
->skb
;
32 struct mptcp_sock
*msk
= NULL
;
38 net
= sock_net(in_skb
->sk
);
39 msk
= mptcp_token_get_sock(req
->id
.idiag_cookie
[0]);
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,
53 err
= inet_sk_diag_fill(sk
, inet_csk(sk
), rep
, cb
, req
, 0,
54 netlink_net_capable(in_skb
, CAP_NET_ADMIN
));
56 WARN_ON(err
== -EMSGSIZE
);
60 err
= netlink_unicast(net
->diag_nlsk
, rep
, NETLINK_CB(in_skb
).portid
,
71 static void mptcp_diag_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
,
72 const struct inet_diag_req_v2
*r
)
74 bool net_admin
= netlink_net_capable(cb
->skb
, CAP_NET_ADMIN
);
75 struct net
*net
= sock_net(skb
->sk
);
76 struct inet_diag_dump_data
*cb_data
;
77 struct mptcp_sock
*msk
;
81 bc
= cb_data
->inet_diag_nla_bc
;
83 while ((msk
= mptcp_token_iter_next(net
, &cb
->args
[0], &cb
->args
[1])) !=
85 struct inet_sock
*inet
= (struct inet_sock
*)msk
;
86 struct sock
*sk
= (struct sock
*)msk
;
89 if (!(r
->idiag_states
& (1 << sk
->sk_state
)))
91 if (r
->sdiag_family
!= AF_UNSPEC
&&
92 sk
->sk_family
!= r
->sdiag_family
)
94 if (r
->id
.idiag_sport
!= inet
->inet_sport
&&
97 if (r
->id
.idiag_dport
!= inet
->inet_dport
&&
101 ret
= sk_diag_dump(sk
, skb
, cb
, r
, bc
, net_admin
);
105 /* will retry on the same position */
113 static void mptcp_diag_get_info(struct sock
*sk
, struct inet_diag_msg
*r
,
116 struct mptcp_sock
*msk
= mptcp_sk(sk
);
117 struct mptcp_info
*info
= _info
;
122 r
->idiag_rqueue
= sk_rmem_alloc_get(sk
);
123 r
->idiag_wqueue
= sk_wmem_alloc_get(sk
);
127 slow
= lock_sock_fast(sk
);
128 info
->mptcpi_subflows
= READ_ONCE(msk
->pm
.subflows
);
129 info
->mptcpi_add_addr_signal
= READ_ONCE(msk
->pm
.add_addr_signaled
);
130 info
->mptcpi_add_addr_accepted
= READ_ONCE(msk
->pm
.add_addr_accepted
);
131 info
->mptcpi_subflows_max
= READ_ONCE(msk
->pm
.subflows_max
);
132 val
= READ_ONCE(msk
->pm
.add_addr_signal_max
);
133 info
->mptcpi_add_addr_signal_max
= val
;
134 val
= READ_ONCE(msk
->pm
.add_addr_accept_max
);
135 info
->mptcpi_add_addr_accepted_max
= val
;
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 unlock_sock_fast(sk
, slow
);
148 static const struct inet_diag_handler mptcp_diag_handler
= {
149 .dump
= mptcp_diag_dump
,
150 .dump_one
= mptcp_diag_dump_one
,
151 .idiag_get_info
= mptcp_diag_get_info
,
152 .idiag_type
= IPPROTO_MPTCP
,
153 .idiag_info_size
= sizeof(struct mptcp_info
),
156 static int __init
mptcp_diag_init(void)
158 return inet_diag_register(&mptcp_diag_handler
);
161 static void __exit
mptcp_diag_exit(void)
163 inet_diag_unregister(&mptcp_diag_handler
);
166 module_init(mptcp_diag_init
);
167 module_exit(mptcp_diag_exit
);
168 MODULE_LICENSE("GPL");
169 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK
, NETLINK_SOCK_DIAG
, 2-262 /* AF_INET - IPPROTO_MPTCP */);