@@ -21,13 +21,15 @@ const (
2121)
2222
2323const (
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
3335var 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
0 commit comments