mirror of
https://github.com/vishvananda/netlink
synced 2025-02-17 20:47:12 +00:00
tuntap: Return TunTapLink instead of GenericLink
For tuntap interfaces, return a TunTap Interface instead of a Generic link when retrieving the interface. Use netlink extended attributes to populate the Link attributes for the tuntap link. In case of older tun driver which does not provide these attributes, use sysfs to retrieve these attributes. This commit also adds Owner and Group attributes for the TunTap Link. Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
This commit is contained in:
parent
e99361632b
commit
db99c040b9
2
link.go
2
link.go
@ -311,6 +311,8 @@ type Tuntap struct {
|
||||
NonPersist bool
|
||||
Queues int
|
||||
Fds []*os.File
|
||||
Owner uint32
|
||||
Group uint32
|
||||
}
|
||||
|
||||
func (tuntap *Tuntap) Attrs() *LinkAttrs {
|
||||
|
@ -4,8 +4,10 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
@ -1459,6 +1461,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
|
||||
link = >P{}
|
||||
case "xfrm":
|
||||
link = &Xfrmi{}
|
||||
case "tun":
|
||||
link = &Tuntap{}
|
||||
default:
|
||||
link = &GenericLink{LinkType: linkType}
|
||||
}
|
||||
@ -1502,6 +1506,8 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
|
||||
parseGTPData(link, data)
|
||||
case "xfrm":
|
||||
parseXfrmiData(link, data)
|
||||
case "tun":
|
||||
parseTuntapData(link, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1580,9 +1586,57 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) {
|
||||
}
|
||||
*link.Attrs() = base
|
||||
|
||||
// If the tuntap attributes are not updated by netlink due to
|
||||
// an older driver, use sysfs
|
||||
if link != nil && linkType == "tun" {
|
||||
tuntap := link.(*Tuntap)
|
||||
|
||||
if tuntap.Mode == 0 {
|
||||
ifname := tuntap.Attrs().Name
|
||||
if flags, err := readSysPropAsInt64(ifname, "tun_flags"); err == nil {
|
||||
|
||||
if flags&unix.IFF_TUN != 0 {
|
||||
tuntap.Mode = unix.IFF_TUN
|
||||
} else if flags&unix.IFF_TAP != 0 {
|
||||
tuntap.Mode = unix.IFF_TAP
|
||||
}
|
||||
|
||||
tuntap.NonPersist = false
|
||||
if flags&unix.IFF_PERSIST == 0 {
|
||||
tuntap.NonPersist = true
|
||||
}
|
||||
}
|
||||
|
||||
// The sysfs interface for owner/group returns -1 for root user, instead of returning 0.
|
||||
// So explicitly check for negative value, before assigning the owner uid/gid.
|
||||
if owner, err := readSysPropAsInt64(ifname, "owner"); err == nil && owner > 0 {
|
||||
tuntap.Owner = uint32(owner)
|
||||
}
|
||||
|
||||
if group, err := readSysPropAsInt64(ifname, "group"); err == nil && group > 0 {
|
||||
tuntap.Group = uint32(group)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func readSysPropAsInt64(ifname, prop string) (int64, error) {
|
||||
fname := fmt.Sprintf("/sys/class/net/%s/%s", ifname, prop)
|
||||
contents, err := ioutil.ReadFile(fname)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
num, err := strconv.ParseInt(strings.TrimSpace(string(contents)), 0, 64)
|
||||
if err == nil {
|
||||
return num, nil
|
||||
}
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// LinkList gets a list of link devices.
|
||||
// Equivalent to: `ip link show`
|
||||
func LinkList() ([]Link, error) {
|
||||
@ -2586,3 +2640,22 @@ func VethPeerIndex(link *Veth) (int, error) {
|
||||
}
|
||||
return int(stats.data[0]), nil
|
||||
}
|
||||
|
||||
func parseTuntapData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
tuntap := link.(*Tuntap)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_TUN_OWNER:
|
||||
tuntap.Owner = native.Uint32(datum.Value)
|
||||
case nl.IFLA_TUN_GROUP:
|
||||
tuntap.Group = native.Uint32(datum.Value)
|
||||
case nl.IFLA_TUN_TYPE:
|
||||
tuntap.Mode = TuntapMode(uint8(datum.Value[0]))
|
||||
case nl.IFLA_TUN_PERSIST:
|
||||
tuntap.NonPersist = false
|
||||
if uint8(datum.Value[0]) == 0 {
|
||||
tuntap.NonPersist = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
50
link_test.go
50
link_test.go
@ -6,6 +6,7 @@ import (
|
||||
"bytes"
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -209,6 +210,14 @@ func testLinkAddDel(t *testing.T, link Link) {
|
||||
compareXfrmi(t, xfrmi, other)
|
||||
}
|
||||
|
||||
if tuntap, ok := link.(*Tuntap); ok {
|
||||
other, ok := result.(*Tuntap)
|
||||
if !ok {
|
||||
t.Fatal("Result of create is not a tuntap")
|
||||
}
|
||||
compareTuntap(t, tuntap, other)
|
||||
}
|
||||
|
||||
if err = LinkDel(link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -423,6 +432,24 @@ func compareXfrmi(t *testing.T, expected, actual *Xfrmi) {
|
||||
}
|
||||
}
|
||||
|
||||
func compareTuntap(t *testing.T, expected, actual *Tuntap) {
|
||||
if expected.Mode != actual.Mode {
|
||||
t.Fatalf("Tuntap.Mode doesn't match: expected : %+v, got %+v", expected.Mode, actual.Mode)
|
||||
}
|
||||
|
||||
if expected.Owner != actual.Owner {
|
||||
t.Fatal("Tuntap.Owner doesn't match")
|
||||
}
|
||||
|
||||
if expected.Group != actual.Group {
|
||||
t.Fatal("Tuntap.Group doesn't match")
|
||||
}
|
||||
|
||||
if expected.NonPersist != actual.NonPersist {
|
||||
t.Fatal("Tuntap.Group doesn't match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddDelWithIndex(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
@ -1839,16 +1866,37 @@ func TestLinkAddDelTuntap(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
// Mount sysfs so that sysfs gets the namespace tag of the current network namespace
|
||||
// This is necessary so that /sys shows the network interfaces of the current namespace.
|
||||
if err := syscall.Mount("sysfs", "/sys", "sysfs", syscall.MS_RDONLY, ""); err != nil {
|
||||
t.Fatal("Cannot mount sysfs")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := syscall.Unmount("/sys", 0); err != nil {
|
||||
t.Fatal("Cannot umount /sys")
|
||||
}
|
||||
}()
|
||||
|
||||
testLinkAddDel(t, &Tuntap{
|
||||
LinkAttrs: LinkAttrs{Name: "foo"},
|
||||
Mode: TUNTAP_MODE_TAP})
|
||||
|
||||
}
|
||||
|
||||
func TestLinkAddDelTuntapMq(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
if err := syscall.Mount("sysfs", "/sys", "sysfs", syscall.MS_RDONLY, ""); err != nil {
|
||||
t.Fatal("Cannot mount sysfs")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := syscall.Unmount("/sys", 0); err != nil {
|
||||
t.Fatal("Cannot umount /sys")
|
||||
}
|
||||
}()
|
||||
|
||||
testLinkAddDel(t, &Tuntap{
|
||||
LinkAttrs: LinkAttrs{Name: "foo"},
|
||||
Mode: TUNTAP_MODE_TAP,
|
||||
|
@ -581,3 +581,17 @@ const (
|
||||
|
||||
IFLA_XFRM_MAX = iota - 1
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_TUN_UNSPEC = iota
|
||||
IFLA_TUN_OWNER
|
||||
IFLA_TUN_GROUP
|
||||
IFLA_TUN_TYPE
|
||||
IFLA_TUN_PI
|
||||
IFLA_TUN_VNET_HDR
|
||||
IFLA_TUN_PERSIST
|
||||
IFLA_TUN_MULTI_QUEUE
|
||||
IFLA_TUN_NUM_QUEUES
|
||||
IFLA_TUN_NUM_DISABLED_QUEUES
|
||||
IFLA_TUN_MAX = IFLA_TUN_NUM_DISABLED_QUEUES
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user