mirror of
https://github.com/slackhq/nebula.git
synced 2025-11-09 00:43:57 +01:00
This change is for Linux only. Previously, when running with multiple tun.routines, we would only have one file descriptor. This change instead sets IFF_MULTI_QUEUE and opens a file descriptor for each routine. This allows us to process with multiple threads while preventing out of order packet reception issues. To attempt to distribute the flows across the queues, we try to write to the tun/UDP queue that corresponds with the one we read from. So if we read a packet from tun queue "2", we will write the outgoing encrypted packet to UDP queue "2". Because of the nature of how multi queue works with flows, a given host tunnel will be sticky to a given routine (so if you try to performance benchmark by only using one tunnel between two hosts, you are only going to be using a max of one thread for each direction). Because this system works much better when we can correlate flows between the tun and udp routines, we are deprecating the undocumented "tun.routines" and "listen.routines" parameters and introducing a new "routines" parameter that sets the value for both. If you use the old undocumented parameters, the max of the values will be used and a warning logged. Co-authored-by: Nate Brown <nbrown.us@gmail.com>
108 lines
2.6 KiB
Go
108 lines
2.6 KiB
Go
package nebula
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"os/exec"
|
|
"strconv"
|
|
|
|
"github.com/songgao/water"
|
|
)
|
|
|
|
type Tun struct {
|
|
Device string
|
|
Cidr *net.IPNet
|
|
MTU int
|
|
UnsafeRoutes []route
|
|
|
|
*water.Interface
|
|
}
|
|
|
|
func newTunFromFd(deviceFd int, cidr *net.IPNet, defaultMTU int, routes []route, unsafeRoutes []route, txQueueLen int) (ifce *Tun, err error) {
|
|
return nil, fmt.Errorf("newTunFromFd not supported in Windows")
|
|
}
|
|
|
|
func newTun(deviceName string, cidr *net.IPNet, defaultMTU int, routes []route, unsafeRoutes []route, txQueueLen int, multiqueue bool) (ifce *Tun, err error) {
|
|
if len(routes) > 0 {
|
|
return nil, fmt.Errorf("route MTU not supported in Windows")
|
|
}
|
|
|
|
// NOTE: You cannot set the deviceName under Windows, so you must check tun.Device after calling .Activate()
|
|
return &Tun{
|
|
Cidr: cidr,
|
|
MTU: defaultMTU,
|
|
UnsafeRoutes: unsafeRoutes,
|
|
}, nil
|
|
}
|
|
|
|
func (c *Tun) Activate() error {
|
|
var err error
|
|
c.Interface, err = water.New(water.Config{
|
|
DeviceType: water.TUN,
|
|
PlatformSpecificParams: water.PlatformSpecificParams{
|
|
ComponentID: "tap0901",
|
|
Network: c.Cidr.String(),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("Activate failed: %v", err)
|
|
}
|
|
|
|
c.Device = c.Interface.Name()
|
|
|
|
// TODO use syscalls instead of exec.Command
|
|
err = exec.Command(
|
|
`C:\Windows\System32\netsh.exe`, "interface", "ipv4", "set", "address",
|
|
fmt.Sprintf("name=%s", c.Device),
|
|
"source=static",
|
|
fmt.Sprintf("addr=%s", c.Cidr.IP),
|
|
fmt.Sprintf("mask=%s", net.IP(c.Cidr.Mask)),
|
|
"gateway=none",
|
|
).Run()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run 'netsh' to set address: %s", err)
|
|
}
|
|
err = exec.Command(
|
|
`C:\Windows\System32\netsh.exe`, "interface", "ipv4", "set", "interface",
|
|
c.Device,
|
|
fmt.Sprintf("mtu=%d", c.MTU),
|
|
).Run()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to run 'netsh' to set MTU: %s", err)
|
|
}
|
|
|
|
iface, err := net.InterfaceByName(c.Device)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to find interface named %s: %v", c.Device, err)
|
|
}
|
|
|
|
for _, r := range c.UnsafeRoutes {
|
|
err = exec.Command(
|
|
"C:\\Windows\\System32\\route.exe", "add", r.route.String(), r.via.String(), "IF", strconv.Itoa(iface.Index),
|
|
).Run()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to add the unsafe_route %s: %v", r.route.String(), err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Tun) CidrNet() *net.IPNet {
|
|
return c.Cidr
|
|
}
|
|
|
|
func (c *Tun) DeviceName() string {
|
|
return c.Device
|
|
}
|
|
|
|
func (c *Tun) WriteRaw(b []byte) error {
|
|
_, err := c.Write(b)
|
|
return err
|
|
}
|
|
|
|
func (t *Tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
|
|
return nil, fmt.Errorf("TODO: multiqueue not implemented for windows")
|
|
}
|