wgengine: wrap tun.Device to support filtering and packet injection (#358)

Right now, filtering and packet injection in wgengine depend
on a patch to wireguard-go that probably isn't suitable for upstreaming.

This need not be the case: wireguard-go/tun.Device is an interface.
For example, faketun.go implements it to mock a TUN device for testing.

This patch implements the same interface to provide filtering
and packet injection at the tunnel device level,
at which point the wireguard-go patch should no longer be necessary.

This patch has the following performance impact on i7-7500U @ 2.70GHz,
tested in the following namespace configuration:
┌────────────────┐    ┌─────────────────────────────────┐     ┌────────────────┐
│      $ns1      │    │               $ns0              │     │      $ns2      │
│    client0     │    │      tailcontrol, logcatcher    │     │     client1    │
│  ┌─────┐       │    │  ┌──────┐         ┌──────┐      │     │  ┌─────┐       │
│  │vethc│───────┼────┼──│vethrc│         │vethrs│──────┼─────┼──│veths│       │
│  ├─────┴─────┐ │    │  ├──────┴────┐    ├──────┴────┐ │     │  ├─────┴─────┐ │
│  │10.0.0.2/24│ │    │  │10.0.0.1/24│    │10.0.1.1/24│ │     │  │10.0.1.2/24│ │
│  └───────────┘ │    │  └───────────┘    └───────────┘ │     │  └───────────┘ │
└────────────────┘    └─────────────────────────────────┘     └────────────────┘
Before:
---------------------------------------------------
| TCP send               | UDP send               |
|------------------------|------------------------|
| 557.0 (±8.5) Mbits/sec | 3.03 (±0.02) Gbits/sec |
---------------------------------------------------
After:
---------------------------------------------------
| TCP send               | UDP send               |
|------------------------|------------------------|
| 544.8 (±1.6) Mbits/sec | 3.13 (±0.02) Gbits/sec |
---------------------------------------------------
The impact on receive performance is similar.

Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This commit is contained in:
Dmytro Shynkevych
2020-05-13 09:16:17 -04:00
committed by GitHub
parent 9ccbcda612
commit 33b2f30cea
7 changed files with 355 additions and 130 deletions

View File

@@ -28,6 +28,8 @@ import (
"tailscale.com/stun/stuntest"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/wgengine/filter"
"tailscale.com/wgengine/tstun"
)
func TestListen(t *testing.T) {
@@ -326,7 +328,9 @@ func TestTwoDevicePing(t *testing.T) {
//t.Logf("cfg1: %v", uapi2)
tun1 := tuntest.NewChannelTUN()
dev1 := device.NewDevice(tun1.TUN(), &device.DeviceOptions{
tstun1 := tstun.WrapTUN(t.Logf, tun1.TUN())
tstun1.SetFilter(filter.NewAllowAll())
dev1 := device.NewDevice(tstun1, &device.DeviceOptions{
Logger: devLogger(t, "dev1"),
CreateEndpoint: conn1.CreateEndpoint,
CreateBind: conn1.CreateBind,
@@ -339,7 +343,9 @@ func TestTwoDevicePing(t *testing.T) {
defer dev1.Close()
tun2 := tuntest.NewChannelTUN()
dev2 := device.NewDevice(tun2.TUN(), &device.DeviceOptions{
tstun2 := tstun.WrapTUN(t.Logf, tun2.TUN())
tstun2.SetFilter(filter.NewAllowAll())
dev2 := device.NewDevice(tstun2, &device.DeviceOptions{
Logger: devLogger(t, "dev2"),
CreateEndpoint: conn2.CreateEndpoint,
CreateBind: conn2.CreateBind,
@@ -385,7 +391,7 @@ func TestTwoDevicePing(t *testing.T) {
t.Run("ping 1.0.0.2", func(t *testing.T) { ping2(t) })
t.Run("ping 1.0.0.2 via SendPacket", func(t *testing.T) {
msg1to2 := tuntest.Ping(net.ParseIP("1.0.0.2"), net.ParseIP("1.0.0.1"))
if err := dev1.SendPacket(msg1to2); err != nil {
if err := tstun1.InjectOutbound(msg1to2); err != nil {
t.Fatal(err)
}
select {