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.
Unified · Split
| @@ -239,6 +239,12 @@ struct tun_struct { · 238 unmodified lines | |||
| 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) · 791 unmodified lines | |||
| 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) · 19 unmodified lines | |||
| 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, · 981 unmodified lines | |||
| 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) · 161 unmodified lines | |||
| 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, · 788 unmodified lines | |||
| 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; |
| @@ -58,6 +58,7 @@ · 57 unmodified lines | |||
| 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 |