Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

VSOCK: Add vsockmon device

Add vsockmon virtual network device that receives packets from the vsock
transports and exposes them to user space.

Based on the nlmon device.

Signed-off-by: Gerard Garcia <ggarcia@deic.uab.cat>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Gerard Garcia and committed by
David S. Miller
0b2e6644 531b3748

+242
+2
MAINTAINERS
··· 13317 13317 S: Maintained 13318 13318 F: include/linux/virtio_vsock.h 13319 13319 F: include/uapi/linux/virtio_vsock.h 13320 + F: include/uapi/linux/vsockmon.h 13320 13321 F: net/vmw_vsock/af_vsock_tap.c 13321 13322 F: net/vmw_vsock/virtio_transport_common.c 13322 13323 F: net/vmw_vsock/virtio_transport.c 13324 + F: drivers/net/vsockmon.c 13323 13325 F: drivers/vhost/vsock.c 13324 13326 F: drivers/vhost/vsock.h 13325 13327
+8
drivers/net/Kconfig
··· 355 355 This option enables the support for mapping interfaces into VRF's. The 356 356 support enables VRF devices. 357 357 358 + config VSOCKMON 359 + tristate "Virtual vsock monitoring device" 360 + depends on VHOST_VSOCK 361 + ---help--- 362 + This option enables a monitoring net device for vsock sockets. It is 363 + mostly intended for developers or support to debug vsock issues. If 364 + unsure, say N. 365 + 358 366 endif # NET_CORE 359 367 360 368 config SUNGEM_PHY
+1
drivers/net/Makefile
··· 30 30 obj-$(CONFIG_GTP) += gtp.o 31 31 obj-$(CONFIG_NLMON) += nlmon.o 32 32 obj-$(CONFIG_NET_VRF) += vrf.o 33 + obj-$(CONFIG_VSOCKMON) += vsockmon.o 33 34 34 35 # 35 36 # Networking Drivers
+170
drivers/net/vsockmon.c
··· 1 + #include <linux/module.h> 2 + #include <linux/kernel.h> 3 + #include <linux/if_arp.h> 4 + #include <net/rtnetlink.h> 5 + #include <net/sock.h> 6 + #include <net/af_vsock.h> 7 + #include <uapi/linux/vsockmon.h> 8 + #include <linux/virtio_vsock.h> 9 + 10 + /* Virtio transport max packet size plus header */ 11 + #define DEFAULT_MTU (VIRTIO_VSOCK_MAX_PKT_BUF_SIZE + \ 12 + sizeof(struct af_vsockmon_hdr)) 13 + 14 + struct pcpu_lstats { 15 + u64 rx_packets; 16 + u64 rx_bytes; 17 + struct u64_stats_sync syncp; 18 + }; 19 + 20 + static int vsockmon_dev_init(struct net_device *dev) 21 + { 22 + dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); 23 + if (!dev->lstats) 24 + return -ENOMEM; 25 + return 0; 26 + } 27 + 28 + static void vsockmon_dev_uninit(struct net_device *dev) 29 + { 30 + free_percpu(dev->lstats); 31 + } 32 + 33 + struct vsockmon { 34 + struct vsock_tap vt; 35 + }; 36 + 37 + static int vsockmon_open(struct net_device *dev) 38 + { 39 + struct vsockmon *vsockmon = netdev_priv(dev); 40 + 41 + vsockmon->vt.dev = dev; 42 + vsockmon->vt.module = THIS_MODULE; 43 + return vsock_add_tap(&vsockmon->vt); 44 + } 45 + 46 + static int vsockmon_close(struct net_device *dev) 47 + { 48 + struct vsockmon *vsockmon = netdev_priv(dev); 49 + 50 + return vsock_remove_tap(&vsockmon->vt); 51 + } 52 + 53 + static netdev_tx_t vsockmon_xmit(struct sk_buff *skb, struct net_device *dev) 54 + { 55 + int len = skb->len; 56 + struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); 57 + 58 + u64_stats_update_begin(&stats->syncp); 59 + stats->rx_bytes += len; 60 + stats->rx_packets++; 61 + u64_stats_update_end(&stats->syncp); 62 + 63 + dev_kfree_skb(skb); 64 + 65 + return NETDEV_TX_OK; 66 + } 67 + 68 + static void 69 + vsockmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 70 + { 71 + int i; 72 + u64 bytes = 0, packets = 0; 73 + 74 + for_each_possible_cpu(i) { 75 + const struct pcpu_lstats *vstats; 76 + u64 tbytes, tpackets; 77 + unsigned int start; 78 + 79 + vstats = per_cpu_ptr(dev->lstats, i); 80 + 81 + do { 82 + start = u64_stats_fetch_begin_irq(&vstats->syncp); 83 + tbytes = vstats->rx_bytes; 84 + tpackets = vstats->rx_packets; 85 + } while (u64_stats_fetch_retry_irq(&vstats->syncp, start)); 86 + 87 + packets += tpackets; 88 + bytes += tbytes; 89 + } 90 + 91 + stats->rx_packets = packets; 92 + stats->tx_packets = 0; 93 + 94 + stats->rx_bytes = bytes; 95 + stats->tx_bytes = 0; 96 + } 97 + 98 + static int vsockmon_is_valid_mtu(int new_mtu) 99 + { 100 + return new_mtu >= (int)sizeof(struct af_vsockmon_hdr); 101 + } 102 + 103 + static int vsockmon_change_mtu(struct net_device *dev, int new_mtu) 104 + { 105 + if (!vsockmon_is_valid_mtu(new_mtu)) 106 + return -EINVAL; 107 + 108 + dev->mtu = new_mtu; 109 + return 0; 110 + } 111 + 112 + static const struct net_device_ops vsockmon_ops = { 113 + .ndo_init = vsockmon_dev_init, 114 + .ndo_uninit = vsockmon_dev_uninit, 115 + .ndo_open = vsockmon_open, 116 + .ndo_stop = vsockmon_close, 117 + .ndo_start_xmit = vsockmon_xmit, 118 + .ndo_get_stats64 = vsockmon_get_stats64, 119 + .ndo_change_mtu = vsockmon_change_mtu, 120 + }; 121 + 122 + static u32 always_on(struct net_device *dev) 123 + { 124 + return 1; 125 + } 126 + 127 + static const struct ethtool_ops vsockmon_ethtool_ops = { 128 + .get_link = always_on, 129 + }; 130 + 131 + static void vsockmon_setup(struct net_device *dev) 132 + { 133 + dev->type = ARPHRD_VSOCKMON; 134 + dev->priv_flags |= IFF_NO_QUEUE; 135 + 136 + dev->netdev_ops = &vsockmon_ops; 137 + dev->ethtool_ops = &vsockmon_ethtool_ops; 138 + dev->destructor = free_netdev; 139 + 140 + dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | 141 + NETIF_F_HIGHDMA | NETIF_F_LLTX; 142 + 143 + dev->flags = IFF_NOARP; 144 + 145 + dev->mtu = DEFAULT_MTU; 146 + } 147 + 148 + static struct rtnl_link_ops vsockmon_link_ops __read_mostly = { 149 + .kind = "vsockmon", 150 + .priv_size = sizeof(struct vsockmon), 151 + .setup = vsockmon_setup, 152 + }; 153 + 154 + static __init int vsockmon_register(void) 155 + { 156 + return rtnl_link_register(&vsockmon_link_ops); 157 + } 158 + 159 + static __exit void vsockmon_unregister(void) 160 + { 161 + rtnl_link_unregister(&vsockmon_link_ops); 162 + } 163 + 164 + module_init(vsockmon_register); 165 + module_exit(vsockmon_unregister); 166 + 167 + MODULE_LICENSE("GPL v2"); 168 + MODULE_AUTHOR("Gerard Garcia <ggarcia@deic.uab.cat>"); 169 + MODULE_DESCRIPTION("Vsock monitoring device. Based on nlmon device."); 170 + MODULE_ALIAS_RTNL_LINK("vsockmon");
+1
include/uapi/linux/Kbuild
··· 477 477 header-y += virtio_vsock.h 478 478 header-y += virtio_crypto.h 479 479 header-y += vm_sockets.h 480 + header-y += vsockmon.h 480 481 header-y += vt.h 481 482 header-y += vtpm_proxy.h 482 483 header-y += wait.h
+60
include/uapi/linux/vsockmon.h
··· 1 + #ifndef _UAPI_VSOCKMON_H 2 + #define _UAPI_VSOCKMON_H 3 + 4 + #include <linux/virtio_vsock.h> 5 + 6 + /* 7 + * vsockmon is the AF_VSOCK packet capture device. Packets captured have the 8 + * following layout: 9 + * 10 + * +-----------------------------------+ 11 + * | vsockmon header | 12 + * | (struct af_vsockmon_hdr) | 13 + * +-----------------------------------+ 14 + * | transport header | 15 + * | (af_vsockmon_hdr->len bytes long) | 16 + * +-----------------------------------+ 17 + * | payload | 18 + * | (until end of packet) | 19 + * +-----------------------------------+ 20 + * 21 + * The vsockmon header is a transport-independent description of the packet. 22 + * It duplicates some of the information from the transport header so that 23 + * no transport-specific knowledge is necessary to process packets. 24 + * 25 + * The transport header is useful for low-level transport-specific packet 26 + * analysis. Transport type is given in af_vsockmon_hdr->transport and 27 + * transport header length is given in af_vsockmon_hdr->len. 28 + * 29 + * If af_vsockmon_hdr->op is AF_VSOCK_OP_PAYLOAD then the payload follows the 30 + * transport header. Other ops do not have a payload. 31 + */ 32 + 33 + struct af_vsockmon_hdr { 34 + __le64 src_cid; 35 + __le64 dst_cid; 36 + __le32 src_port; 37 + __le32 dst_port; 38 + __le16 op; /* enum af_vsockmon_op */ 39 + __le16 transport; /* enum af_vsockmon_transport */ 40 + __le16 len; /* Transport header length */ 41 + __u8 reserved[2]; 42 + }; 43 + 44 + enum af_vsockmon_op { 45 + AF_VSOCK_OP_UNKNOWN = 0, 46 + AF_VSOCK_OP_CONNECT = 1, 47 + AF_VSOCK_OP_DISCONNECT = 2, 48 + AF_VSOCK_OP_CONTROL = 3, 49 + AF_VSOCK_OP_PAYLOAD = 4, 50 + }; 51 + 52 + enum af_vsockmon_transport { 53 + AF_VSOCK_TRANSPORT_UNKNOWN = 0, 54 + AF_VSOCK_TRANSPORT_NO_INFO = 1, /* No transport information */ 55 + 56 + /* Transport header type: struct virtio_vsock_hdr */ 57 + AF_VSOCK_TRANSPORT_VIRTIO = 2, 58 + }; 59 + 60 + #endif