Allow Tuntap non-persist, allow empty tuntap name

chg: addtl comment and made minor logic optimization as disscussed in PR #296
chg: flipped Persist to NonPersist
chg: comments, only unpersist tuntap if flag is set
chg: tuntap persist optional, allow empty intfc name
chg: added conditional build
Signed-off-by: Ralph Schmieder <ralph.schmieder@gmail.com>
This commit is contained in:
Ralph Schmieder 2018-07-16 18:19:51 +02:00 committed by Flavio Crisciani
parent d77c86a2e2
commit d85e18ed5b
3 changed files with 36 additions and 13 deletions

2
fou.go
View File

@ -1,3 +1,5 @@
// +build linux
package netlink package netlink
import ( import (

View File

@ -302,10 +302,11 @@ type TuntapFlag uint16
// Tuntap links created via /dev/tun/tap, but can be destroyed via netlink // Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
type Tuntap struct { type Tuntap struct {
LinkAttrs LinkAttrs
Mode TuntapMode Mode TuntapMode
Flags TuntapFlag Flags TuntapFlag
Queues int NonPersist bool
Fds []*os.File Queues int
Fds []*os.File
} }
func (tuntap *Tuntap) Attrs() *LinkAttrs { func (tuntap *Tuntap) Attrs() *LinkAttrs {

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"net" "net"
"os" "os"
"strings"
"syscall" "syscall"
"unsafe" "unsafe"
@ -941,7 +942,7 @@ func LinkAdd(link Link) error {
} }
// LinkAdd adds a new link device. The type and features of the device // LinkAdd adds a new link device. The type and features of the device
// are taken fromt the parameters in the link object. // are taken from the parameters in the link object.
// Equivalent to: `ip link add $link` // Equivalent to: `ip link add $link`
func (h *Handle) LinkAdd(link Link) error { func (h *Handle) LinkAdd(link Link) error {
return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK)
@ -951,14 +952,16 @@ func (h *Handle) linkModify(link Link, flags int) error {
// TODO: support extra data for macvlan // TODO: support extra data for macvlan
base := link.Attrs() base := link.Attrs()
if base.Name == "" { // if tuntap, then the name can be empty, OS will provide a name
tuntap, isTuntap := link.(*Tuntap)
if base.Name == "" && !isTuntap {
return fmt.Errorf("LinkAttrs.Name cannot be empty!") return fmt.Errorf("LinkAttrs.Name cannot be empty!")
} }
if tuntap, ok := link.(*Tuntap); ok { if isTuntap {
// TODO: support user // TODO: support user
// TODO: support group // TODO: support group
// TODO: support non- persistent
if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP { if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP {
return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode) return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode)
} }
@ -1001,12 +1004,25 @@ func (h *Handle) linkModify(link Link, flags int) error {
cleanupFds(fds) cleanupFds(fds)
return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno) return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno)
} }
// 1) we only care for the name of the first tap in the multi queue set
// 2) if the original name was empty, the localReq has now the actual name
//
// In addition:
// This ensures that the link name is always identical to what the kernel returns.
// Not only in case of an empty name, but also when using name templates.
// e.g. when the provided name is "tap%d", the kernel replaces %d with the next available number.
if i == 0 {
link.Attrs().Name = strings.Trim(string(localReq.Name[:]), "\x00")
}
} }
_, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1) // only persist interface if NonPersist is NOT set
if errno != 0 { if !tuntap.NonPersist {
cleanupFds(fds) _, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1)
return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) if errno != 0 {
cleanupFds(fds)
return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
}
} }
h.ensureIndex(base) h.ensureIndex(base)
@ -1016,7 +1032,11 @@ func (h *Handle) linkModify(link Link, flags int) error {
// TODO: verify MasterIndex is actually a bridge? // TODO: verify MasterIndex is actually a bridge?
err := h.LinkSetMasterByIndex(link, base.MasterIndex) err := h.LinkSetMasterByIndex(link, base.MasterIndex)
if err != nil { if err != nil {
_, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0) // un-persist (e.g. allow the interface to be removed) the tuntap
// should not hurt if not set prior, condition might be not needed
if !tuntap.NonPersist {
_, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0)
}
cleanupFds(fds) cleanupFds(fds)
return err return err
} }