mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Update libcontainer to 185328a42654f6dc9a41814e578
Mac address support to the netlink pkg. Cgroup performance and memory issues. Netlink refactoring. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
41f2b3c6bc
commit
2531fba389
11 changed files with 267 additions and 148 deletions
|
@ -62,7 +62,7 @@ if [ "$1" = '--go' ]; then
|
|||
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
|
||||
fi
|
||||
|
||||
clone git github.com/docker/libcontainer 84ad9386a0240acb7475429a835d826007032bf9
|
||||
clone git github.com/docker/libcontainer 185328a42654f6dc9a41814e57882f69d65f6ab7
|
||||
# see src/github.com/docker/libcontainer/update-vendor.sh which is the "source of truth" for libcontainer deps (just like this file)
|
||||
rm -rf src/github.com/docker/libcontainer/vendor
|
||||
eval "$(grep '^clone ' src/github.com/docker/libcontainer/update-vendor.sh | grep -v 'github.com/codegangsta/cli')"
|
||||
|
|
|
@ -24,6 +24,23 @@ var (
|
|||
CgroupProcesses = "cgroup.procs"
|
||||
)
|
||||
|
||||
// The absolute path to the root of the cgroup hierarchies.
|
||||
var cgroupRoot string
|
||||
|
||||
// TODO(vmarmol): Report error here, we'll probably need to wait for the new API.
|
||||
func init() {
|
||||
// we can pick any subsystem to find the root
|
||||
cpuRoot, err := cgroups.FindCgroupMountpoint("cpu")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cgroupRoot = filepath.Dir(cpuRoot)
|
||||
|
||||
if _, err := os.Stat(cgroupRoot); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type subsystem interface {
|
||||
// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
|
||||
GetStats(path string, stats *cgroups.Stats) error
|
||||
|
@ -121,15 +138,8 @@ func GetPids(c *cgroups.Cgroup) ([]int, error) {
|
|||
}
|
||||
|
||||
func getCgroupData(c *cgroups.Cgroup, pid int) (*data, error) {
|
||||
// we can pick any subsystem to find the root
|
||||
cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cgroupRoot = filepath.Dir(cgroupRoot)
|
||||
|
||||
if _, err := os.Stat(cgroupRoot); err != nil {
|
||||
return nil, fmt.Errorf("cgroups fs not found")
|
||||
if cgroupRoot == "" {
|
||||
return nil, fmt.Errorf("failed to find the cgroup root")
|
||||
}
|
||||
|
||||
cgroup := c.Name
|
||||
|
|
|
@ -14,58 +14,65 @@ type Container interface {
|
|||
|
||||
// Returns the current run state of the container.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
RunState() (*RunState, error)
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
RunState() (*RunState, Error)
|
||||
|
||||
// Returns the current config of the container.
|
||||
Config() *Config
|
||||
|
||||
// Start a process inside the container. Returns the PID of the new process (in the caller process's namespace) and a channel that will return the exit status of the process whenever it dies.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// config is invalid,
|
||||
// container is paused,
|
||||
// system error.
|
||||
Start(*ProcessConfig) (pid int, exitChan chan int, err error)
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// ConfigInvalid - config is invalid,
|
||||
// ContainerPaused - Container is paused,
|
||||
// SystemError - System error.
|
||||
Start(config *ProcessConfig) (pid int, exitChan chan int, err Error)
|
||||
|
||||
// Destroys the container after killing all running processes.
|
||||
//
|
||||
// Any event registrations are removed before the container is destroyed.
|
||||
// No error is returned if the container is already destroyed.
|
||||
//
|
||||
// Errors: system error.
|
||||
Destroy() error
|
||||
// Errors:
|
||||
// SystemError - System error.
|
||||
Destroy() Error
|
||||
|
||||
// Returns the PIDs inside this container. The PIDs are in the namespace of the calling process.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
//
|
||||
// Some of the returned PIDs may no longer refer to processes in the Container, unless
|
||||
// the Container state is PAUSED in which case every PID in the slice is valid.
|
||||
Processes() ([]int, error)
|
||||
Processes() ([]int, Error)
|
||||
|
||||
// Returns statistics for the container.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
Stats() (*ContainerStats, error)
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
Stats() (*ContainerStats, Error)
|
||||
|
||||
// If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses
|
||||
// the execution of any user processes. Asynchronously, when the container finished being paused the
|
||||
// state is changed to PAUSED.
|
||||
// If the Container state is PAUSED, do nothing.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
Pause() error
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
Pause() Error
|
||||
|
||||
// If the Container state is PAUSED, resumes the execution of any user processes in the
|
||||
// Container before setting the Container state to RUNNING.
|
||||
// If the Container state is RUNNING, do nothing.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
Resume() error
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
Resume() Error
|
||||
}
|
||||
|
|
|
@ -17,6 +17,12 @@ var (
|
|||
ErrNotADeviceNode = errors.New("not a device node")
|
||||
)
|
||||
|
||||
// Testing dependencies
|
||||
var (
|
||||
osLstat = os.Lstat
|
||||
ioutilReadDir = ioutil.ReadDir
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
Type rune `json:"type,omitempty"`
|
||||
Path string `json:"path,omitempty"` // It is fine if this is an empty string in the case that you are using Wildcards
|
||||
|
@ -42,7 +48,7 @@ func (device *Device) GetCgroupAllowString() string {
|
|||
|
||||
// Given the path to a device and it's cgroup_permissions(which cannot be easilly queried) look up the information about a linux device and return that information as a Device struct.
|
||||
func GetDevice(path, cgroupPermissions string) (*Device, error) {
|
||||
fileInfo, err := os.Lstat(path)
|
||||
fileInfo, err := osLstat(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -87,7 +93,7 @@ func GetHostDeviceNodes() ([]*Device, error) {
|
|||
}
|
||||
|
||||
func getDeviceNodes(path string) ([]*Device, error) {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
files, err := ioutilReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
61
vendor/src/github.com/docker/libcontainer/devices/devices_test.go
vendored
Normal file
61
vendor/src/github.com/docker/libcontainer/devices/devices_test.go
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package devices
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDeviceLstatFailure(t *testing.T) {
|
||||
testError := errors.New("test error")
|
||||
|
||||
// Override os.Lstat to inject error.
|
||||
osLstat = func(path string) (os.FileInfo, error) {
|
||||
return nil, testError
|
||||
}
|
||||
|
||||
_, err := GetDevice("", "")
|
||||
if err != testError {
|
||||
t.Fatalf("Unexpected error %v, expected %v", err, testError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHostDeviceNodesIoutilReadDirFailure(t *testing.T) {
|
||||
testError := errors.New("test error")
|
||||
|
||||
// Override ioutil.ReadDir to inject error.
|
||||
ioutilReadDir = func(dirname string) ([]os.FileInfo, error) {
|
||||
return nil, testError
|
||||
}
|
||||
|
||||
_, err := GetHostDeviceNodes()
|
||||
if err != testError {
|
||||
t.Fatalf("Unexpected error %v, expected %v", err, testError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetHostDeviceNodesIoutilReadDirDeepFailure(t *testing.T) {
|
||||
testError := errors.New("test error")
|
||||
called := false
|
||||
|
||||
// Override ioutil.ReadDir to inject error after the first call.
|
||||
ioutilReadDir = func(dirname string) ([]os.FileInfo, error) {
|
||||
if called {
|
||||
return nil, testError
|
||||
}
|
||||
called = true
|
||||
|
||||
// Provoke a second call.
|
||||
fi, err := os.Lstat("/tmp")
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
}
|
||||
|
||||
return []os.FileInfo{fi}, nil
|
||||
}
|
||||
|
||||
_, err := GetHostDeviceNodes()
|
||||
if err != testError {
|
||||
t.Fatalf("Unexpected error %v, expected %v", err, testError)
|
||||
}
|
||||
}
|
37
vendor/src/github.com/docker/libcontainer/error.go
vendored
Normal file
37
vendor/src/github.com/docker/libcontainer/error.go
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package libcontainer
|
||||
|
||||
// API error code type.
|
||||
type ErrorCode int
|
||||
|
||||
// API error codes.
|
||||
const (
|
||||
// Factory errors
|
||||
IdInUse ErrorCode = iota
|
||||
InvalidIdFormat
|
||||
// TODO: add Load errors
|
||||
|
||||
// Container errors
|
||||
ContainerDestroyed
|
||||
ContainerPaused
|
||||
|
||||
// Common errors
|
||||
ConfigInvalid
|
||||
SystemError
|
||||
)
|
||||
|
||||
// API Error type.
|
||||
type Error interface {
|
||||
error
|
||||
|
||||
// Returns the stack trace, if any, which identifies the
|
||||
// point at which the error occurred.
|
||||
Stack() []byte
|
||||
|
||||
// Returns a verbose string including the error message
|
||||
// and a representation of the stack trace suitable for
|
||||
// printing.
|
||||
Detail() string
|
||||
|
||||
// Returns the error code for this error.
|
||||
Code() ErrorCode
|
||||
}
|
|
@ -12,13 +12,13 @@ type Factory interface {
|
|||
// Returns the new container with a running process.
|
||||
//
|
||||
// Errors:
|
||||
// id is already in use by a container
|
||||
// id has incorrect format
|
||||
// config is invalid
|
||||
// System error
|
||||
// IdInUse - id is already in use by a container
|
||||
// InvalidIdFormat - id has incorrect format
|
||||
// ConfigInvalid - config is invalid
|
||||
// SystemError - System error
|
||||
//
|
||||
// On error, any partially created container parts are cleaned up (the operation is atomic).
|
||||
Create(id string, config *Config) (Container, error)
|
||||
Create(id string, config *Config) (Container, Error)
|
||||
|
||||
// Load takes an ID for an existing container and reconstructs the container
|
||||
// from the state.
|
||||
|
@ -27,5 +27,6 @@ type Factory interface {
|
|||
// Path does not exist
|
||||
// Container is stopped
|
||||
// System error
|
||||
Load(id string) (Container, error)
|
||||
// TODO: fix description
|
||||
Load(id string) (Container, Error)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package netlink
|
|||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
@ -38,12 +40,15 @@ type ifreqFlags struct {
|
|||
Ifruflags uint16
|
||||
}
|
||||
|
||||
func nativeEndian() binary.ByteOrder {
|
||||
var native binary.ByteOrder
|
||||
|
||||
func init() {
|
||||
var x uint32 = 0x01020304
|
||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
||||
return binary.BigEndian
|
||||
native = binary.BigEndian
|
||||
} else {
|
||||
native = binary.LittleEndian
|
||||
}
|
||||
return binary.LittleEndian
|
||||
}
|
||||
|
||||
func getIpFamily(ip net.IP) int {
|
||||
|
@ -80,8 +85,6 @@ func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
|
|||
}
|
||||
|
||||
func (msg *IfInfomsg) ToWireFormat() []byte {
|
||||
native := nativeEndian()
|
||||
|
||||
length := syscall.SizeofIfInfomsg
|
||||
b := make([]byte, length)
|
||||
b[0] = msg.Family
|
||||
|
@ -110,8 +113,6 @@ func newIfAddrmsg(family int) *IfAddrmsg {
|
|||
}
|
||||
|
||||
func (msg *IfAddrmsg) ToWireFormat() []byte {
|
||||
native := nativeEndian()
|
||||
|
||||
length := syscall.SizeofIfAddrmsg
|
||||
b := make([]byte, length)
|
||||
b[0] = msg.Family
|
||||
|
@ -142,8 +143,6 @@ func newRtMsg() *RtMsg {
|
|||
}
|
||||
|
||||
func (msg *RtMsg) ToWireFormat() []byte {
|
||||
native := nativeEndian()
|
||||
|
||||
length := syscall.SizeofRtMsg
|
||||
b := make([]byte, length)
|
||||
b[0] = msg.Family
|
||||
|
@ -202,8 +201,6 @@ func (a *RtAttr) Len() int {
|
|||
}
|
||||
|
||||
func (a *RtAttr) ToWireFormat() []byte {
|
||||
native := nativeEndian()
|
||||
|
||||
length := a.Len()
|
||||
buf := make([]byte, rtaAlignOf(length))
|
||||
|
||||
|
@ -225,14 +222,18 @@ func (a *RtAttr) ToWireFormat() []byte {
|
|||
return buf
|
||||
}
|
||||
|
||||
func uint32Attr(t int, n uint32) *RtAttr {
|
||||
buf := make([]byte, 4)
|
||||
native.PutUint32(buf, n)
|
||||
return newRtAttr(t, buf)
|
||||
}
|
||||
|
||||
type NetlinkRequest struct {
|
||||
syscall.NlMsghdr
|
||||
Data []NetlinkRequestData
|
||||
}
|
||||
|
||||
func (rr *NetlinkRequest) ToWireFormat() []byte {
|
||||
native := nativeEndian()
|
||||
|
||||
length := rr.Len
|
||||
dataBytes := make([][]byte, len(rr.Data))
|
||||
for i, data := range rr.Data {
|
||||
|
@ -329,36 +330,44 @@ func (s *NetlinkSocket) GetPid() (uint32, error) {
|
|||
return 0, ErrWrongSockType
|
||||
}
|
||||
|
||||
func (s *NetlinkSocket) HandleAck(seq uint32) error {
|
||||
native := nativeEndian()
|
||||
func (s *NetlinkSocket) CheckMessage(m syscall.NetlinkMessage, seq, pid uint32) error {
|
||||
if m.Header.Seq != seq {
|
||||
return fmt.Errorf("netlink: invalid seq %d, expected %d", m.Header.Seq, seq)
|
||||
}
|
||||
if m.Header.Pid != pid {
|
||||
return fmt.Errorf("netlink: wrong pid %d, expected %d", m.Header.Pid, pid)
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_DONE {
|
||||
return io.EOF
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_ERROR {
|
||||
e := int32(native.Uint32(m.Data[0:4]))
|
||||
if e == 0 {
|
||||
return io.EOF
|
||||
}
|
||||
return syscall.Errno(-e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *NetlinkSocket) HandleAck(seq uint32) error {
|
||||
pid, err := s.GetPid()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
done:
|
||||
outer:
|
||||
for {
|
||||
msgs, err := s.Receive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Seq != seq {
|
||||
return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, seq)
|
||||
}
|
||||
if m.Header.Pid != pid {
|
||||
return fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_DONE {
|
||||
break done
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_ERROR {
|
||||
error := int32(native.Uint32(m.Data[0:4]))
|
||||
if error == 0 {
|
||||
break done
|
||||
if err := s.CheckMessage(m, seq, pid); err != nil {
|
||||
if err == io.EOF {
|
||||
break outer
|
||||
}
|
||||
return syscall.Errno(-error)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -454,17 +463,11 @@ func AddRoute(destination, source, gateway, device string) error {
|
|||
wb.AddData(attr)
|
||||
}
|
||||
|
||||
var (
|
||||
native = nativeEndian()
|
||||
b = make([]byte, 4)
|
||||
)
|
||||
iface, err := net.InterfaceByName(device)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
native.PutUint32(b, uint32(iface.Index))
|
||||
|
||||
wb.AddData(newRtAttr(syscall.RTA_OIF, b))
|
||||
wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
|
@ -538,15 +541,7 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
|||
msg.Index = int32(iface.Index)
|
||||
msg.Change = DEFAULT_CHANGE
|
||||
wb.AddData(msg)
|
||||
|
||||
var (
|
||||
b = make([]byte, 4)
|
||||
native = nativeEndian()
|
||||
)
|
||||
native.PutUint32(b, uint32(mtu))
|
||||
|
||||
data := newRtAttr(syscall.IFLA_MTU, b)
|
||||
wb.AddData(data)
|
||||
wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu)))
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
|
@ -570,15 +565,7 @@ func NetworkSetMaster(iface, master *net.Interface) error {
|
|||
msg.Index = int32(iface.Index)
|
||||
msg.Change = DEFAULT_CHANGE
|
||||
wb.AddData(msg)
|
||||
|
||||
var (
|
||||
b = make([]byte, 4)
|
||||
native = nativeEndian()
|
||||
)
|
||||
native.PutUint32(b, uint32(master.Index))
|
||||
|
||||
data := newRtAttr(syscall.IFLA_MASTER, b)
|
||||
wb.AddData(data)
|
||||
wb.AddData(uint32Attr(syscall.IFLA_MASTER, uint32(master.Index)))
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
|
@ -602,15 +589,7 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
|||
msg.Index = int32(iface.Index)
|
||||
msg.Change = DEFAULT_CHANGE
|
||||
wb.AddData(msg)
|
||||
|
||||
var (
|
||||
b = make([]byte, 4)
|
||||
native = nativeEndian()
|
||||
)
|
||||
native.PutUint32(b, uint32(nspid))
|
||||
|
||||
data := newRtAttr(syscall.IFLA_NET_NS_PID, b)
|
||||
wb.AddData(data)
|
||||
wb.AddData(uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid)))
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
|
@ -634,15 +613,7 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
|||
msg.Index = int32(iface.Index)
|
||||
msg.Change = DEFAULT_CHANGE
|
||||
wb.AddData(msg)
|
||||
|
||||
var (
|
||||
b = make([]byte, 4)
|
||||
native = nativeEndian()
|
||||
)
|
||||
native.PutUint32(b, uint32(fd))
|
||||
|
||||
data := newRtAttr(IFLA_NET_NS_FD, b)
|
||||
wb.AddData(data)
|
||||
wb.AddData(uint32Attr(IFLA_NET_NS_FD, uint32(fd)))
|
||||
|
||||
if err := s.Send(wb); err != nil {
|
||||
return err
|
||||
|
@ -782,8 +753,6 @@ func NetworkLinkDel(name string) error {
|
|||
// Returns an array of IPNet for all the currently routed subnets on ipv4
|
||||
// This is similar to the first column of "ip route" output
|
||||
func NetworkGetRoutes() ([]Route, error) {
|
||||
native := nativeEndian()
|
||||
|
||||
s, err := getNetlinkSocket()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -806,28 +775,18 @@ func NetworkGetRoutes() ([]Route, error) {
|
|||
|
||||
res := make([]Route, 0)
|
||||
|
||||
done:
|
||||
outer:
|
||||
for {
|
||||
msgs, err := s.Receive()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, m := range msgs {
|
||||
if m.Header.Seq != wb.Seq {
|
||||
return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
|
||||
}
|
||||
if m.Header.Pid != pid {
|
||||
return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_DONE {
|
||||
break done
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_ERROR {
|
||||
error := int32(native.Uint32(m.Data[0:4]))
|
||||
if error == 0 {
|
||||
break done
|
||||
if err := s.CheckMessage(m, wb.Seq, pid); err != nil {
|
||||
if err == io.EOF {
|
||||
break outer
|
||||
}
|
||||
return nil, syscall.Errno(-error)
|
||||
return nil, err
|
||||
}
|
||||
if m.Header.Type != syscall.RTM_NEWROUTE {
|
||||
continue
|
||||
|
@ -974,7 +933,7 @@ func CreateBridge(name string, setMacAddr bool) error {
|
|||
return err
|
||||
}
|
||||
if setMacAddr {
|
||||
return setBridgeMacAddress(s, name)
|
||||
return NetworkSetMacAddress(name, randMacAddr())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1030,22 +989,40 @@ func AddToBridge(iface, master *net.Interface) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func setBridgeMacAddress(s int, name string) error {
|
||||
func randMacAddr() string {
|
||||
hw := make(net.HardwareAddr, 6)
|
||||
for i := 0; i < 6; i++ {
|
||||
hw[i] = byte(rand.Intn(255))
|
||||
}
|
||||
hw[0] &^= 0x1 // clear multicast bit
|
||||
hw[0] |= 0x2 // set local assignment bit (IEEE802)
|
||||
return hw.String()
|
||||
}
|
||||
|
||||
func NetworkSetMacAddress(name, addr string) error {
|
||||
if len(name) >= IFNAMSIZ {
|
||||
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] = randIfrDataByte()
|
||||
ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i])
|
||||
}
|
||||
|
||||
ifr.IfruHwaddr.Data[0] &^= 0x1 // clear multicast bit
|
||||
ifr.IfruHwaddr.Data[0] |= 0x2 // set local assignment bit (IEEE802)
|
||||
|
||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package netlink
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func randIfrDataByte() uint8 {
|
||||
return uint8(rand.Intn(255))
|
||||
func ifrDataByte(b byte) uint8 {
|
||||
return uint8(b)
|
||||
}
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
package netlink
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func randIfrDataByte() int8 {
|
||||
return int8(rand.Intn(255))
|
||||
func ifrDataByte(b byte) int8 {
|
||||
return int8(b)
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ func TestCreateVethPair(t *testing.T) {
|
|||
if err := NetworkCreateVethPair(name1, name2); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer NetworkLinkDel(name1)
|
||||
|
||||
if _, err := net.InterfaceByName(name1); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -124,3 +125,30 @@ func TestCreateVethPair(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMACAddress(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
name := "testmac"
|
||||
mac := randMacAddr()
|
||||
|
||||
if err := NetworkLinkAdd(name, "bridge"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer NetworkLinkDel(name)
|
||||
|
||||
if err := NetworkSetMacAddress(name, mac); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
iface, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if iface.HardwareAddr.String() != mac {
|
||||
t.Fatalf("mac address %q does not match %q", iface.HardwareAddr, mac)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue