forked from moby/libnetwork
/
netlink_deprecated_linux.go
131 lines (109 loc) · 2.8 KB
/
netlink_deprecated_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package bridge
import (
"fmt"
"math/rand"
"net"
"syscall"
"time"
"unsafe"
"github.com/docker/libnetwork/netutils"
)
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 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, netutils.GenerateRandomMAC().String())
}
return nil
}