1 // SPDX-License-Identifier: GPL-2.0
2 /* XDP sockets monitoring support
4 * Copyright(c) 2019 Intel Corporation.
6 * Author: Björn Töpel <bjorn.topel@intel.com>
9 #include <linux/module.h>
10 #include <net/xdp_sock.h>
11 #include <linux/xdp_diag.h>
12 #include <linux/sock_diag.h>
14 #include "xsk_queue.h"
17 static int xsk_diag_put_info(const struct xdp_sock
*xs
, struct sk_buff
*nlskb
)
19 struct xdp_diag_info di
= {};
21 di
.ifindex
= xs
->dev
? xs
->dev
->ifindex
: 0;
22 di
.queue_id
= xs
->queue_id
;
23 return nla_put(nlskb
, XDP_DIAG_INFO
, sizeof(di
), &di
);
26 static int xsk_diag_put_ring(const struct xsk_queue
*queue
, int nl_type
,
27 struct sk_buff
*nlskb
)
29 struct xdp_diag_ring dr
= {};
31 dr
.entries
= queue
->nentries
;
32 return nla_put(nlskb
, nl_type
, sizeof(dr
), &dr
);
35 static int xsk_diag_put_rings_cfg(const struct xdp_sock
*xs
,
36 struct sk_buff
*nlskb
)
41 err
= xsk_diag_put_ring(xs
->rx
, XDP_DIAG_RX_RING
, nlskb
);
43 err
= xsk_diag_put_ring(xs
->tx
, XDP_DIAG_TX_RING
, nlskb
);
47 static int xsk_diag_put_umem(const struct xdp_sock
*xs
, struct sk_buff
*nlskb
)
49 struct xdp_umem
*umem
= xs
->umem
;
50 struct xdp_diag_umem du
= {};
58 du
.num_pages
= umem
->npgs
;
59 du
.chunk_size
= umem
->chunk_size_nohr
+ umem
->headroom
;
60 du
.headroom
= umem
->headroom
;
61 du
.ifindex
= umem
->dev
? umem
->dev
->ifindex
: 0;
62 du
.queue_id
= umem
->queue_id
;
65 du
.flags
|= XDP_DU_F_ZEROCOPY
;
66 du
.refs
= refcount_read(&umem
->users
);
68 err
= nla_put(nlskb
, XDP_DIAG_UMEM
, sizeof(du
), &du
);
71 err
= xsk_diag_put_ring(umem
->fq
, XDP_DIAG_UMEM_FILL_RING
, nlskb
);
72 if (!err
&& umem
->cq
) {
73 err
= xsk_diag_put_ring(umem
->cq
, XDP_DIAG_UMEM_COMPLETION_RING
,
79 static int xsk_diag_fill(struct sock
*sk
, struct sk_buff
*nlskb
,
80 struct xdp_diag_req
*req
,
81 struct user_namespace
*user_ns
,
82 u32 portid
, u32 seq
, u32 flags
, int sk_ino
)
84 struct xdp_sock
*xs
= xdp_sk(sk
);
85 struct xdp_diag_msg
*msg
;
88 nlh
= nlmsg_put(nlskb
, portid
, seq
, SOCK_DIAG_BY_FAMILY
, sizeof(*msg
),
93 msg
= nlmsg_data(nlh
);
94 memset(msg
, 0, sizeof(*msg
));
95 msg
->xdiag_family
= AF_XDP
;
96 msg
->xdiag_type
= sk
->sk_type
;
97 msg
->xdiag_ino
= sk_ino
;
98 sock_diag_save_cookie(sk
, msg
->xdiag_cookie
);
100 mutex_lock(&xs
->mutex
);
101 if ((req
->xdiag_show
& XDP_SHOW_INFO
) && xsk_diag_put_info(xs
, nlskb
))
104 if ((req
->xdiag_show
& XDP_SHOW_INFO
) &&
105 nla_put_u32(nlskb
, XDP_DIAG_UID
,
106 from_kuid_munged(user_ns
, sock_i_uid(sk
))))
109 if ((req
->xdiag_show
& XDP_SHOW_RING_CFG
) &&
110 xsk_diag_put_rings_cfg(xs
, nlskb
))
113 if ((req
->xdiag_show
& XDP_SHOW_UMEM
) &&
114 xsk_diag_put_umem(xs
, nlskb
))
117 if ((req
->xdiag_show
& XDP_SHOW_MEMINFO
) &&
118 sock_diag_put_meminfo(sk
, nlskb
, XDP_DIAG_MEMINFO
))
121 mutex_unlock(&xs
->mutex
);
122 nlmsg_end(nlskb
, nlh
);
126 mutex_unlock(&xs
->mutex
);
127 nlmsg_cancel(nlskb
, nlh
);
131 static int xsk_diag_dump(struct sk_buff
*nlskb
, struct netlink_callback
*cb
)
133 struct xdp_diag_req
*req
= nlmsg_data(cb
->nlh
);
134 struct net
*net
= sock_net(nlskb
->sk
);
135 int num
= 0, s_num
= cb
->args
[0];
138 mutex_lock(&net
->xdp
.lock
);
140 sk_for_each(sk
, &net
->xdp
.list
) {
141 if (!net_eq(sock_net(sk
), net
))
146 if (xsk_diag_fill(sk
, nlskb
, req
,
147 sk_user_ns(NETLINK_CB(cb
->skb
).sk
),
148 NETLINK_CB(cb
->skb
).portid
,
149 cb
->nlh
->nlmsg_seq
, NLM_F_MULTI
,
150 sock_i_ino(sk
)) < 0) {
156 mutex_unlock(&net
->xdp
.lock
);
161 static int xsk_diag_handler_dump(struct sk_buff
*nlskb
, struct nlmsghdr
*hdr
)
163 struct netlink_dump_control c
= { .dump
= xsk_diag_dump
};
164 int hdrlen
= sizeof(struct xdp_diag_req
);
165 struct net
*net
= sock_net(nlskb
->sk
);
167 if (nlmsg_len(hdr
) < hdrlen
)
170 if (!(hdr
->nlmsg_flags
& NLM_F_DUMP
))
173 return netlink_dump_start(net
->diag_nlsk
, nlskb
, hdr
, &c
);
176 static const struct sock_diag_handler xsk_diag_handler
= {
178 .dump
= xsk_diag_handler_dump
,
181 static int __init
xsk_diag_init(void)
183 return sock_diag_register(&xsk_diag_handler
);
186 static void __exit
xsk_diag_exit(void)
188 sock_diag_unregister(&xsk_diag_handler
);
191 module_init(xsk_diag_init
);
192 module_exit(xsk_diag_exit
);
193 MODULE_LICENSE("GPL");
194 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK
, NETLINK_SOCK_DIAG
, AF_XDP
);