diff --git a/hack/vendor.sh b/hack/vendor.sh index 23c768e96a..e4473c2ea8 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -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 185328a42654f6dc9a41814e57882f69d65f6ab7 +clone git github.com/docker/libcontainer c744f6470e37be5ce1f1ae09b842c15c1bee120d # 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')" diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go index 02cdff5a7d..14b55ccd4e 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/cpuacct.go @@ -40,7 +40,7 @@ func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error { return err } - totalUsage, err := getCgroupParamInt(path, "cpuacct.usage") + totalUsage, err := getCgroupParamUint(path, "cpuacct.usage") if err != nil { return err } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go index ea92934a0f..3f9647c2fd 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/memory.go @@ -2,6 +2,7 @@ package fs import ( "bufio" + "fmt" "os" "path/filepath" "strconv" @@ -66,25 +67,25 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error { for sc.Scan() { t, v, err := getCgroupParamKeyValue(sc.Text()) if err != nil { - return err + return fmt.Errorf("failed to parse memory.stat (%q) - %v", sc.Text(), err) } stats.MemoryStats.Stats[t] = v } // Set memory usage and max historical usage. - value, err := getCgroupParamInt(path, "memory.usage_in_bytes") + value, err := getCgroupParamUint(path, "memory.usage_in_bytes") if err != nil { - return err + return fmt.Errorf("failed to parse memory.usage_in_bytes - %v", err) } stats.MemoryStats.Usage = value - value, err = getCgroupParamInt(path, "memory.max_usage_in_bytes") + value, err = getCgroupParamUint(path, "memory.max_usage_in_bytes") if err != nil { - return err + return fmt.Errorf("failed to parse memory.max_usage_in_bytes - %v", err) } stats.MemoryStats.MaxUsage = value - value, err = getCgroupParamInt(path, "memory.failcnt") + value, err = getCgroupParamUint(path, "memory.failcnt") if err != nil { - return err + return fmt.Errorf("failed to parse memory.failcnt - %v", err) } stats.MemoryStats.Failcnt = value diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils.go index f65622a80f..f37a3a485a 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils.go @@ -14,27 +14,49 @@ var ( ErrNotValidFormat = errors.New("line is not a valid key value format") ) +// Saturates negative values at zero and returns a uint64. +// Due to kernel bugs, some of the memory cgroup stats can be negative. +func parseUint(s string, base, bitSize int) (uint64, error) { + value, err := strconv.ParseUint(s, base, bitSize) + if err != nil { + intValue, intErr := strconv.ParseInt(s, base, bitSize) + // 1. Handle negative values greater than MinInt64 (and) + // 2. Handle negative values lesser than MinInt64 + if intErr == nil && intValue < 0 { + return 0, nil + } else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 { + return 0, nil + } + + return value, err + } + + return value, nil +} + // Parses a cgroup param and returns as name, value // i.e. "io_service_bytes 1234" will return as io_service_bytes, 1234 func getCgroupParamKeyValue(t string) (string, uint64, error) { parts := strings.Fields(t) switch len(parts) { case 2: - value, err := strconv.ParseUint(parts[1], 10, 64) + value, err := parseUint(parts[1], 10, 64) if err != nil { - return "", 0, fmt.Errorf("Unable to convert param value to uint64: %s", err) + return "", 0, fmt.Errorf("Unable to convert param value (%q) to uint64: %v", parts[1], err) } + return parts[0], value, nil default: return "", 0, ErrNotValidFormat } } -// Gets a single int64 value from the specified cgroup file. -func getCgroupParamInt(cgroupPath, cgroupFile string) (uint64, error) { +// Gets a single uint64 value from the specified cgroup file. +func getCgroupParamUint(cgroupPath, cgroupFile string) (uint64, error) { contents, err := ioutil.ReadFile(filepath.Join(cgroupPath, cgroupFile)) if err != nil { return 0, err } - return strconv.ParseUint(strings.TrimSpace(string(contents)), 10, 64) + + return parseUint(strings.TrimSpace(string(contents)), 10, 64) } diff --git a/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils_test.go b/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils_test.go index 63d743f06e..f1afd49411 100644 --- a/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils_test.go +++ b/vendor/src/github.com/docker/libcontainer/cgroups/fs/utils_test.go @@ -2,8 +2,10 @@ package fs import ( "io/ioutil" + "math" "os" "path/filepath" + "strconv" "testing" ) @@ -27,7 +29,7 @@ func TestGetCgroupParamsInt(t *testing.T) { if err != nil { t.Fatal(err) } - value, err := getCgroupParamInt(tempDir, cgroupFile) + value, err := getCgroupParamUint(tempDir, cgroupFile) if err != nil { t.Fatal(err) } else if value != floatValue { @@ -39,19 +41,44 @@ func TestGetCgroupParamsInt(t *testing.T) { if err != nil { t.Fatal(err) } - value, err = getCgroupParamInt(tempDir, cgroupFile) + value, err = getCgroupParamUint(tempDir, cgroupFile) if err != nil { t.Fatal(err) } else if value != floatValue { t.Fatalf("Expected %d to equal %f", value, floatValue) } + // Success with negative values + err = ioutil.WriteFile(tempFile, []byte("-12345"), 0755) + if err != nil { + t.Fatal(err) + } + value, err = getCgroupParamUint(tempDir, cgroupFile) + if err != nil { + t.Fatal(err) + } else if value != 0 { + t.Fatalf("Expected %d to equal %f", value, 0) + } + + // Success with negative values lesser than min int64 + s := strconv.FormatFloat(math.MinInt64, 'f', -1, 64) + err = ioutil.WriteFile(tempFile, []byte(s), 0755) + if err != nil { + t.Fatal(err) + } + value, err = getCgroupParamUint(tempDir, cgroupFile) + if err != nil { + t.Fatal(err) + } else if value != 0 { + t.Fatalf("Expected %d to equal %f", value, 0) + } + // Not a float. err = ioutil.WriteFile(tempFile, []byte("not-a-float"), 0755) if err != nil { t.Fatal(err) } - _, err = getCgroupParamInt(tempDir, cgroupFile) + _, err = getCgroupParamUint(tempDir, cgroupFile) if err == nil { t.Fatal("Expecting error, got none") } @@ -61,7 +88,7 @@ func TestGetCgroupParamsInt(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = getCgroupParamInt(tempDir, cgroupFile) + _, err = getCgroupParamUint(tempDir, cgroupFile) if err == nil { t.Fatal("Expecting error, got none") } diff --git a/vendor/src/github.com/docker/libcontainer/config.go b/vendor/src/github.com/docker/libcontainer/config.go index 8fe95c24f7..1fb377dcef 100644 --- a/vendor/src/github.com/docker/libcontainer/config.go +++ b/vendor/src/github.com/docker/libcontainer/config.go @@ -15,6 +15,9 @@ type Config struct { // Mount specific options. MountConfig *MountConfig `json:"mount_config,omitempty"` + // Pathname to container's root filesystem + RootFs string `json:"root_fs,omitempty"` + // Hostname optionally sets the container's hostname if provided Hostname string `json:"hostname,omitempty"` diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/create.go b/vendor/src/github.com/docker/libcontainer/namespaces/create.go index 15a844bc0b..b6418b6e9f 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/create.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/create.go @@ -7,4 +7,4 @@ import ( "github.com/docker/libcontainer" ) -type CreateCommand func(container *libcontainer.Config, console, rootfs, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd +type CreateCommand func(container *libcontainer.Config, console, dataPath, init string, childPipe *os.File, args []string) *exec.Cmd diff --git a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go index 382abfbccc..4440ccd0d5 100644 --- a/vendor/src/github.com/docker/libcontainer/namespaces/exec.go +++ b/vendor/src/github.com/docker/libcontainer/namespaces/exec.go @@ -21,7 +21,7 @@ import ( // Move this to libcontainer package. // Exec performs setup outside of a namespace so that a container can be // executed. Exec is a high level function for working with container namespaces. -func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Writer, console string, rootfs, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { +func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Writer, console, dataPath string, args []string, createCommand CreateCommand, startCallback func()) (int, error) { var ( err error ) @@ -34,7 +34,7 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri } defer syncPipe.Close() - command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.Child(), args) + command := createCommand(container, console, dataPath, os.Args[0], syncPipe.Child(), args) // Note: these are only used in non-tty mode // if there is a tty for the container it will be opened within the namespace and the // fds will be duped to stdin, stdiout, and stderr @@ -121,7 +121,7 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri // root: the path to the container json file and information // pipe: sync pipe to synchronize the parent and child processes // args: the arguments to pass to the container to run as the user's program -func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { +func DefaultCreateCommand(container *libcontainer.Config, console, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { // get our binary name from arg0 so we can always reexec ourself env := []string{ "console=" + console, @@ -141,7 +141,7 @@ func DefaultCreateCommand(container *libcontainer.Config, console, rootfs, dataP command := exec.Command(init, append([]string{"init", "--"}, args...)...) // make sure the process is executed inside the context of the rootfs - command.Dir = rootfs + command.Dir = container.RootFs command.Env = append(os.Environ(), env...) if command.SysProcAttr == nil { diff --git a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go index 7517a6de9e..738af8798a 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go +++ b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux.go @@ -12,15 +12,25 @@ import ( ) 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 @@ -375,6 +385,564 @@ outer: return nil } +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() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + wb.AddData(msg) + + 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 + } + + 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!") + } + + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + iface, err := net.InterfaceByName(name) + if err != nil { + return err + } + + 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 { + return err + } + + return s.HandleAck(wb.Seq) +} + +// Bring up a particular network interface. +// This is identical to running: ip link set dev $name up +func NetworkLinkUp(iface *net.Interface) 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) + msg.Flags = syscall.IFF_UP + msg.Change = syscall.IFF_UP + wb.AddData(msg) + + if err := s.Send(wb); err != nil { + return err + } + + 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 { + 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) + msg.Flags = 0 & ^syscall.IFF_UP + msg.Change = DEFAULT_CHANGE + wb.AddData(msg) + + if err := s.Send(wb); err != nil { + return err + } + + return s.HandleAck(wb.Seq) +} + +// 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() + if err != nil { + return err + } + 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) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Index = int32(iface.Index) + msg.Change = DEFAULT_CHANGE + wb.AddData(msg) + + macdata := make([]byte, 6) + copy(macdata, hwaddr) + data := newRtAttr(IFLA_ADDRESS, macdata) + wb.AddData(data) + + if err := s.Send(wb); err != nil { + return err + } + return s.HandleAck(wb.Seq) +} + +// 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() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Type = syscall.RTM_SETLINK + msg.Flags = syscall.NLM_F_REQUEST + msg.Index = int32(iface.Index) + msg.Change = DEFAULT_CHANGE + wb.AddData(msg) + wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu))) + + if err := s.Send(wb); err != nil { + return err + } + return s.HandleAck(wb.Seq) +} + +func networkMasterAction(iface *net.Interface, rtattr *RtAttr) error { + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Type = syscall.RTM_SETLINK + msg.Flags = syscall.NLM_F_REQUEST + msg.Index = int32(iface.Index) + msg.Change = DEFAULT_CHANGE + wb.AddData(msg) + 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 { + return err + } + + 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 { + 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() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + msg.Index = int32(iface.Index) + msg.Change = DEFAULT_CHANGE + wb.AddData(msg) + + nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(newName)) + wb.AddData(nameData) + + if err := s.Send(wb); err != nil { + return err + } + + return s.HandleAck(wb.Seq) +} + +// 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() + if err != nil { + return err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + wb.AddData(msg) + + 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) + + if err := s.Send(wb); err != nil { + return err + } + return s.HandleAck(wb.Seq) +} + +// 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() + + 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) + wb.AddData(msg) + + 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() + if err != nil { + return err + } + 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) + + masterDevIfc, err := net.InterfaceByName(masterDev) + if err != nil { + return err + } + + msg := newIfInfomsg(syscall.AF_UNSPEC) + wb.AddData(msg) + + nest1 := newRtAttr(syscall.IFLA_LINKINFO, nil) + newRtAttrChild(nest1, IFLA_INFO_KIND, nonZeroTerminated("macvlan")) + + 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 { + return err + } + return s.HandleAck(wb.Seq) +} + +func networkLinkIpAction(action, flags int, ifa IfAddr) error { + s, err := getNetlinkSocket() + if err != nil { + return err + } + defer s.Close() + + family := getIpFamily(ifa.IP) + + wb := newNetlinkRequest(action, flags) + + msg := newIfAddrmsg(family) + msg.Index = uint32(ifa.Iface.Index) + prefixLen, _ := ifa.IPNet.Mask.Size() + msg.Prefixlen = uint8(prefixLen) + 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 { + return err + } + + 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 +// This is similar to the first column of "ip route" output +func NetworkGetRoutes() ([]Route, error) { + s, err := getNetlinkSocket() + if err != nil { + return nil, err + } + defer s.Close() + + wb := newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) + + msg := newIfInfomsg(syscall.AF_UNSPEC) + wb.AddData(msg) + + if err := s.Send(wb); err != nil { + return nil, err + } + + pid, err := s.GetPid() + if err != nil { + return nil, err + } + + res := make([]Route, 0) + +outer: + for { + msgs, err := s.Receive() + if err != nil { + return nil, err + } + for _, m := range msgs { + if err := s.CheckMessage(m, wb.Seq, pid); err != nil { + if err == io.EOF { + break outer + } + return nil, err + } + if m.Header.Type != syscall.RTM_NEWROUTE { + continue + } + + var r Route + + msg := (*RtMsg)(unsafe.Pointer(&m.Data[0:syscall.SizeofRtMsg][0])) + + if msg.Flags&syscall.RTM_F_CLONED != 0 { + // Ignore cloned routes + continue + } + + if msg.Table != syscall.RT_TABLE_MAIN { + // Ignore non-main tables + continue + } + + if msg.Family != syscall.AF_INET { + // Ignore non-ipv4 routes + continue + } + + if msg.Dst_len == 0 { + // Default routes + r.Default = true + } + + attrs, err := syscall.ParseNetlinkRouteAttr(&m) + if err != nil { + return nil, err + } + for _, attr := range attrs { + switch attr.Attr.Type { + case syscall.RTA_DST: + ip := attr.Value + r.IPNet = &net.IPNet{ + IP: ip, + Mask: net.CIDRMask(int(msg.Dst_len), 8*len(ip)), + } + case syscall.RTA_OIF: + index := int(native.Uint32(attr.Value[0:4])) + r.Iface, _ = net.InterfaceByIndex(index) + } + } + if r.Default || r.IPNet != nil { + res = append(res, r) + } + } + } + + return res, nil +} + // Add a new route table entry. func AddRoute(destination, source, gateway, device string) error { if destination == "" && source == "" && gateway == "" { @@ -481,367 +1049,9 @@ func AddDefaultGw(ip, device string) error { return AddRoute("", "", ip, device) } -// Bring up a particular network interface -func NetworkLinkUp(iface *net.Interface) 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.Change = syscall.IFF_UP - msg.Flags = syscall.IFF_UP - msg.Index = int32(iface.Index) - wb.AddData(msg) - - if err := s.Send(wb); err != nil { - return err - } - - return s.HandleAck(wb.Seq) -} - -func NetworkLinkDown(iface *net.Interface) 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.Change = syscall.IFF_UP - msg.Flags = 0 & ^syscall.IFF_UP - msg.Index = int32(iface.Index) - wb.AddData(msg) - - if err := s.Send(wb); err != nil { - return err - } - - return s.HandleAck(wb.Seq) -} - -func NetworkSetMTU(iface *net.Interface, mtu int) error { - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - msg.Type = syscall.RTM_SETLINK - msg.Flags = syscall.NLM_F_REQUEST - msg.Index = int32(iface.Index) - msg.Change = DEFAULT_CHANGE - wb.AddData(msg) - wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu))) - - if err := s.Send(wb); err != nil { - return err - } - return s.HandleAck(wb.Seq) -} - -// same as ip link set $name master $master -func NetworkSetMaster(iface, master *net.Interface) error { - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - msg.Type = syscall.RTM_SETLINK - msg.Flags = syscall.NLM_F_REQUEST - msg.Index = int32(iface.Index) - msg.Change = DEFAULT_CHANGE - wb.AddData(msg) - wb.AddData(uint32Attr(syscall.IFLA_MASTER, uint32(master.Index))) - - if err := s.Send(wb); err != nil { - return err - } - - return s.HandleAck(wb.Seq) -} - -func NetworkSetNsPid(iface *net.Interface, nspid int) error { - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - msg.Type = syscall.RTM_SETLINK - msg.Flags = syscall.NLM_F_REQUEST - msg.Index = int32(iface.Index) - msg.Change = DEFAULT_CHANGE - wb.AddData(msg) - wb.AddData(uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid))) - - if err := s.Send(wb); err != nil { - return err - } - - return s.HandleAck(wb.Seq) -} - -func NetworkSetNsFd(iface *net.Interface, fd int) error { - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - msg.Type = syscall.RTM_SETLINK - msg.Flags = syscall.NLM_F_REQUEST - msg.Index = int32(iface.Index) - msg.Change = DEFAULT_CHANGE - wb.AddData(msg) - wb.AddData(uint32Attr(IFLA_NET_NS_FD, uint32(fd))) - - if err := s.Send(wb); err != nil { - return err - } - - return s.HandleAck(wb.Seq) -} - -func networkLinkIpAction(action, flags int, ifa IfAddr) error { - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - family := getIpFamily(ifa.IP) - - wb := newNetlinkRequest(action, flags) - - msg := newIfAddrmsg(family) - msg.Index = uint32(ifa.Iface.Index) - prefixLen, _ := ifa.IPNet.Mask.Size() - msg.Prefixlen = uint8(prefixLen) - 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 { - return err - } - - 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}, - ) -} - -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 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!") - } - - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - wb.AddData(msg) - - 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 - } - - 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!") - } - - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - iface, err := net.InterfaceByName(name) - if err != nil { - return err - } - - 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 { - return err - } - - return s.HandleAck(wb.Seq) -} - -// 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) { - s, err := getNetlinkSocket() - if err != nil { - return nil, err - } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - wb.AddData(msg) - - if err := s.Send(wb); err != nil { - return nil, err - } - - pid, err := s.GetPid() - if err != nil { - return nil, err - } - - res := make([]Route, 0) - -outer: - for { - msgs, err := s.Receive() - if err != nil { - return nil, err - } - for _, m := range msgs { - if err := s.CheckMessage(m, wb.Seq, pid); err != nil { - if err == io.EOF { - break outer - } - return nil, err - } - if m.Header.Type != syscall.RTM_NEWROUTE { - continue - } - - var r Route - - msg := (*RtMsg)(unsafe.Pointer(&m.Data[0:syscall.SizeofRtMsg][0])) - - if msg.Flags&syscall.RTM_F_CLONED != 0 { - // Ignore cloned routes - continue - } - - if msg.Table != syscall.RT_TABLE_MAIN { - // Ignore non-main tables - continue - } - - if msg.Family != syscall.AF_INET { - // Ignore non-ipv4 routes - continue - } - - if msg.Dst_len == 0 { - // Default routes - r.Default = true - } - - attrs, err := syscall.ParseNetlinkRouteAttr(&m) - if err != nil { - return nil, err - } - for _, attr := range attrs { - switch attr.Attr.Type { - case syscall.RTA_DST: - ip := attr.Value - r.IPNet = &net.IPNet{ - IP: ip, - Mask: net.CIDRMask(int(msg.Dst_len), 8*len(ip)), - } - case syscall.RTA_OIF: - index := int(native.Uint32(attr.Value[0:4])) - r.Iface, _ = net.InterfaceByIndex(index) - } - } - if r.Default || r.IPNet != nil { - res = append(res, r) - } - } - } - - return res, nil -} - +// 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, @@ -858,60 +1068,6 @@ func getIfSocket() (fd int, err error) { return -1, err } -func NetworkChangeName(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 -} - -func NetworkCreateVethPair(name1, name2 string) error { - s, err := getNetlinkSocket() - if err != nil { - return err - } - defer s.Close() - - wb := newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) - - msg := newIfInfomsg(syscall.AF_UNSPEC) - wb.AddData(msg) - - 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) - - if err := s.Send(wb); err != nil { - return err - } - return s.HandleAck(wb.Seq) -} - // Create the actual bridge device. This is more backward-compatible than // netlink.NetworkLinkAdd and works on RHEL 6. func CreateBridge(name string, setMacAddr bool) error { @@ -933,7 +1089,7 @@ func CreateBridge(name string, setMacAddr bool) error { return err } if setMacAddr { - return NetworkSetMacAddress(name, randMacAddr()) + return SetMacAddress(name, randMacAddr()) } return nil } @@ -999,7 +1155,7 @@ func randMacAddr() string { return hw.String() } -func NetworkSetMacAddress(name, addr string) error { +func SetMacAddress(name, addr string) error { if len(name) >= IFNAMSIZ { return fmt.Errorf("Interface name %s too long", name) } @@ -1028,3 +1184,26 @@ func NetworkSetMacAddress(name, addr string) error { } 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 +} diff --git a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go index 6c596ed9ff..b2bac2eb8d 100644 --- a/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go +++ b/vendor/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go @@ -3,9 +3,50 @@ package netlink import ( "net" "strings" + "syscall" "testing" ) +type testLink struct { + name string + linkType string +} + +func addLink(t *testing.T, name string, linkType string) { + if err := NetworkLinkAdd(name, linkType); err != nil { + t.Fatalf("Unable to create %s link: %s", name, err) + } +} + +func readLink(t *testing.T, name string) *net.Interface { + iface, err := net.InterfaceByName(name) + if err != nil { + t.Fatalf("Could not find %s interface: %s", name, err) + } + + return iface +} + +func deleteLink(t *testing.T, name string) { + if err := NetworkLinkDel(name); err != nil { + t.Fatalf("Unable to delete %s link: %s", name, err) + } +} + +func upLink(t *testing.T, name string) { + iface := readLink(t, name) + if err := NetworkLinkUp(iface); err != nil { + t.Fatalf("Could not bring UP %#v interface: %s", iface, err) + } +} + +func downLink(t *testing.T, name string) { + iface := readLink(t, name) + if err := NetworkLinkDown(iface); err != nil { + t.Fatalf("Could not bring DOWN %#v interface: %s", iface, err) + } +} + func ipAssigned(iface *net.Interface, ip net.IP) bool { addrs, _ := iface.Addrs() @@ -19,6 +60,194 @@ func ipAssigned(iface *net.Interface, ip net.IP) bool { return false } +func TestNetworkLinkAddDel(t *testing.T) { + if testing.Short() { + return + } + + testLinks := []testLink{ + {"tstEth", "dummy"}, + {"tstBr", "bridge"}, + } + + for _, tl := range testLinks { + addLink(t, tl.name, tl.linkType) + defer deleteLink(t, tl.name) + readLink(t, tl.name) + } +} + +func TestNetworkLinkUpDown(t *testing.T) { + if testing.Short() { + return + } + + tl := testLink{name: "tstEth", linkType: "dummy"} + + addLink(t, tl.name, tl.linkType) + defer deleteLink(t, tl.name) + + upLink(t, tl.name) + ifcAfterUp := readLink(t, tl.name) + + if (ifcAfterUp.Flags & syscall.IFF_UP) != syscall.IFF_UP { + t.Fatalf("Could not bring UP %#v initerface", tl) + } + + downLink(t, tl.name) + ifcAfterDown := readLink(t, tl.name) + + if (ifcAfterDown.Flags & syscall.IFF_UP) == syscall.IFF_UP { + t.Fatalf("Could not bring DOWN %#v initerface", tl) + } +} + +func TestNetworkSetMacAddress(t *testing.T) { + if testing.Short() { + return + } + + tl := testLink{name: "tstEth", linkType: "dummy"} + macaddr := "22:ce:e0:99:63:6f" + + addLink(t, tl.name, tl.linkType) + defer deleteLink(t, tl.name) + + ifcBeforeSet := readLink(t, tl.name) + + if err := NetworkSetMacAddress(ifcBeforeSet, macaddr); err != nil { + t.Fatalf("Could not set %s MAC address on %#v interface: err", macaddr, tl, err) + } + + ifcAfterSet := readLink(t, tl.name) + + if ifcAfterSet.HardwareAddr.String() != macaddr { + t.Fatalf("Could not set %s MAC address on %#v interface", macaddr, tl) + } +} + +func TestNetworkSetMTU(t *testing.T) { + if testing.Short() { + return + } + + tl := testLink{name: "tstEth", linkType: "dummy"} + mtu := 1400 + + addLink(t, tl.name, tl.linkType) + defer deleteLink(t, tl.name) + + ifcBeforeSet := readLink(t, tl.name) + + if err := NetworkSetMTU(ifcBeforeSet, mtu); err != nil { + t.Fatalf("Could not set %d MTU on %#v interface: err", mtu, tl, err) + } + + ifcAfterSet := readLink(t, tl.name) + + if ifcAfterSet.MTU != mtu { + t.Fatalf("Could not set %d MTU on %#v interface", mtu, tl) + } +} + +func TestNetworkSetMasterNoMaster(t *testing.T) { + if testing.Short() { + return + } + + master := testLink{"tstBr", "bridge"} + slave := testLink{"tstEth", "dummy"} + testLinks := []testLink{master, slave} + + for _, tl := range testLinks { + addLink(t, tl.name, tl.linkType) + defer deleteLink(t, tl.name) + upLink(t, tl.name) + } + + masterIfc := readLink(t, master.name) + slaveIfc := readLink(t, slave.name) + if err := NetworkSetMaster(slaveIfc, masterIfc); err != nil { + t.Fatalf("Could not set %#v to be the master of %#v: %s", master, slave, err) + } + + // Trying to figure out a way to test which will not break on RHEL6. + // We could check for existence of /sys/class/net/tstEth/upper_tstBr + // which should point to the ../tstBr which is the UPPER device i.e. network bridge + + if err := NetworkSetNoMaster(slaveIfc); err != nil { + t.Fatalf("Could not UNset %#v master of %#v: %s", master, slave, err) + } +} + +func TestNetworkChangeName(t *testing.T) { + if testing.Short() { + return + } + + tl := testLink{"tstEth", "dummy"} + newName := "newTst" + + addLink(t, tl.name, tl.linkType) + + linkIfc := readLink(t, tl.name) + if err := NetworkChangeName(linkIfc, newName); err != nil { + deleteLink(t, tl.name) + t.Fatalf("Could not change %#v interface name to %s: %s", tl, newName, err) + } + + readLink(t, newName) + deleteLink(t, newName) +} + +func TestNetworkLinkAddVlan(t *testing.T) { + if testing.Short() { + return + } + + tl := struct { + name string + id uint16 + }{ + name: "tstVlan", + id: 32, + } + masterLink := testLink{"tstEth", "dummy"} + + addLink(t, masterLink.name, masterLink.linkType) + defer deleteLink(t, masterLink.name) + + if err := NetworkLinkAddVlan(masterLink.name, tl.name, tl.id); err != nil { + t.Fatalf("Unable to create %#v VLAN interface: %s", tl, err) + } + + readLink(t, tl.name) +} + +func TestNetworkLinkAddMacVlan(t *testing.T) { + if testing.Short() { + return + } + + tl := struct { + name string + mode string + }{ + name: "tstVlan", + mode: "private", + } + masterLink := testLink{"tstEth", "dummy"} + + addLink(t, masterLink.name, masterLink.linkType) + defer deleteLink(t, masterLink.name) + + if err := NetworkLinkAddMacVlan(masterLink.name, tl.name, tl.mode); err != nil { + t.Fatalf("Unable to create %#v MAC VLAN interface: %s", tl, err) + } + + readLink(t, tl.name) +} + func TestAddDelNetworkIp(t *testing.T) { if testing.Short() { return @@ -35,7 +264,7 @@ func TestAddDelNetworkIp(t *testing.T) { } if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil { - t.Fatal(err) + t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err) } if !ipAssigned(iface, ip) { @@ -43,7 +272,7 @@ func TestAddDelNetworkIp(t *testing.T) { } if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil { - t.Fatal(err) + t.Fatalf("Could not delete IP address %s from interface %#v: %s", ip.String(), iface, err) } if ipAssigned(iface, ip) { @@ -51,6 +280,28 @@ func TestAddDelNetworkIp(t *testing.T) { } } +func TestCreateVethPair(t *testing.T) { + if testing.Short() { + return + } + + var ( + name1 = "veth1" + name2 = "veth2" + ) + + if err := NetworkCreateVethPair(name1, name2); err != nil { + t.Fatalf("Could not create veth pair %s %s: %s", name1, name2, err) + } + defer NetworkLinkDel(name1) + + readLink(t, name1) + readLink(t, name2) +} + +// +// netlink package tests which do not use RTNETLINK +// func TestCreateBridgeWithMac(t *testing.T) { if testing.Short() { return @@ -77,55 +328,6 @@ func TestCreateBridgeWithMac(t *testing.T) { } } -func TestCreateBridgeLink(t *testing.T) { - if testing.Short() { - return - } - - name := "mybrlink" - - if err := NetworkLinkAdd(name, "bridge"); err != nil { - t.Fatal(err) - } - - if _, err := net.InterfaceByName(name); err != nil { - t.Fatal(err) - } - - if err := NetworkLinkDel(name); err != nil { - t.Fatal(err) - } - - if _, err := net.InterfaceByName(name); err == nil { - t.Fatalf("expected error getting interface because %s bridge was deleted", name) - } - -} - -func TestCreateVethPair(t *testing.T) { - if testing.Short() { - return - } - - var ( - name1 = "veth1" - name2 = "veth2" - ) - - if err := NetworkCreateVethPair(name1, name2); err != nil { - t.Fatal(err) - } - defer NetworkLinkDel(name1) - - if _, err := net.InterfaceByName(name1); err != nil { - t.Fatal(err) - } - - if _, err := net.InterfaceByName(name2); err != nil { - t.Fatal(err) - } -} - func TestSetMACAddress(t *testing.T) { if testing.Short() { return @@ -139,7 +341,7 @@ func TestSetMACAddress(t *testing.T) { } defer NetworkLinkDel(name) - if err := NetworkSetMacAddress(name, mac); err != nil { + if err := SetMacAddress(name, mac); err != nil { t.Fatal(err) } diff --git a/vendor/src/github.com/docker/libcontainer/network/netns.go b/vendor/src/github.com/docker/libcontainer/network/netns.go index 1ff7506452..73cd8de530 100644 --- a/vendor/src/github.com/docker/libcontainer/network/netns.go +++ b/vendor/src/github.com/docker/libcontainer/network/netns.go @@ -30,8 +30,10 @@ func (v *NetNS) Initialize(config *Network, networkState *NetworkState) error { } if err := system.Setns(f.Fd(), syscall.CLONE_NEWNET); err != nil { + f.Close() return fmt.Errorf("failed to setns current network namespace: %v", err) } + f.Close() return nil } diff --git a/vendor/src/github.com/docker/libcontainer/network/types.go b/vendor/src/github.com/docker/libcontainer/network/types.go index 3b7a4e395c..ae098981b8 100644 --- a/vendor/src/github.com/docker/libcontainer/network/types.go +++ b/vendor/src/github.com/docker/libcontainer/network/types.go @@ -17,12 +17,18 @@ type Network struct { // Prefix for the veth interfaces. VethPrefix string `json:"veth_prefix,omitempty"` - // Address contains the IP and mask to set on the network interface + // Address contains the IPv4 and mask to set on the network interface Address string `json:"address,omitempty"` + // IPv6Address contains the IPv6 and mask to set on the network interface + IPv6Address string `json:"ipv6_address,omitempty"` + // Gateway sets the gateway address that is used as the default for the interface Gateway string `json:"gateway,omitempty"` + // IPv6Gateway sets the ipv6 gateway address that is used as the default for the interface + IPv6Gateway string `json:"ipv6_gateway,omitempty"` + // Mtu sets the mtu value for the interface and will be mirrored on both the host and // container's interfaces if a pair is created, specifically in the case of type veth // Note: This does not apply to loopback interfaces. diff --git a/vendor/src/github.com/docker/libcontainer/network/veth.go b/vendor/src/github.com/docker/libcontainer/network/veth.go index fcafd85ccf..c38fe3d2d5 100644 --- a/vendor/src/github.com/docker/libcontainer/network/veth.go +++ b/vendor/src/github.com/docker/libcontainer/network/veth.go @@ -63,6 +63,12 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error { if err := SetInterfaceIp(defaultDevice, config.Address); err != nil { return fmt.Errorf("set %s ip %s", defaultDevice, err) } + if config.IPv6Address != "" { + if err := SetInterfaceIp(defaultDevice, config.IPv6Address); err != nil { + return fmt.Errorf("set %s ipv6 %s", defaultDevice, err) + } + } + if err := SetMtu(defaultDevice, config.Mtu); err != nil { return fmt.Errorf("set %s mtu to %d %s", defaultDevice, config.Mtu, err) } @@ -74,6 +80,11 @@ func (v *Veth) Initialize(config *Network, networkState *NetworkState) error { return fmt.Errorf("set gateway to %s on device %s failed with %s", config.Gateway, defaultDevice, err) } } + if config.IPv6Gateway != "" { + if err := SetDefaultGateway(config.IPv6Gateway, defaultDevice); err != nil { + return fmt.Errorf("set gateway for ipv6 to %s on device %s failed with %s", config.IPv6Gateway, defaultDevice, err) + } + } return nil } diff --git a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go index c46b191782..6fc553b8f9 100644 --- a/vendor/src/github.com/docker/libcontainer/nsinit/exec.go +++ b/vendor/src/github.com/docker/libcontainer/nsinit/exec.go @@ -135,8 +135,8 @@ func startContainer(container *libcontainer.Config, dataPath string, args []stri signal.Notify(sigc) - createCommand := func(container *libcontainer.Config, console, rootfs, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { - cmd = namespaces.DefaultCreateCommand(container, console, rootfs, dataPath, init, pipe, args) + createCommand := func(container *libcontainer.Config, console, dataPath, init string, pipe *os.File, args []string) *exec.Cmd { + cmd = namespaces.DefaultCreateCommand(container, console, dataPath, init, pipe, args) if logPath != "" { cmd.Env = append(cmd.Env, fmt.Sprintf("log=%s", logPath)) } @@ -189,7 +189,7 @@ func startContainer(container *libcontainer.Config, dataPath string, args []stri }() } - return namespaces.Exec(container, stdin, stdout, stderr, console, "", dataPath, args, createCommand, startCallback) + return namespaces.Exec(container, stdin, stdout, stderr, console, dataPath, args, createCommand, startCallback) } func resizeTty(master *os.File) {