mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
140 lines
3 KiB
Go
140 lines
3 KiB
Go
|
package bridge
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math/rand"
|
||
|
"net"
|
||
|
"syscall"
|
||
|
"time"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
ifNameSize = 16
|
||
|
ioctlBrAdd = 0x89a0
|
||
|
ioctlBrAddIf = 0x89a2
|
||
|
)
|
||
|
|
||
|
type ifreqIndex struct {
|
||
|
IfrnName [ifNameSize]byte
|
||
|
IfruIndex int32
|
||
|
}
|
||
|
|
||
|
type ifreqHwaddr struct {
|
||
|
IfrnName [ifNameSize]byte
|
||
|
IfruHwaddr syscall.RawSockaddr
|
||
|
}
|
||
|
|
||
|
var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
|
||
|
func ifIoctBridge(iface, master *net.Interface, op uintptr) error {
|
||
|
if len(master.Name) >= ifNameSize {
|
||
|
return fmt.Errorf("Interface name %s too long", master.Name)
|
||
|
}
|
||
|
|
||
|
s, err := getIfSocket()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer syscall.Close(s)
|
||
|
|
||
|
ifr := ifreqIndex{}
|
||
|
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], master.Name)
|
||
|
ifr.IfruIndex = int32(iface.Index)
|
||
|
|
||
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), op, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Add a slave to a bridge device. This is more backward-compatible than
|
||
|
// netlink.NetworkSetMaster and works on RHEL 6.
|
||
|
func ioctlAddToBridge(iface, master *net.Interface) error {
|
||
|
return ifIoctBridge(iface, master, ioctlBrAddIf)
|
||
|
}
|
||
|
|
||
|
func randMacAddr() string {
|
||
|
hw := make(net.HardwareAddr, 6)
|
||
|
for i := 0; i < 6; i++ {
|
||
|
hw[i] = byte(rnd.Intn(255))
|
||
|
}
|
||
|
hw[0] &^= 0x1 // clear multicast bit
|
||
|
hw[0] |= 0x2 // set local assignment bit (IEEE802)
|
||
|
return hw.String()
|
||
|
}
|
||
|
|
||
|
func ioctlSetMacAddress(name, addr string) error {
|
||
|
if len(name) >= ifNameSize {
|
||
|
return fmt.Errorf("Interface name %s too long", name)
|
||
|
}
|
||
|
|
||
|
hw, err := net.ParseMAC(addr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
s, err := getIfSocket()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer syscall.Close(s)
|
||
|
|
||
|
ifr := ifreqHwaddr{}
|
||
|
ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
|
||
|
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
|
||
|
|
||
|
for i := 0; i < 6; i++ {
|
||
|
ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i])
|
||
|
}
|
||
|
|
||
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func ioctlCreateBridge(name string, setMacAddr bool) error {
|
||
|
if len(name) >= ifNameSize {
|
||
|
return fmt.Errorf("Interface name %s too long", name)
|
||
|
}
|
||
|
|
||
|
s, err := getIfSocket()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer syscall.Close(s)
|
||
|
|
||
|
nameBytePtr, err := syscall.BytePtrFromString(name)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), ioctlBrAdd, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
|
||
|
return err
|
||
|
}
|
||
|
if setMacAddr {
|
||
|
return ioctlSetMacAddress(name, randMacAddr())
|
||
|
}
|
||
|
return nil
|
||
|
}
|