Merge pull request #8133 from crosbymichael/update-libcontainer-sep7
Update libcontainer to 185328a42654f6dc9a41814e578
This commit is contained in:
commit
7fafe170cf
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
|
mv tmp-tar src/code.google.com/p/go/src/pkg/archive/tar
|
||||||
fi
|
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)
|
# 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
|
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')"
|
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"
|
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 {
|
type subsystem interface {
|
||||||
// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
|
// Returns the stats, as 'stats', corresponding to the cgroup under 'path'.
|
||||||
GetStats(path string, stats *cgroups.Stats) error
|
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) {
|
func getCgroupData(c *cgroups.Cgroup, pid int) (*data, error) {
|
||||||
// we can pick any subsystem to find the root
|
if cgroupRoot == "" {
|
||||||
cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
|
return nil, fmt.Errorf("failed to find the cgroup root")
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cgroup := c.Name
|
cgroup := c.Name
|
||||||
|
|
|
@ -14,58 +14,65 @@ type Container interface {
|
||||||
|
|
||||||
// Returns the current run state of the container.
|
// Returns the current run state of the container.
|
||||||
//
|
//
|
||||||
// Errors: container no longer exists,
|
// Errors:
|
||||||
// system error.
|
// ContainerDestroyed - Container no longer exists,
|
||||||
RunState() (*RunState, error)
|
// SystemError - System error.
|
||||||
|
RunState() (*RunState, Error)
|
||||||
|
|
||||||
// Returns the current config of the container.
|
// Returns the current config of the container.
|
||||||
Config() *Config
|
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.
|
// 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,
|
// Errors:
|
||||||
// config is invalid,
|
// ContainerDestroyed - Container no longer exists,
|
||||||
// container is paused,
|
// ConfigInvalid - config is invalid,
|
||||||
// system error.
|
// ContainerPaused - Container is paused,
|
||||||
Start(*ProcessConfig) (pid int, exitChan chan int, err error)
|
// SystemError - System error.
|
||||||
|
Start(config *ProcessConfig) (pid int, exitChan chan int, err Error)
|
||||||
|
|
||||||
// Destroys the container after killing all running processes.
|
// Destroys the container after killing all running processes.
|
||||||
//
|
//
|
||||||
// Any event registrations are removed before the container is destroyed.
|
// Any event registrations are removed before the container is destroyed.
|
||||||
// No error is returned if the container is already destroyed.
|
// No error is returned if the container is already destroyed.
|
||||||
//
|
//
|
||||||
// Errors: system error.
|
// Errors:
|
||||||
Destroy() error
|
// SystemError - System error.
|
||||||
|
Destroy() Error
|
||||||
|
|
||||||
// Returns the PIDs inside this container. The PIDs are in the namespace of the calling process.
|
// Returns the PIDs inside this container. The PIDs are in the namespace of the calling process.
|
||||||
//
|
//
|
||||||
// Errors: container no longer exists,
|
// Errors:
|
||||||
// system error.
|
// ContainerDestroyed - Container no longer exists,
|
||||||
|
// SystemError - System error.
|
||||||
//
|
//
|
||||||
// Some of the returned PIDs may no longer refer to processes in the Container, unless
|
// 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.
|
// 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.
|
// Returns statistics for the container.
|
||||||
//
|
//
|
||||||
// Errors: container no longer exists,
|
// Errors:
|
||||||
// system error.
|
// ContainerDestroyed - Container no longer exists,
|
||||||
Stats() (*ContainerStats, error)
|
// SystemError - System error.
|
||||||
|
Stats() (*ContainerStats, Error)
|
||||||
|
|
||||||
// If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses
|
// 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
|
// the execution of any user processes. Asynchronously, when the container finished being paused the
|
||||||
// state is changed to PAUSED.
|
// state is changed to PAUSED.
|
||||||
// If the Container state is PAUSED, do nothing.
|
// If the Container state is PAUSED, do nothing.
|
||||||
//
|
//
|
||||||
// Errors: container no longer exists,
|
// Errors:
|
||||||
// system error.
|
// ContainerDestroyed - Container no longer exists,
|
||||||
Pause() error
|
// SystemError - System error.
|
||||||
|
Pause() Error
|
||||||
|
|
||||||
// If the Container state is PAUSED, resumes the execution of any user processes in the
|
// If the Container state is PAUSED, resumes the execution of any user processes in the
|
||||||
// Container before setting the Container state to RUNNING.
|
// Container before setting the Container state to RUNNING.
|
||||||
// If the Container state is RUNNING, do nothing.
|
// If the Container state is RUNNING, do nothing.
|
||||||
//
|
//
|
||||||
// Errors: container no longer exists,
|
// Errors:
|
||||||
// system error.
|
// ContainerDestroyed - Container no longer exists,
|
||||||
Resume() error
|
// SystemError - System error.
|
||||||
|
Resume() Error
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,12 @@ var (
|
||||||
ErrNotADeviceNode = errors.New("not a device node")
|
ErrNotADeviceNode = errors.New("not a device node")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Testing dependencies
|
||||||
|
var (
|
||||||
|
osLstat = os.Lstat
|
||||||
|
ioutilReadDir = ioutil.ReadDir
|
||||||
|
)
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
Type rune `json:"type,omitempty"`
|
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
|
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.
|
// 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) {
|
func GetDevice(path, cgroupPermissions string) (*Device, error) {
|
||||||
fileInfo, err := os.Lstat(path)
|
fileInfo, err := osLstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -87,7 +93,7 @@ func GetHostDeviceNodes() ([]*Device, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDeviceNodes(path string) ([]*Device, error) {
|
func getDeviceNodes(path string) ([]*Device, error) {
|
||||||
files, err := ioutil.ReadDir(path)
|
files, err := ioutilReadDir(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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.
|
// Returns the new container with a running process.
|
||||||
//
|
//
|
||||||
// Errors:
|
// Errors:
|
||||||
// id is already in use by a container
|
// IdInUse - id is already in use by a container
|
||||||
// id has incorrect format
|
// InvalidIdFormat - id has incorrect format
|
||||||
// config is invalid
|
// ConfigInvalid - config is invalid
|
||||||
// System error
|
// SystemError - System error
|
||||||
//
|
//
|
||||||
// On error, any partially created container parts are cleaned up (the operation is atomic).
|
// 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
|
// Load takes an ID for an existing container and reconstructs the container
|
||||||
// from the state.
|
// from the state.
|
||||||
|
@ -27,5 +27,6 @@ type Factory interface {
|
||||||
// Path does not exist
|
// Path does not exist
|
||||||
// Container is stopped
|
// Container is stopped
|
||||||
// System error
|
// System error
|
||||||
Load(id string) (Container, error)
|
// TODO: fix description
|
||||||
|
Load(id string) (Container, Error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package netlink
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -38,12 +40,15 @@ type ifreqFlags struct {
|
||||||
Ifruflags uint16
|
Ifruflags uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func nativeEndian() binary.ByteOrder {
|
var native binary.ByteOrder
|
||||||
|
|
||||||
|
func init() {
|
||||||
var x uint32 = 0x01020304
|
var x uint32 = 0x01020304
|
||||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
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 {
|
func getIpFamily(ip net.IP) int {
|
||||||
|
@ -80,8 +85,6 @@ func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *IfInfomsg) ToWireFormat() []byte {
|
func (msg *IfInfomsg) ToWireFormat() []byte {
|
||||||
native := nativeEndian()
|
|
||||||
|
|
||||||
length := syscall.SizeofIfInfomsg
|
length := syscall.SizeofIfInfomsg
|
||||||
b := make([]byte, length)
|
b := make([]byte, length)
|
||||||
b[0] = msg.Family
|
b[0] = msg.Family
|
||||||
|
@ -110,8 +113,6 @@ func newIfAddrmsg(family int) *IfAddrmsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *IfAddrmsg) ToWireFormat() []byte {
|
func (msg *IfAddrmsg) ToWireFormat() []byte {
|
||||||
native := nativeEndian()
|
|
||||||
|
|
||||||
length := syscall.SizeofIfAddrmsg
|
length := syscall.SizeofIfAddrmsg
|
||||||
b := make([]byte, length)
|
b := make([]byte, length)
|
||||||
b[0] = msg.Family
|
b[0] = msg.Family
|
||||||
|
@ -142,8 +143,6 @@ func newRtMsg() *RtMsg {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg *RtMsg) ToWireFormat() []byte {
|
func (msg *RtMsg) ToWireFormat() []byte {
|
||||||
native := nativeEndian()
|
|
||||||
|
|
||||||
length := syscall.SizeofRtMsg
|
length := syscall.SizeofRtMsg
|
||||||
b := make([]byte, length)
|
b := make([]byte, length)
|
||||||
b[0] = msg.Family
|
b[0] = msg.Family
|
||||||
|
@ -202,8 +201,6 @@ func (a *RtAttr) Len() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *RtAttr) ToWireFormat() []byte {
|
func (a *RtAttr) ToWireFormat() []byte {
|
||||||
native := nativeEndian()
|
|
||||||
|
|
||||||
length := a.Len()
|
length := a.Len()
|
||||||
buf := make([]byte, rtaAlignOf(length))
|
buf := make([]byte, rtaAlignOf(length))
|
||||||
|
|
||||||
|
@ -225,14 +222,18 @@ func (a *RtAttr) ToWireFormat() []byte {
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func uint32Attr(t int, n uint32) *RtAttr {
|
||||||
|
buf := make([]byte, 4)
|
||||||
|
native.PutUint32(buf, n)
|
||||||
|
return newRtAttr(t, buf)
|
||||||
|
}
|
||||||
|
|
||||||
type NetlinkRequest struct {
|
type NetlinkRequest struct {
|
||||||
syscall.NlMsghdr
|
syscall.NlMsghdr
|
||||||
Data []NetlinkRequestData
|
Data []NetlinkRequestData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *NetlinkRequest) ToWireFormat() []byte {
|
func (rr *NetlinkRequest) ToWireFormat() []byte {
|
||||||
native := nativeEndian()
|
|
||||||
|
|
||||||
length := rr.Len
|
length := rr.Len
|
||||||
dataBytes := make([][]byte, len(rr.Data))
|
dataBytes := make([][]byte, len(rr.Data))
|
||||||
for i, data := range rr.Data {
|
for i, data := range rr.Data {
|
||||||
|
@ -329,36 +330,44 @@ func (s *NetlinkSocket) GetPid() (uint32, error) {
|
||||||
return 0, ErrWrongSockType
|
return 0, ErrWrongSockType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetlinkSocket) HandleAck(seq uint32) error {
|
func (s *NetlinkSocket) CheckMessage(m syscall.NetlinkMessage, seq, pid uint32) error {
|
||||||
native := nativeEndian()
|
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()
|
pid, err := s.GetPid()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
outer:
|
||||||
for {
|
for {
|
||||||
msgs, err := s.Receive()
|
msgs, err := s.Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
if m.Header.Seq != seq {
|
if err := s.CheckMessage(m, seq, pid); err != nil {
|
||||||
return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, seq)
|
if err == io.EOF {
|
||||||
}
|
break outer
|
||||||
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
|
|
||||||
}
|
}
|
||||||
return syscall.Errno(-error)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -454,17 +463,11 @@ func AddRoute(destination, source, gateway, device string) error {
|
||||||
wb.AddData(attr)
|
wb.AddData(attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
native = nativeEndian()
|
|
||||||
b = make([]byte, 4)
|
|
||||||
)
|
|
||||||
iface, err := net.InterfaceByName(device)
|
iface, err := net.InterfaceByName(device)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
native.PutUint32(b, uint32(iface.Index))
|
wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
|
||||||
|
|
||||||
wb.AddData(newRtAttr(syscall.RTA_OIF, b))
|
|
||||||
|
|
||||||
if err := s.Send(wb); err != nil {
|
if err := s.Send(wb); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -538,15 +541,7 @@ func NetworkSetMTU(iface *net.Interface, mtu 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_MTU, uint32(mtu)))
|
||||||
var (
|
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nativeEndian()
|
|
||||||
)
|
|
||||||
native.PutUint32(b, uint32(mtu))
|
|
||||||
|
|
||||||
data := newRtAttr(syscall.IFLA_MTU, b)
|
|
||||||
wb.AddData(data)
|
|
||||||
|
|
||||||
if err := s.Send(wb); err != nil {
|
if err := s.Send(wb); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -570,15 +565,7 @@ 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)))
|
||||||
var (
|
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nativeEndian()
|
|
||||||
)
|
|
||||||
native.PutUint32(b, uint32(master.Index))
|
|
||||||
|
|
||||||
data := newRtAttr(syscall.IFLA_MASTER, b)
|
|
||||||
wb.AddData(data)
|
|
||||||
|
|
||||||
if err := s.Send(wb); err != nil {
|
if err := s.Send(wb); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -602,15 +589,7 @@ 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)))
|
||||||
var (
|
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nativeEndian()
|
|
||||||
)
|
|
||||||
native.PutUint32(b, uint32(nspid))
|
|
||||||
|
|
||||||
data := newRtAttr(syscall.IFLA_NET_NS_PID, b)
|
|
||||||
wb.AddData(data)
|
|
||||||
|
|
||||||
if err := s.Send(wb); err != nil {
|
if err := s.Send(wb); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -634,15 +613,7 @@ func NetworkSetNsFd(iface *net.Interface, fd 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(IFLA_NET_NS_FD, uint32(fd)))
|
||||||
var (
|
|
||||||
b = make([]byte, 4)
|
|
||||||
native = nativeEndian()
|
|
||||||
)
|
|
||||||
native.PutUint32(b, uint32(fd))
|
|
||||||
|
|
||||||
data := newRtAttr(IFLA_NET_NS_FD, b)
|
|
||||||
wb.AddData(data)
|
|
||||||
|
|
||||||
if err := s.Send(wb); err != nil {
|
if err := s.Send(wb); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -782,8 +753,6 @@ func NetworkLinkDel(name string) error {
|
||||||
// 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) {
|
||||||
native := nativeEndian()
|
|
||||||
|
|
||||||
s, err := getNetlinkSocket()
|
s, err := getNetlinkSocket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -806,28 +775,18 @@ func NetworkGetRoutes() ([]Route, error) {
|
||||||
|
|
||||||
res := make([]Route, 0)
|
res := make([]Route, 0)
|
||||||
|
|
||||||
done:
|
outer:
|
||||||
for {
|
for {
|
||||||
msgs, err := s.Receive()
|
msgs, err := s.Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, m := range msgs {
|
for _, m := range msgs {
|
||||||
if m.Header.Seq != wb.Seq {
|
if err := s.CheckMessage(m, wb.Seq, pid); err != nil {
|
||||||
return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
|
if err == io.EOF {
|
||||||
}
|
break outer
|
||||||
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
|
|
||||||
}
|
}
|
||||||
return nil, syscall.Errno(-error)
|
return nil, err
|
||||||
}
|
}
|
||||||
if m.Header.Type != syscall.RTM_NEWROUTE {
|
if m.Header.Type != syscall.RTM_NEWROUTE {
|
||||||
continue
|
continue
|
||||||
|
@ -974,7 +933,7 @@ func CreateBridge(name string, setMacAddr bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if setMacAddr {
|
if setMacAddr {
|
||||||
return setBridgeMacAddress(s, name)
|
return NetworkSetMacAddress(name, randMacAddr())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1030,22 +989,40 @@ func AddToBridge(iface, master *net.Interface) error {
|
||||||
return nil
|
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 {
|
if len(name) >= IFNAMSIZ {
|
||||||
return fmt.Errorf("Interface name %s too long", name)
|
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 := ifreqHwaddr{}
|
||||||
ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
|
ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
|
||||||
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
|
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
|
||||||
|
|
||||||
for i := 0; i < 6; i++ {
|
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 {
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import (
|
func ifrDataByte(b byte) uint8 {
|
||||||
"math/rand"
|
return uint8(b)
|
||||||
)
|
|
||||||
|
|
||||||
func randIfrDataByte() uint8 {
|
|
||||||
return uint8(rand.Intn(255))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
|
|
||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import (
|
func ifrDataByte(b byte) int8 {
|
||||||
"math/rand"
|
return int8(b)
|
||||||
)
|
|
||||||
|
|
||||||
func randIfrDataByte() int8 {
|
|
||||||
return int8(rand.Intn(255))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,6 +115,7 @@ func TestCreateVethPair(t *testing.T) {
|
||||||
if err := NetworkCreateVethPair(name1, name2); err != nil {
|
if err := NetworkCreateVethPair(name1, name2); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
defer NetworkLinkDel(name1)
|
||||||
|
|
||||||
if _, err := net.InterfaceByName(name1); err != nil {
|
if _, err := net.InterfaceByName(name1); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -124,3 +125,30 @@ func TestCreateVethPair(t *testing.T) {
|
||||||
t.Fatal(err)
|
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