Skip to content

Commit a18bd6f

Browse files
committed
tuntap: Add multiqueue support
Add multi queue support to tuntap without breaking legacy users of tuntap. Signed-off-by: Manohar Castelino <[email protected]>
1 parent 63ca7e4 commit a18bd6f

3 files changed

Lines changed: 97 additions & 24 deletions

File tree

link.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package netlink
33
import (
44
"fmt"
55
"net"
6+
"os"
67
)
78

89
// Link represents a link device from netlink. Shared link attributes
@@ -284,8 +285,10 @@ type TuntapFlag uint16
284285
// Tuntap links created via /dev/tun/tap, but can be destroyed via netlink
285286
type Tuntap struct {
286287
LinkAttrs
287-
Mode TuntapMode
288-
Flags TuntapFlag
288+
Mode TuntapMode
289+
Flags TuntapFlag
290+
Queues int
291+
Fds []*os.File
289292
}
290293

291294
func (tuntap *Tuntap) Attrs() *LinkAttrs {

link_linux.go

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ const (
2121
)
2222

2323
const (
24-
TUNTAP_MODE_TUN TuntapMode = unix.IFF_TUN
25-
TUNTAP_MODE_TAP TuntapMode = unix.IFF_TAP
26-
TUNTAP_DEFAULTS TuntapFlag = unix.IFF_TUN_EXCL | unix.IFF_ONE_QUEUE
27-
TUNTAP_VNET_HDR TuntapFlag = unix.IFF_VNET_HDR
28-
TUNTAP_TUN_EXCL TuntapFlag = unix.IFF_TUN_EXCL
29-
TUNTAP_NO_PI TuntapFlag = unix.IFF_NO_PI
30-
TUNTAP_ONE_QUEUE TuntapFlag = unix.IFF_ONE_QUEUE
24+
TUNTAP_MODE_TUN TuntapMode = unix.IFF_TUN
25+
TUNTAP_MODE_TAP TuntapMode = unix.IFF_TAP
26+
TUNTAP_DEFAULTS TuntapFlag = unix.IFF_TUN_EXCL | unix.IFF_ONE_QUEUE
27+
TUNTAP_VNET_HDR TuntapFlag = unix.IFF_VNET_HDR
28+
TUNTAP_TUN_EXCL TuntapFlag = unix.IFF_TUN_EXCL
29+
TUNTAP_NO_PI TuntapFlag = unix.IFF_NO_PI
30+
TUNTAP_ONE_QUEUE TuntapFlag = unix.IFF_ONE_QUEUE
31+
TUNTAP_MULTI_QUEUE TuntapFlag = 0x0100
32+
TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI
3133
)
3234

3335
var lookupByDump = false
@@ -767,6 +769,12 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
767769
}
768770
}
769771

772+
func cleanupFds(fds []*os.File) {
773+
for _, f := range fds {
774+
f.Close()
775+
}
776+
}
777+
770778
// LinkAdd adds a new link device. The type and features of the device
771779
// are taken from the parameters in the link object.
772780
// Equivalent to: `ip link add $link`
@@ -792,39 +800,75 @@ func (h *Handle) linkModify(link Link, flags int) error {
792800
if tuntap, ok := link.(*Tuntap); ok {
793801
// TODO: support user
794802
// TODO: support group
795-
// TODO: multi_queue
796803
// TODO: support non- persistent
797804
if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP {
798805
return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode)
799806
}
800-
file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
801-
if err != nil {
802-
return err
803-
}
804-
defer file.Close()
807+
808+
queues := tuntap.Queues
809+
810+
var fds []*os.File
805811
var req ifReq
806-
if tuntap.Flags == 0 {
807-
req.Flags = uint16(TUNTAP_DEFAULTS)
812+
copy(req.Name[:15], base.Name)
813+
814+
req.Flags = uint16(tuntap.Flags)
815+
816+
if queues == 0 { //Legacy compatibility
817+
queues = 1
818+
if tuntap.Flags == 0 {
819+
req.Flags = uint16(TUNTAP_DEFAULTS)
820+
}
808821
} else {
809-
req.Flags = uint16(tuntap.Flags)
822+
// For best peformance set Flags to TUNTAP_MULTI_QUEUE_DEFAULTS | TUNTAP_VNET_HDR
823+
// when a) KVM has support for this ABI and
824+
// b) the value of the flag is queryable using the TUNGETIFF ioctl
825+
if tuntap.Flags == 0 {
826+
req.Flags = uint16(TUNTAP_MULTI_QUEUE_DEFAULTS)
827+
}
810828
}
829+
811830
req.Flags |= uint16(tuntap.Mode)
812-
copy(req.Name[:15], base.Name)
813-
_, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req)))
814-
if errno != 0 {
815-
return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed, errno %v", errno)
831+
832+
for i := 0; i < queues; i++ {
833+
localReq := req
834+
file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
835+
if err != nil {
836+
cleanupFds(fds)
837+
return err
838+
}
839+
840+
fds = append(fds, file)
841+
_, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&localReq)))
842+
if errno != 0 {
843+
cleanupFds(fds)
844+
return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno)
845+
}
816846
}
817-
_, _, errno = unix.Syscall(unix.SYS_IOCTL, file.Fd(), uintptr(unix.TUNSETPERSIST), 1)
847+
848+
_, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1)
818849
if errno != 0 {
850+
cleanupFds(fds)
819851
return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
820852
}
853+
821854
h.ensureIndex(base)
822855

823856
// can't set master during create, so set it afterwards
824857
if base.MasterIndex != 0 {
825858
// TODO: verify MasterIndex is actually a bridge?
826-
return h.LinkSetMasterByIndex(link, base.MasterIndex)
859+
err := h.LinkSetMasterByIndex(link, base.MasterIndex)
860+
if err != nil {
861+
_, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0)
862+
cleanupFds(fds)
863+
}
827864
}
865+
866+
if tuntap.Queues == 0 {
867+
cleanupFds(fds)
868+
} else {
869+
tuntap.Fds = fds
870+
}
871+
828872
return nil
829873
}
830874

link_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,3 +1475,29 @@ func TestLinkByAliasWhenLinkIsNotFound(t *testing.T) {
14751475
t.Errorf("Error returned expected to of LinkNotFoundError type: %v", err)
14761476
}
14771477
}
1478+
1479+
func TestLinkAddDelTuntap(t *testing.T) {
1480+
tearDown := setUpNetlinkTest(t)
1481+
defer tearDown()
1482+
1483+
testLinkAddDel(t, &Tuntap{
1484+
LinkAttrs: LinkAttrs{Name: "foo"},
1485+
Mode: TUNTAP_MODE_TAP})
1486+
1487+
}
1488+
1489+
func TestLinkAddDelTuntapMq(t *testing.T) {
1490+
tearDown := setUpNetlinkTest(t)
1491+
defer tearDown()
1492+
1493+
testLinkAddDel(t, &Tuntap{
1494+
LinkAttrs: LinkAttrs{Name: "foo"},
1495+
Mode: TUNTAP_MODE_TAP,
1496+
Queues: 4})
1497+
1498+
testLinkAddDel(t, &Tuntap{
1499+
LinkAttrs: LinkAttrs{Name: "foo"},
1500+
Mode: TUNTAP_MODE_TAP,
1501+
Queues: 4,
1502+
Flags: TUNTAP_MULTI_QUEUE_DEFAULTS | TUNTAP_VNET_HDR})
1503+
}

0 commit comments

Comments
 (0)