From de4cc349a50bb2aa94ae8963a56742710f46ec52 Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Fri, 25 Sep 2015 10:28:19 +0100 Subject: [PATCH] Add basic support for TUN/TAP link type and creation. --- link.go | 26 +++++++++++++++++++++++++- link_linux.go | 40 ++++++++++++++++++++++++++++++++++++++++ link_tuntap_linux.go | 17 +++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 link_tuntap_linux.go diff --git a/link.go b/link.go index 18fd175..5472a25 100644 --- a/link.go +++ b/link.go @@ -1,6 +1,9 @@ package netlink -import "net" +import ( + "net" + "syscall" +) // Link represents a link device from netlink. Shared link attributes // like name may be retrieved using the Attrs() method. Unique data @@ -136,6 +139,27 @@ func (macvtap Macvtap) Type() string { return "macvtap" } +type TuntapMode uint16 + +const ( + TUNTAP_MODE_TUN TuntapMode = syscall.IFF_TUN + TUNTAP_MODE_TAP TuntapMode = syscall.IFF_TAP +) + +// Tuntap links created via /dev/tun/tap, but can be destroyed via netlink +type Tuntap struct { + LinkAttrs + Mode TuntapMode +} + +func (tuntap *Tuntap) Attrs() *LinkAttrs { + return &tuntap.LinkAttrs +} + +func (tuntap *Tuntap) Type() string { + return "tuntap" +} + // Veth devices must specify PeerName on create type Veth struct { LinkAttrs diff --git a/link_linux.go b/link_linux.go index 842a21f..638306b 100644 --- a/link_linux.go +++ b/link_linux.go @@ -5,6 +5,8 @@ import ( "encoding/binary" "fmt" "net" + "os" + "unsafe" "syscall" "github.com/vishvananda/netlink/nl" @@ -285,6 +287,44 @@ func LinkAdd(link Link) error { return fmt.Errorf("LinkAttrs.Name cannot be empty!") } + if tuntap, ok := link.(*Tuntap); ok { + // TODO: support user + // TODO: support group + // TODO: support non- one_queue + // TODO: support pi | vnet_hdr | multi_queue + // TODO: support non- exclusive + // TODO: support non- persistent + if (tuntap.Mode < syscall.IFF_TUN || tuntap.Mode > syscall.IFF_TAP) { + return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode) + } + file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0) + if err != nil { + return err + } + defer file.Close() + var req ifReq + req.Flags |= syscall.IFF_ONE_QUEUE + req.Flags |= syscall.IFF_TUN_EXCL + copy(req.Name[:15], base.Name) + req.Flags |= uint16(tuntap.Mode) + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&req))) + if errno != 0 { + return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed, errno %v", errno) + } + _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETPERSIST), 1) + if errno != 0 { + return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) + } + ensureIndex(base) + + // can't set master during create, so set it afterwards + if base.MasterIndex != 0 { + // TODO: verify MasterIndex is actually a bridge? + return LinkSetMasterByIndex(link, base.MasterIndex) + } + return nil + } + req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) diff --git a/link_tuntap_linux.go b/link_tuntap_linux.go new file mode 100644 index 0000000..bfee56a --- /dev/null +++ b/link_tuntap_linux.go @@ -0,0 +1,17 @@ +package netlink + +/* +#include +#include +#include +#include + +#define IFREQ_SIZE sizeof(struct ifreq) +*/ +import "C" + +type ifReq struct { + Name [C.IFNAMSIZ]byte + Flags uint16 + pad [C.IFREQ_SIZE-C.IFNAMSIZ-2]byte +}