diff options
author | Jason Wang <jasowang@redhat.com> | 2018-01-16 03:31:02 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-17 15:32:10 -0500 |
commit | aff3d70a07fffc0abb53663e4a4acb059d2f36af (patch) | |
tree | 6274d9253d5cd93105e5759e616212876ceb2ec9 | |
parent | cd5681d7d8903bf43a571aaf96cf6d2e2e00118c (diff) |
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 <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/tun.c | 38 | ||||
-rw-r--r-- | include/uapi/linux/if_tun.h | 1 |
2 files changed, 35 insertions, 4 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 76197ede22a9..170a3e89b5af 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -239,6 +239,12 @@ struct tun_struct { | |||
239 | struct tun_pcpu_stats __percpu *pcpu_stats; | 239 | struct tun_pcpu_stats __percpu *pcpu_stats; |
240 | struct bpf_prog __rcu *xdp_prog; | 240 | struct bpf_prog __rcu *xdp_prog; |
241 | struct tun_prog __rcu *steering_prog; | 241 | 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; | ||
242 | }; | 248 | }; |
243 | 249 | ||
244 | bool tun_is_xdp_buff(void *ptr) | 250 | bool tun_is_xdp_buff(void *ptr) |
@@ -1036,12 +1042,25 @@ static void tun_automq_xmit(struct tun_struct *tun, struct sk_buff *skb) | |||
1036 | #endif | 1042 | #endif |
1037 | } | 1043 | } |
1038 | 1044 | ||
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 | |||
1039 | /* Net device start xmit */ | 1057 | /* Net device start xmit */ |
1040 | static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) | 1058 | static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev) |
1041 | { | 1059 | { |
1042 | struct tun_struct *tun = netdev_priv(dev); | 1060 | struct tun_struct *tun = netdev_priv(dev); |
1043 | int txq = skb->queue_mapping; | 1061 | int txq = skb->queue_mapping; |
1044 | struct tun_file *tfile; | 1062 | struct tun_file *tfile; |
1063 | int len = skb->len; | ||
1045 | 1064 | ||
1046 | rcu_read_lock(); | 1065 | rcu_read_lock(); |
1047 | tfile = rcu_dereference(tun->tfiles[txq]); | 1066 | 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) | |||
1067 | sk_filter(tfile->socket.sk, skb)) | 1086 | sk_filter(tfile->socket.sk, skb)) |
1068 | goto drop; | 1087 | goto drop; |
1069 | 1088 | ||
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 | |||
1070 | if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC))) | 1098 | if (unlikely(skb_orphan_frags_rx(skb, GFP_ATOMIC))) |
1071 | goto drop; | 1099 | goto drop; |
1072 | 1100 | ||
@@ -2054,10 +2082,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
2054 | 2082 | ||
2055 | if (vlan_hlen) { | 2083 | if (vlan_hlen) { |
2056 | int ret; | 2084 | int ret; |
2057 | struct { | 2085 | struct veth veth; |
2058 | __be16 h_vlan_proto; | ||
2059 | __be16 h_vlan_TCI; | ||
2060 | } veth; | ||
2061 | 2086 | ||
2062 | veth.h_vlan_proto = skb->vlan_proto; | 2087 | veth.h_vlan_proto = skb->vlan_proto; |
2063 | veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb)); | 2088 | veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb)); |
@@ -2225,6 +2250,7 @@ static void tun_free_netdev(struct net_device *dev) | |||
2225 | tun_flow_uninit(tun); | 2250 | tun_flow_uninit(tun); |
2226 | security_tun_dev_free_security(tun->security); | 2251 | security_tun_dev_free_security(tun->security); |
2227 | __tun_set_ebpf(tun, &tun->steering_prog, NULL); | 2252 | __tun_set_ebpf(tun, &tun->steering_prog, NULL); |
2253 | __tun_set_ebpf(tun, &tun->filter_prog, NULL); | ||
2228 | } | 2254 | } |
2229 | 2255 | ||
2230 | static void tun_setup(struct net_device *dev) | 2256 | static void tun_setup(struct net_device *dev) |
@@ -3019,6 +3045,10 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, | |||
3019 | ret = tun_set_ebpf(tun, &tun->steering_prog, argp); | 3045 | ret = tun_set_ebpf(tun, &tun->steering_prog, argp); |
3020 | break; | 3046 | break; |
3021 | 3047 | ||
3048 | case TUNSETFILTEREBPF: | ||
3049 | ret = tun_set_ebpf(tun, &tun->filter_prog, argp); | ||
3050 | break; | ||
3051 | |||
3022 | default: | 3052 | default: |
3023 | ret = -EINVAL; | 3053 | ret = -EINVAL; |
3024 | break; | 3054 | break; |
diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h index fb38c1797131..ee432cd3018c 100644 --- a/include/uapi/linux/if_tun.h +++ b/include/uapi/linux/if_tun.h | |||
@@ -58,6 +58,7 @@ | |||
58 | #define TUNSETVNETBE _IOW('T', 222, int) | 58 | #define TUNSETVNETBE _IOW('T', 222, int) |
59 | #define TUNGETVNETBE _IOR('T', 223, int) | 59 | #define TUNGETVNETBE _IOR('T', 223, int) |
60 | #define TUNSETSTEERINGEBPF _IOR('T', 224, int) | 60 | #define TUNSETSTEERINGEBPF _IOR('T', 224, int) |
61 | #define TUNSETFILTEREBPF _IOR('T', 225, int) | ||
61 | 62 | ||
62 | /* TUNSETIFF ifr flags */ | 63 | /* TUNSETIFF ifr flags */ |
63 | #define IFF_TUN 0x0001 | 64 | #define IFF_TUN 0x0001 |