Skip to content

Commit aff3d70

Browse files
jasowangdavem330
authored andcommitted
tun: allow to attach ebpf socket filter
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent cd5681d commit aff3d70

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

drivers/net/tun.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ struct tun_struct {
239239
struct tun_pcpu_stats __percpu *pcpu_stats;
240240
struct bpf_prog __rcu *xdp_prog;
241241
struct tun_prog __rcu *steering_prog;
242+
struct tun_prog __rcu *filter_prog;
243+
};
244+
245+
struct veth {
246+
__be16 h_vlan_proto;
247+
__be16 h_vlan_TCI;
242248
};
243249

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

1045+
static unsigned int run_ebpf_filter(struct tun_struct *tun,
1046+
struct sk_buff *skb,
1047+
int len)
1048+
{
1049+
struct tun_prog *prog = rcu_dereference(tun->filter_prog);
1050+
1051+
if (prog)
1052+
len = bpf_prog_run_clear_cb(prog->prog, skb);
1053+
1054+
return len;
1055+
}
1056+
10391057
/* Net device start xmit */
10401058
static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
10411059
{
10421060
struct tun_struct *tun = netdev_priv(dev);
10431061
int txq = skb->queue_mapping;
10441062
struct tun_file *tfile;
1063+
int len = skb->len;
10451064

10461065
rcu_read_lock();
10471066
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)
10671086
sk_filter(tfile->socket.sk, skb))
10681087
goto drop;
10691088

1089+
len = run_ebpf_filter(tun, skb, len);
1090+
1091+
/* Trim extra bytes since we may insert vlan proto & TCI
1092+
* in tun_put_user().
1093+
*/
1094+
len -= skb_vlan_tag_present(skb) ? sizeof(struct veth) : 0;
1095+
if (len <= 0 || pskb_trim(skb, len))
1096+
goto drop;
1097+
10701098
if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC)))
10711099
goto drop;
10721100

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

20552083
if (vlan_hlen) {
20562084
int ret;
2057-
struct {
2058-
__be16 h_vlan_proto;
2059-
__be16 h_vlan_TCI;
2060-
} veth;
2085+
struct veth veth;
20612086

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

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

3048+
case TUNSETFILTEREBPF:
3049+
ret = tun_set_ebpf(tun, &tun->filter_prog, argp);
3050+
break;
3051+
30223052
default:
30233053
ret = -EINVAL;
30243054
break;

include/uapi/linux/if_tun.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#define TUNSETVNETBE _IOW('T', 222, int)
5959
#define TUNGETVNETBE _IOR('T', 223, int)
6060
#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
61+
#define TUNSETFILTEREBPF _IOR('T', 225, int)
6162

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

0 commit comments

Comments
 (0)