Преглед на файлове

Merge pull request #360 from mrjana/cnm

Cherry picks from docker1.7_integ branch
Jana Radhakrishnan преди 10 години
родител
ревизия
0dbbe8b696
променени са 28 файла, в които са добавени 2262 реда и са изтрити 73 реда
  1. 6 1
      libnetwork/Godeps/Godeps.json
  2. 2 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS
  3. 31 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
  4. 1307 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
  5. 5 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go
  6. 7 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go
  7. 408 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
  8. 88 0
      libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
  9. 7 1
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md
  10. 2 2
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go
  11. 16 2
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go
  12. 28 3
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go
  13. 73 15
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go
  14. 114 5
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go
  15. 1 1
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go
  16. 15 0
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go
  17. 11 11
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go
  18. 3 4
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go
  19. 1 1
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go
  20. 2 2
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go
  21. 1 1
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go
  22. 1 1
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go
  23. 36 11
      libnetwork/drivers/bridge/bridge.go
  24. 5 10
      libnetwork/drivers/bridge/setup_device.go
  25. 5 1
      libnetwork/drivers/host/host.go
  26. 1 1
      libnetwork/drivers/overlay/ov_network.go
  27. 18 0
      libnetwork/endpoint.go
  28. 68 0
      libnetwork/libnetwork_test.go

+ 6 - 1
libnetwork/Godeps/Godeps.json

@@ -69,6 +69,11 @@
 			"Comment": "v1.4.1-4106-g637023a",
 			"Rev": "637023a5f8d8347a0e271c09d5c9bc84fbc97693"
 		},
+		{
+			"ImportPath": "github.com/docker/libcontainer/netlink",
+			"Comment": "v1.4.0-495-g3e66118",
+			"Rev": "3e661186ba24f259d3860f067df052c7f6904bee"
+		},
 		{
 			"ImportPath": "github.com/docker/libcontainer/user",
 			"Comment": "v1.4.0-495-g3e66118",
@@ -127,7 +132,7 @@
 		},
 		{
 			"ImportPath": "github.com/vishvananda/netlink",
-			"Rev": "8eb64238879fed52fd51c5b30ad20b928fb4c36c"
+			"Rev": "20397a138846e4d6590e01783ed023ed7e1c38a6"
 		},
 		{
 			"ImportPath": "github.com/vishvananda/netns",

+ 2 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS

@@ -0,0 +1,2 @@
+Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
+Guillaume J. Charmes <guillaume@docker.com> (@creack)

+ 31 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go

@@ -0,0 +1,31 @@
+// Packet netlink provide access to low level Netlink sockets and messages.
+//
+// Actual implementations are in:
+// netlink_linux.go
+// netlink_darwin.go
+package netlink
+
+import (
+	"errors"
+	"net"
+)
+
+var (
+	ErrWrongSockType   = errors.New("Wrong socket type")
+	ErrShortResponse   = errors.New("Got short response from netlink")
+	ErrInterfaceExists = errors.New("Network interface already exists")
+)
+
+// A Route is a subnet associated with the interface to reach it.
+type Route struct {
+	*net.IPNet
+	Iface   *net.Interface
+	Default bool
+}
+
+// An IfAddr defines IP network settings for a given network interface
+type IfAddr struct {
+	Iface *net.Interface
+	IP    net.IP
+	IPNet *net.IPNet
+}

+ 1307 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go

@@ -0,0 +1,1307 @@
+package netlink
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+	"math/rand"
+	"net"
+	"os"
+	"sync/atomic"
+	"syscall"
+	"unsafe"
+)
+
+const (
+	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
+	IFLA_BRPORT_MODE  = 4
+	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
+
+type ifreqHwaddr struct {
+	IfrnName   [IFNAMSIZ]byte
+	IfruHwaddr syscall.RawSockaddr
+}
+
+type ifreqIndex struct {
+	IfrnName  [IFNAMSIZ]byte
+	IfruIndex int32
+}
+
+type ifreqFlags struct {
+	IfrnName  [IFNAMSIZ]byte
+	Ifruflags uint16
+}
+
+var native binary.ByteOrder
+
+func init() {
+	var x uint32 = 0x01020304
+	if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
+		native = binary.BigEndian
+	} else {
+		native = binary.LittleEndian
+	}
+}
+
+func getIpFamily(ip net.IP) int {
+	if len(ip) <= net.IPv4len {
+		return syscall.AF_INET
+	}
+	if ip.To4() != nil {
+		return syscall.AF_INET
+	}
+	return syscall.AF_INET6
+}
+
+type NetlinkRequestData interface {
+	Len() int
+	ToWireFormat() []byte
+}
+
+type IfInfomsg struct {
+	syscall.IfInfomsg
+}
+
+func newIfInfomsg(family int) *IfInfomsg {
+	return &IfInfomsg{
+		IfInfomsg: syscall.IfInfomsg{
+			Family: uint8(family),
+		},
+	}
+}
+
+func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
+	msg := newIfInfomsg(family)
+	parent.children = append(parent.children, msg)
+	return msg
+}
+
+func (msg *IfInfomsg) ToWireFormat() []byte {
+	length := syscall.SizeofIfInfomsg
+	b := make([]byte, length)
+	b[0] = msg.Family
+	b[1] = 0
+	native.PutUint16(b[2:4], msg.Type)
+	native.PutUint32(b[4:8], uint32(msg.Index))
+	native.PutUint32(b[8:12], msg.Flags)
+	native.PutUint32(b[12:16], msg.Change)
+	return b
+}
+
+func (msg *IfInfomsg) Len() int {
+	return syscall.SizeofIfInfomsg
+}
+
+type IfAddrmsg struct {
+	syscall.IfAddrmsg
+}
+
+func newIfAddrmsg(family int) *IfAddrmsg {
+	return &IfAddrmsg{
+		IfAddrmsg: syscall.IfAddrmsg{
+			Family: uint8(family),
+		},
+	}
+}
+
+func (msg *IfAddrmsg) ToWireFormat() []byte {
+	length := syscall.SizeofIfAddrmsg
+	b := make([]byte, length)
+	b[0] = msg.Family
+	b[1] = msg.Prefixlen
+	b[2] = msg.Flags
+	b[3] = msg.Scope
+	native.PutUint32(b[4:8], msg.Index)
+	return b
+}
+
+func (msg *IfAddrmsg) Len() int {
+	return syscall.SizeofIfAddrmsg
+}
+
+type RtMsg struct {
+	syscall.RtMsg
+}
+
+func newRtMsg() *RtMsg {
+	return &RtMsg{
+		RtMsg: syscall.RtMsg{
+			Table:    syscall.RT_TABLE_MAIN,
+			Scope:    syscall.RT_SCOPE_UNIVERSE,
+			Protocol: syscall.RTPROT_BOOT,
+			Type:     syscall.RTN_UNICAST,
+		},
+	}
+}
+
+func (msg *RtMsg) ToWireFormat() []byte {
+	length := syscall.SizeofRtMsg
+	b := make([]byte, length)
+	b[0] = msg.Family
+	b[1] = msg.Dst_len
+	b[2] = msg.Src_len
+	b[3] = msg.Tos
+	b[4] = msg.Table
+	b[5] = msg.Protocol
+	b[6] = msg.Scope
+	b[7] = msg.Type
+	native.PutUint32(b[8:12], msg.Flags)
+	return b
+}
+
+func (msg *RtMsg) Len() int {
+	return syscall.SizeofRtMsg
+}
+
+func rtaAlignOf(attrlen int) int {
+	return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
+}
+
+type RtAttr struct {
+	syscall.RtAttr
+	Data     []byte
+	children []NetlinkRequestData
+}
+
+func newRtAttr(attrType int, data []byte) *RtAttr {
+	return &RtAttr{
+		RtAttr: syscall.RtAttr{
+			Type: uint16(attrType),
+		},
+		children: []NetlinkRequestData{},
+		Data:     data,
+	}
+}
+
+func newRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr {
+	attr := newRtAttr(attrType, data)
+	parent.children = append(parent.children, attr)
+	return attr
+}
+
+func (a *RtAttr) Len() int {
+	if len(a.children) == 0 {
+		return (syscall.SizeofRtAttr + len(a.Data))
+	}
+
+	l := 0
+	for _, child := range a.children {
+		l += child.Len()
+	}
+	l += syscall.SizeofRtAttr
+	return rtaAlignOf(l + len(a.Data))
+}
+
+func (a *RtAttr) ToWireFormat() []byte {
+	length := a.Len()
+	buf := make([]byte, rtaAlignOf(length))
+
+	if a.Data != nil {
+		copy(buf[4:], a.Data)
+	} else {
+		next := 4
+		for _, child := range a.children {
+			childBuf := child.ToWireFormat()
+			copy(buf[next:], childBuf)
+			next += rtaAlignOf(len(childBuf))
+		}
+	}
+
+	if l := uint16(length); l != 0 {
+		native.PutUint16(buf[0:2], l)
+	}
+	native.PutUint16(buf[2:4], a.Type)
+	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 {
+	length := rr.Len
+	dataBytes := make([][]byte, len(rr.Data))
+	for i, data := range rr.Data {
+		dataBytes[i] = data.ToWireFormat()
+		length += uint32(len(dataBytes[i]))
+	}
+	b := make([]byte, length)
+	native.PutUint32(b[0:4], length)
+	native.PutUint16(b[4:6], rr.Type)
+	native.PutUint16(b[6:8], rr.Flags)
+	native.PutUint32(b[8:12], rr.Seq)
+	native.PutUint32(b[12:16], rr.Pid)
+
+	next := 16
+	for _, data := range dataBytes {
+		copy(b[next:], data)
+		next += len(data)
+	}
+	return b
+}
+
+func (rr *NetlinkRequest) AddData(data NetlinkRequestData) {
+	if data != nil {
+		rr.Data = append(rr.Data, data)
+	}
+}
+
+func newNetlinkRequest(proto, flags int) *NetlinkRequest {
+	return &NetlinkRequest{
+		NlMsghdr: syscall.NlMsghdr{
+			Len:   uint32(syscall.NLMSG_HDRLEN),
+			Type:  uint16(proto),
+			Flags: syscall.NLM_F_REQUEST | uint16(flags),
+			Seq:   atomic.AddUint32(&nextSeqNr, 1),
+		},
+	}
+}
+
+type NetlinkSocket struct {
+	fd  int
+	lsa syscall.SockaddrNetlink
+}
+
+func getNetlinkSocket() (*NetlinkSocket, error) {
+	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_ROUTE)
+	if err != nil {
+		return nil, err
+	}
+	s := &NetlinkSocket{
+		fd: fd,
+	}
+	s.lsa.Family = syscall.AF_NETLINK
+	if err := syscall.Bind(fd, &s.lsa); err != nil {
+		syscall.Close(fd)
+		return nil, err
+	}
+
+	return s, nil
+}
+
+func (s *NetlinkSocket) Close() {
+	syscall.Close(s.fd)
+}
+
+func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
+	if err := syscall.Sendto(s.fd, request.ToWireFormat(), 0, &s.lsa); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
+	rb := make([]byte, syscall.Getpagesize())
+	nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
+	if err != nil {
+		return nil, err
+	}
+	if nr < syscall.NLMSG_HDRLEN {
+		return nil, ErrShortResponse
+	}
+	rb = rb[:nr]
+	return syscall.ParseNetlinkMessage(rb)
+}
+
+func (s *NetlinkSocket) GetPid() (uint32, error) {
+	lsa, err := syscall.Getsockname(s.fd)
+	if err != nil {
+		return 0, err
+	}
+	switch v := lsa.(type) {
+	case *syscall.SockaddrNetlink:
+		return v.Pid, nil
+	}
+	return 0, ErrWrongSockType
+}
+
+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
+	}
+
+outer:
+	for {
+		msgs, err := s.Receive()
+		if err != nil {
+			return err
+		}
+		for _, m := range msgs {
+			if err := s.CheckMessage(m, seq, pid); err != nil {
+				if err == io.EOF {
+					break outer
+				}
+				return err
+			}
+		}
+	}
+
+	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
+	)
+
+	if hwaddr[0]&0x1 == MULTICAST {
+		return fmt.Errorf("Multicast MAC Address is not supported: %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)
+}
+
+// Set link queue length
+// This is identical to running: ip link set dev $name txqueuelen $QLEN
+func NetworkSetTxQueueLen(iface *net.Interface, txQueueLen 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_TXQLEN, uint32(txQueueLen)))
+
+	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 identical 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)
+}
+
+// Rename 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, txQueueLen int) 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)
+
+	txqLen := make([]byte, 4)
+	native.PutUint32(txqLen, uint32(txQueueLen))
+	txqData := newRtAttr(syscall.IFLA_TXQLEN, txqLen)
+	wb.AddData(txqData)
+
+	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))
+
+	txqLen2 := make([]byte, 4)
+	native.PutUint32(txqLen2, uint32(txQueueLen))
+	newRtAttrChild(nest3, syscall.IFLA_TXQLEN, txqLen2)
+
+	wb.AddData(nest1)
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+
+	if err := s.HandleAck(wb.Seq); err != nil {
+		if os.IsExist(err) {
+			return ErrInterfaceExists
+		}
+
+		return err
+	}
+
+	return nil
+}
+
+// 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)
+}
+
+// MacVlan link has LowerDev, UpperDev and operates in Mode mode
+// This simplifies the code when creating MacVlan or MacVtap interface
+type MacVlanLink struct {
+	MasterDev string
+	SlaveDev  string
+	mode      string
+}
+
+func (m MacVlanLink) Mode() uint32 {
+	modeMap := map[string]uint32{
+		"private":  MACVLAN_MODE_PRIVATE,
+		"vepa":     MACVLAN_MODE_VEPA,
+		"bridge":   MACVLAN_MODE_BRIDGE,
+		"passthru": MACVLAN_MODE_PASSTHRU,
+	}
+
+	return modeMap[m.mode]
+}
+
+// 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 networkLinkMacVlan(dev_type string, mcvln *MacVlanLink) 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(mcvln.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(dev_type))
+
+	nest2 := newRtAttrChild(nest1, IFLA_INFO_DATA, nil)
+	macVlanData := make([]byte, 4)
+	native.PutUint32(macVlanData, mcvln.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(mcvln.SlaveDev)))
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+func NetworkLinkAddMacVlan(masterDev, macVlanDev string, mode string) error {
+	return networkLinkMacVlan("macvlan", &MacVlanLink{
+		MasterDev: masterDev,
+		SlaveDev:  macVlanDev,
+		mode:      mode,
+	})
+}
+
+func NetworkLinkAddMacVtap(masterDev, macVlanDev string, mode string) error {
+	return networkLinkMacVlan("macvtap", &MacVlanLink{
+		MasterDev: masterDev,
+		SlaveDev:  macVlanDev,
+		mode:      mode,
+	})
+}
+
+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 == "" {
+		return fmt.Errorf("one of destination, source or gateway must not be blank")
+	}
+
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+
+	wb := newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	msg := newRtMsg()
+	currentFamily := -1
+	var rtAttrs []*RtAttr
+
+	if destination != "" {
+		destIP, destNet, err := net.ParseCIDR(destination)
+		if err != nil {
+			return fmt.Errorf("destination CIDR %s couldn't be parsed", destination)
+		}
+		destFamily := getIpFamily(destIP)
+		currentFamily = destFamily
+		destLen, bits := destNet.Mask.Size()
+		if destLen == 0 && bits == 0 {
+			return fmt.Errorf("destination CIDR %s generated a non-canonical Mask", destination)
+		}
+		msg.Family = uint8(destFamily)
+		msg.Dst_len = uint8(destLen)
+		var destData []byte
+		if destFamily == syscall.AF_INET {
+			destData = destIP.To4()
+		} else {
+			destData = destIP.To16()
+		}
+		rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_DST, destData))
+	}
+
+	if source != "" {
+		srcIP := net.ParseIP(source)
+		if srcIP == nil {
+			return fmt.Errorf("source IP %s couldn't be parsed", source)
+		}
+		srcFamily := getIpFamily(srcIP)
+		if currentFamily != -1 && currentFamily != srcFamily {
+			return fmt.Errorf("source and destination ip were not the same IP family")
+		}
+		currentFamily = srcFamily
+		msg.Family = uint8(srcFamily)
+		var srcData []byte
+		if srcFamily == syscall.AF_INET {
+			srcData = srcIP.To4()
+		} else {
+			srcData = srcIP.To16()
+		}
+		rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_PREFSRC, srcData))
+	}
+
+	if gateway != "" {
+		gwIP := net.ParseIP(gateway)
+		if gwIP == nil {
+			return fmt.Errorf("gateway IP %s couldn't be parsed", gateway)
+		}
+		gwFamily := getIpFamily(gwIP)
+		if currentFamily != -1 && currentFamily != gwFamily {
+			return fmt.Errorf("gateway, source, and destination ip were not the same IP family")
+		}
+		msg.Family = uint8(gwFamily)
+		var gwData []byte
+		if gwFamily == syscall.AF_INET {
+			gwData = gwIP.To4()
+		} else {
+			gwData = gwIP.To16()
+		}
+		rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_GATEWAY, gwData))
+	}
+
+	wb.AddData(msg)
+	for _, attr := range rtAttrs {
+		wb.AddData(attr)
+	}
+
+	iface, err := net.InterfaceByName(device)
+	if err != nil {
+		return err
+	}
+	wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
+
+	if err := s.Send(wb); err != nil {
+		return err
+	}
+	return s.HandleAck(wb.Seq)
+}
+
+// Add a new default gateway. Identical to:
+// ip route add default via $ip
+func AddDefaultGw(ip, device string) error {
+	return AddRoute("", "", ip, device)
+}
+
+// THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
+// IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
+// WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
+func getIfSocket() (fd int, err error) {
+	for _, socket := range []int{
+		syscall.AF_INET,
+		syscall.AF_PACKET,
+		syscall.AF_INET6,
+	} {
+		if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
+			break
+		}
+	}
+	if err == nil {
+		return fd, nil
+	}
+	return -1, err
+}
+
+// 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 {
+	if len(name) >= IFNAMSIZ {
+		return fmt.Errorf("Interface name %s too long", name)
+	}
+
+	s, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(s)
+
+	nameBytePtr, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), SIOC_BRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
+		return err
+	}
+	if setMacAddr {
+		return SetMacAddress(name, randMacAddr())
+	}
+	return nil
+}
+
+// Delete the actual bridge device.
+func DeleteBridge(name string) error {
+	s, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(s)
+
+	nameBytePtr, err := syscall.BytePtrFromString(name)
+	if err != nil {
+		return err
+	}
+
+	var ifr ifreqFlags
+	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], []byte(name))
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s),
+		syscall.SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifr))); err != 0 {
+		return err
+	}
+
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s),
+		SIOC_BRDELBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
+		return err
+	}
+	return nil
+}
+
+// Add a slave to abridge device.  This is more backward-compatible than
+// netlink.NetworkSetMaster and works on RHEL 6.
+func AddToBridge(iface, master *net.Interface) error {
+	if len(master.Name) >= IFNAMSIZ {
+		return fmt.Errorf("Interface name %s too long", master.Name)
+	}
+
+	s, err := getIfSocket()
+	if err != nil {
+		return err
+	}
+	defer syscall.Close(s)
+
+	ifr := ifreqIndex{}
+	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], master.Name)
+	ifr.IfruIndex = int32(iface.Index)
+
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), SIOC_BRADDIF, uintptr(unsafe.Pointer(&ifr))); err != 0 {
+		return err
+	}
+
+	return nil
+}
+
+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 SetMacAddress(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] = ifrDataByte(hw[i])
+	}
+
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
+		return err
+	}
+	return nil
+}
+
+func SetHairpinMode(iface *net.Interface, enabled bool) error {
+	s, err := getNetlinkSocket()
+	if err != nil {
+		return err
+	}
+	defer s.Close()
+	req := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := newIfInfomsg(syscall.AF_BRIDGE)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(iface.Index)
+	msg.Change = DEFAULT_CHANGE
+	req.AddData(msg)
+
+	mode := []byte{0}
+	if enabled {
+		mode[0] = byte(1)
+	}
+
+	br := newRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
+	newRtAttrChild(br, IFLA_BRPORT_MODE, mode)
+	req.AddData(br)
+	if err := s.Send(req); err != nil {
+		return err
+	}
+
+	return s.HandleAck(req.Seq)
+}
+
+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
+}

+ 5 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go

@@ -0,0 +1,5 @@
+package netlink
+
+func ifrDataByte(b byte) uint8 {
+	return uint8(b)
+}

+ 7 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go

@@ -0,0 +1,7 @@
+// +build !arm
+
+package netlink
+
+func ifrDataByte(b byte) int8 {
+	return int8(b)
+}

+ 408 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go

@@ -0,0 +1,408 @@
+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()
+
+	for _, addr := range addrs {
+		args := strings.SplitN(addr.String(), "/", 2)
+		if args[0] == ip.String() {
+			return true
+		}
+	}
+
+	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: %s", 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: %s", 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 TestNetworkLinkAddMacVtap(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	tl := struct {
+		name string
+		mode string
+	}{
+		name: "tstVtap",
+		mode: "private",
+	}
+	masterLink := testLink{"tstEth", "dummy"}
+
+	addLink(t, masterLink.name, masterLink.linkType)
+	defer deleteLink(t, masterLink.name)
+
+	if err := NetworkLinkAddMacVtap(masterLink.name, tl.name, tl.mode); err != nil {
+		t.Fatalf("Unable to create %#v MAC VTAP interface: %s", tl, err)
+	}
+
+	readLink(t, tl.name)
+}
+
+func TestAddDelNetworkIp(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	ifaceName := "lo"
+	ip := net.ParseIP("127.0.1.1")
+	mask := net.IPv4Mask(255, 255, 255, 255)
+	ipNet := &net.IPNet{IP: ip, Mask: mask}
+
+	iface, err := net.InterfaceByName(ifaceName)
+	if err != nil {
+		t.Skip("No 'lo' interface; skipping tests")
+	}
+
+	if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
+		t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
+	}
+
+	if !ipAssigned(iface, ip) {
+		t.Fatalf("Could not locate address '%s' in lo address list.", ip.String())
+	}
+
+	if err := NetworkLinkDelIp(iface, ip, ipNet); err != nil {
+		t.Fatalf("Could not delete IP address %s from interface %#v: %s", ip.String(), iface, err)
+	}
+
+	if ipAssigned(iface, ip) {
+		t.Fatalf("Located address '%s' in lo address list after removal.", ip.String())
+	}
+}
+
+func TestAddRouteSourceSelection(t *testing.T) {
+	tstIp := "127.1.1.1"
+	tl := testLink{name: "tstEth", linkType: "dummy"}
+
+	addLink(t, tl.name, tl.linkType)
+	defer deleteLink(t, tl.name)
+
+	ip := net.ParseIP(tstIp)
+	mask := net.IPv4Mask(255, 255, 255, 255)
+	ipNet := &net.IPNet{IP: ip, Mask: mask}
+
+	iface, err := net.InterfaceByName(tl.name)
+	if err != nil {
+		t.Fatalf("Lost created link %#v", tl)
+	}
+
+	if err := NetworkLinkAddIp(iface, ip, ipNet); err != nil {
+		t.Fatalf("Could not add IP address %s to interface %#v: %s", ip.String(), iface, err)
+	}
+
+	upLink(t, tl.name)
+	defer downLink(t, tl.name)
+
+	if err := AddRoute("127.0.0.0/8", tstIp, "", tl.name); err != nil {
+		t.Fatalf("Failed to add route with source address")
+	}
+}
+
+func TestCreateVethPair(t *testing.T) {
+	if testing.Short() {
+		return
+	}
+
+	var (
+		name1 = "veth1"
+		name2 = "veth2"
+	)
+
+	if err := NetworkCreateVethPair(name1, name2, 0); 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
+	}
+
+	name := "testbridge"
+
+	if err := CreateBridge(name, true); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := net.InterfaceByName(name); err != nil {
+		t.Fatal(err)
+	}
+
+	// cleanup and tests
+
+	if err := DeleteBridge(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 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 := SetMacAddress(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)
+	}
+}

+ 88 - 0
libnetwork/Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go

@@ -0,0 +1,88 @@
+// +build !linux
+
+package netlink
+
+import (
+	"errors"
+	"net"
+)
+
+var (
+	ErrNotImplemented = errors.New("not implemented")
+)
+
+func NetworkGetRoutes() ([]Route, error) {
+	return nil, ErrNotImplemented
+}
+
+func NetworkLinkAdd(name string, linkType string) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkDel(name string) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkUp(iface *net.Interface) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
+	return ErrNotImplemented
+}
+
+func AddRoute(destination, source, gateway, device string) error {
+	return ErrNotImplemented
+}
+
+func AddDefaultGw(ip, device string) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetMTU(iface *net.Interface, mtu int) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetTxQueueLen(iface *net.Interface, txQueueLen int) error {
+	return ErrNotImplemented
+}
+
+func NetworkCreateVethPair(name1, name2 string, txQueueLen int) error {
+	return ErrNotImplemented
+}
+
+func NetworkChangeName(iface *net.Interface, newName string) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetNsFd(iface *net.Interface, fd int) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetNsPid(iface *net.Interface, nspid int) error {
+	return ErrNotImplemented
+}
+
+func NetworkSetMaster(iface, master *net.Interface) error {
+	return ErrNotImplemented
+}
+
+func NetworkLinkDown(iface *net.Interface) error {
+	return ErrNotImplemented
+}
+
+func CreateBridge(name string, setMacAddr bool) error {
+	return ErrNotImplemented
+}
+
+func DeleteBridge(name string) error {
+	return ErrNotImplemented
+}
+
+func AddToBridge(iface, master *net.Interface) error {
+	return ErrNotImplemented
+}

+ 7 - 1
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md

@@ -43,13 +43,19 @@ import (
 )
 
 func main() {
-    mybridge := &netlink.Bridge{netlink.LinkAttrs{Name: "foo"}}
+    la := netlink.NewLinkAttrs()
+    la.Name = "foo"
+    mybridge := &netlink.Bridge{la}}
     _ := netlink.LinkAdd(mybridge)
     eth1, _ := netlink.LinkByName("eth1")
     netlink.LinkSetMaster(eth1, mybridge)
 }
 
 ```
+Note `NewLinkAttrs` constructor, it sets default values in structure. For now
+it sets only `TxQLen` to `-1`, so kernel will set default by itself. If you're
+using simple initialization(`LinkAttrs{Name: "foo"}`) `TxQLen` will be set to
+`0` unless you specify it like `LinkAttrs{Name: "foo", TxQLen: 1000}`.
 
 Add a new ip address to loopback:
 

+ 2 - 2
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go

@@ -14,8 +14,8 @@ type Addr struct {
 }
 
 // String returns $ip/$netmask $label
-func (addr Addr) String() string {
-	return fmt.Sprintf("%s %s", addr.IPNet, addr.Label)
+func (a Addr) String() string {
+	return fmt.Sprintf("%s %s", a.IPNet, a.Label)
 }
 
 // ParseAddr parses the string representation of an address in the

+ 16 - 2
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go

@@ -81,7 +81,7 @@ func AddrList(link Link, family int) ([]Addr, error) {
 		index = base.Index
 	}
 
-	res := make([]Addr, 0)
+	var res []Addr
 	for _, m := range msgs {
 		msg := nl.DeserializeIfAddrmsg(m)
 
@@ -95,11 +95,17 @@ func AddrList(link Link, family int) ([]Addr, error) {
 			return nil, err
 		}
 
+		var local, dst *net.IPNet
 		var addr Addr
 		for _, attr := range attrs {
 			switch attr.Attr.Type {
 			case syscall.IFA_ADDRESS:
-				addr.IPNet = &net.IPNet{
+				dst = &net.IPNet{
+					IP:   attr.Value,
+					Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
+				}
+			case syscall.IFA_LOCAL:
+				local = &net.IPNet{
 					IP:   attr.Value,
 					Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
 				}
@@ -107,6 +113,14 @@ func AddrList(link Link, family int) ([]Addr, error) {
 				addr.Label = string(attr.Value[:len(attr.Value)-1])
 			}
 		}
+
+		// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
+		if local != nil {
+			addr.IPNet = local
+		} else {
+			addr.IPNet = dst
+		}
+
 		res = append(res, addr)
 	}
 

+ 28 - 3
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go

@@ -10,16 +10,29 @@ type Link interface {
 	Type() string
 }
 
+type (
+	NsPid int
+	NsFd  int
+)
+
 // LinkAttrs represents data shared by most link types
 type LinkAttrs struct {
 	Index        int
 	MTU          int
-	TxQLen       uint32 // Transmit Queue Length
+	TxQLen       int // Transmit Queue Length
 	Name         string
 	HardwareAddr net.HardwareAddr
 	Flags        net.Flags
-	ParentIndex  int // index of the parent link device
-	MasterIndex  int // must be the index of a bridge
+	ParentIndex  int         // index of the parent link device
+	MasterIndex  int         // must be the index of a bridge
+	Namespace    interface{} // nil | NsPid | NsFd
+}
+
+// NewLinkAttrs returns LinkAttrs structure filled with default values
+func NewLinkAttrs() LinkAttrs {
+	return LinkAttrs{
+		TxQLen: -1,
+	}
 }
 
 // Device links cannot be created via netlink. These links
@@ -76,9 +89,21 @@ func (vlan *Vlan) Type() string {
 	return "vlan"
 }
 
+type MacvlanMode uint16
+
+const (
+	MACVLAN_MODE_DEFAULT MacvlanMode = iota
+	MACVLAN_MODE_PRIVATE
+	MACVLAN_MODE_VEPA
+	MACVLAN_MODE_BRIDGE
+	MACVLAN_MODE_PASSTHRU
+	MACVLAN_MODE_SOURCE
+)
+
 // Macvlan links have ParentIndex set in their Attrs()
 type Macvlan struct {
 	LinkAttrs
+	Mode MacvlanMode
 }
 
 func (macvlan *Macvlan) Attrs() *LinkAttrs {

+ 73 - 15
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go

@@ -13,6 +13,15 @@ import (
 var native = nl.NativeEndian()
 var lookupByDump = false
 
+var macvlanModes = [...]uint32{
+	0,
+	nl.MACVLAN_MODE_PRIVATE,
+	nl.MACVLAN_MODE_VEPA,
+	nl.MACVLAN_MODE_BRIDGE,
+	nl.MACVLAN_MODE_PASSTHRU,
+	nl.MACVLAN_MODE_SOURCE,
+}
+
 func ensureIndex(link *LinkAttrs) {
 	if link != nil && link.Index == 0 {
 		newlink, _ := LinkByName(link.Name)
@@ -39,7 +48,7 @@ func LinkSetUp(link Link) error {
 	return err
 }
 
-// LinkSetUp disables link device.
+// LinkSetDown disables link device.
 // Equivalent to: `ip link set $link down`
 func LinkSetDown(link Link) error {
 	base := link.Attrs()
@@ -67,7 +76,7 @@ func LinkSetMTU(link Link, mtu int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_MTU
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -91,7 +100,7 @@ func LinkSetName(link Link, name string) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_IFNAME
 	req.AddData(msg)
 
 	data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
@@ -112,7 +121,7 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_ADDRESS
 	req.AddData(msg)
 
 	data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
@@ -145,7 +154,7 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_MASTER
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -170,7 +179,7 @@ func LinkSetNsPid(link Link, nspid int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_NET_NS_PID
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -183,7 +192,7 @@ func LinkSetNsPid(link Link, nspid int) error {
 	return err
 }
 
-// LinkSetNsPid puts the device into a new network namespace. The
+// LinkSetNsFd puts the device into a new network namespace. The
 // fd must be an open file descriptor to a network namespace.
 // Similar to: `ip link set $link netns $ns`
 func LinkSetNsFd(link Link, fd int) error {
@@ -195,7 +204,7 @@ func LinkSetNsFd(link Link, fd int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = nl.IFLA_NET_NS_FD
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -312,11 +321,28 @@ func LinkAdd(link Link) error {
 		req.AddData(mtu)
 	}
 
+	if base.TxQLen >= 0 {
+		qlen := nl.NewRtAttr(syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
+		req.AddData(qlen)
+	}
+
+	if base.Namespace != nil {
+		var attr *nl.RtAttr
+		switch base.Namespace.(type) {
+		case NsPid:
+			val := nl.Uint32Attr(uint32(base.Namespace.(NsPid)))
+			attr = nl.NewRtAttr(syscall.IFLA_NET_NS_PID, val)
+		case NsFd:
+			val := nl.Uint32Attr(uint32(base.Namespace.(NsFd)))
+			attr = nl.NewRtAttr(nl.IFLA_NET_NS_FD, val)
+		}
+
+		req.AddData(attr)
+	}
+
 	linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
 	nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
 
-	nl.NewRtAttrChild(linkInfo, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
-
 	if vlan, ok := link.(*Vlan); ok {
 		b := make([]byte, 2)
 		native.PutUint16(b, uint16(vlan.VlanId))
@@ -327,15 +353,23 @@ func LinkAdd(link Link) error {
 		peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
 		nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
 		nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
-		nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
+		if base.TxQLen >= 0 {
+			nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen)))
+		}
 		if base.MTU > 0 {
 			nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
 		}
+
 	} else if vxlan, ok := link.(*Vxlan); ok {
 		addVxlanAttrs(vxlan, linkInfo)
 	} else if ipv, ok := link.(*IPVlan); ok {
 		data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
 		nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode)))
+	} else if macv, ok := link.(*Macvlan); ok {
+		if macv.Mode != MACVLAN_MODE_DEFAULT {
+			data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+			nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode]))
+		}
 	}
 
 	req.AddData(linkInfo)
@@ -483,6 +517,8 @@ func linkDeserialize(m []byte) (Link, error) {
 						link = &Vxlan{}
 					case "ipvlan":
 						link = &IPVlan{}
+					case "macvlan":
+						link = &Macvlan{}
 					default:
 						link = &Generic{LinkType: linkType}
 					}
@@ -498,6 +534,8 @@ func linkDeserialize(m []byte) (Link, error) {
 						parseVxlanData(link, data)
 					case "ipvlan":
 						parseIPVlanData(link, data)
+					case "macvlan":
+						parseMacvlanData(link, data)
 					}
 				}
 			}
@@ -520,7 +558,7 @@ func linkDeserialize(m []byte) (Link, error) {
 		case syscall.IFLA_MASTER:
 			base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
 		case syscall.IFLA_TXQLEN:
-			base.TxQLen = native.Uint32(attr.Value[0:4])
+			base.TxQLen = int(native.Uint32(attr.Value[0:4]))
 		}
 	}
 	// Links that don't have IFLA_INFO_KIND are hardware devices
@@ -547,8 +585,7 @@ func LinkList() ([]Link, error) {
 		return nil, err
 	}
 
-	res := make([]Link, 0)
-
+	var res []Link
 	for _, m := range msgs {
 		link, err := linkDeserialize(m)
 		if err != nil {
@@ -593,7 +630,7 @@ func setProtinfoAttr(link Link, mode bool, attr int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED
 	req.AddData(msg)
 
 	br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
@@ -674,6 +711,27 @@ func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
 	}
 }
 
+func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
+	macv := link.(*Macvlan)
+	for _, datum := range data {
+		if datum.Attr.Type == nl.IFLA_MACVLAN_MODE {
+			switch native.Uint32(datum.Value[0:4]) {
+			case nl.MACVLAN_MODE_PRIVATE:
+				macv.Mode = MACVLAN_MODE_PRIVATE
+			case nl.MACVLAN_MODE_VEPA:
+				macv.Mode = MACVLAN_MODE_VEPA
+			case nl.MACVLAN_MODE_BRIDGE:
+				macv.Mode = MACVLAN_MODE_BRIDGE
+			case nl.MACVLAN_MODE_PASSTHRU:
+				macv.Mode = MACVLAN_MODE_PASSTHRU
+			case nl.MACVLAN_MODE_SOURCE:
+				macv.Mode = MACVLAN_MODE_SOURCE
+			}
+			return
+		}
+	}
+}
+
 // copied from pkg/net_linux.go
 func linkFlags(rawFlags uint32) net.Flags {
 	var f net.Flags

+ 114 - 5
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go

@@ -8,7 +8,10 @@ import (
 	"github.com/vishvananda/netns"
 )
 
-const testTxQLen uint32 = 100
+const (
+	testTxQLen    int = 100
+	defaultTxQLen int = 1000
+)
 
 func testLinkAddDel(t *testing.T, link Link) {
 	links, err := LinkList()
@@ -50,9 +53,9 @@ func testLinkAddDel(t *testing.T, link Link) {
 		}
 	}
 
-	if veth, ok := link.(*Veth); ok {
-		if veth.TxQLen != testTxQLen {
-			t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, testTxQLen)
+	if veth, ok := result.(*Veth); ok {
+		if rBase.TxQLen != base.TxQLen {
+			t.Fatalf("qlen is %d, should be %d", rBase.TxQLen, base.TxQLen)
 		}
 		if rBase.MTU != base.MTU {
 			t.Fatalf("MTU is %d, should be %d", rBase.MTU, base.MTU)
@@ -91,6 +94,16 @@ func testLinkAddDel(t *testing.T, link Link) {
 		}
 	}
 
+	if macv, ok := link.(*Macvlan); ok {
+		other, ok := result.(*Macvlan)
+		if !ok {
+			t.Fatal("Result of create is not a macvlan")
+		}
+		if macv.Mode != other.Mode {
+			t.Fatalf("Got unexpected mode: %d, expected: %d", other.Mode, macv.Mode)
+		}
+	}
+
 	if err = LinkDel(link); err != nil {
 		t.Fatal(err)
 	}
@@ -199,7 +212,10 @@ func TestLinkAddDelMacvlan(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	testLinkAddDel(t, &Macvlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}})
+	testLinkAddDel(t, &Macvlan{
+		LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
+		Mode:      MACVLAN_MODE_PRIVATE,
+	})
 
 	if err := LinkDel(parent); err != nil {
 		t.Fatal(err)
@@ -213,6 +229,99 @@ func TestLinkAddDelVeth(t *testing.T) {
 	testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar"})
 }
 
+func TestLinkAddVethWithDefaultTxQLen(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+	la := NewLinkAttrs()
+	la.Name = "foo"
+
+	veth := &Veth{LinkAttrs: la, PeerName: "bar"}
+	if err := LinkAdd(veth); err != nil {
+		t.Fatal(err)
+	}
+	link, err := LinkByName("foo")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if veth, ok := link.(*Veth); !ok {
+		t.Fatalf("unexpected link type: %T", link)
+	} else {
+		if veth.TxQLen != defaultTxQLen {
+			t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, defaultTxQLen)
+		}
+	}
+	peer, err := LinkByName("bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if veth, ok := peer.(*Veth); !ok {
+		t.Fatalf("unexpected link type: %T", link)
+	} else {
+		if veth.TxQLen != defaultTxQLen {
+			t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, defaultTxQLen)
+		}
+	}
+}
+
+func TestLinkAddVethWithZeroTxQLen(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+	la := NewLinkAttrs()
+	la.Name = "foo"
+	la.TxQLen = 0
+
+	veth := &Veth{LinkAttrs: la, PeerName: "bar"}
+	if err := LinkAdd(veth); err != nil {
+		t.Fatal(err)
+	}
+	link, err := LinkByName("foo")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if veth, ok := link.(*Veth); !ok {
+		t.Fatalf("unexpected link type: %T", link)
+	} else {
+		if veth.TxQLen != 0 {
+			t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, 0)
+		}
+	}
+	peer, err := LinkByName("bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if veth, ok := peer.(*Veth); !ok {
+		t.Fatalf("unexpected link type: %T", link)
+	} else {
+		if veth.TxQLen != 0 {
+			t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, 0)
+		}
+	}
+}
+
+func TestLinkAddDummyWithTxQLen(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+	la := NewLinkAttrs()
+	la.Name = "foo"
+	la.TxQLen = 1500
+
+	dummy := &Dummy{LinkAttrs: la}
+	if err := LinkAdd(dummy); err != nil {
+		t.Fatal(err)
+	}
+	link, err := LinkByName("foo")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if dummy, ok := link.(*Dummy); !ok {
+		t.Fatalf("unexpected link type: %T", link)
+	} else {
+		if dummy.TxQLen != 1500 {
+			t.Fatalf("TxQLen is %d, should be %d", dummy.TxQLen, 1500)
+		}
+	}
+}
+
 func TestLinkAddDelBridgeMaster(t *testing.T) {
 	tearDown := setUpNetlinkTest(t)
 	defer tearDown()

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go

@@ -141,7 +141,7 @@ func NeighList(linkIndex, family int) ([]Neigh, error) {
 		return nil, err
 	}
 
-	res := make([]Neigh, 0)
+	var res []Neigh
 	for _, m := range msgs {
 		ndm := deserializeNdmsg(m)
 		if linkIndex != 0 && int(ndm.Index) != linkIndex {

+ 15 - 0
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go

@@ -79,3 +79,18 @@ const (
 	// not defined in syscall
 	IFLA_NET_NS_FD = 28
 )
+
+const (
+	IFLA_MACVLAN_UNSPEC = iota
+	IFLA_MACVLAN_MODE
+	IFLA_MACVLAN_FLAGS
+	IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS
+)
+
+const (
+	MACVLAN_MODE_PRIVATE  = 1
+	MACVLAN_MODE_VEPA     = 2
+	MACVLAN_MODE_BRIDGE   = 4
+	MACVLAN_MODE_PASSTHRU = 8
+	MACVLAN_MODE_SOURCE   = 16
+)

+ 11 - 11
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go

@@ -172,16 +172,16 @@ type NetlinkRequest struct {
 }
 
 // Serialize the Netlink Request into a byte array
-func (msg *NetlinkRequest) Serialize() []byte {
+func (req *NetlinkRequest) Serialize() []byte {
 	length := syscall.SizeofNlMsghdr
-	dataBytes := make([][]byte, len(msg.Data))
-	for i, data := range msg.Data {
+	dataBytes := make([][]byte, len(req.Data))
+	for i, data := range req.Data {
 		dataBytes[i] = data.Serialize()
 		length = length + len(dataBytes[i])
 	}
-	msg.Len = uint32(length)
+	req.Len = uint32(length)
 	b := make([]byte, length)
-	hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(msg)))[:]
+	hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(req)))[:]
 	next := syscall.SizeofNlMsghdr
 	copy(b[0:next], hdr)
 	for _, data := range dataBytes {
@@ -193,9 +193,9 @@ func (msg *NetlinkRequest) Serialize() []byte {
 	return b
 }
 
-func (msg *NetlinkRequest) AddData(data NetlinkRequestData) {
+func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
 	if data != nil {
-		msg.Data = append(msg.Data, data)
+		req.Data = append(req.Data, data)
 	}
 }
 
@@ -218,11 +218,11 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
 		return nil, err
 	}
 
-	res := make([][]byte, 0)
+	var res [][]byte
 
 done:
 	for {
-		msgs, err := s.Recieve()
+		msgs, err := s.Receive()
 		if err != nil {
 			return nil, err
 		}
@@ -294,7 +294,7 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
 
 // Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
 // and subscribe it to multicast groups passed in variable argument list.
-// Returns the netlink socket on whic hReceive() method can be called
+// Returns the netlink socket on which Receive() method can be called
 // to retrieve the messages from the kernel.
 func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
 	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
@@ -329,7 +329,7 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
 	return nil
 }
 
-func (s *NetlinkSocket) Recieve() ([]syscall.NetlinkMessage, error) {
+func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
 	rb := make([]byte, syscall.Getpagesize())
 	nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
 	if err != nil {

+ 3 - 4
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go

@@ -104,9 +104,8 @@ func (x *XfrmAddress) ToIPNet(prefixlen uint8) *net.IPNet {
 	ip := x.ToIP()
 	if GetIPFamily(ip) == FAMILY_V4 {
 		return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 32)}
-	} else {
-		return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
 	}
+	return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
 }
 
 func (x *XfrmAddress) FromIP(ip net.IP) {
@@ -125,8 +124,8 @@ func DeserializeXfrmAddress(b []byte) *XfrmAddress {
 	return (*XfrmAddress)(unsafe.Pointer(&b[0:SizeofXfrmAddress][0]))
 }
 
-func (msg *XfrmAddress) Serialize() []byte {
-	return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(msg)))[:]
+func (x *XfrmAddress) Serialize() []byte {
+	return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(x)))[:]
 }
 
 // struct xfrm_selector {

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go

@@ -16,7 +16,7 @@ type Protinfo struct {
 
 // String returns a list of enabled flags
 func (prot *Protinfo) String() string {
-	boolStrings := make([]string, 0)
+	var boolStrings []string
 	if prot.Hairpin {
 		boolStrings = append(boolStrings, "Hairpin")
 	}

+ 2 - 2
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go

@@ -119,7 +119,7 @@ func RouteList(link Link, family int) ([]Route, error) {
 	}
 
 	native := nl.NativeEndian()
-	res := make([]Route, 0)
+	var res []Route
 	for _, m := range msgs {
 		msg := nl.DeserializeRtMsg(m)
 
@@ -193,7 +193,7 @@ func RouteGet(destination net.IP) ([]Route, error) {
 	}
 
 	native := nl.NativeEndian()
-	res := make([]Route, 0)
+	var res []Route
 	for _, m := range msgs {
 		msg := nl.DeserializeRtMsg(m)
 		attrs, err := nl.ParseRouteAttr(m[msg.Len():])

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go

@@ -84,7 +84,7 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
 		return nil, err
 	}
 
-	res := make([]XfrmPolicy, 0)
+	var res []XfrmPolicy
 	for _, m := range msgs {
 		msg := nl.DeserializeXfrmUserpolicyInfo(m)
 

+ 1 - 1
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go

@@ -118,7 +118,7 @@ func XfrmStateList(family int) ([]XfrmState, error) {
 		return nil, err
 	}
 
-	res := make([]XfrmState, 0)
+	var res []XfrmState
 	for _, m := range msgs {
 		msg := nl.DeserializeXfrmUsersaInfo(m)
 

+ 36 - 11
libnetwork/drivers/bridge/bridge.go

@@ -2,12 +2,14 @@ package bridge
 
 import (
 	"errors"
+	"fmt"
 	"net"
 	"os/exec"
 	"strconv"
 	"sync"
 
 	"github.com/Sirupsen/logrus"
+	bri "github.com/docker/libcontainer/netlink"
 	"github.com/docker/libnetwork/driverapi"
 	"github.com/docker/libnetwork/ipallocator"
 	"github.com/docker/libnetwork/iptables"
@@ -754,6 +756,20 @@ func (d *driver) DeleteNetwork(nid types.UUID) error {
 	return err
 }
 
+func addToBridge(ifaceName, bridgeName string) error {
+	iface, err := net.InterfaceByName(ifaceName)
+	if err != nil {
+		return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
+	}
+
+	master, err := net.InterfaceByName(bridgeName)
+	if err != nil {
+		return fmt.Errorf("could not find bridge %s: %v", bridgeName, err)
+	}
+
+	return bri.AddToBridge(iface, master)
+}
+
 func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointInfo, epOptions map[string]interface{}) error {
 	var (
 		ipv6Addr *net.IPNet
@@ -821,27 +837,27 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	}()
 
 	// Generate a name for what will be the host side pipe interface
-	name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	hostIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
 	if err != nil {
 		return err
 	}
 
 	// Generate a name for what will be the sandbox side pipe interface
-	name2, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
+	containerIfName, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
 	if err != nil {
 		return err
 	}
 
 	// Generate and add the interface pipe host <-> sandbox
 	veth := &netlink.Veth{
-		LinkAttrs: netlink.LinkAttrs{Name: name1, TxQLen: 0},
-		PeerName:  name2}
+		LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
+		PeerName:  containerIfName}
 	if err = netlink.LinkAdd(veth); err != nil {
 		return err
 	}
 
 	// Get the host side pipe interface handler
-	host, err := netlink.LinkByName(name1)
+	host, err := netlink.LinkByName(hostIfName)
 	if err != nil {
 		return err
 	}
@@ -852,7 +868,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	}()
 
 	// Get the sandbox side pipe interface handler
-	sbox, err := netlink.LinkByName(name2)
+	sbox, err := netlink.LinkByName(containerIfName)
 	if err != nil {
 		return err
 	}
@@ -879,9 +895,8 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	}
 
 	// Attach host side pipe interface into the bridge
-	if err = netlink.LinkSetMaster(host,
-		&netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName}}); err != nil {
-		return err
+	if err = addToBridge(hostIfName, config.BridgeName); err != nil {
+		return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
 	}
 
 	if !config.EnableUserlandProxy {
@@ -898,14 +913,24 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	}
 	ipv4Addr := &net.IPNet{IP: ip4, Mask: n.bridge.bridgeIPv4.Mask}
 
+	// Down the interface before configuring mac address.
+	if err := netlink.LinkSetDown(sbox); err != nil {
+		return fmt.Errorf("could not set link down for container interface %s: %v", containerIfName, err)
+	}
+
 	// Set the sbox's MAC. If specified, use the one configured by user, otherwise generate one based on IP.
 	mac := electMacAddress(epConfig, ip4)
 	err = netlink.LinkSetHardwareAddr(sbox, mac)
 	if err != nil {
-		return err
+		return fmt.Errorf("could not set mac address for container interface %s: %v", containerIfName, err)
 	}
 	endpoint.macAddress = mac
 
+	// Up the host interface after finishing all netlink configuration
+	if err := netlink.LinkSetUp(host); err != nil {
+		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
+	}
+
 	// v6 address for the sandbox side pipe interface
 	ipv6Addr = &net.IPNet{}
 	if config.EnableIPv6 {
@@ -934,7 +959,7 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
 	}
 
 	// Create the sandbox side pipe interface
-	endpoint.srcName = name2
+	endpoint.srcName = containerIfName
 	endpoint.addr = ipv4Addr
 
 	if config.EnableIPv6 {

+ 5 - 10
libnetwork/drivers/bridge/setup_device.go

@@ -1,15 +1,15 @@
 package bridge
 
 import (
-	log "github.com/Sirupsen/logrus"
 	"github.com/docker/docker/pkg/parsers/kernel"
-	"github.com/docker/libnetwork/netutils"
-	"github.com/docker/libnetwork/types"
+	bri "github.com/docker/libcontainer/netlink"
 	"github.com/vishvananda/netlink"
 )
 
 // SetupDevice create a new bridge interface/
 func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
+	var setMac bool
+
 	// We only attempt to create the bridge when the requested device name is
 	// the default one.
 	if config.BridgeName != DefaultBridgeName && !config.AllowNonDefaultBridge {
@@ -27,15 +27,10 @@ func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
 	// was not supported before that.
 	kv, err := kernel.GetKernelVersion()
 	if err == nil && (kv.Kernel >= 3 && kv.Major >= 3) {
-		i.Link.Attrs().HardwareAddr = netutils.GenerateRandomMAC()
-		log.Debugf("Setting bridge mac address to %s", i.Link.Attrs().HardwareAddr)
+		setMac = true
 	}
 
-	// Call out to netlink to create the device.
-	if err = netlink.LinkAdd(i.Link); err != nil {
-		return types.InternalErrorf("Failed to program bridge link: %s", err.Error())
-	}
-	return nil
+	return bri.CreateBridge(config.BridgeName, setMac)
 }
 
 // SetupDeviceUp ups the given bridge interface.

+ 5 - 1
libnetwork/drivers/host/host.go

@@ -57,7 +57,11 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
 
 // Join method is invoked when a Sandbox is attached to an endpoint.
 func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
-	return (jinfo.SetHostsPath("/etc/hosts"))
+	if err := jinfo.SetHostsPath("/etc/hosts"); err != nil {
+		return err
+	}
+
+	return jinfo.SetResolvConfPath("/etc/resolv.conf")
 }
 
 // Leave method is invoked when a Sandbox detaches from an endpoint.

+ 1 - 1
libnetwork/drivers/overlay/ov_network.go

@@ -155,7 +155,7 @@ func (n *network) initSandbox() error {
 
 func (n *network) watchMiss(nlSock *nl.NetlinkSocket) {
 	for {
-		msgs, err := nlSock.Recieve()
+		msgs, err := nlSock.Receive()
 		if err != nil {
 			logrus.Errorf("Failed to receive from netlink: %v ", err)
 			continue

+ 18 - 0
libnetwork/endpoint.go

@@ -811,9 +811,19 @@ func (ep *endpoint) updateDNS(resolvConf []byte) error {
 	return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
 }
 
+func copyFile(src, dst string) error {
+	sBytes, err := ioutil.ReadFile(src)
+	if err != nil {
+		return err
+	}
+
+	return ioutil.WriteFile(dst, sBytes, 0644)
+}
+
 func (ep *endpoint) setupDNS() error {
 	ep.Lock()
 	container := ep.container
+	joinInfo := ep.joinInfo
 	ep.Unlock()
 
 	if container == nil {
@@ -830,6 +840,14 @@ func (ep *endpoint) setupDNS() error {
 		return err
 	}
 
+	if joinInfo.resolvConfPath != "" {
+		if err := copyFile(joinInfo.resolvConfPath, container.config.resolvConfPath); err != nil {
+			return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", joinInfo.resolvConfPath, container.config.resolvConfPath, err)
+		}
+
+		return nil
+	}
+
 	resolvConf, err := resolvconf.Get()
 	if err != nil {
 		return err

+ 68 - 0
libnetwork/libnetwork_test.go

@@ -1564,6 +1564,74 @@ func TestEnableIPv6(t *testing.T) {
 	}
 }
 
+func TestResolvConfHost(t *testing.T) {
+	if !netutils.IsRunningInContainer() {
+		defer netutils.SetupTestNetNS(t)()
+	}
+
+	tmpResolvConf := []byte("search localhost.net\nnameserver 127.0.0.1\nnameserver 2001:4860:4860::8888")
+
+	//take a copy of resolv.conf for restoring after test completes
+	resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
+	if err != nil {
+		t.Fatal(err)
+	}
+	//cleanup
+	defer func() {
+		if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	n, err := controller.NetworkByName("testhost")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ep1, err := n.CreateEndpoint("ep1", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	resolvConfPath := "/tmp/libnetwork_test/resolv.conf"
+	defer os.Remove(resolvConfPath)
+
+	err = ep1.Join(containerID,
+		libnetwork.JoinOptionResolvConfPath(resolvConfPath))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		err = ep1.Leave(containerID)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	finfo, err := os.Stat(resolvConfPath)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	fmode := (os.FileMode)(0644)
+	if finfo.Mode() != fmode {
+		t.Fatalf("Expected file mode %s, got %s", fmode.String(), finfo.Mode().String())
+	}
+
+	content, err := ioutil.ReadFile(resolvConfPath)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !bytes.Equal(content, tmpResolvConf) {
+		t.Fatalf("Expected %s, Got %s", string(tmpResolvConf), string(content))
+	}
+}
+
 func TestResolvConf(t *testing.T) {
 	if !netutils.IsRunningInContainer() {
 		defer netutils.SetupTestNetNS(t)()