|
@@ -12,15 +12,25 @@ import (
|
|
)
|
|
)
|
|
|
|
|
|
const (
|
|
const (
|
|
- IFNAMSIZ = 16
|
|
|
|
- DEFAULT_CHANGE = 0xFFFFFFFF
|
|
|
|
- IFLA_INFO_KIND = 1
|
|
|
|
- IFLA_INFO_DATA = 2
|
|
|
|
- VETH_INFO_PEER = 1
|
|
|
|
- IFLA_NET_NS_FD = 28
|
|
|
|
- SIOC_BRADDBR = 0x89a0
|
|
|
|
- SIOC_BRDELBR = 0x89a1
|
|
|
|
- SIOC_BRADDIF = 0x89a2
|
|
|
|
|
|
+ IFNAMSIZ = 16
|
|
|
|
+ DEFAULT_CHANGE = 0xFFFFFFFF
|
|
|
|
+ IFLA_INFO_KIND = 1
|
|
|
|
+ IFLA_INFO_DATA = 2
|
|
|
|
+ VETH_INFO_PEER = 1
|
|
|
|
+ IFLA_MACVLAN_MODE = 1
|
|
|
|
+ IFLA_VLAN_ID = 1
|
|
|
|
+ IFLA_NET_NS_FD = 28
|
|
|
|
+ IFLA_ADDRESS = 1
|
|
|
|
+ SIOC_BRADDBR = 0x89a0
|
|
|
|
+ SIOC_BRDELBR = 0x89a1
|
|
|
|
+ SIOC_BRADDIF = 0x89a2
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+const (
|
|
|
|
+ MACVLAN_MODE_PRIVATE = 1 << iota
|
|
|
|
+ MACVLAN_MODE_VEPA
|
|
|
|
+ MACVLAN_MODE_BRIDGE
|
|
|
|
+ MACVLAN_MODE_PASSTHRU
|
|
)
|
|
)
|
|
|
|
|
|
var nextSeqNr uint32
|
|
var nextSeqNr uint32
|
|
@@ -375,10 +385,19 @@ outer:
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-// Add a new route table entry.
|
|
|
|
-func AddRoute(destination, source, gateway, device string) error {
|
|
|
|
- if destination == "" && source == "" && gateway == "" {
|
|
|
|
- return fmt.Errorf("one of destination, source or gateway must not be blank")
|
|
|
|
|
|
+func zeroTerminated(s string) []byte {
|
|
|
|
+ return []byte(s + "\000")
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func nonZeroTerminated(s string) []byte {
|
|
|
|
+ return []byte(s)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Add a new network link of a specified type.
|
|
|
|
+// This is identical to running: ip link add $name type $linkType
|
|
|
|
+func NetworkLinkAdd(name string, linkType string) error {
|
|
|
|
+ if name == "" || linkType == "" {
|
|
|
|
+ return fmt.Errorf("Neither link name nor link type can be empty!")
|
|
}
|
|
}
|
|
|
|
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
@@ -387,101 +406,58 @@ func AddRoute(destination, source, gateway, device string) error {
|
|
}
|
|
}
|
|
defer s.Close()
|
|
defer s.Close()
|
|
|
|
|
|
- wb := newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
|
|
- msg := newRtMsg()
|
|
|
|
- currentFamily := -1
|
|
|
|
- var rtAttrs []*RtAttr
|
|
|
|
|
|
+ wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
|
|
|
|
- if destination != "" {
|
|
|
|
- destIP, destNet, err := net.ParseCIDR(destination)
|
|
|
|
- if err != nil {
|
|
|
|
- return fmt.Errorf("destination CIDR %s couldn't be parsed", destination)
|
|
|
|
- }
|
|
|
|
- destFamily := getIpFamily(destIP)
|
|
|
|
- currentFamily = destFamily
|
|
|
|
- destLen, bits := destNet.Mask.Size()
|
|
|
|
- if destLen == 0 && bits == 0 {
|
|
|
|
- return fmt.Errorf("destination CIDR %s generated a non-canonical Mask", destination)
|
|
|
|
- }
|
|
|
|
- msg.Family = uint8(destFamily)
|
|
|
|
- msg.Dst_len = uint8(destLen)
|
|
|
|
- var destData []byte
|
|
|
|
- if destFamily == syscall.AF_INET {
|
|
|
|
- destData = destIP.To4()
|
|
|
|
- } else {
|
|
|
|
- destData = destIP.To16()
|
|
|
|
- }
|
|
|
|
- rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_DST, destData))
|
|
|
|
- }
|
|
|
|
|
|
+ msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
|
|
+ wb.AddData(msg)
|
|
|
|
|
|
- if source != "" {
|
|
|
|
- srcIP, srcNet, err := net.ParseCIDR(source)
|
|
|
|
- if err != nil {
|
|
|
|
- return fmt.Errorf("source CIDR %s couldn't be parsed", source)
|
|
|
|
- }
|
|
|
|
- srcFamily := getIpFamily(srcIP)
|
|
|
|
- if currentFamily != -1 && currentFamily != srcFamily {
|
|
|
|
- return fmt.Errorf("source and destination ip were not the same IP family")
|
|
|
|
- }
|
|
|
|
- currentFamily = srcFamily
|
|
|
|
- srcLen, bits := srcNet.Mask.Size()
|
|
|
|
- if srcLen == 0 && bits == 0 {
|
|
|
|
- return fmt.Errorf("source CIDR %s generated a non-canonical Mask", source)
|
|
|
|
- }
|
|
|
|
- msg.Family = uint8(srcFamily)
|
|
|
|
- msg.Src_len = uint8(srcLen)
|
|
|
|
- var srcData []byte
|
|
|
|
- if srcFamily == syscall.AF_INET {
|
|
|
|
- srcData = srcIP.To4()
|
|
|
|
- } else {
|
|
|
|
- srcData = srcIP.To16()
|
|
|
|
- }
|
|
|
|
- rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_SRC, srcData))
|
|
|
|
|
|
+ linkInfo := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
|
|
|
+ newRtAttrChild(linkInfo, IFLA_INFO_KIND, nonZeroTerminated(linkType))
|
|
|
|
+ wb.AddData(linkInfo)
|
|
|
|
+
|
|
|
|
+ nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name))
|
|
|
|
+ wb.AddData(nameData)
|
|
|
|
+
|
|
|
|
+ if err := s.Send(wb); err != nil {
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
|
|
- if gateway != "" {
|
|
|
|
- gwIP := net.ParseIP(gateway)
|
|
|
|
- if gwIP == nil {
|
|
|
|
- return fmt.Errorf("gateway IP %s couldn't be parsed", gateway)
|
|
|
|
- }
|
|
|
|
- gwFamily := getIpFamily(gwIP)
|
|
|
|
- if currentFamily != -1 && currentFamily != gwFamily {
|
|
|
|
- return fmt.Errorf("gateway, source, and destination ip were not the same IP family")
|
|
|
|
- }
|
|
|
|
- msg.Family = uint8(gwFamily)
|
|
|
|
- var gwData []byte
|
|
|
|
- if gwFamily == syscall.AF_INET {
|
|
|
|
- gwData = gwIP.To4()
|
|
|
|
- } else {
|
|
|
|
- gwData = gwIP.To16()
|
|
|
|
- }
|
|
|
|
- rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_GATEWAY, gwData))
|
|
|
|
|
|
+ return s.HandleAck(wb.Seq)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Delete a network link.
|
|
|
|
+// This is identical to running: ip link del $name
|
|
|
|
+func NetworkLinkDel(name string) error {
|
|
|
|
+ if name == "" {
|
|
|
|
+ return fmt.Errorf("Network link name can not be empty!")
|
|
}
|
|
}
|
|
|
|
|
|
- wb.AddData(msg)
|
|
|
|
- for _, attr := range rtAttrs {
|
|
|
|
- wb.AddData(attr)
|
|
|
|
|
|
+ s, err := getNetlinkSocket()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
+ defer s.Close()
|
|
|
|
|
|
- iface, err := net.InterfaceByName(device)
|
|
|
|
|
|
+ iface, err := net.InterfaceByName(name)
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
- wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
|
|
|
|
|
|
+
|
|
|
|
+ wb := newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
|
|
|
|
+
|
|
|
|
+ msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
|
|
+ msg.Index = int32(iface.Index)
|
|
|
|
+ wb.AddData(msg)
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
- return s.HandleAck(wb.Seq)
|
|
|
|
-}
|
|
|
|
|
|
|
|
-// Add a new default gateway. Identical to:
|
|
|
|
-// ip route add default via $ip
|
|
|
|
-func AddDefaultGw(ip, device string) error {
|
|
|
|
- return AddRoute("", "", ip, device)
|
|
|
|
|
|
+ return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
-// Bring up a particular network interface
|
|
|
|
|
|
+// Bring up a particular network interface.
|
|
|
|
+// This is identical to running: ip link set dev $name up
|
|
func NetworkLinkUp(iface *net.Interface) error {
|
|
func NetworkLinkUp(iface *net.Interface) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -492,9 +468,9 @@ func NetworkLinkUp(iface *net.Interface) error {
|
|
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
|
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
- msg.Change = syscall.IFF_UP
|
|
|
|
- msg.Flags = syscall.IFF_UP
|
|
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
|
|
+ msg.Flags = syscall.IFF_UP
|
|
|
|
+ msg.Change = syscall.IFF_UP
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
@@ -504,6 +480,8 @@ func NetworkLinkUp(iface *net.Interface) error {
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Bring down a particular network interface.
|
|
|
|
+// This is identical to running: ip link set $name down
|
|
func NetworkLinkDown(iface *net.Interface) error {
|
|
func NetworkLinkDown(iface *net.Interface) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -514,9 +492,9 @@ func NetworkLinkDown(iface *net.Interface) error {
|
|
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
|
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
- msg.Change = syscall.IFF_UP
|
|
|
|
- msg.Flags = 0 & ^syscall.IFF_UP
|
|
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
|
|
+ msg.Flags = 0 & ^syscall.IFF_UP
|
|
|
|
+ msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
@@ -526,22 +504,40 @@ func NetworkLinkDown(iface *net.Interface) error {
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
-func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
|
|
|
|
|
+// Set link layer address ie. MAC Address.
|
|
|
|
+// This is identical to running: ip link set dev $name address $macaddress
|
|
|
|
+func NetworkSetMacAddress(iface *net.Interface, macaddr string) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
defer s.Close()
|
|
defer s.Close()
|
|
|
|
|
|
|
|
+ hwaddr, err := net.ParseMAC(macaddr)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var (
|
|
|
|
+ MULTICAST byte = 0x1
|
|
|
|
+ LOCALOUI byte = 0x2
|
|
|
|
+ )
|
|
|
|
+
|
|
|
|
+ if hwaddr[0]&0x1 == MULTICAST || hwaddr[0]&0x2 != LOCALOUI {
|
|
|
|
+ return fmt.Errorf("Incorrect Local MAC Address specified: %s", macaddr)
|
|
|
|
+ }
|
|
|
|
+
|
|
wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
- wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu)))
|
|
|
|
|
|
+
|
|
|
|
+ macdata := make([]byte, 6)
|
|
|
|
+ copy(macdata, hwaddr)
|
|
|
|
+ data := newRtAttr(IFLA_ADDRESS, macdata)
|
|
|
|
+ wb.AddData(data)
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -549,8 +545,13 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
-// same as ip link set $name master $master
|
|
|
|
-func NetworkSetMaster(iface, master *net.Interface) error {
|
|
|
|
|
|
+// Set link Maximum Transmission Unit
|
|
|
|
+// This is identical to running: ip link set dev $name mtu $MTU
|
|
|
|
+// bridge is a bitch here https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=292088
|
|
|
|
+// https://bugzilla.redhat.com/show_bug.cgi?id=697021
|
|
|
|
+// There is a discussion about how to deal with ifcs joining bridge with MTU > 1500
|
|
|
|
+// Regular network nterfaces do seem to work though!
|
|
|
|
+func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
@@ -565,16 +566,15 @@ func NetworkSetMaster(iface, master *net.Interface) error {
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
- wb.AddData(uint32Attr(syscall.IFLA_MASTER, uint32(master.Index)))
|
|
|
|
|
|
+ wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
-
|
|
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
-func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
|
|
|
|
|
+func networkMasterAction(iface *net.Interface, rtattr *RtAttr) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
@@ -589,7 +589,41 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
- wb.AddData(uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid)))
|
|
|
|
|
|
+ wb.AddData(rtattr)
|
|
|
|
+
|
|
|
|
+ if err := s.Send(wb); err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return s.HandleAck(wb.Seq)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Add an interface to bridge.
|
|
|
|
+// This is identical to running: ip link set $name master $master
|
|
|
|
+func NetworkSetMaster(iface, master *net.Interface) error {
|
|
|
|
+ data := uint32Attr(syscall.IFLA_MASTER, uint32(master.Index))
|
|
|
|
+ return networkMasterAction(iface, data)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Remove an interface from the bridge
|
|
|
|
+// This is is identical to to running: ip link $name set nomaster
|
|
|
|
+func NetworkSetNoMaster(iface *net.Interface) error {
|
|
|
|
+ data := uint32Attr(syscall.IFLA_MASTER, 0)
|
|
|
|
+ return networkMasterAction(iface, data)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func networkSetNsAction(iface *net.Interface, rtattr *RtAttr) error {
|
|
|
|
+ s, err := getNetlinkSocket()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ defer s.Close()
|
|
|
|
+
|
|
|
|
+ wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
|
|
|
|
+ msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
|
|
+ msg.Index = int32(iface.Index)
|
|
|
|
+ wb.AddData(msg)
|
|
|
|
+ wb.AddData(rtattr)
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -598,7 +632,29 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Move a particular network interface to a particular network namespace
|
|
|
|
+// specified by PID. This is idential to running: ip link set dev $name netns $pid
|
|
|
|
+func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
|
|
|
+ data := uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid))
|
|
|
|
+ return networkSetNsAction(iface, data)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Move a particular network interface to a particular mounted
|
|
|
|
+// network namespace specified by file descriptor.
|
|
|
|
+// This is idential to running: ip link set dev $name netns $fd
|
|
func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
|
func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
|
|
|
+ data := uint32Attr(IFLA_NET_NS_FD, uint32(fd))
|
|
|
|
+ return networkSetNsAction(iface, data)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Rname a particular interface to a different name
|
|
|
|
+// !!! Note that you can't rename an active interface. You need to bring it down before renaming it.
|
|
|
|
+// This is identical to running: ip link set dev ${oldName} name ${newName}
|
|
|
|
+func NetworkChangeName(iface *net.Interface, newName string) error {
|
|
|
|
+ if len(newName) >= IFNAMSIZ {
|
|
|
|
+ return fmt.Errorf("Interface name %s too long", newName)
|
|
|
|
+ }
|
|
|
|
+
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
@@ -608,12 +664,12 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
|
wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
- msg.Type = syscall.RTM_SETLINK
|
|
|
|
- msg.Flags = syscall.NLM_F_REQUEST
|
|
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
- wb.AddData(uint32Attr(IFLA_NET_NS_FD, uint32(fd)))
|
|
|
|
|
|
+
|
|
|
|
+ nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(newName))
|
|
|
|
+ wb.AddData(nameData)
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -622,127 +678,152 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
-func networkLinkIpAction(action, flags int, ifa IfAddr) error {
|
|
|
|
|
|
+// Add a new VETH pair link on the host
|
|
|
|
+// This is identical to running: ip link add name $name type veth peer name $peername
|
|
|
|
+func NetworkCreateVethPair(name1, name2 string) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
defer s.Close()
|
|
defer s.Close()
|
|
|
|
|
|
- family := getIpFamily(ifa.IP)
|
|
|
|
-
|
|
|
|
- wb := newNetlinkRequest(action, flags)
|
|
|
|
|
|
+ wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
|
|
|
|
- msg := newIfAddrmsg(family)
|
|
|
|
- msg.Index = uint32(ifa.Iface.Index)
|
|
|
|
- prefixLen, _ := ifa.IPNet.Mask.Size()
|
|
|
|
- msg.Prefixlen = uint8(prefixLen)
|
|
|
|
|
|
+ msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
|
|
|
|
- var ipData []byte
|
|
|
|
- if family == syscall.AF_INET {
|
|
|
|
- ipData = ifa.IP.To4()
|
|
|
|
- } else {
|
|
|
|
- ipData = ifa.IP.To16()
|
|
|
|
- }
|
|
|
|
|
|
+ nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1))
|
|
|
|
+ wb.AddData(nameData)
|
|
|
|
|
|
- localData := newRtAttr(syscall.IFA_LOCAL, ipData)
|
|
|
|
- wb.AddData(localData)
|
|
|
|
|
|
+ nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
|
|
|
+ newRtAttrChild(nest1, IFLA_INFO_KIND, zeroTerminated("veth"))
|
|
|
|
+ nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
|
|
|
+ nest3 := newRtAttrChild(nest2, VETH_INFO_PEER, nil)
|
|
|
|
|
|
- addrData := newRtAttr(syscall.IFA_ADDRESS, ipData)
|
|
|
|
- wb.AddData(addrData)
|
|
|
|
|
|
+ newIfInfomsgChild(nest3, syscall.AF_UNSPEC)
|
|
|
|
+ newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2))
|
|
|
|
+
|
|
|
|
+ wb.AddData(nest1)
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
-
|
|
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
-// Delete an IP address from an interface. This is identical to:
|
|
|
|
-// ip addr del $ip/$ipNet dev $iface
|
|
|
|
-func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
|
|
- return networkLinkIpAction(
|
|
|
|
- syscall.RTM_DELADDR,
|
|
|
|
- syscall.NLM_F_ACK,
|
|
|
|
- IfAddr{iface, ip, ipNet},
|
|
|
|
- )
|
|
|
|
-}
|
|
|
|
|
|
+// Add a new VLAN interface with masterDev as its upper device
|
|
|
|
+// This is identical to running:
|
|
|
|
+// ip link add name $name link $masterdev type vlan id $id
|
|
|
|
+func NetworkLinkAddVlan(masterDev, vlanDev string, vlanId uint16) error {
|
|
|
|
+ s, err := getNetlinkSocket()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ defer s.Close()
|
|
|
|
|
|
-// Add an Ip address to an interface. This is identical to:
|
|
|
|
-// ip addr add $ip/$ipNet dev $iface
|
|
|
|
-func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
|
|
- return networkLinkIpAction(
|
|
|
|
- syscall.RTM_NEWADDR,
|
|
|
|
- syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK,
|
|
|
|
- IfAddr{iface, ip, ipNet},
|
|
|
|
- )
|
|
|
|
-}
|
|
|
|
|
|
+ wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
|
|
|
|
-func zeroTerminated(s string) []byte {
|
|
|
|
- return []byte(s + "\000")
|
|
|
|
-}
|
|
|
|
|
|
+ masterDevIfc, err := net.InterfaceByName(masterDev)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
|
|
-func nonZeroTerminated(s string) []byte {
|
|
|
|
- return []byte(s)
|
|
|
|
-}
|
|
|
|
|
|
+ msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
|
|
+ wb.AddData(msg)
|
|
|
|
|
|
-// Add a new network link of a specified type. This is identical to
|
|
|
|
-// running: ip add link $name type $linkType
|
|
|
|
-func NetworkLinkAdd(name string, linkType string) error {
|
|
|
|
- if name == "" || linkType == "" {
|
|
|
|
- return fmt.Errorf("Neither link name nor link type can be empty!")
|
|
|
|
|
|
+ nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
|
|
|
+ newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("vlan"))
|
|
|
|
+
|
|
|
|
+ nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
|
|
|
+ vlanData := make([]byte, 2)
|
|
|
|
+ native.PutUint16(vlanData, vlanId)
|
|
|
|
+ newRtAttrChild(nest2, IFLA_VLAN_ID, vlanData)
|
|
|
|
+ wb.AddData(nest1)
|
|
|
|
+
|
|
|
|
+ wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
|
|
|
|
+ wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(vlanDev)))
|
|
|
|
+
|
|
|
|
+ if err := s.Send(wb); err != nil {
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
+ return s.HandleAck(wb.Seq)
|
|
|
|
+}
|
|
|
|
|
|
|
|
+// Add MAC VLAN network interface with masterDev as its upper device
|
|
|
|
+// This is identical to running:
|
|
|
|
+// ip link add name $name link $masterdev type macvlan mode $mode
|
|
|
|
+func NetworkLinkAddMacVlan(masterDev, macVlanDev string, mode string) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
defer s.Close()
|
|
defer s.Close()
|
|
|
|
|
|
|
|
+ macVlan := map[string]uint32{
|
|
|
|
+ "private": MACVLAN_MODE_PRIVATE,
|
|
|
|
+ "vepa": MACVLAN_MODE_VEPA,
|
|
|
|
+ "bridge": MACVLAN_MODE_BRIDGE,
|
|
|
|
+ "passthru": MACVLAN_MODE_PASSTHRU,
|
|
|
|
+ }
|
|
|
|
+
|
|
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
|
|
|
|
|
|
+ masterDevIfc, err := net.InterfaceByName(masterDev)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
|
|
|
|
- linkInfo := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
|
|
|
- newRtAttrChild(linkInfo, IFLA_INFO_KIND, nonZeroTerminated(linkType))
|
|
|
|
- wb.AddData(linkInfo)
|
|
|
|
|
|
+ nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
|
|
|
+ newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("macvlan"))
|
|
|
|
|
|
- nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name))
|
|
|
|
- wb.AddData(nameData)
|
|
|
|
|
|
+ nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
|
|
|
+ macVlanData := make([]byte, 4)
|
|
|
|
+ native.PutUint32(macVlanData, macVlan[mode])
|
|
|
|
+ newRtAttrChild(nest2, IFLA_MACVLAN_MODE, macVlanData)
|
|
|
|
+ wb.AddData(nest1)
|
|
|
|
+
|
|
|
|
+ wb.AddData(uint32Attr(syscall.IFLA_LINK, uint32(masterDevIfc.Index)))
|
|
|
|
+ wb.AddData(newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(macVlanDev)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
-
|
|
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
-// Delete a network link. This is identical to
|
|
|
|
-// running: ip link del $name
|
|
|
|
-func NetworkLinkDel(name string) error {
|
|
|
|
- if name == "" {
|
|
|
|
- return fmt.Errorf("Network link name can not be empty!")
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+func networkLinkIpAction(action, flags int, ifa IfAddr) error {
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
defer s.Close()
|
|
defer s.Close()
|
|
|
|
|
|
- iface, err := net.InterfaceByName(name)
|
|
|
|
- if err != nil {
|
|
|
|
- return err
|
|
|
|
- }
|
|
|
|
|
|
+ family := getIpFamily(ifa.IP)
|
|
|
|
|
|
- wb := newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
|
|
|
|
|
|
+ wb := newNetlinkRequest(action, flags)
|
|
|
|
|
|
- msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
|
|
- msg.Index = int32(iface.Index)
|
|
|
|
|
|
+ msg := newIfAddrmsg(family)
|
|
|
|
+ msg.Index = uint32(ifa.Iface.Index)
|
|
|
|
+ prefixLen, _ := ifa.IPNet.Mask.Size()
|
|
|
|
+ msg.Prefixlen = uint8(prefixLen)
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
|
|
|
|
|
|
+ var ipData []byte
|
|
|
|
+ if family == syscall.AF_INET {
|
|
|
|
+ ipData = ifa.IP.To4()
|
|
|
|
+ } else {
|
|
|
|
+ ipData = ifa.IP.To16()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ localData := newRtAttr(syscall.IFA_LOCAL, ipData)
|
|
|
|
+ wb.AddData(localData)
|
|
|
|
+
|
|
|
|
+ addrData := newRtAttr(syscall.IFA_ADDRESS, ipData)
|
|
|
|
+ wb.AddData(addrData)
|
|
|
|
+
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
@@ -750,6 +831,26 @@ func NetworkLinkDel(name string) error {
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Delete an IP address from an interface. This is identical to:
|
|
|
|
+// ip addr del $ip/$ipNet dev $iface
|
|
|
|
+func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
|
|
+ return networkLinkIpAction(
|
|
|
|
+ syscall.RTM_DELADDR,
|
|
|
|
+ syscall.NLM_F_ACK,
|
|
|
|
+ IfAddr{iface, ip, ipNet},
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// Add an Ip address to an interface. This is identical to:
|
|
|
|
+// ip addr add $ip/$ipNet dev $iface
|
|
|
|
+func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
|
|
+ return networkLinkIpAction(
|
|
|
|
+ syscall.RTM_NEWADDR,
|
|
|
|
+ syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK,
|
|
|
|
+ IfAddr{iface, ip, ipNet},
|
|
|
|
+ )
|
|
|
|
+}
|
|
|
|
+
|
|
// Returns an array of IPNet for all the currently routed subnets on ipv4
|
|
// Returns an array of IPNet for all the currently routed subnets on ipv4
|
|
// This is similar to the first column of "ip route" output
|
|
// This is similar to the first column of "ip route" output
|
|
func NetworkGetRoutes() ([]Route, error) {
|
|
func NetworkGetRoutes() ([]Route, error) {
|
|
@@ -842,69 +943,99 @@ outer:
|
|
return res, nil
|
|
return res, nil
|
|
}
|
|
}
|
|
|
|
|
|
-func getIfSocket() (fd int, err error) {
|
|
|
|
- for _, socket := range []int{
|
|
|
|
- syscall.AF_INET,
|
|
|
|
- syscall.AF_PACKET,
|
|
|
|
- syscall.AF_INET6,
|
|
|
|
- } {
|
|
|
|
- if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if err == nil {
|
|
|
|
- return fd, nil
|
|
|
|
- }
|
|
|
|
- return -1, err
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func NetworkChangeName(iface *net.Interface, newName string) error {
|
|
|
|
- if len(newName) >= IFNAMSIZ {
|
|
|
|
- return fmt.Errorf("Interface name %s too long", newName)
|
|
|
|
|
|
+// Add a new route table entry.
|
|
|
|
+func AddRoute(destination, source, gateway, device string) error {
|
|
|
|
+ if destination == "" && source == "" && gateway == "" {
|
|
|
|
+ return fmt.Errorf("one of destination, source or gateway must not be blank")
|
|
}
|
|
}
|
|
|
|
|
|
- fd, err := getIfSocket()
|
|
|
|
|
|
+ s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
- defer syscall.Close(fd)
|
|
|
|
|
|
+ defer s.Close()
|
|
|
|
|
|
- data := [IFNAMSIZ * 2]byte{}
|
|
|
|
- // the "-1"s here are very important for ensuring we get proper null
|
|
|
|
- // termination of our new C strings
|
|
|
|
- copy(data[:IFNAMSIZ-1], iface.Name)
|
|
|
|
- copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName)
|
|
|
|
|
|
+ wb := newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
|
|
+ msg := newRtMsg()
|
|
|
|
+ currentFamily := -1
|
|
|
|
+ var rtAttrs []*RtAttr
|
|
|
|
|
|
- if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
|
|
|
|
- return errno
|
|
|
|
|
|
+ if destination != "" {
|
|
|
|
+ destIP, destNet, err := net.ParseCIDR(destination)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("destination CIDR %s couldn't be parsed", destination)
|
|
|
|
+ }
|
|
|
|
+ destFamily := getIpFamily(destIP)
|
|
|
|
+ currentFamily = destFamily
|
|
|
|
+ destLen, bits := destNet.Mask.Size()
|
|
|
|
+ if destLen == 0 && bits == 0 {
|
|
|
|
+ return fmt.Errorf("destination CIDR %s generated a non-canonical Mask", destination)
|
|
|
|
+ }
|
|
|
|
+ msg.Family = uint8(destFamily)
|
|
|
|
+ msg.Dst_len = uint8(destLen)
|
|
|
|
+ var destData []byte
|
|
|
|
+ if destFamily == syscall.AF_INET {
|
|
|
|
+ destData = destIP.To4()
|
|
|
|
+ } else {
|
|
|
|
+ destData = destIP.To16()
|
|
|
|
+ }
|
|
|
|
+ rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_DST, destData))
|
|
}
|
|
}
|
|
- return nil
|
|
|
|
-}
|
|
|
|
|
|
|
|
-func NetworkCreateVethPair(name1, name2 string) error {
|
|
|
|
- s, err := getNetlinkSocket()
|
|
|
|
- if err != nil {
|
|
|
|
- return err
|
|
|
|
|
|
+ if source != "" {
|
|
|
|
+ srcIP, srcNet, err := net.ParseCIDR(source)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return fmt.Errorf("source CIDR %s couldn't be parsed", source)
|
|
|
|
+ }
|
|
|
|
+ srcFamily := getIpFamily(srcIP)
|
|
|
|
+ if currentFamily != -1 && currentFamily != srcFamily {
|
|
|
|
+ return fmt.Errorf("source and destination ip were not the same IP family")
|
|
|
|
+ }
|
|
|
|
+ currentFamily = srcFamily
|
|
|
|
+ srcLen, bits := srcNet.Mask.Size()
|
|
|
|
+ if srcLen == 0 && bits == 0 {
|
|
|
|
+ return fmt.Errorf("source CIDR %s generated a non-canonical Mask", source)
|
|
|
|
+ }
|
|
|
|
+ msg.Family = uint8(srcFamily)
|
|
|
|
+ msg.Src_len = uint8(srcLen)
|
|
|
|
+ var srcData []byte
|
|
|
|
+ if srcFamily == syscall.AF_INET {
|
|
|
|
+ srcData = srcIP.To4()
|
|
|
|
+ } else {
|
|
|
|
+ srcData = srcIP.To16()
|
|
|
|
+ }
|
|
|
|
+ rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_SRC, srcData))
|
|
}
|
|
}
|
|
- defer s.Close()
|
|
|
|
|
|
|
|
- wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
|
|
|
|
|
+ if gateway != "" {
|
|
|
|
+ gwIP := net.ParseIP(gateway)
|
|
|
|
+ if gwIP == nil {
|
|
|
|
+ return fmt.Errorf("gateway IP %s couldn't be parsed", gateway)
|
|
|
|
+ }
|
|
|
|
+ gwFamily := getIpFamily(gwIP)
|
|
|
|
+ if currentFamily != -1 && currentFamily != gwFamily {
|
|
|
|
+ return fmt.Errorf("gateway, source, and destination ip were not the same IP family")
|
|
|
|
+ }
|
|
|
|
+ msg.Family = uint8(gwFamily)
|
|
|
|
+ var gwData []byte
|
|
|
|
+ if gwFamily == syscall.AF_INET {
|
|
|
|
+ gwData = gwIP.To4()
|
|
|
|
+ } else {
|
|
|
|
+ gwData = gwIP.To16()
|
|
|
|
+ }
|
|
|
|
+ rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_GATEWAY, gwData))
|
|
|
|
+ }
|
|
|
|
|
|
- msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
|
|
+ for _, attr := range rtAttrs {
|
|
|
|
+ wb.AddData(attr)
|
|
|
|
+ }
|
|
|
|
|
|
- nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name1))
|
|
|
|
- wb.AddData(nameData)
|
|
|
|
-
|
|
|
|
- nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil)
|
|
|
|
- newRtAttrChild(nest1, IFLA_INFO_KIND, zeroTerminated("veth"))
|
|
|
|
- nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
|
|
|
|
- nest3 := newRtAttrChild(nest2, VETH_INFO_PEER, nil)
|
|
|
|
-
|
|
|
|
- newIfInfomsgChild(nest3, syscall.AF_UNSPEC)
|
|
|
|
- newRtAttrChild(nest3, syscall.IFLA_IFNAME, zeroTerminated(name2))
|
|
|
|
-
|
|
|
|
- wb.AddData(nest1)
|
|
|
|
|
|
+ iface, err := net.InterfaceByName(device)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -912,6 +1043,31 @@ func NetworkCreateVethPair(name1, name2 string) error {
|
|
return s.HandleAck(wb.Seq)
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Add a new default gateway. Identical to:
|
|
|
|
+// ip route add default via $ip
|
|
|
|
+func AddDefaultGw(ip, device string) error {
|
|
|
|
+ return AddRoute("", "", ip, device)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
|
|
|
|
+// IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
|
|
|
|
+// WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
|
|
|
|
+func getIfSocket() (fd int, err error) {
|
|
|
|
+ for _, socket := range []int{
|
|
|
|
+ syscall.AF_INET,
|
|
|
|
+ syscall.AF_PACKET,
|
|
|
|
+ syscall.AF_INET6,
|
|
|
|
+ } {
|
|
|
|
+ if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if err == nil {
|
|
|
|
+ return fd, nil
|
|
|
|
+ }
|
|
|
|
+ return -1, err
|
|
|
|
+}
|
|
|
|
+
|
|
// Create the actual bridge device. This is more backward-compatible than
|
|
// Create the actual bridge device. This is more backward-compatible than
|
|
// netlink.NetworkLinkAdd and works on RHEL 6.
|
|
// netlink.NetworkLinkAdd and works on RHEL 6.
|
|
func CreateBridge(name string, setMacAddr bool) error {
|
|
func CreateBridge(name string, setMacAddr bool) error {
|
|
@@ -933,7 +1089,7 @@ func CreateBridge(name string, setMacAddr bool) error {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
if setMacAddr {
|
|
if setMacAddr {
|
|
- return NetworkSetMacAddress(name, randMacAddr())
|
|
|
|
|
|
+ return SetMacAddress(name, randMacAddr())
|
|
}
|
|
}
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
@@ -999,7 +1155,7 @@ func randMacAddr() string {
|
|
return hw.String()
|
|
return hw.String()
|
|
}
|
|
}
|
|
|
|
|
|
-func NetworkSetMacAddress(name, addr string) error {
|
|
|
|
|
|
+func SetMacAddress(name, addr string) error {
|
|
if len(name) >= IFNAMSIZ {
|
|
if len(name) >= IFNAMSIZ {
|
|
return fmt.Errorf("Interface name %s too long", name)
|
|
return fmt.Errorf("Interface name %s too long", name)
|
|
}
|
|
}
|
|
@@ -1028,3 +1184,26 @@ func NetworkSetMacAddress(name, addr string) error {
|
|
}
|
|
}
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+func ChangeName(iface *net.Interface, newName string) error {
|
|
|
|
+ if len(newName) >= IFNAMSIZ {
|
|
|
|
+ return fmt.Errorf("Interface name %s too long", newName)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fd, err := getIfSocket()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ defer syscall.Close(fd)
|
|
|
|
+
|
|
|
|
+ data := [IFNAMSIZ * 2]byte{}
|
|
|
|
+ // the "-1"s here are very important for ensuring we get proper null
|
|
|
|
+ // termination of our new C strings
|
|
|
|
+ copy(data[:IFNAMSIZ-1], iface.Name)
|
|
|
|
+ copy(data[IFNAMSIZ:IFNAMSIZ*2-1], newName)
|
|
|
|
+
|
|
|
|
+ if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
|
|
|
|
+ return errno
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+}
|