Skip to content

Commit

Permalink
tun: allow to attach ebpf socket filter
Browse files Browse the repository at this point in the history
This patch allows userspace to attach eBPF filter to tun. This will
allow to implement VM dataplane filtering in a more efficient way
compared to cBPF filter by allowing either qemu or libvirt to
attach eBPF filter to tun.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jason Wang authored and David S. Miller committed Jan 17, 2018
1 parent cd5681d commit aff3d70
Showing 2 changed files with 35 additions and 4 deletions.
38 changes: 34 additions & 4 deletions drivers/net/tun.c
Original file line number Diff line number Diff line change
@@ -239,6 +239,12 @@ struct tun_struct {
struct tun_pcpu_stats __percpu *pcpu_stats;
struct bpf_prog __rcu *xdp_prog;
struct tun_prog __rcu *steering_prog;
struct tun_prog __rcu *filter_prog;
};

struct veth {
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
};

bool tun_is_xdp_buff(void *ptr)
@@ -1036,12 +1042,25 @@ static void tun_automq_xmit(struct tun_struct *tun, struct sk_buff *skb)
#endif
}

static unsigned int run_ebpf_filter(struct tun_struct *tun,
struct sk_buff *skb,
int len)
{
struct tun_prog *prog = rcu_dereference(tun->filter_prog);

if (prog)
len = bpf_prog_run_clear_cb(prog->prog, skb);

return len;
}

/* Net device start xmit */
static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);
int txq = skb->queue_mapping;
struct tun_file *tfile;
int len = skb->len;

rcu_read_lock();
tfile = rcu_dereference(tun->tfiles[txq]);
@@ -1067,6 +1086,15 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
sk_filter(tfile->socket.sk, skb))
goto drop;

len = run_ebpf_filter(tun, skb, len);

/* Trim extra bytes since we may insert vlan proto & TCI
* in tun_put_user().
*/
len -= skb_vlan_tag_present(skb) ? sizeof(struct veth) : 0;
if (len <= 0 || pskb_trim(skb, len))
goto drop;

if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC)))
goto drop;

@@ -2054,10 +2082,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,

if (vlan_hlen) {
int ret;
struct {
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
} veth;
struct veth veth;

veth.h_vlan_proto = skb->vlan_proto;
veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb));
@@ -2225,6 +2250,7 @@ static void tun_free_netdev(struct net_device *dev)
tun_flow_uninit(tun);
security_tun_dev_free_security(tun->security);
__tun_set_ebpf(tun, &tun->steering_prog, NULL);
__tun_set_ebpf(tun, &tun->filter_prog, NULL);
}

static void tun_setup(struct net_device *dev)
@@ -3019,6 +3045,10 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
ret = tun_set_ebpf(tun, &tun->steering_prog, argp);
break;

case TUNSETFILTEREBPF:
ret = tun_set_ebpf(tun, &tun->filter_prog, argp);
break;

default:
ret = -EINVAL;
break;
1 change: 1 addition & 0 deletions include/uapi/linux/if_tun.h
Original file line number Diff line number Diff line change
@@ -58,6 +58,7 @@
#define TUNSETVNETBE _IOW('T', 222, int)
#define TUNGETVNETBE _IOR('T', 223, int)
#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
#define TUNSETFILTEREBPF _IOR('T', 225, int)

/* TUNSETIFF ifr flags */
#define IFF_TUN 0x0001

0 comments on commit aff3d70

Please sign in to comment.