|
@@ -5,7 +5,9 @@ import (
|
|
|
"encoding/binary"
|
|
|
"fmt"
|
|
|
"net"
|
|
|
+ "os"
|
|
|
"syscall"
|
|
|
+ "unsafe"
|
|
|
|
|
|
"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
|
|
|
)
|
|
@@ -48,7 +50,7 @@ func LinkSetUp(link Link) error {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
-// LinkSetUp disables link device.
|
|
|
+// LinkSetDown disables link device.
|
|
|
// Equivalent to: `ip link set $link down`
|
|
|
func LinkSetDown(link Link) error {
|
|
|
base := link.Attrs()
|
|
@@ -73,10 +75,7 @@ func LinkSetMTU(link Link, mtu int) error {
|
|
|
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
msg.Index = int32(base.Index)
|
|
|
- msg.Change = syscall.IFLA_MTU
|
|
|
req.AddData(msg)
|
|
|
|
|
|
b := make([]byte, 4)
|
|
@@ -97,10 +96,7 @@ func LinkSetName(link Link, name string) error {
|
|
|
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
msg.Index = int32(base.Index)
|
|
|
- msg.Change = syscall.IFLA_IFNAME
|
|
|
req.AddData(msg)
|
|
|
|
|
|
data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
|
|
@@ -118,10 +114,7 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
|
|
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
msg.Index = int32(base.Index)
|
|
|
- msg.Change = syscall.IFLA_ADDRESS
|
|
|
req.AddData(msg)
|
|
|
|
|
|
data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
|
|
@@ -151,10 +144,7 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
|
|
|
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
msg.Index = int32(base.Index)
|
|
|
- msg.Change = syscall.IFLA_MASTER
|
|
|
req.AddData(msg)
|
|
|
|
|
|
b := make([]byte, 4)
|
|
@@ -176,10 +166,7 @@ func LinkSetNsPid(link Link, nspid int) error {
|
|
|
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
msg.Index = int32(base.Index)
|
|
|
- msg.Change = syscall.IFLA_NET_NS_PID
|
|
|
req.AddData(msg)
|
|
|
|
|
|
b := make([]byte, 4)
|
|
@@ -201,10 +188,7 @@ func LinkSetNsFd(link Link, fd int) error {
|
|
|
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
msg.Index = int32(base.Index)
|
|
|
- msg.Change = nl.IFLA_NET_NS_FD
|
|
|
req.AddData(msg)
|
|
|
|
|
|
b := make([]byte, 4)
|
|
@@ -266,6 +250,10 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
|
|
|
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
|
|
|
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
|
|
|
|
|
|
+ if vxlan.GBP {
|
|
|
+ nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, boolAttr(vxlan.GBP))
|
|
|
+ }
|
|
|
+
|
|
|
if vxlan.NoAge {
|
|
|
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
|
|
|
} else if vxlan.Age > 0 {
|
|
@@ -299,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)
|
|
@@ -321,6 +347,11 @@ func LinkAdd(link Link) error {
|
|
|
req.AddData(mtu)
|
|
|
}
|
|
|
|
|
|
+ if base.TxQLen >= 0 {
|
|
|
+ qlen := nl.NewRtAttr(syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
|
|
|
+ req.AddData(qlen)
|
|
|
+ }
|
|
|
+
|
|
|
if base.Namespace != nil {
|
|
|
var attr *nl.RtAttr
|
|
|
switch base.Namespace.(type) {
|
|
@@ -338,8 +369,6 @@ func LinkAdd(link Link) error {
|
|
|
linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
|
|
|
nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
|
|
|
|
|
|
- nl.NewRtAttrChild(linkInfo, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
|
|
|
-
|
|
|
if vlan, ok := link.(*Vlan); ok {
|
|
|
b := make([]byte, 2)
|
|
|
native.PutUint16(b, uint16(vlan.VlanId))
|
|
@@ -350,10 +379,13 @@ func LinkAdd(link Link) error {
|
|
|
peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
|
|
|
nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
|
|
|
nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
|
|
|
- nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
|
|
|
+ if base.TxQLen >= 0 {
|
|
|
+ nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
|
|
|
+ }
|
|
|
if base.MTU > 0 {
|
|
|
nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
|
|
|
}
|
|
|
+
|
|
|
} else if vxlan, ok := link.(*Vxlan); ok {
|
|
|
addVxlanAttrs(vxlan, linkInfo)
|
|
|
} else if ipv, ok := link.(*IPVlan); ok {
|
|
@@ -501,6 +533,8 @@ func linkDeserialize(m []byte) (Link, error) {
|
|
|
switch linkType {
|
|
|
case "dummy":
|
|
|
link = &Dummy{}
|
|
|
+ case "ifb":
|
|
|
+ link = &Ifb{}
|
|
|
case "bridge":
|
|
|
link = &Bridge{}
|
|
|
case "vlan":
|
|
@@ -513,8 +547,10 @@ func linkDeserialize(m []byte) (Link, error) {
|
|
|
link = &IPVlan{}
|
|
|
case "macvlan":
|
|
|
link = &Macvlan{}
|
|
|
+ case "macvtap":
|
|
|
+ link = &Macvtap{}
|
|
|
default:
|
|
|
- link = &Generic{LinkType: linkType}
|
|
|
+ link = &GenericLink{LinkType: linkType}
|
|
|
}
|
|
|
case nl.IFLA_INFO_DATA:
|
|
|
data, err := nl.ParseRouteAttr(info.Value)
|
|
@@ -530,6 +566,8 @@ func linkDeserialize(m []byte) (Link, error) {
|
|
|
parseIPVlanData(link, data)
|
|
|
case "macvlan":
|
|
|
parseMacvlanData(link, data)
|
|
|
+ case "macvtap":
|
|
|
+ parseMacvtapData(link, data)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -552,7 +590,7 @@ func linkDeserialize(m []byte) (Link, error) {
|
|
|
case syscall.IFLA_MASTER:
|
|
|
base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
|
|
|
case syscall.IFLA_TXQLEN:
|
|
|
- base.TxQLen = native.Uint32(attr.Value[0:4])
|
|
|
+ base.TxQLen = int(native.Uint32(attr.Value[0:4]))
|
|
|
}
|
|
|
}
|
|
|
// Links that don't have IFLA_INFO_KIND are hardware devices
|
|
@@ -579,8 +617,7 @@ func LinkList() ([]Link, error) {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- res := make([]Link, 0)
|
|
|
-
|
|
|
+ var res []Link
|
|
|
for _, m := range msgs {
|
|
|
link, err := linkDeserialize(m)
|
|
|
if err != nil {
|
|
@@ -592,6 +629,46 @@ func LinkList() ([]Link, error) {
|
|
|
return res, nil
|
|
|
}
|
|
|
|
|
|
+// LinkUpdate is used to pass information back from LinkSubscribe()
|
|
|
+type LinkUpdate struct {
|
|
|
+ nl.IfInfomsg
|
|
|
+ Link
|
|
|
+}
|
|
|
+
|
|
|
+// LinkSubscribe takes a chan down which notifications will be sent
|
|
|
+// when links change. Close the 'done' chan to stop subscription.
|
|
|
+func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
|
|
|
+ s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if done != nil {
|
|
|
+ go func() {
|
|
|
+ <-done
|
|
|
+ s.Close()
|
|
|
+ }()
|
|
|
+ }
|
|
|
+ go func() {
|
|
|
+ defer close(ch)
|
|
|
+ for {
|
|
|
+ msgs, err := s.Receive()
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for _, m := range msgs {
|
|
|
+ ifmsg := nl.DeserializeIfInfomsg(m.Data)
|
|
|
+ link, err := linkDeserialize(m.Data)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ch <- LinkUpdate{IfInfomsg: *ifmsg, Link: link}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }()
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
func LinkSetHairpin(link Link, mode bool) error {
|
|
|
return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE)
|
|
|
}
|
|
@@ -622,10 +699,7 @@ func setProtinfoAttr(link Link, mode bool, attr int) error {
|
|
|
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
|
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
msg.Index = int32(base.Index)
|
|
|
- msg.Change = syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED
|
|
|
req.AddData(msg)
|
|
|
|
|
|
br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
|
|
@@ -678,6 +752,8 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
|
|
vxlan.L2miss = int8(datum.Value[0]) != 0
|
|
|
case nl.IFLA_VXLAN_L3MISS:
|
|
|
vxlan.L3miss = int8(datum.Value[0]) != 0
|
|
|
+ case nl.IFLA_VXLAN_GBP:
|
|
|
+ vxlan.GBP = int8(datum.Value[0]) != 0
|
|
|
case nl.IFLA_VXLAN_AGEING:
|
|
|
vxlan.Age = int(native.Uint32(datum.Value[0:4]))
|
|
|
vxlan.NoAge = vxlan.Age == 0
|
|
@@ -706,6 +782,11 @@ func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func parseMacvtapData(link Link, data []syscall.NetlinkRouteAttr) {
|
|
|
+ macv := link.(*Macvtap)
|
|
|
+ parseMacvlanData(&macv.Macvlan, data)
|
|
|
+}
|
|
|
+
|
|
|
func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
|
|
macv := link.(*Macvlan)
|
|
|
for _, datum := range data {
|