Skip to content

Commit

Permalink
VSOCK: Add vsockmon tap functions
Browse files Browse the repository at this point in the history
Add tap functions that can be used by the vsock transports to
deliver packets to vsockmon virtual network devices.

Signed-off-by: Gerard Garcia <[email protected]>
Signed-off-by: Stefan Hajnoczi <[email protected]>
Reviewed-by: Jorgen Hansen <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Gerard Garcia authored and davem330 committed Apr 24, 2017
1 parent ac2291c commit 531b374
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 1 deletion.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -13317,6 +13317,7 @@ L: [email protected]
S: Maintained
F: include/linux/virtio_vsock.h
F: include/uapi/linux/virtio_vsock.h
F: net/vmw_vsock/af_vsock_tap.c
F: net/vmw_vsock/virtio_transport_common.c
F: net/vmw_vsock/virtio_transport.c
F: drivers/vhost/vsock.c
Expand Down
13 changes: 13 additions & 0 deletions include/net/af_vsock.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,17 @@ struct sock *vsock_find_connected_socket(struct sockaddr_vm *src,
void vsock_remove_sock(struct vsock_sock *vsk);
void vsock_for_each_connected_socket(void (*fn)(struct sock *sk));

/**** TAP ****/

struct vsock_tap {
struct net_device *dev;
struct module *module;
struct list_head list;
};

int vsock_init_tap(void);
int vsock_add_tap(struct vsock_tap *vt);
int vsock_remove_tap(struct vsock_tap *vt);
void vsock_deliver_tap(struct sk_buff *build_skb(void *opaque), void *opaque);

#endif /* __AF_VSOCK_H__ */
1 change: 1 addition & 0 deletions include/uapi/linux/if_arp.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */
#define ARPHRD_NETLINK 824 /* Netlink header */
#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */
#define ARPHRD_VSOCKMON 826 /* Vsock monitor header */

#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */
Expand Down
2 changes: 1 addition & 1 deletion net/vmw_vsock/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ obj-$(CONFIG_VMWARE_VMCI_VSOCKETS) += vmw_vsock_vmci_transport.o
obj-$(CONFIG_VIRTIO_VSOCKETS) += vmw_vsock_virtio_transport.o
obj-$(CONFIG_VIRTIO_VSOCKETS_COMMON) += vmw_vsock_virtio_transport_common.o

vsock-y += af_vsock.o vsock_addr.o
vsock-y += af_vsock.o af_vsock_tap.o vsock_addr.o

vmw_vsock_vmci_transport-y += vmci_transport.o vmci_transport_notify.o \
vmci_transport_notify_qstate.o
Expand Down
114 changes: 114 additions & 0 deletions net/vmw_vsock/af_vsock_tap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Tap functions for AF_VSOCK sockets.
*
* Code based on net/netlink/af_netlink.c tap functions.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/

#include <linux/module.h>
#include <net/sock.h>
#include <net/af_vsock.h>
#include <linux/if_arp.h>

static DEFINE_SPINLOCK(vsock_tap_lock);
static struct list_head vsock_tap_all __read_mostly =
LIST_HEAD_INIT(vsock_tap_all);

int vsock_add_tap(struct vsock_tap *vt)
{
if (unlikely(vt->dev->type != ARPHRD_VSOCKMON))
return -EINVAL;

__module_get(vt->module);

spin_lock(&vsock_tap_lock);
list_add_rcu(&vt->list, &vsock_tap_all);
spin_unlock(&vsock_tap_lock);

return 0;
}
EXPORT_SYMBOL_GPL(vsock_add_tap);

int vsock_remove_tap(struct vsock_tap *vt)
{
struct vsock_tap *tmp;
bool found = false;

spin_lock(&vsock_tap_lock);

list_for_each_entry(tmp, &vsock_tap_all, list) {
if (vt == tmp) {
list_del_rcu(&vt->list);
found = true;
goto out;
}
}

pr_warn("vsock_remove_tap: %p not found\n", vt);
out:
spin_unlock(&vsock_tap_lock);

synchronize_net();

if (found)
module_put(vt->module);

return found ? 0 : -ENODEV;
}
EXPORT_SYMBOL_GPL(vsock_remove_tap);

static int __vsock_deliver_tap_skb(struct sk_buff *skb,
struct net_device *dev)
{
int ret = 0;
struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);

if (nskb) {
dev_hold(dev);

nskb->dev = dev;
ret = dev_queue_xmit(nskb);
if (unlikely(ret > 0))
ret = net_xmit_errno(ret);

dev_put(dev);
}

return ret;
}

static void __vsock_deliver_tap(struct sk_buff *skb)
{
int ret;
struct vsock_tap *tmp;

list_for_each_entry_rcu(tmp, &vsock_tap_all, list) {
ret = __vsock_deliver_tap_skb(skb, tmp->dev);
if (unlikely(ret))
break;
}
}

void vsock_deliver_tap(struct sk_buff *build_skb(void *opaque), void *opaque)
{
struct sk_buff *skb;

rcu_read_lock();

if (likely(list_empty(&vsock_tap_all)))
goto out;

skb = build_skb(opaque);
if (skb) {
__vsock_deliver_tap(skb);
consume_skb(skb);
}

out:
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(vsock_deliver_tap);

0 comments on commit 531b374

Please sign in to comment.