1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun #include <linux/module.h>
3*4882a593Smuzhiyun #include <linux/kernel.h>
4*4882a593Smuzhiyun #include <linux/if_arp.h>
5*4882a593Smuzhiyun #include <net/rtnetlink.h>
6*4882a593Smuzhiyun #include <net/sock.h>
7*4882a593Smuzhiyun #include <net/af_vsock.h>
8*4882a593Smuzhiyun #include <uapi/linux/vsockmon.h>
9*4882a593Smuzhiyun #include <linux/virtio_vsock.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun /* Virtio transport max packet size plus header */
12*4882a593Smuzhiyun #define DEFAULT_MTU (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + \
13*4882a593Smuzhiyun sizeof(struct af_vsockmon_hdr))
14*4882a593Smuzhiyun
vsockmon_dev_init(struct net_device * dev)15*4882a593Smuzhiyun static int vsockmon_dev_init(struct net_device *dev)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
18*4882a593Smuzhiyun if (!dev->lstats)
19*4882a593Smuzhiyun return -ENOMEM;
20*4882a593Smuzhiyun return 0;
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun
vsockmon_dev_uninit(struct net_device * dev)23*4882a593Smuzhiyun static void vsockmon_dev_uninit(struct net_device *dev)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun free_percpu(dev->lstats);
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun struct vsockmon {
29*4882a593Smuzhiyun struct vsock_tap vt;
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun
vsockmon_open(struct net_device * dev)32*4882a593Smuzhiyun static int vsockmon_open(struct net_device *dev)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun struct vsockmon *vsockmon = netdev_priv(dev);
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun vsockmon->vt.dev = dev;
37*4882a593Smuzhiyun vsockmon->vt.module = THIS_MODULE;
38*4882a593Smuzhiyun return vsock_add_tap(&vsockmon->vt);
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
vsockmon_close(struct net_device * dev)41*4882a593Smuzhiyun static int vsockmon_close(struct net_device *dev)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct vsockmon *vsockmon = netdev_priv(dev);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun return vsock_remove_tap(&vsockmon->vt);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
vsockmon_xmit(struct sk_buff * skb,struct net_device * dev)48*4882a593Smuzhiyun static netdev_tx_t vsockmon_xmit(struct sk_buff *skb, struct net_device *dev)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun dev_lstats_add(dev, skb->len);
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun dev_kfree_skb(skb);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun return NETDEV_TX_OK;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static void
vsockmon_get_stats64(struct net_device * dev,struct rtnl_link_stats64 * stats)58*4882a593Smuzhiyun vsockmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun dev_lstats_read(dev, &stats->rx_packets, &stats->rx_bytes);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun stats->tx_packets = 0;
63*4882a593Smuzhiyun stats->tx_bytes = 0;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
vsockmon_is_valid_mtu(int new_mtu)66*4882a593Smuzhiyun static int vsockmon_is_valid_mtu(int new_mtu)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun return new_mtu >= (int)sizeof(struct af_vsockmon_hdr);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
vsockmon_change_mtu(struct net_device * dev,int new_mtu)71*4882a593Smuzhiyun static int vsockmon_change_mtu(struct net_device *dev, int new_mtu)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun if (!vsockmon_is_valid_mtu(new_mtu))
74*4882a593Smuzhiyun return -EINVAL;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun dev->mtu = new_mtu;
77*4882a593Smuzhiyun return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun static const struct net_device_ops vsockmon_ops = {
81*4882a593Smuzhiyun .ndo_init = vsockmon_dev_init,
82*4882a593Smuzhiyun .ndo_uninit = vsockmon_dev_uninit,
83*4882a593Smuzhiyun .ndo_open = vsockmon_open,
84*4882a593Smuzhiyun .ndo_stop = vsockmon_close,
85*4882a593Smuzhiyun .ndo_start_xmit = vsockmon_xmit,
86*4882a593Smuzhiyun .ndo_get_stats64 = vsockmon_get_stats64,
87*4882a593Smuzhiyun .ndo_change_mtu = vsockmon_change_mtu,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
always_on(struct net_device * dev)90*4882a593Smuzhiyun static u32 always_on(struct net_device *dev)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun return 1;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun static const struct ethtool_ops vsockmon_ethtool_ops = {
96*4882a593Smuzhiyun .get_link = always_on,
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun
vsockmon_setup(struct net_device * dev)99*4882a593Smuzhiyun static void vsockmon_setup(struct net_device *dev)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun dev->type = ARPHRD_VSOCKMON;
102*4882a593Smuzhiyun dev->priv_flags |= IFF_NO_QUEUE;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun dev->netdev_ops = &vsockmon_ops;
105*4882a593Smuzhiyun dev->ethtool_ops = &vsockmon_ethtool_ops;
106*4882a593Smuzhiyun dev->needs_free_netdev = true;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
109*4882a593Smuzhiyun NETIF_F_HIGHDMA | NETIF_F_LLTX;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun dev->flags = IFF_NOARP;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun dev->mtu = DEFAULT_MTU;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun static struct rtnl_link_ops vsockmon_link_ops __read_mostly = {
117*4882a593Smuzhiyun .kind = "vsockmon",
118*4882a593Smuzhiyun .priv_size = sizeof(struct vsockmon),
119*4882a593Smuzhiyun .setup = vsockmon_setup,
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun
vsockmon_register(void)122*4882a593Smuzhiyun static __init int vsockmon_register(void)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun return rtnl_link_register(&vsockmon_link_ops);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun
vsockmon_unregister(void)127*4882a593Smuzhiyun static __exit void vsockmon_unregister(void)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun rtnl_link_unregister(&vsockmon_link_ops);
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun module_init(vsockmon_register);
133*4882a593Smuzhiyun module_exit(vsockmon_unregister);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
136*4882a593Smuzhiyun MODULE_AUTHOR("Gerard Garcia <ggarcia@deic.uab.cat>");
137*4882a593Smuzhiyun MODULE_DESCRIPTION("Vsock monitoring device. Based on nlmon device.");
138*4882a593Smuzhiyun MODULE_ALIAS_RTNL_LINK("vsockmon");
139