소스 검색

Switching to Vish's netlink library

This is in preparation for merging vxlan branch that uses
Vish's netlink library. This library is better designed
and now supports vxlan devices.
Eugene Yakubovich 10 년 전
부모
커밋
bc080e891d
56개의 변경된 파일5279개의 추가작업 그리고 1208개의 파일을 삭제
  1. 5 6
      Godeps/Godeps.json
  2. 0 2
      Godeps/_workspace/src/github.com/docker/libcontainer/netlink/MAINTAINERS
  3. 0 23
      Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink.go
  4. 0 1002
      Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux.go
  5. 0 9
      Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_arm.go
  6. 0 11
      Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_notarm.go
  7. 0 55
      Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_linux_test.go
  8. 0 76
      Godeps/_workspace/src/github.com/docker/libcontainer/netlink/netlink_unsupported.go
  9. 192 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/LICENSE
  10. 81 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/README.md
  11. 43 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go
  12. 114 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go
  13. 45 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/addr_test.go
  14. 154 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/link.go
  15. 549 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go
  16. 387 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go
  17. 22 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/neigh.go
  18. 189 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go
  19. 102 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go
  20. 39 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go
  21. 33 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_test.go
  22. 119 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go
  23. 48 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go
  24. 39 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux_test.go
  25. 56 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go
  26. 414 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go
  27. 60 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux_test.go
  28. 34 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go
  29. 43 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux_test.go
  30. 259 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go
  31. 161 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux_test.go
  32. 120 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go
  33. 109 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux_test.go
  34. 222 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go
  35. 207 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux_test.go
  36. 35 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/route.go
  37. 166 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go
  38. 53 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/route_test.go
  39. 64 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go
  40. 59 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go
  41. 127 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go
  42. 49 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_test.go
  43. 54 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go
  44. 181 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go
  45. 50 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_test.go
  46. 192 0
      Godeps/_workspace/src/github.com/vishvananda/netns/LICENSE
  47. 49 0
      Godeps/_workspace/src/github.com/vishvananda/netns/README.md
  48. 242 0
      Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux.go
  49. 5 0
      Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux_386.go
  50. 5 0
      Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux_amd.go
  51. 5 0
      Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux_arm.go
  52. 37 0
      Godeps/_workspace/src/github.com/vishvananda/netns/netns_test.go
  53. 35 0
      Godeps/_workspace/src/github.com/vishvananda/netns/netns_unspecified.go
  54. 15 14
      backend/udp/udp.go
  55. 6 5
      pkg/ip/iface.go
  56. 4 5
      pkg/ip/tun.go

+ 5 - 6
Godeps/Godeps.json

@@ -1,6 +1,6 @@
 {
 	"ImportPath": "github.com/coreos/flannel",
-	"GoVersion": "go1.2.2",
+	"GoVersion": "go1.3.1",
 	"Packages": [
 		"./..."
 	],
@@ -15,14 +15,13 @@
 			"Comment": "v2-26-ga606a1e",
 			"Rev": "a606a1e936df81b70d85448221c7b1c6d8a74ef1"
 		},
-		{
-			"ImportPath": "github.com/docker/libcontainer/netlink",
-			"Comment": "v1.1.0-131-g164cd80",
-			"Rev": "164cd807a16e63ed539cddda55ce3bbc32e1791e"
-		},
 		{
 			"ImportPath": "github.com/golang/glog",
 			"Rev": "d1c4472bf2efd3826f2b5bdcc02d8416798d678c"
+		},
+		{
+			"ImportPath": "github.com/vishvananda/netlink",
+			"Rev": "dd2d5f17ae986599e165402a77c7e85fea606bec"
 		}
 	]
 }

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

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

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

@@ -1,23 +0,0 @@
-// 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")
-)
-
-// A Route is a subnet associated with the interface to reach it.
-type Route struct {
-	*net.IPNet
-	Iface   *net.Interface
-	Default bool
-}

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

@@ -1,1002 +0,0 @@
-package netlink
-
-import (
-	"encoding/binary"
-	"fmt"
-	"net"
-	"sync/atomic"
-	"syscall"
-	"unsafe"
-)
-
-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
-)
-
-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
-}
-
-func nativeEndian() binary.ByteOrder {
-	var x uint32 = 0x01020304
-	if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
-		return binary.BigEndian
-	}
-	return 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 {
-	native := nativeEndian()
-
-	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 {
-	native := nativeEndian()
-
-	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 {
-	native := nativeEndian()
-
-	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 {
-	l := 0
-	for _, child := range a.children {
-		l += child.Len() + syscall.SizeofRtAttr
-	}
-	if l == 0 {
-		l++
-	}
-	return rtaAlignOf(l + len(a.Data))
-}
-
-func (a *RtAttr) ToWireFormat() []byte {
-	native := nativeEndian()
-
-	length := a.Len()
-	buf := make([]byte, rtaAlignOf(length+syscall.SizeofRtAttr))
-
-	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(rtaAlignOf(length)); l != 0 {
-		native.PutUint16(buf[0:2], l+1)
-	}
-	native.PutUint16(buf[2:4], a.Type)
-
-	return buf
-}
-
-type NetlinkRequest struct {
-	syscall.NlMsghdr
-	Data []NetlinkRequestData
-}
-
-func (rr *NetlinkRequest) ToWireFormat() []byte {
-	native := nativeEndian()
-
-	length := rr.Len
-	dataBytes := make([][]byte, len(rr.Data))
-	for i, data := range rr.Data {
-		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) HandleAck(seq uint32) error {
-	native := nativeEndian()
-
-	pid, err := s.GetPid()
-	if err != nil {
-		return err
-	}
-
-done:
-	for {
-		msgs, err := s.Receive()
-		if err != nil {
-			return err
-		}
-		for _, m := range msgs {
-			if m.Header.Seq != seq {
-				return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, seq)
-			}
-			if m.Header.Pid != pid {
-				return fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
-			}
-			if m.Header.Type == syscall.NLMSG_DONE {
-				break done
-			}
-			if m.Header.Type == syscall.NLMSG_ERROR {
-				error := int32(native.Uint32(m.Data[0:4]))
-				if error == 0 {
-					break done
-				}
-				return syscall.Errno(-error)
-			}
-		}
-	}
-
-	return 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, srcNet, err := net.ParseCIDR(source)
-		if err != nil {
-			return fmt.Errorf("source CIDR %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
-		srcLen, bits := srcNet.Mask.Size()
-		if srcLen == 0 && bits == 0 {
-			return fmt.Errorf("source CIDR %s generated a non-canonical Mask", source)
-		}
-		msg.Family = uint8(srcFamily)
-		msg.Src_len = uint8(srcLen)
-		var srcData []byte
-		if srcFamily == syscall.AF_INET {
-			srcData = srcIP.To4()
-		} else {
-			srcData = srcIP.To16()
-		}
-		rtAttrs = append(rtAttrs, newRtAttr(syscall.RTA_SRC, 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)
-	}
-
-	var (
-		native = nativeEndian()
-		b      = make([]byte, 4)
-	)
-	iface, err := net.InterfaceByName(device)
-	if err != nil {
-		return err
-	}
-	native.PutUint32(b, uint32(iface.Index))
-
-	wb.AddData(newRtAttr(syscall.RTA_OIF, b))
-
-	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)
-}
-
-// 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)
-
-	var (
-		b      = make([]byte, 4)
-		native = nativeEndian()
-	)
-	native.PutUint32(b, uint32(mtu))
-
-	data := newRtAttr(syscall.IFLA_MTU, b)
-	wb.AddData(data)
-
-	if err := s.Send(wb); err != nil {
-		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)
-
-	var (
-		b      = make([]byte, 4)
-		native = nativeEndian()
-	)
-	native.PutUint32(b, uint32(master.Index))
-
-	data := newRtAttr(syscall.IFLA_MASTER, b)
-	wb.AddData(data)
-
-	if err := s.Send(wb); err != nil {
-		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)
-
-	var (
-		b      = make([]byte, 4)
-		native = nativeEndian()
-	)
-	native.PutUint32(b, uint32(nspid))
-
-	data := newRtAttr(syscall.IFLA_NET_NS_PID, b)
-	wb.AddData(data)
-
-	if err := s.Send(wb); err != nil {
-		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)
-
-	var (
-		b      = make([]byte, 4)
-		native = nativeEndian()
-	)
-	native.PutUint32(b, uint32(fd))
-
-	data := newRtAttr(IFLA_NET_NS_FD, b)
-	wb.AddData(data)
-
-	if err := s.Send(wb); err != nil {
-		return err
-	}
-
-	return s.HandleAck(wb.Seq)
-}
-
-// 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 {
-	s, err := getNetlinkSocket()
-	if err != nil {
-		return err
-	}
-	defer s.Close()
-
-	family := getIpFamily(ip)
-
-	wb := newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
-
-	msg := newIfAddrmsg(family)
-	msg.Index = uint32(iface.Index)
-	prefixLen, _ := ipNet.Mask.Size()
-	msg.Prefixlen = uint8(prefixLen)
-	wb.AddData(msg)
-
-	var ipData []byte
-	if family == syscall.AF_INET {
-		ipData = ip.To4()
-	} else {
-		ipData = 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)
-}
-
-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 {
-	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)
-
-	if name != "" {
-		nameData := newRtAttr(syscall.IFLA_IFNAME, zeroTerminated(name))
-		wb.AddData(nameData)
-	}
-
-	kindData := newRtAttr(IFLA_INFO_KIND, nonZeroTerminated(linkType))
-
-	infoData := newRtAttr(syscall.IFLA_LINKINFO, kindData.ToWireFormat())
-	wb.AddData(infoData)
-
-	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) {
-	native := nativeEndian()
-
-	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)
-
-done:
-	for {
-		msgs, err := s.Receive()
-		if err != nil {
-			return nil, err
-		}
-		for _, m := range msgs {
-			if m.Header.Seq != wb.Seq {
-				return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
-			}
-			if m.Header.Pid != pid {
-				return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
-			}
-			if m.Header.Type == syscall.NLMSG_DONE {
-				break done
-			}
-			if m.Header.Type == syscall.NLMSG_ERROR {
-				error := int32(native.Uint32(m.Data[0:4]))
-				if error == 0 {
-					break done
-				}
-				return nil, syscall.Errno(-error)
-			}
-			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
-}
-
-func getIfSocket() (fd int, err error) {
-	for _, socket := range []int{
-		syscall.AF_INET,
-		syscall.AF_PACKET,
-		syscall.AF_INET6,
-	} {
-		if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
-			break
-		}
-	}
-	if err == nil {
-		return fd, nil
-	}
-	return -1, err
-}
-
-func 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 {
-	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 setBridgeMacAddress(s, name)
-	}
-	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 setBridgeMacAddress(s int, name string) error {
-	if len(name) >= IFNAMSIZ {
-		return fmt.Errorf("Interface name %s too long", name)
-	}
-
-	ifr := ifreqHwaddr{}
-	ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
-	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
-
-	for i := 0; i < 6; i++ {
-		ifr.IfruHwaddr.Data[i] = randIfrDataByte()
-	}
-
-	ifr.IfruHwaddr.Data[0] &^= 0x1 // clear multicast bit
-	ifr.IfruHwaddr.Data[0] |= 0x2  // set local assignment bit (IEEE802)
-
-	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
-		return err
-	}
-	return nil
-}

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

@@ -1,9 +0,0 @@
-package netlink
-
-import (
-	"math/rand"
-)
-
-func randIfrDataByte() uint8 {
-	return uint8(rand.Intn(255))
-}

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

@@ -1,11 +0,0 @@
-// +build !arm
-
-package netlink
-
-import (
-	"math/rand"
-)
-
-func randIfrDataByte() int8 {
-	return int8(rand.Intn(255))
-}

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

@@ -1,55 +0,0 @@
-package netlink
-
-import (
-	"net"
-	"testing"
-)
-
-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.Fatal("expected error getting interface because bridge was deleted")
-	}
-}
-
-func TestCreateVethPair(t *testing.T) {
-	if testing.Short() {
-		return
-	}
-
-	var (
-		name1 = "veth1"
-		name2 = "veth2"
-	)
-
-	if err := NetworkCreateVethPair(name1, name2); err != nil {
-		t.Fatal(err)
-	}
-
-	if _, err := net.InterfaceByName(name1); err != nil {
-		t.Fatal(err)
-	}
-
-	if _, err := net.InterfaceByName(name2); err != nil {
-		t.Fatal(err)
-	}
-}

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

@@ -1,76 +0,0 @@
-// +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 NetworkLinkUp(iface *net.Interface) error {
-	return ErrNotImplemented
-}
-
-func NetworkLinkAddIp(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 NetworkCreateVethPair(name1, name2 string) 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
-}

+ 192 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/LICENSE

@@ -0,0 +1,192 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2014 Vishvananda Ishaya.
+   Copyright 2014 Docker, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 81 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/README.md

@@ -0,0 +1,81 @@
+# netlink - netlink library for go #
+
+The netlink package provides a simple netlink library for go. Netlink
+is the interface a user-space program in linux uses to communicate with
+the kernel. It can be used to add and remove interfaces, set ip addresses
+and routes, and configure ipsec. Netlink communication requires elevated
+privileges, so in most cases this code needs to be run as root. Since
+low-level netlink messages are inscrutable at best, the library attempts
+to provide an api that is loosely modeled on the CLI provied by iproute2.
+Actions like `ip link add` will be accomplished via a similarly named
+function like AddLink(). This library began its life as a fork of the
+netlink functionality in
+[docker/libcontainer](https://github.com/docker/libcontainer) but was
+heavily rewritten to improve testability, performance, and to add new
+functionality like ipsec xfrm handling.
+
+## Local Build and Test ##
+
+You can use go get command:
+
+    go get github.com/vishvananda/netlink
+
+Testing dependencies:
+
+    go get github.com/vishvananda/netns
+
+Testing (requires root):
+
+    sudo -E go test github.com/vishvananda/netlink
+
+## Examples ##
+
+Add a new bridge and add eth1 into it:
+
+```go
+package main
+
+import (
+    "net"
+    "github.com/vishvananada/netlink"
+)
+
+func main() {
+    mybridge := &netlink.Link{Name: "mybridge", Type: "bridge"}
+    netlink, _ := netlink.LinkAdd(mybridge)
+    eth1, _ := netlink.LinkByName("eth1")
+    netlink.LinkSetMaster(eth1, mybridge)
+}
+
+```
+
+Add a new ip address to loopback:
+
+```go
+package main
+
+import (
+    "net"
+    "github.com/vishvananada/netlink"
+)
+
+func main() {
+    lo, _ := netlink.LinkByName("lo")
+    addr, _ := netlink.ParseAddr("169.254.169.254/32")
+    netlink.AddrAdd(lo, addr)
+}
+
+```
+
+## Future Work ##
+
+Many pieces of netlink are not yet fully supported in the high-level
+interface. Aspects of virtually all of the high-level objects don't exist.
+Many of the underlying primitives are there, so its a matter of putting
+the right fields into the high-level objects and making sure that they
+are serialized and deserialized correctly in the Add and List methods.
+
+There are also a few pieces of low level netlink functionality that still
+need to be implemented. Routing rules are not in place and some of the
+more advanced link types. Hopefully there is decent structure and testing
+in place to make these fairly straightforward to add.

+ 43 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/addr.go

@@ -0,0 +1,43 @@
+package netlink
+
+import (
+	"fmt"
+	"net"
+	"strings"
+)
+
+// Addr represents an IP address from netlink. Netlink ip addresses
+// include a mask, so it stores the address as a net.IPNet.
+type Addr struct {
+	*net.IPNet
+	Label string
+}
+
+// String returns $ip/$netmask $label
+func (addr Addr) String() string {
+	return fmt.Sprintf("%s %s", addr.IPNet, addr.Label)
+}
+
+// ParseAddr parses the string representation of an address in the
+// form $ip/$netmask $label. The label portion is optional
+func ParseAddr(s string) (*Addr, error) {
+	label := ""
+	parts := strings.Split(s, " ")
+	if len(parts) > 1 {
+		s = parts[0]
+		label = parts[1]
+	}
+	m, err := ParseIPNet(s)
+	if err != nil {
+		return nil, err
+	}
+	return &Addr{IPNet: m, Label: label}, nil
+}
+
+// Equal returns true if both Addrs have the same net.IPNet value.
+func (a Addr) Equal(x Addr) bool {
+	sizea, _ := a.Mask.Size()
+	sizeb, _ := x.Mask.Size()
+	// ignore label for comparison
+	return a.IP.Equal(x.IP) && sizea == sizeb
+}

+ 114 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go

@@ -0,0 +1,114 @@
+package netlink
+
+import (
+	"fmt"
+	"net"
+	"strings"
+	"syscall"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+// AddrAdd will add an IP address to a link device.
+// Equivalent to: `ip addr del $addr dev $link`
+func AddrAdd(link Link, addr *Addr) error {
+
+	req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	return addrHandle(link, addr, req)
+}
+
+// AddrDel will delete an IP address from a link device.
+// Equivalent to: `ip addr del $addr dev $link`
+func AddrDel(link Link, addr *Addr) error {
+	req := nl.NewNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
+	return addrHandle(link, addr, req)
+}
+
+func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
+	base := link.Attrs()
+	if addr.Label != "" && !strings.HasPrefix(addr.Label, base.Name) {
+		return fmt.Errorf("label must begin with interface name")
+	}
+	ensureIndex(base)
+
+	family := nl.GetIPFamily(addr.IP)
+
+	msg := nl.NewIfAddrmsg(family)
+	msg.Index = uint32(base.Index)
+	prefixlen, _ := addr.Mask.Size()
+	msg.Prefixlen = uint8(prefixlen)
+	req.AddData(msg)
+
+	var addrData []byte
+	if family == FAMILY_V4 {
+		addrData = addr.IP.To4()
+	} else {
+		addrData = addr.IP.To16()
+	}
+
+	localData := nl.NewRtAttr(syscall.IFA_LOCAL, addrData)
+	req.AddData(localData)
+
+	addressData := nl.NewRtAttr(syscall.IFA_ADDRESS, addrData)
+	req.AddData(addressData)
+
+	if addr.Label != "" {
+		labelData := nl.NewRtAttr(syscall.IFA_LABEL, nl.ZeroTerminated(addr.Label))
+		req.AddData(labelData)
+	}
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// AddrList gets a list of IP addresses in the system.
+// Equivalent to: `ip addr show`.
+// The list can be filtered by link and ip family.
+func AddrList(link Link, family int) ([]Addr, error) {
+	req := nl.NewNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
+	msg := nl.NewIfInfomsg(family)
+	req.AddData(msg)
+
+	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWADDR)
+	if err != nil {
+		return nil, err
+	}
+
+	index := 0
+	if link != nil {
+		base := link.Attrs()
+		ensureIndex(base)
+		index = base.Index
+	}
+
+	res := make([]Addr, 0)
+	for _, m := range msgs {
+		msg := nl.DeserializeIfAddrmsg(m)
+
+		if link != nil && msg.Index != uint32(index) {
+			// Ignore messages from other interfaces
+			continue
+		}
+
+		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+		if err != nil {
+			return nil, err
+		}
+
+		var addr Addr
+		for _, attr := range attrs {
+			switch attr.Attr.Type {
+			case syscall.IFA_ADDRESS:
+				addr.IPNet = &net.IPNet{
+					IP:   attr.Value,
+					Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
+				}
+			case syscall.IFA_LABEL:
+				addr.Label = string(attr.Value[:len(attr.Value)-1])
+			}
+		}
+		res = append(res, addr)
+	}
+
+	return res, nil
+}

+ 45 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/addr_test.go

@@ -0,0 +1,45 @@
+package netlink
+
+import (
+	"testing"
+)
+
+func TestAddrAddDel(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	link, err := LinkByName("lo")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	addr, err := ParseAddr("127.1.1.1/24 local")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err = AddrAdd(link, addr); err != nil {
+		t.Fatal(err)
+	}
+
+	addrs, err := AddrList(link, FAMILY_ALL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(addrs) != 1 || !addr.Equal(addrs[0]) || addrs[0].Label != addr.Label {
+		t.Fatal("Address not added properly")
+	}
+
+	if err = AddrDel(link, addr); err != nil {
+		t.Fatal(err)
+	}
+	addrs, err = AddrList(link, FAMILY_ALL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(addrs) != 0 {
+		t.Fatal("Address not removed properly")
+	}
+}

+ 154 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/link.go

@@ -0,0 +1,154 @@
+package netlink
+
+import (
+	"net"
+)
+
+// Link represents a link device from netlink. Shared link attributes
+// like name may be retrieved using the Attrs() method. Unique data
+// can be retrieved by casting the object to the proper type.
+type Link interface {
+	Attrs() *LinkAttrs
+	Type() string
+}
+
+// LinkAttrs represents data shared by most link types
+type LinkAttrs struct {
+	Index        int
+	MTU          int
+	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
+}
+
+// Device links cannot be created via netlink. These links
+// are links created by udev like 'lo' and 'etho0'
+type Device struct {
+	LinkAttrs
+}
+
+func (device *Device) Attrs() *LinkAttrs {
+	return &device.LinkAttrs
+}
+
+func (device *Device) Type() string {
+	return "device"
+}
+
+// Dummy links are dummy ethernet devices
+type Dummy struct {
+	LinkAttrs
+}
+
+func (dummy *Dummy) Attrs() *LinkAttrs {
+	return &dummy.LinkAttrs
+}
+
+func (dummy *Dummy) Type() string {
+	return "dummy"
+}
+
+// Bridge links are simple linux bridges
+type Bridge struct {
+	LinkAttrs
+}
+
+func (bridge *Bridge) Attrs() *LinkAttrs {
+	return &bridge.LinkAttrs
+}
+
+func (bridge *Bridge) Type() string {
+	return "bridge"
+}
+
+// Vlan links have ParentIndex set in their Attrs()
+type Vlan struct {
+	LinkAttrs
+	VlanId int
+}
+
+func (vlan *Vlan) Attrs() *LinkAttrs {
+	return &vlan.LinkAttrs
+}
+
+func (vlan *Vlan) Type() string {
+	return "vlan"
+}
+
+// Macvlan links have ParentIndex set in their Attrs()
+type Macvlan struct {
+	LinkAttrs
+}
+
+func (macvlan *Macvlan) Attrs() *LinkAttrs {
+	return &macvlan.LinkAttrs
+}
+
+func (macvlan *Macvlan) Type() string {
+	return "macvlan"
+}
+
+// Veth devices must specify PeerName on create
+type Veth struct {
+	LinkAttrs
+	PeerName string // veth on create only
+}
+
+func (veth *Veth) Attrs() *LinkAttrs {
+	return &veth.LinkAttrs
+}
+
+func (veth *Veth) Type() string {
+	return "veth"
+}
+
+// Generic links represent types that are not currently understood
+// by this netlink library.
+type Generic struct {
+	LinkAttrs
+	LinkType string
+}
+
+func (generic *Generic) Attrs() *LinkAttrs {
+	return &generic.LinkAttrs
+}
+
+func (generic *Generic) Type() string {
+	return generic.LinkType
+}
+
+type Vxlan struct {
+	LinkAttrs
+	VxlanId      int
+	VtepDevIndex int
+	SrcAddr      net.IP
+	Group        net.IP
+	TTL          int
+	TOS          int
+	Learning     bool
+	Proxy        bool
+	RSC          bool
+	L2miss       bool
+	L3miss       bool
+	NoAge        bool
+	Age          int
+	Limit        int
+	Port         int
+	PortLow      int
+	PortHigh     int
+}
+
+func (vxlan *Vxlan) Attrs() *LinkAttrs {
+	return &vxlan.LinkAttrs
+}
+
+func (vxlan *Vxlan) Type() string {
+	return "vxlan"
+}
+
+// iproute2 supported devices;
+// vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
+// can | bridge | bond | ipoib | ip6tnl | ipip | sit |
+// vxlan | gre | gretap | ip6gre | ip6gretap | vti

+ 549 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go

@@ -0,0 +1,549 @@
+package netlink
+
+import (
+	"bytes"
+	"encoding/binary"
+	"fmt"
+	"net"
+	"syscall"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+var native = nl.NativeEndian()
+
+func ensureIndex(link *LinkAttrs) {
+	if link != nil && link.Index == 0 {
+		newlink, _ := LinkByName(link.Name)
+		if newlink != nil {
+			link.Index = newlink.Attrs().Index
+		}
+	}
+}
+
+// LinkSetUp enables the link device.
+// Equivalent to: `ip link set $link up`
+func LinkSetUp(link Link) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Change = syscall.IFF_UP
+	msg.Flags = syscall.IFF_UP
+	msg.Index = int32(base.Index)
+	req.AddData(msg)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// LinkSetUp disables link device.
+// Equivalent to: `ip link set $link down`
+func LinkSetDown(link Link) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Change = syscall.IFF_UP
+	msg.Flags = 0 & ^syscall.IFF_UP
+	msg.Index = int32(base.Index)
+	req.AddData(msg)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// LinkSetMTU sets the mtu of the link device.
+// Equivalent to: `ip link set $link mtu $mtu`
+func LinkSetMTU(link Link, mtu int) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(base.Index)
+	msg.Change = nl.DEFAULT_CHANGE
+	req.AddData(msg)
+
+	b := make([]byte, 4)
+	native.PutUint32(b, uint32(mtu))
+
+	data := nl.NewRtAttr(syscall.IFLA_MTU, b)
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// LinkSetMaster sets the master of the link device.
+// Equivalent to: `ip link set $link master $master`
+func LinkSetMaster(link Link, master *Bridge) error {
+	index := 0
+	if master != nil {
+		masterBase := master.Attrs()
+		ensureIndex(masterBase)
+		index = masterBase.Index
+	}
+	return LinkSetMasterByIndex(link, index)
+}
+
+// LinkSetMasterByIndex sets the master of the link device.
+// Equivalent to: `ip link set $link master $master`
+func LinkSetMasterByIndex(link Link, masterIndex int) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(base.Index)
+	msg.Change = nl.DEFAULT_CHANGE
+	req.AddData(msg)
+
+	b := make([]byte, 4)
+	native.PutUint32(b, uint32(masterIndex))
+
+	data := nl.NewRtAttr(syscall.IFLA_MASTER, b)
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// LinkSetNsPid puts the device into a new network namespace. The
+// pid must be a pid of a running process.
+// Equivalent to: `ip link set $link netns $pid`
+func LinkSetNsPid(link Link, nspid int) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(base.Index)
+	msg.Change = nl.DEFAULT_CHANGE
+	req.AddData(msg)
+
+	b := make([]byte, 4)
+	native.PutUint32(b, uint32(nspid))
+
+	data := nl.NewRtAttr(syscall.IFLA_NET_NS_PID, b)
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// LinkSetNsPid 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 {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(base.Index)
+	msg.Change = nl.DEFAULT_CHANGE
+	req.AddData(msg)
+
+	b := make([]byte, 4)
+	native.PutUint32(b, uint32(fd))
+
+	data := nl.NewRtAttr(nl.IFLA_NET_NS_FD, b)
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+func boolAttr(val bool) []byte {
+	var v uint8
+	if val {
+		v = 1
+	}
+	return nl.Uint8Attr(v)
+}
+
+type vxlanPortRange struct {
+	Lo, Hi uint16
+}
+
+func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
+	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId)))
+	if vxlan.VtepDevIndex != 0 {
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex)))
+	}
+	if vxlan.SrcAddr != nil {
+		ip := vxlan.SrcAddr.To4()
+		if ip != nil {
+			nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL, []byte(ip))
+		} else {
+			ip = vxlan.SrcAddr.To16()
+			if ip != nil {
+				nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL6, []byte(ip))
+			}
+		}
+	}
+	if vxlan.Group != nil {
+		group := vxlan.Group.To4()
+		if group != nil {
+			nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP, []byte(group))
+		} else {
+			group = vxlan.Group.To16()
+			if group != nil {
+				nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP6, []byte(group))
+			}
+		}
+	}
+
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL)))
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS)))
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning))
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy))
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC))
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
+	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
+
+	if vxlan.NoAge {
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
+	} else if vxlan.Age > 0 {
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age)))
+	}
+	if vxlan.Limit > 0 {
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit)))
+	}
+	if vxlan.Port > 0 {
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, nl.Uint16Attr(uint16(vxlan.Port)))
+	}
+	if vxlan.PortLow > 0 || vxlan.PortHigh > 0 {
+		pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)}
+
+		buf := new(bytes.Buffer)
+		binary.Write(buf, binary.BigEndian, &pr)
+
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes())
+	}
+}
+
+// LinkAdd adds a new link device. The type and features of the device
+// are taken fromt the parameters in the link object.
+// Equivalent to: `ip link add $link`
+func LinkAdd(link Link) error {
+	// TODO: set mtu and hardware address
+	// TODO: support extra data for macvlan
+	base := link.Attrs()
+
+	if base.Name == "" {
+		return fmt.Errorf("LinkAttrs.Name cannot be empty!")
+	}
+
+	req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	req.AddData(msg)
+
+	if base.ParentIndex != 0 {
+		b := make([]byte, 4)
+		native.PutUint32(b, uint32(base.ParentIndex))
+		data := nl.NewRtAttr(syscall.IFLA_LINK, b)
+		req.AddData(data)
+	}
+
+	nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
+	req.AddData(nameData)
+
+	linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
+	nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
+
+	if vlan, ok := link.(*Vlan); ok {
+		b := make([]byte, 2)
+		native.PutUint16(b, uint16(vlan.VlanId))
+		data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+		nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b)
+	} else if veth, ok := link.(*Veth); ok {
+		data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+		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))
+	} else if vxlan, ok := link.(*Vxlan); ok {
+		addVxlanAttrs(vxlan, linkInfo)
+	}
+
+	req.AddData(linkInfo)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	if err != nil {
+		return err
+	}
+
+	ensureIndex(base)
+
+	// can't set master during create, so set it afterwards
+	if base.MasterIndex != 0 {
+		// TODO: verify MasterIndex is actually a bridge?
+		return LinkSetMasterByIndex(link, base.MasterIndex)
+	}
+	return nil
+}
+
+// LinkAdd adds a new link device. Either Index or Name must be set in
+// the link object for it to be deleted. The other values are ignored.
+// Equivalent to: `ip link del $link`
+func LinkDel(link Link) error {
+	base := link.Attrs()
+
+	ensureIndex(base)
+
+	req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(base.Index)
+	req.AddData(msg)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// LinkByName finds a link by name and returns a pointer to the object.
+func LinkByName(name string) (Link, error) {
+	req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	req.AddData(msg)
+
+	nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(name))
+	req.AddData(nameData)
+
+	return execGetLink(req)
+}
+
+// LinkByIndex finds a link by index and returns a pointer to the object.
+func LinkByIndex(index int) (Link, error) {
+	req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Index = int32(index)
+	req.AddData(msg)
+
+	return execGetLink(req)
+}
+
+func execGetLink(req *nl.NetlinkRequest) (Link, error) {
+	msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	if err != nil {
+		if errno, ok := err.(syscall.Errno); ok {
+			if errno == syscall.ENODEV {
+				return nil, fmt.Errorf("Link not found")
+			}
+		}
+		return nil, err
+	}
+
+	switch {
+	case len(msgs) == 0:
+		return nil, fmt.Errorf("Link not found")
+
+	case len(msgs) == 1:
+		return linkDeserialize(msgs[0])
+
+	default:
+		return nil, fmt.Errorf("More than one link found")
+	}
+}
+
+// linkDeserialize deserializes a raw message received from netlink into
+// a link object.
+func linkDeserialize(m []byte) (Link, error) {
+	msg := nl.DeserializeIfInfomsg(m)
+
+	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+	if err != nil {
+		return nil, err
+	}
+
+	base := LinkAttrs{Index: int(msg.Index), Flags: linkFlags(msg.Flags)}
+	var link Link
+	linkType := ""
+	for _, attr := range attrs {
+		switch attr.Attr.Type {
+		case syscall.IFLA_LINKINFO:
+			infos, err := nl.ParseRouteAttr(attr.Value)
+			if err != nil {
+				return nil, err
+			}
+			for _, info := range infos {
+				switch info.Attr.Type {
+				case nl.IFLA_INFO_KIND:
+					linkType = string(info.Value[:len(info.Value)-1])
+					switch linkType {
+					case "dummy":
+						link = &Dummy{}
+					case "bridge":
+						link = &Bridge{}
+					case "vlan":
+						link = &Vlan{}
+					case "veth":
+						link = &Veth{}
+					case "vxlan":
+						link = &Vxlan{}
+					default:
+						link = &Generic{LinkType: linkType}
+					}
+				case nl.IFLA_INFO_DATA:
+					data, err := nl.ParseRouteAttr(info.Value)
+					if err != nil {
+						return nil, err
+					}
+					switch linkType {
+					case "vlan":
+						parseVlanData(link, data)
+					case "vxlan":
+						parseVxlanData(link, data)
+					}
+				}
+			}
+		case syscall.IFLA_ADDRESS:
+			var nonzero bool
+			for _, b := range attr.Value {
+				if b != 0 {
+					nonzero = true
+				}
+			}
+			if nonzero {
+				base.HardwareAddr = attr.Value[:]
+			}
+		case syscall.IFLA_IFNAME:
+			base.Name = string(attr.Value[:len(attr.Value)-1])
+		case syscall.IFLA_MTU:
+			base.MTU = int(native.Uint32(attr.Value[0:4]))
+		case syscall.IFLA_LINK:
+			base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
+		case syscall.IFLA_MASTER:
+			base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
+		}
+	}
+	// Links that don't have IFLA_INFO_KIND are hardware devices
+	if link == nil {
+		link = &Device{}
+	}
+	*link.Attrs() = base
+
+	return link, nil
+}
+
+// LinkList gets a list of link devices.
+// Equivalent to: `ip link show`
+func LinkList() ([]Link, error) {
+	// NOTE(vish): This duplicates functionality in net/iface_linux.go, but we need
+	//             to get the message ourselves to parse link type.
+	req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	req.AddData(msg)
+
+	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK)
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]Link, 0)
+
+	for _, m := range msgs {
+		link, err := linkDeserialize(m)
+		if err != nil {
+			return nil, err
+		}
+		res = append(res, link)
+	}
+
+	return res, nil
+}
+
+func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
+	vlan := link.(*Vlan)
+	for _, datum := range data {
+		switch datum.Attr.Type {
+		case nl.IFLA_VLAN_ID:
+			vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
+		}
+	}
+}
+
+func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
+	vxlan := link.(*Vxlan)
+	for _, datum := range data {
+		switch datum.Attr.Type {
+		case nl.IFLA_VXLAN_ID:
+			vxlan.VxlanId = int(native.Uint32(datum.Value[0:4]))
+		case nl.IFLA_VXLAN_LINK:
+			vxlan.VtepDevIndex = int(native.Uint32(datum.Value[0:4]))
+		case nl.IFLA_VXLAN_LOCAL:
+			vxlan.SrcAddr = net.IP(datum.Value[0:4])
+		case nl.IFLA_VXLAN_LOCAL6:
+			vxlan.SrcAddr = net.IP(datum.Value[0:16])
+		case nl.IFLA_VXLAN_GROUP:
+			vxlan.Group = net.IP(datum.Value[0:4])
+		case nl.IFLA_VXLAN_GROUP6:
+			vxlan.Group = net.IP(datum.Value[0:16])
+		case nl.IFLA_VXLAN_TTL:
+			vxlan.TTL = int(datum.Value[0])
+		case nl.IFLA_VXLAN_TOS:
+			vxlan.TOS = int(datum.Value[0])
+		case nl.IFLA_VXLAN_LEARNING:
+			vxlan.Learning = int8(datum.Value[0]) != 0
+		case nl.IFLA_VXLAN_PROXY:
+			vxlan.Proxy = int8(datum.Value[0]) != 0
+		case nl.IFLA_VXLAN_RSC:
+			vxlan.RSC = int8(datum.Value[0]) != 0
+		case nl.IFLA_VXLAN_L2MISS:
+			vxlan.L2miss = int8(datum.Value[0]) != 0
+		case nl.IFLA_VXLAN_L3MISS:
+			vxlan.L3miss = int8(datum.Value[0]) != 0
+		case nl.IFLA_VXLAN_AGEING:
+			vxlan.Age = int(native.Uint32(datum.Value[0:4]))
+			vxlan.NoAge = vxlan.Age == 0
+		case nl.IFLA_VXLAN_LIMIT:
+			vxlan.Limit = int(native.Uint32(datum.Value[0:4]))
+		case nl.IFLA_VXLAN_PORT:
+			vxlan.Port = int(native.Uint16(datum.Value[0:2]))
+		case nl.IFLA_VXLAN_PORT_RANGE:
+			buf := bytes.NewBuffer(datum.Value[0:4])
+			var pr vxlanPortRange
+			if binary.Read(buf, binary.BigEndian, &pr) != nil {
+				vxlan.PortLow = int(pr.Lo)
+				vxlan.PortHigh = int(pr.Hi)
+			}
+		}
+	}
+}
+
+// copied from pkg/net_linux.go
+func linkFlags(rawFlags uint32) net.Flags {
+	var f net.Flags
+	if rawFlags&syscall.IFF_UP != 0 {
+		f |= net.FlagUp
+	}
+	if rawFlags&syscall.IFF_BROADCAST != 0 {
+		f |= net.FlagBroadcast
+	}
+	if rawFlags&syscall.IFF_LOOPBACK != 0 {
+		f |= net.FlagLoopback
+	}
+	if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+		f |= net.FlagPointToPoint
+	}
+	if rawFlags&syscall.IFF_MULTICAST != 0 {
+		f |= net.FlagMulticast
+	}
+	return f
+}

+ 387 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go

@@ -0,0 +1,387 @@
+package netlink
+
+import (
+	"github.com/vishvananda/netns"
+	"testing"
+)
+
+func testLinkAddDel(t *testing.T, link Link) {
+	links, err := LinkList()
+	if err != nil {
+		t.Fatal(err)
+	}
+	num := len(links)
+
+	if err := LinkAdd(link); err != nil {
+		t.Fatal(err)
+	}
+
+	base := link.Attrs()
+
+	result, err := LinkByName(base.Name)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	rBase := result.Attrs()
+
+	if vlan, ok := link.(*Vlan); ok {
+		other, ok := result.(*Vlan)
+		if !ok {
+			t.Fatal("Result of create is not a vlan")
+		}
+		if vlan.VlanId != other.VlanId {
+			t.Fatal("Link.VlanId id doesn't match")
+		}
+	}
+
+	if rBase.ParentIndex == 0 && base.ParentIndex != 0 {
+		t.Fatal("Created link doesn't have a Parent but it should")
+	} else if rBase.ParentIndex != 0 && base.ParentIndex == 0 {
+		t.Fatal("Created link has a Parent but it shouldn't")
+	} else if rBase.ParentIndex != 0 && base.ParentIndex != 0 {
+		if rBase.ParentIndex != base.ParentIndex {
+			t.Fatal("Link.ParentIndex doesn't match")
+		}
+	}
+
+	if veth, ok := link.(*Veth); ok {
+		if veth.PeerName != "" {
+			other, err := LinkByName(veth.PeerName)
+			if err != nil {
+				t.Fatal("Peer %s not created", veth.PeerName)
+			}
+			if _, ok = other.(*Veth); !ok {
+				t.Fatal("Peer %s is incorrect type", veth.PeerName)
+			}
+		}
+	}
+
+	if vxlan, ok := link.(*Vxlan); ok {
+		other, ok := result.(*Vxlan)
+		if !ok {
+			t.Fatal("Result of create is not a vxlan")
+		}
+		compareVxlan(t, vxlan, other)
+	}
+
+	if err = LinkDel(link); err != nil {
+		t.Fatal(err)
+	}
+
+	links, err = LinkList()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(links) != num {
+		t.Fatal("Link not removed properly")
+	}
+}
+
+func compareVxlan(t *testing.T, expected, actual *Vxlan) {
+
+	if actual.VxlanId != expected.VxlanId {
+		t.Fatalf("Vxlan.VxlanId doesn't match")
+	}
+	if expected.SrcAddr != nil && !actual.SrcAddr.Equal(expected.SrcAddr) {
+		t.Fatalf("Vxlan.SrcAddr doesn't match")
+	}
+	if expected.Group != nil && !actual.Group.Equal(expected.Group) {
+		t.Fatalf("Vxlan.Group doesn't match")
+	}
+	if expected.TTL != -1 && actual.TTL != expected.TTL {
+		t.Fatalf("Vxlan.TTL doesn't match")
+	}
+	if expected.TOS != -1 && actual.TOS != expected.TOS {
+		t.Fatalf("Vxlan.TOS doesn't match")
+	}
+	if actual.Learning != expected.Learning {
+		t.Fatalf("Vxlan.Learning doesn't match")
+	}
+	if actual.Proxy != expected.Proxy {
+		t.Fatalf("Vxlan.Proxy doesn't match")
+	}
+	if actual.RSC != expected.RSC {
+		t.Fatalf("Vxlan.RSC doesn't match", actual, expected)
+	}
+	if actual.L2miss != expected.L2miss {
+		t.Fatalf("Vxlan.L2miss doesn't match")
+	}
+	if actual.L3miss != expected.L3miss {
+		t.Fatalf("Vxlan.L3miss doesn't match")
+	}
+	if expected.NoAge {
+		if !actual.NoAge {
+			t.Fatalf("Vxlan.NoAge doesn't match")
+		}
+	} else if expected.Age > 0 && actual.Age != expected.Age {
+		t.Fatalf("Vxlan.Age doesn't match")
+	}
+	if expected.Limit > 0 && actual.Limit != expected.Limit {
+		t.Fatalf("Vxlan.Limit doesn't match")
+	}
+	if expected.Port > 0 && actual.Port != expected.Port {
+		t.Fatalf("Vxlan.Port doesn't match")
+	}
+	if expected.PortLow > 0 || expected.PortHigh > 0 {
+		if actual.PortLow != expected.PortLow {
+			t.Fatalf("Vxlan.PortLow doesn't match")
+		}
+		if actual.PortHigh != expected.PortHigh {
+			t.Fatalf("Vxlan.PortHigh doesn't match")
+		}
+	}
+}
+
+func TestLinkAddDelDummy(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	testLinkAddDel(t, &Dummy{LinkAttrs{Name: "foo"}})
+}
+
+func TestLinkAddDelBridge(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo"}})
+}
+
+func TestLinkAddDelVlan(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	parent := &Dummy{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(parent); err != nil {
+		t.Fatal(err)
+	}
+
+	testLinkAddDel(t, &Vlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}, 900})
+
+	if err := LinkDel(parent); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestLinkAddDelMacvlan(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	parent := &Dummy{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(parent); err != nil {
+		t.Fatal(err)
+	}
+
+	testLinkAddDel(t, &Macvlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}})
+
+	if err := LinkDel(parent); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestLinkAddDelVeth(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo"}, "bar"})
+}
+
+func TestLinkAddDelBridgeMaster(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	master := &Bridge{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(master); err != nil {
+		t.Fatal(err)
+	}
+	testLinkAddDel(t, &Dummy{LinkAttrs{Name: "bar", MasterIndex: master.Attrs().Index}})
+
+	if err := LinkDel(master); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestLinkSetUnsetResetMaster(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	master := &Bridge{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(master); err != nil {
+		t.Fatal(err)
+	}
+
+	newmaster := &Bridge{LinkAttrs{Name: "bar"}}
+	if err := LinkAdd(newmaster); err != nil {
+		t.Fatal(err)
+	}
+
+	slave := &Dummy{LinkAttrs{Name: "baz"}}
+	if err := LinkAdd(slave); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := LinkSetMaster(slave, master); err != nil {
+		t.Fatal(err)
+	}
+
+	link, err := LinkByName("baz")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if link.Attrs().MasterIndex != master.Attrs().Index {
+		t.Fatal("Master not set properly")
+	}
+
+	if err := LinkSetMaster(slave, newmaster); err != nil {
+		t.Fatal(err)
+	}
+
+	link, err = LinkByName("baz")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if link.Attrs().MasterIndex != newmaster.Attrs().Index {
+		t.Fatal("Master not reset properly")
+	}
+
+	if err := LinkSetMaster(slave, nil); err != nil {
+		t.Fatal(err)
+	}
+
+	link, err = LinkByName("baz")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if link.Attrs().MasterIndex != 0 {
+		t.Fatal("Master not unset properly")
+	}
+	if err := LinkDel(slave); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := LinkDel(newmaster); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := LinkDel(master); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestLinkSetNs(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	basens, err := netns.Get()
+	if err != nil {
+		t.Fatal("Failed to get basens")
+	}
+	defer basens.Close()
+
+	newns, err := netns.New()
+	if err != nil {
+		t.Fatal("Failed to create newns")
+	}
+	defer newns.Close()
+
+	link := &Veth{LinkAttrs{Name: "foo"}, "bar"}
+	if err := LinkAdd(link); err != nil {
+		t.Fatal(err)
+	}
+
+	peer, err := LinkByName("bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	LinkSetNsFd(peer, int(basens))
+	if err != nil {
+		t.Fatal("Failed to set newns for link")
+	}
+
+	_, err = LinkByName("bar")
+	if err == nil {
+		t.Fatal("Link bar is still in newns")
+	}
+
+	err = netns.Set(basens)
+	if err != nil {
+		t.Fatal("Failed to set basens")
+	}
+
+	peer, err = LinkByName("bar")
+	if err != nil {
+		t.Fatal("Link is not in basens")
+	}
+
+	if err := LinkDel(peer); err != nil {
+		t.Fatal(err)
+	}
+
+	err = netns.Set(newns)
+	if err != nil {
+		t.Fatal("Failed to set newns")
+	}
+
+	_, err = LinkByName("foo")
+	if err == nil {
+		t.Fatal("Other half of veth pair not deleted")
+	}
+
+}
+
+func TestLinkAddDelVxlan(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	parent := &Dummy{
+		LinkAttrs{Name: "foo"},
+	}
+	if err := LinkAdd(parent); err != nil {
+		t.Fatal(err)
+	}
+
+	vxlan := Vxlan{
+		LinkAttrs: LinkAttrs{
+			Name: "bar",
+		},
+		VxlanId: 10,
+		VtepDevIndex: parent.Index,
+		Learning:     true,
+		L2miss:       true,
+		L3miss:       true,
+	}
+
+	testLinkAddDel(t, &vxlan)
+	if err := LinkDel(parent); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestLinkByIndex(t *testing.T) {
+	dummy := &Dummy{LinkAttrs{Name: "dummy"}}
+	if err := LinkAdd(dummy); err != nil {
+		t.Fatal(err)
+	}
+
+	found, err := LinkByIndex(dummy.Index)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if found.Attrs().Index != dummy.Attrs().Index {
+		t.Fatalf("Indices don't match: %v != %v", found.Attrs().Index, dummy.Attrs().Index)
+	}
+
+	LinkDel(dummy)
+
+	// test not found
+	_, err = LinkByIndex(dummy.Attrs().Index)
+	if err == nil {
+		t.Fatalf("LinkByIndex(%v) found deleted link", err)
+	}
+}

+ 22 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/neigh.go

@@ -0,0 +1,22 @@
+package netlink
+
+import (
+	"fmt"
+	"net"
+)
+
+// Neigh represents a link layer neighbor from netlink.
+type Neigh struct {
+	LinkIndex    int
+	Family       int
+	State        int
+	Type         int
+	Flags        int
+	IP           net.IP
+	HardwareAddr net.HardwareAddr
+}
+
+// String returns $ip/$hwaddr $label
+func (neigh *Neigh) String() string {
+	return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr)
+}

+ 189 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go

@@ -0,0 +1,189 @@
+package netlink
+
+import (
+	"net"
+	"syscall"
+	"unsafe"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+const (
+	NDA_UNSPEC    = iota
+	NDA_DST       = iota
+	NDA_LLADDR    = iota
+	NDA_CACHEINFO = iota
+	NDA_PROBES    = iota
+	NDA_VLAN      = iota
+	NDA_PORT      = iota
+	NDA_VNI       = iota
+	NDA_IFINDEX   = iota
+	NDA_MAX       = NDA_IFINDEX
+)
+
+// Neighbor Cache Entry States.
+const (
+	NUD_NONE       = 0x00
+	NUD_INCOMPLETE = 0x01
+	NUD_REACHABLE  = 0x02
+	NUD_STALE      = 0x04
+	NUD_DELAY      = 0x08
+	NUD_PROBE      = 0x10
+	NUD_FAILED     = 0x20
+	NUD_NOARP      = 0x40
+	NUD_PERMANENT  = 0x80
+)
+
+// Neighbor Flags
+const (
+	NTF_USE    = 0x01
+	NTF_SELF   = 0x02
+	NTF_MASTER = 0x04
+	NTF_PROXY  = 0x08
+	NTF_ROUTER = 0x80
+)
+
+type Ndmsg struct {
+	Family uint8
+	Index  uint32
+	State  uint16
+	Flags  uint8
+	Type   uint8
+}
+
+func deserializeNdmsg(b []byte) *Ndmsg {
+	var dummy Ndmsg
+	return (*Ndmsg)(unsafe.Pointer(&b[0:unsafe.Sizeof(dummy)][0]))
+}
+
+func (msg *Ndmsg) Serialize() []byte {
+	return (*(*[unsafe.Sizeof(*msg)]byte)(unsafe.Pointer(msg)))[:]
+}
+
+func (msg *Ndmsg) Len() int {
+	return int(unsafe.Sizeof(*msg))
+}
+
+// NeighAdd will add an IP to MAC mapping to the ARP table
+// Equivalent to: `ip neigh add ....`
+func NeighAdd(neigh *Neigh) error {
+	return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL)
+}
+
+// NeighAdd will add or replace an IP to MAC mapping to the ARP table
+// Equivalent to: `ip neigh replace....`
+func NeighSet(neigh *Neigh) error {
+	return neighAdd(neigh, syscall.NLM_F_CREATE)
+}
+
+// NeighAppend will append an entry to FDB
+// Equivalent to: `bridge fdb append...`
+func NeighAppend(neigh *Neigh) error {
+	return neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND)
+}
+
+func neighAdd(neigh *Neigh, mode int) error {
+	req := nl.NewNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK)
+	return neighHandle(neigh, req)
+}
+
+// NeighDel will delete an IP address from a link device.
+// Equivalent to: `ip addr del $addr dev $link`
+func NeighDel(neigh *Neigh) error {
+	req := nl.NewNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK)
+	return neighHandle(neigh, req)
+}
+
+func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
+	var family int
+	if neigh.Family > 0 {
+		family = neigh.Family
+	} else {
+		family = nl.GetIPFamily(neigh.IP)
+	}
+
+	msg := Ndmsg{
+		Family: uint8(family),
+		Index:  uint32(neigh.LinkIndex),
+		State:  uint16(neigh.State),
+		Type:   uint8(neigh.Type),
+		Flags:  uint8(neigh.Flags),
+	}
+	req.AddData(&msg)
+
+	ipData := neigh.IP.To4()
+	if ipData == nil {
+		ipData = neigh.IP.To16()
+	}
+
+	dstData := nl.NewRtAttr(NDA_DST, ipData)
+	req.AddData(dstData)
+
+	hwData := nl.NewRtAttr(NDA_LLADDR, []byte(neigh.HardwareAddr))
+	req.AddData(hwData)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// NeighList gets a list of IP-MAC mappings in the system (ARP table).
+// Equivalent to: `ip neighbor show`.
+// The list can be filtered by link and ip family.
+func NeighList(linkIndex, family int) ([]Neigh, error) {
+	req := nl.NewNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP)
+	msg := Ndmsg{
+		Family: uint8(family),
+	}
+	req.AddData(&msg)
+
+	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWNEIGH)
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]Neigh, 0)
+	for _, m := range msgs {
+		ndm := deserializeNdmsg(m)
+		if linkIndex != 0 && int(ndm.Index) != linkIndex {
+			// Ignore messages from other interfaces
+			continue
+		}
+
+		neigh, err := NeighDeserialize(m)
+		if err != nil {
+			continue
+		}
+
+		res = append(res, *neigh)
+	}
+
+	return res, nil
+}
+
+func NeighDeserialize(m []byte) (*Neigh, error) {
+	msg := deserializeNdmsg(m)
+
+	neigh := Neigh{
+		LinkIndex: int(msg.Index),
+		Family:    int(msg.Family),
+		State:     int(msg.State),
+		Type:      int(msg.Type),
+		Flags:     int(msg.Flags),
+	}
+
+	attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+	if err != nil {
+		return nil, err
+	}
+
+	for _, attr := range attrs {
+		switch attr.Attr.Type {
+		case NDA_DST:
+			neigh.IP = net.IP(attr.Value)
+		case NDA_LLADDR:
+			neigh.HardwareAddr = net.HardwareAddr(attr.Value)
+		}
+	}
+
+	return &neigh, nil
+}

+ 102 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go

@@ -0,0 +1,102 @@
+package netlink
+
+import (
+	"net"
+	"testing"
+)
+
+type arpEntry struct {
+	ip  net.IP
+	mac net.HardwareAddr
+}
+
+func parseMAC(s string) net.HardwareAddr {
+	m, err := net.ParseMAC(s)
+	if err != nil {
+		panic(err)
+	}
+	return m
+}
+
+func dumpContains(dump []Neigh, e arpEntry) bool {
+	for _, n := range dump {
+		if n.IP.Equal(e.ip) && (n.State & NUD_INCOMPLETE) == 0 {
+			return true
+		}
+	}
+	return false
+}
+
+func TestNeighAddDel(t *testing.T) {
+	dummy := Dummy{LinkAttrs{Name: "neigh0"}}
+	if err := LinkAdd(&dummy); err != nil {
+		t.Fatal(err)
+	}
+
+	ensureIndex(dummy.Attrs())
+
+	arpTable := []arpEntry{
+		{ net.ParseIP("10.99.0.1"), parseMAC("aa:bb:cc:dd:00:01") },
+		{ net.ParseIP("10.99.0.2"), parseMAC("aa:bb:cc:dd:00:02") },
+		{ net.ParseIP("10.99.0.3"), parseMAC("aa:bb:cc:dd:00:03") },
+		{ net.ParseIP("10.99.0.4"), parseMAC("aa:bb:cc:dd:00:04") },
+		{ net.ParseIP("10.99.0.5"), parseMAC("aa:bb:cc:dd:00:05") },
+	}
+
+	// Add the arpTable
+	for _, entry := range arpTable {
+		err := NeighAdd(&Neigh{
+			LinkIndex:    dummy.Index,
+			State:        NUD_REACHABLE,
+			IP:           entry.ip,
+			HardwareAddr: entry.mac,
+		})
+
+		if err != nil {
+			t.Errorf("Failed to NeighAdd: %v", err)
+		}
+	}
+
+	// Dump and see that all added entries are there
+	dump, err := NeighList(dummy.Index, 0)
+	if err != nil {
+		t.Errorf("Failed to NeighList: %v", err)
+	}
+
+	for _, entry := range arpTable {
+		if !dumpContains(dump, entry) {
+			t.Errorf("Dump does not contain: %v", entry)
+		}
+	}
+
+	return
+
+	// Delete the arpTable
+	for _, entry := range arpTable {
+		err := NeighDel(&Neigh{
+			LinkIndex:    dummy.Index,
+			IP:           entry.ip,
+			HardwareAddr: entry.mac,
+		})
+
+		if err != nil {
+			t.Errorf("Failed to NeighDel: %v", err)
+		}
+	}
+
+	// Dump and see that none of deleted entries are there
+	dump, err = NeighList(dummy.Index, 0)
+	if err != nil {
+		t.Errorf("Failed to NeighList: %v", err)
+	}
+
+	for _, entry := range arpTable {
+		if dumpContains(dump, entry) {
+			t.Errorf("Dump contains: %v", entry)
+		}
+	}
+
+	if err := LinkDel(&dummy); err != nil {
+		t.Fatal(err)
+	}
+}

+ 39 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go

@@ -0,0 +1,39 @@
+// Package netlink provides a simple library for netlink. Netlink is
+// the interface a user-space program in linux uses to communicate with
+// the kernel. It can be used to add and remove interfaces, set up ip
+// addresses and routes, and confiugre ipsec. Netlink communication
+// requires elevated privileges, so in most cases this code needs to
+// be run as root. The low level primitives for netlink are contained
+// in the nl subpackage. This package attempts to provide a high-level
+// interface that is loosly modeled on the iproute2 cli.
+package netlink
+
+import (
+	"net"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+const (
+	// Family type definitions
+	FAMILY_ALL = nl.FAMILY_ALL
+	FAMILY_V4  = nl.FAMILY_V4
+	FAMILY_V6  = nl.FAMILY_V6
+)
+
+// ParseIPNet parses a string in ip/net format and returns a net.IPNet.
+// This is valuable because addresses in netlink are often IPNets and
+// ParseCIDR returns an IPNet with the IP part set to the base IP of the
+// range.
+func ParseIPNet(s string) (*net.IPNet, error) {
+	ip, ipNet, err := net.ParseCIDR(s)
+	if err != nil {
+		return nil, err
+	}
+	return &net.IPNet{ip, ipNet.Mask}, nil
+}
+
+// NewIPNet generates an IPNet from an ip address using a netmask of 32.
+func NewIPNet(ip net.IP) *net.IPNet {
+	return &net.IPNet{ip, net.CIDRMask(32, 32)}
+}

+ 33 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_test.go

@@ -0,0 +1,33 @@
+package netlink
+
+import (
+	"github.com/vishvananda/netns"
+	"log"
+	"os"
+	"runtime"
+	"testing"
+)
+
+type tearDownNetlinkTest func()
+
+func setUpNetlinkTest(t *testing.T) tearDownNetlinkTest {
+	if os.Getuid() != 0 {
+		msg := "Skipped test because it requires root privileges."
+		log.Printf(msg)
+		t.Skip(msg)
+	}
+
+	// new temporary namespace so we don't pollute the host
+	// lock thread since the namespace is thread local
+	runtime.LockOSThread()
+	var err error
+	ns, err := netns.New()
+	if err != nil {
+		t.Fatal("Failed to create newns", ns)
+	}
+
+	return func() {
+		ns.Close()
+		runtime.UnlockOSThread()
+	}
+}

+ 119 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go

@@ -0,0 +1,119 @@
+// +build !linux
+
+package netlink
+
+import (
+	"errors"
+)
+
+var (
+	ErrNotImplemented = errors.New("not implemented")
+)
+
+func LinkSetUp(link *Link) error {
+	return ErrNotImplemented
+}
+
+func LinkSetDown(link *Link) error {
+	return ErrNotImplemented
+}
+
+func LinkSetMTU(link *Link, mtu int) error {
+	return ErrNotImplemented
+}
+
+func LinkSetMaster(link *Link, master *Link) error {
+	return ErrNotImplemented
+}
+
+func LinkSetNsPid(link *Link, nspid int) error {
+	return ErrNotImplemented
+}
+
+func LinkSetNsFd(link *Link, fd int) error {
+	return ErrNotImplemented
+}
+
+func LinkAdd(link *Link) error {
+	return ErrNotImplemented
+}
+
+func LinkDel(link *Link) error {
+	return ErrNotImplemented
+}
+
+func LinkList() ([]Link, error) {
+	return nil, ErrNotImplemented
+}
+
+func AddrAdd(link *Link, addr *Addr) error {
+	return ErrNotImplemented
+}
+
+func AddrDel(link *Link, addr *Addr) error {
+	return ErrNotImplemented
+}
+
+func AddrList(link *Link, family int) ([]Addr, error) {
+	return nil, ErrNotImplemented
+}
+
+func RouteAdd(route *Route) error {
+	return ErrNotImplemented
+}
+
+func RouteDel(route *Route) error {
+	return ErrNotImplemented
+}
+
+func RouteList(link *Link, family int) ([]Route, error) {
+	return nil, ErrNotImplemented
+}
+
+func XfrmPolicyAdd(policy *XfrmPolicy) error {
+	return ErrNotImplemented
+}
+
+func XfrmPolicyDel(policy *XfrmPolicy) error {
+	return ErrNotImplemented
+}
+
+func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
+	return nil, ErrNotImplemented
+}
+
+func XfrmStateAdd(policy *XfrmState) error {
+	return ErrNotImplemented
+}
+
+func XfrmStateDel(policy *XfrmState) error {
+	return ErrNotImplemented
+}
+
+func XfrmStateList(family int) ([]XfrmState, error) {
+	return nil, ErrNotImplemented
+}
+
+func NeighAdd(neigh *Neigh) error {
+	return ErrNotImplemented
+}
+
+func NeighSet(neigh *Neigh) error {
+	return ErrNotImplemented
+}
+
+func NeighAppend(neigh *Neigh) error {
+	return ErrNotImplemented
+}
+
+func NeighDel(neigh *Neigh) error {
+	return ErrNotImplemented
+}
+
+func NeighList(linkIndex, family int) ([]Neigh, error) {
+	return nil, ErrNotImplemented
+}
+
+func NeighDeserialize(m []byte) (*Ndmsg, *Neigh, error) {
+	return nil, nil, ErrNotImplemented
+}

+ 48 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go

@@ -0,0 +1,48 @@
+package nl
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+type IfAddrmsg struct {
+	syscall.IfAddrmsg
+}
+
+func NewIfAddrmsg(family int) *IfAddrmsg {
+	return &IfAddrmsg{
+		IfAddrmsg: syscall.IfAddrmsg{
+			Family: uint8(family),
+		},
+	}
+}
+
+// struct ifaddrmsg {
+//   __u8    ifa_family;
+//   __u8    ifa_prefixlen;  /* The prefix length    */
+//   __u8    ifa_flags;  /* Flags      */
+//   __u8    ifa_scope;  /* Address scope    */
+//   __u32   ifa_index;  /* Link index     */
+// };
+
+// type IfAddrmsg struct {
+// 	Family    uint8
+// 	Prefixlen uint8
+// 	Flags     uint8
+// 	Scope     uint8
+// 	Index     uint32
+// }
+// SizeofIfAddrmsg     = 0x8
+
+func DeserializeIfAddrmsg(b []byte) *IfAddrmsg {
+	return (*IfAddrmsg)(unsafe.Pointer(&b[0:syscall.SizeofIfAddrmsg][0]))
+}
+
+func (msg *IfAddrmsg) Serialize() []byte {
+	return (*(*[syscall.SizeofIfAddrmsg]byte)(unsafe.Pointer(msg)))[:]
+}
+
+func (msg *IfAddrmsg) Len() int {
+	return syscall.SizeofIfAddrmsg
+}
+

+ 39 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux_test.go

@@ -0,0 +1,39 @@
+package nl
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/binary"
+	"syscall"
+	"testing"
+)
+
+func (msg *IfAddrmsg) write(b []byte) {
+	native := NativeEndian()
+	b[0] = msg.Family
+	b[1] = msg.Prefixlen
+	b[2] = msg.Flags
+	b[3] = msg.Scope
+	native.PutUint32(b[4:8], msg.Index)
+}
+
+func (msg *IfAddrmsg) serializeSafe() []byte {
+	len := syscall.SizeofIfAddrmsg
+	b := make([]byte, len)
+	msg.write(b)
+	return b
+}
+
+func deserializeIfAddrmsgSafe(b []byte) *IfAddrmsg {
+	var msg = IfAddrmsg{}
+	binary.Read(bytes.NewReader(b[0:syscall.SizeofIfAddrmsg]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestIfAddrmsgDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, syscall.SizeofIfAddrmsg)
+	rand.Read(orig)
+	safemsg := deserializeIfAddrmsgSafe(orig)
+	msg := DeserializeIfAddrmsg(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}

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

@@ -0,0 +1,56 @@
+package nl
+
+const (
+	DEFAULT_CHANGE = 0xFFFFFFFF
+)
+
+const (
+	IFLA_INFO_UNSPEC = iota
+	IFLA_INFO_KIND   = iota
+	IFLA_INFO_DATA   = iota
+	IFLA_INFO_XSTATS = iota
+	IFLA_INFO_MAX    = IFLA_INFO_XSTATS
+)
+
+const (
+	IFLA_VLAN_UNSPEC      = iota
+	IFLA_VLAN_ID          = iota
+	IFLA_VLAN_FLAGS       = iota
+	IFLA_VLAN_EGRESS_QOS  = iota
+	IFLA_VLAN_INGRESS_QOS = iota
+	IFLA_VLAN_PROTOCOL    = iota
+	IFLA_VLAN_MAX         = IFLA_VLAN_PROTOCOL
+)
+
+const (
+	VETH_INFO_UNSPEC = iota
+	VETH_INFO_PEER   = iota
+	VETH_INFO_MAX    = VETH_INFO_PEER
+)
+
+const (
+	IFLA_VXLAN_UNSPEC     = iota
+	IFLA_VXLAN_ID         = iota
+	IFLA_VXLAN_GROUP      = iota
+	IFLA_VXLAN_LINK       = iota
+	IFLA_VXLAN_LOCAL      = iota
+	IFLA_VXLAN_TTL        = iota
+	IFLA_VXLAN_TOS        = iota
+	IFLA_VXLAN_LEARNING   = iota
+	IFLA_VXLAN_AGEING     = iota
+	IFLA_VXLAN_LIMIT      = iota
+	IFLA_VXLAN_PORT_RANGE = iota
+	IFLA_VXLAN_PROXY      = iota
+	IFLA_VXLAN_RSC        = iota
+	IFLA_VXLAN_L2MISS     = iota
+	IFLA_VXLAN_L3MISS     = iota
+	IFLA_VXLAN_PORT       = iota
+	IFLA_VXLAN_GROUP6     = iota
+	IFLA_VXLAN_LOCAL6     = iota
+	IFLA_VXLAN_MAX        = IFLA_VXLAN_LOCAL6
+)
+
+const (
+	// not defined in syscall
+	IFLA_NET_NS_FD = 28
+)

+ 414 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go

@@ -0,0 +1,414 @@
+// Package nl has low level primitives for making Netlink calls.
+package nl
+
+import (
+	"bytes"
+	"encoding/binary"
+	"net"
+	"fmt"
+	"sync/atomic"
+	"syscall"
+	"unsafe"
+)
+
+const (
+	// Family type definitions
+	FAMILY_ALL = syscall.AF_UNSPEC
+	FAMILY_V4  = syscall.AF_INET
+	FAMILY_V6  = syscall.AF_INET6
+)
+
+var nextSeqNr uint32
+
+// GetIPFamily returns the family type of a net.IP.
+func GetIPFamily(ip net.IP) int {
+	if len(ip) <= net.IPv4len {
+		return FAMILY_V4
+	}
+	if ip.To4() != nil {
+		return FAMILY_V4
+	}
+	return FAMILY_V6
+}
+
+var nativeEndian binary.ByteOrder
+
+// Get native endianness for the system
+func NativeEndian() binary.ByteOrder {
+	if nativeEndian == nil {
+		var x uint32 = 0x01020304
+		if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
+			nativeEndian = binary.BigEndian
+		}
+		nativeEndian = binary.LittleEndian
+	}
+	return nativeEndian
+}
+
+// Byte swap a 16 bit value if we aren't big endian
+func Swap16(i uint16) uint16 {
+	if NativeEndian() == binary.BigEndian {
+		return i
+	}
+	return (i&0xff00)>>8 | (i&0xff)<<8
+}
+
+// Byte swap a 32 bit value if aren't big endian
+func Swap32(i uint32) uint32 {
+	if NativeEndian() == binary.BigEndian {
+		return i
+	}
+	return (i&0xff000000)>>24 | (i&0xff0000)>>8 | (i&0xff00)<<8 | (i&0xff)<<24
+}
+
+type NetlinkRequestData interface {
+	Len() int
+	Serialize() []byte
+}
+
+// IfInfomsg is related to links, but it is used for list requests as well
+type IfInfomsg struct {
+	syscall.IfInfomsg
+}
+
+// Create an IfInfomsg with family specified
+func NewIfInfomsg(family int) *IfInfomsg {
+	return &IfInfomsg{
+		IfInfomsg: syscall.IfInfomsg{
+			Family: uint8(family),
+		},
+	}
+}
+
+func DeserializeIfInfomsg(b []byte) *IfInfomsg {
+	return (*IfInfomsg)(unsafe.Pointer(&b[0:syscall.SizeofIfInfomsg][0]))
+}
+
+func (msg *IfInfomsg) Serialize() []byte {
+	return (*(*[syscall.SizeofIfInfomsg]byte)(unsafe.Pointer(msg)))[:]
+}
+
+func (msg *IfInfomsg) Len() int {
+	return syscall.SizeofIfInfomsg
+}
+
+func rtaAlignOf(attrlen int) int {
+	return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
+}
+
+func NewIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
+	msg := NewIfInfomsg(family)
+	parent.children = append(parent.children, msg)
+	return msg
+}
+
+// Extend RtAttr to handle data and children
+type RtAttr struct {
+	syscall.RtAttr
+	Data     []byte
+	children []NetlinkRequestData
+}
+
+// Create a new Extended RtAttr object
+func NewRtAttr(attrType int, data []byte) *RtAttr {
+	return &RtAttr{
+		RtAttr: syscall.RtAttr{
+			Type: uint16(attrType),
+		},
+		children: []NetlinkRequestData{},
+		Data:     data,
+	}
+}
+
+// Create a new RtAttr obj anc add it as a child of an existing object
+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 += rtaAlignOf(child.Len())
+	}
+	l += syscall.SizeofRtAttr
+	return rtaAlignOf(l + len(a.Data))
+}
+
+// Serialize the RtAttr into a byte array
+// This can't ust unsafe.cast because it must iterate through children.
+func (a *RtAttr) Serialize() []byte {
+	native := NativeEndian()
+
+	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.Serialize()
+			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
+}
+
+type NetlinkRequest struct {
+	syscall.NlMsghdr
+	Data []NetlinkRequestData
+}
+
+// Serialize the Netlink Request into a byte array
+func (msg *NetlinkRequest) Serialize() []byte {
+	length := syscall.SizeofNlMsghdr
+	dataBytes := make([][]byte, len(msg.Data))
+	for i, data := range msg.Data {
+		dataBytes[i] = data.Serialize()
+		length = length + len(dataBytes[i])
+	}
+	msg.Len = uint32(length)
+	b := make([]byte, length)
+	hdr := (*(*[syscall.SizeofNlMsghdr]byte)(unsafe.Pointer(msg)))[:]
+	next := syscall.SizeofNlMsghdr
+	copy(b[0:next], hdr)
+	for _, data := range dataBytes {
+		for _, dataByte := range data {
+			b[next] = dataByte
+			next = next + 1
+		}
+	}
+	return b
+}
+
+func (msg *NetlinkRequest) AddData(data NetlinkRequestData) {
+	if data != nil {
+		msg.Data = append(msg.Data, data)
+	}
+}
+
+// Execute the request against a the given sockType.
+// Returns a list of netlink messages in seriaized format, optionally filtered
+// by resType.
+func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, error) {
+	s, err := getNetlinkSocket(sockType)
+	if err != nil {
+		return nil, err
+	}
+	defer s.Close()
+
+	if err := s.Send(req); err != nil {
+		return nil, err
+	}
+
+	pid, err := s.GetPid()
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([][]byte, 0)
+
+done:
+	for {
+		msgs, err := s.Recieve()
+		if err != nil {
+			return nil, err
+		}
+		for _, m := range msgs {
+			if m.Header.Seq != req.Seq {
+				return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
+			}
+			if m.Header.Pid != pid {
+				return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
+			}
+			if m.Header.Type == syscall.NLMSG_DONE {
+				break done
+			}
+			if m.Header.Type == syscall.NLMSG_ERROR {
+				native := NativeEndian()
+				error := int32(native.Uint32(m.Data[0:4]))
+				if error == 0 {
+					break done
+				}
+				return nil, syscall.Errno(-error)
+			}
+			if resType != 0 && m.Header.Type != resType {
+				continue
+			}
+			res = append(res, m.Data)
+		}
+	}
+	return res, nil
+}
+
+// Create a new netlink request from proto and flags
+// Note the Len value will be inaccurate once data is added until
+// the message is serialized
+func NewNetlinkRequest(proto, flags int) *NetlinkRequest {
+	return &NetlinkRequest{
+		NlMsghdr: syscall.NlMsghdr{
+			Len:   uint32(syscall.SizeofNlMsghdr),
+			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(protocol int) (*NetlinkSocket, error) {
+	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
+	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
+}
+
+// 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
+// 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)
+	if err != nil {
+		return nil, err
+	}
+	s := &NetlinkSocket{
+		fd: fd,
+	}
+	s.lsa.Family = syscall.AF_NETLINK
+
+	for _, g := range groups {
+		s.lsa.Groups |= (1 << (g-1))
+	}
+
+	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.Serialize(), 0, &s.lsa); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *NetlinkSocket) Recieve() ([]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, fmt.Errorf("Got short response from netlink")
+	}
+	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, fmt.Errorf("Wrong socket type")
+}
+
+func ZeroTerminated(s string) []byte {
+	bytes := make([]byte, len(s)+1)
+	for i := 0; i < len(s); i++ {
+		bytes[i] = s[i]
+	}
+	bytes[len(s)] = 0
+	return bytes
+}
+
+func NonZeroTerminated(s string) []byte {
+	bytes := make([]byte, len(s))
+	for i := 0; i < len(s); i++ {
+		bytes[i] = s[i]
+	}
+	return bytes
+}
+
+func BytesToString(b []byte) string {
+	n := bytes.Index(b, []byte{0})
+	return string(b[:n])
+}
+
+func Uint8Attr(v uint8) []byte {
+	return []byte{byte(v)}
+}
+
+func Uint16Attr(v uint16) []byte {
+	native := NativeEndian()
+	bytes := make([]byte, 2)
+	native.PutUint16(bytes, v)
+	return bytes
+}
+
+func Uint32Attr(v uint32) []byte {
+	native := NativeEndian()
+	bytes := make([]byte, 4)
+	native.PutUint32(bytes, v)
+	return bytes
+}
+
+func ParseRouteAttr(b []byte) ([]syscall.NetlinkRouteAttr, error) {
+	var attrs []syscall.NetlinkRouteAttr
+	for len(b) >= syscall.SizeofRtAttr {
+		a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
+		if err != nil {
+			return nil, err
+		}
+		ra := syscall.NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]}
+		attrs = append(attrs, ra)
+		b = b[alen:]
+	}
+	return attrs, nil
+}
+
+func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
+	a := (*syscall.RtAttr)(unsafe.Pointer(&b[0]))
+	if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) {
+		return nil, nil, 0, syscall.EINVAL
+	}
+	return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
+}

+ 60 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux_test.go

@@ -0,0 +1,60 @@
+package nl
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/binary"
+	"reflect"
+	"syscall"
+	"testing"
+)
+
+type testSerializer interface {
+	serializeSafe() []byte
+	Serialize() []byte
+}
+
+func testDeserializeSerialize(t *testing.T, orig []byte, safemsg testSerializer, msg testSerializer) {
+	if !reflect.DeepEqual(safemsg, msg) {
+		t.Fatal("Deserialization failed.\n", safemsg, "\n", msg)
+	}
+	safe := msg.serializeSafe()
+	if !bytes.Equal(safe, orig) {
+		t.Fatal("Safe serialization failed.\n", safe, "\n", orig)
+	}
+	b := msg.Serialize()
+	if !bytes.Equal(b, safe) {
+		t.Fatal("Serialization failed.\n", b, "\n", safe)
+	}
+}
+
+func (msg *IfInfomsg) write(b []byte) {
+	native := NativeEndian()
+	b[0] = msg.Family
+	b[1] = msg.X__ifi_pad
+	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)
+}
+
+func (msg *IfInfomsg) serializeSafe() []byte {
+	length := syscall.SizeofIfInfomsg
+	b := make([]byte, length)
+	msg.write(b)
+	return b
+}
+
+func deserializeIfInfomsgSafe(b []byte) *IfInfomsg {
+	var msg = IfInfomsg{}
+	binary.Read(bytes.NewReader(b[0:syscall.SizeofIfInfomsg]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestIfInfomsgDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, syscall.SizeofIfInfomsg)
+	rand.Read(orig)
+	safemsg := deserializeIfInfomsgSafe(orig)
+	msg := DeserializeIfInfomsg(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}

+ 34 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go

@@ -0,0 +1,34 @@
+package nl
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+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) Len() int {
+	return syscall.SizeofRtMsg
+}
+
+func DeserializeRtMsg(b []byte) *RtMsg {
+	return (*RtMsg)(unsafe.Pointer(&b[0:syscall.SizeofRtMsg][0]))
+}
+
+func (msg *RtMsg) Serialize() []byte {
+	return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:]
+}
+

+ 43 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux_test.go

@@ -0,0 +1,43 @@
+package nl
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/binary"
+	"syscall"
+	"testing"
+)
+
+func (msg *RtMsg) write(b []byte) {
+	native := NativeEndian()
+	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)
+}
+
+func (msg *RtMsg) serializeSafe() []byte {
+	len := syscall.SizeofRtMsg
+	b := make([]byte, len)
+	msg.write(b)
+	return b
+}
+
+func deserializeRtMsgSafe(b []byte) *RtMsg {
+	var msg = RtMsg{}
+	binary.Read(bytes.NewReader(b[0:syscall.SizeofRtMsg]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestRtMsgDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, syscall.SizeofRtMsg)
+	rand.Read(orig)
+	safemsg := deserializeRtMsgSafe(orig)
+	msg := DeserializeRtMsg(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}

+ 259 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go

@@ -0,0 +1,259 @@
+package nl
+
+import (
+	"bytes"
+	"net"
+	"unsafe"
+)
+
+// Infinity for packet and byte counts
+const (
+	XFRM_INF = ^uint64(0)
+)
+
+// Message Types
+const (
+	XFRM_MSG_BASE        = 0x10
+	XFRM_MSG_NEWSA       = 0x10
+	XFRM_MSG_DELSA       = 0x11
+	XFRM_MSG_GETSA       = 0x12
+	XFRM_MSG_NEWPOLICY   = 0x13
+	XFRM_MSG_DELPOLICY   = 0x14
+	XFRM_MSG_GETPOLICY   = 0x15
+	XFRM_MSG_ALLOCSPI    = 0x16
+	XFRM_MSG_ACQUIRE     = 0x17
+	XFRM_MSG_EXPIRE      = 0x18
+	XFRM_MSG_UPDPOLICY   = 0x19
+	XFRM_MSG_UPDSA       = 0x1a
+	XFRM_MSG_POLEXPIRE   = 0x1b
+	XFRM_MSG_FLUSHSA     = 0x1c
+	XFRM_MSG_FLUSHPOLICY = 0x1d
+	XFRM_MSG_NEWAE       = 0x1e
+	XFRM_MSG_GETAE       = 0x1f
+	XFRM_MSG_REPORT      = 0x20
+	XFRM_MSG_MIGRATE     = 0x21
+	XFRM_MSG_NEWSADINFO  = 0x22
+	XFRM_MSG_GETSADINFO  = 0x23
+	XFRM_MSG_NEWSPDINFO  = 0x24
+	XFRM_MSG_GETSPDINFO  = 0x25
+	XFRM_MSG_MAPPING     = 0x26
+	XFRM_MSG_MAX         = 0x26
+	XFRM_NR_MSGTYPES     = 0x17
+)
+
+// Attribute types
+const (
+	/* Netlink message attributes.  */
+	XFRMA_UNSPEC         = 0x00
+	XFRMA_ALG_AUTH       = 0x01 /* struct xfrm_algo */
+	XFRMA_ALG_CRYPT      = 0x02 /* struct xfrm_algo */
+	XFRMA_ALG_COMP       = 0x03 /* struct xfrm_algo */
+	XFRMA_ENCAP          = 0x04 /* struct xfrm_algo + struct xfrm_encap_tmpl */
+	XFRMA_TMPL           = 0x05 /* 1 or more struct xfrm_user_tmpl */
+	XFRMA_SA             = 0x06 /* struct xfrm_usersa_info  */
+	XFRMA_POLICY         = 0x07 /* struct xfrm_userpolicy_info */
+	XFRMA_SEC_CTX        = 0x08 /* struct xfrm_sec_ctx */
+	XFRMA_LTIME_VAL      = 0x09
+	XFRMA_REPLAY_VAL     = 0x0a
+	XFRMA_REPLAY_THRESH  = 0x0b
+	XFRMA_ETIMER_THRESH  = 0x0c
+	XFRMA_SRCADDR        = 0x0d /* xfrm_address_t */
+	XFRMA_COADDR         = 0x0e /* xfrm_address_t */
+	XFRMA_LASTUSED       = 0x0f /* unsigned long  */
+	XFRMA_POLICY_TYPE    = 0x10 /* struct xfrm_userpolicy_type */
+	XFRMA_MIGRATE        = 0x11
+	XFRMA_ALG_AEAD       = 0x12 /* struct xfrm_algo_aead */
+	XFRMA_KMADDRESS      = 0x13 /* struct xfrm_user_kmaddress */
+	XFRMA_ALG_AUTH_TRUNC = 0x14 /* struct xfrm_algo_auth */
+	XFRMA_MARK           = 0x15 /* struct xfrm_mark */
+	XFRMA_TFCPAD         = 0x16 /* __u32 */
+	XFRMA_REPLAY_ESN_VAL = 0x17 /* struct xfrm_replay_esn */
+	XFRMA_SA_EXTRA_FLAGS = 0x18 /* __u32 */
+	XFRMA_MAX            = 0x18
+)
+
+const (
+	SizeofXfrmAddress     = 0x10
+	SizeofXfrmSelector    = 0x38
+	SizeofXfrmLifetimeCfg = 0x40
+	SizeofXfrmLifetimeCur = 0x20
+	SizeofXfrmId          = 0x18
+)
+
+// typedef union {
+//   __be32    a4;
+//   __be32    a6[4];
+// } xfrm_address_t;
+
+type XfrmAddress [SizeofXfrmAddress]byte
+
+func (x *XfrmAddress) ToIP() net.IP {
+	var empty = [12]byte{}
+	ip := make(net.IP, net.IPv6len)
+	if bytes.Equal(x[4:16], empty[:]) {
+		ip[10] = 0xff
+		ip[11] = 0xff
+		copy(ip[12:16], x[0:4])
+	} else {
+		copy(ip[:], x[:])
+	}
+	return ip
+}
+
+func (x *XfrmAddress) ToIPNet(prefixlen uint8) *net.IPNet {
+	ip := x.ToIP()
+	if GetIPFamily(ip) == FAMILY_V4 {
+		return &net.IPNet{ip, net.CIDRMask(int(prefixlen), 32)}
+	} else {
+		return &net.IPNet{ip, net.CIDRMask(int(prefixlen), 128)}
+	}
+}
+
+func (x *XfrmAddress) FromIP(ip net.IP) {
+	var empty = [16]byte{}
+	if len(ip) < net.IPv4len {
+		copy(x[4:16], empty[:])
+	} else if GetIPFamily(ip) == FAMILY_V4 {
+		copy(x[0:4], ip.To4()[0:4])
+		copy(x[4:16], empty[:12])
+	} else {
+		copy(x[0:16], ip.To16()[0:16])
+	}
+}
+
+func DeserializeXfrmAddress(b []byte) *XfrmAddress {
+	return (*XfrmAddress)(unsafe.Pointer(&b[0:SizeofXfrmAddress][0]))
+}
+
+func (msg *XfrmAddress) Serialize() []byte {
+	return (*(*[SizeofXfrmAddress]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_selector {
+//   xfrm_address_t  daddr;
+//   xfrm_address_t  saddr;
+//   __be16  dport;
+//   __be16  dport_mask;
+//   __be16  sport;
+//   __be16  sport_mask;
+//   __u16 family;
+//   __u8  prefixlen_d;
+//   __u8  prefixlen_s;
+//   __u8  proto;
+//   int ifindex;
+//   __kernel_uid32_t  user;
+// };
+
+type XfrmSelector struct {
+	Daddr      XfrmAddress
+	Saddr      XfrmAddress
+	Dport      uint16 // big endian
+	DportMask  uint16 // big endian
+	Sport      uint16 // big endian
+	SportMask  uint16 // big endian
+	Family     uint16
+	PrefixlenD uint8
+	PrefixlenS uint8
+	Proto      uint8
+	Pad        [3]byte
+	Ifindex    int32
+	User       uint32
+}
+
+func (msg *XfrmSelector) Len() int {
+	return SizeofXfrmSelector
+}
+
+func DeserializeXfrmSelector(b []byte) *XfrmSelector {
+	return (*XfrmSelector)(unsafe.Pointer(&b[0:SizeofXfrmSelector][0]))
+}
+
+func (msg *XfrmSelector) Serialize() []byte {
+	return (*(*[SizeofXfrmSelector]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_lifetime_cfg {
+//   __u64 soft_byte_limit;
+//   __u64 hard_byte_limit;
+//   __u64 soft_packet_limit;
+//   __u64 hard_packet_limit;
+//   __u64 soft_add_expires_seconds;
+//   __u64 hard_add_expires_seconds;
+//   __u64 soft_use_expires_seconds;
+//   __u64 hard_use_expires_seconds;
+// };
+//
+
+type XfrmLifetimeCfg struct {
+	SoftByteLimit         uint64
+	HardByteLimit         uint64
+	SoftPacketLimit       uint64
+	HardPacketLimit       uint64
+	SoftAddExpiresSeconds uint64
+	HardAddExpiresSeconds uint64
+	SoftUseExpiresSeconds uint64
+	HardUseExpiresSeconds uint64
+}
+
+func (msg *XfrmLifetimeCfg) Len() int {
+	return SizeofXfrmLifetimeCfg
+}
+
+func DeserializeXfrmLifetimeCfg(b []byte) *XfrmLifetimeCfg {
+	return (*XfrmLifetimeCfg)(unsafe.Pointer(&b[0:SizeofXfrmLifetimeCfg][0]))
+}
+
+func (msg *XfrmLifetimeCfg) Serialize() []byte {
+	return (*(*[SizeofXfrmLifetimeCfg]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_lifetime_cur {
+//   __u64 bytes;
+//   __u64 packets;
+//   __u64 add_time;
+//   __u64 use_time;
+// };
+
+type XfrmLifetimeCur struct {
+	Bytes   uint64
+	Packets uint64
+	AddTime uint64
+	UseTime uint64
+}
+
+func (msg *XfrmLifetimeCur) Len() int {
+	return SizeofXfrmLifetimeCur
+}
+
+func DeserializeXfrmLifetimeCur(b []byte) *XfrmLifetimeCur {
+	return (*XfrmLifetimeCur)(unsafe.Pointer(&b[0:SizeofXfrmLifetimeCur][0]))
+}
+
+func (msg *XfrmLifetimeCur) Serialize() []byte {
+	return (*(*[SizeofXfrmLifetimeCur]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_id {
+//   xfrm_address_t  daddr;
+//   __be32    spi;
+//   __u8    proto;
+// };
+
+type XfrmId struct {
+	Daddr XfrmAddress
+	Spi   uint32 // big endian
+	Proto uint8
+	Pad   [3]byte
+}
+
+func (msg *XfrmId) Len() int {
+	return SizeofXfrmId
+}
+
+func DeserializeXfrmId(b []byte) *XfrmId {
+	return (*XfrmId)(unsafe.Pointer(&b[0:SizeofXfrmId][0]))
+}
+
+func (msg *XfrmId) Serialize() []byte {
+	return (*(*[SizeofXfrmId]byte)(unsafe.Pointer(msg)))[:]
+}

+ 161 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux_test.go

@@ -0,0 +1,161 @@
+package nl
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/binary"
+	"testing"
+)
+
+func (msg *XfrmAddress) write(b []byte) {
+	copy(b[0:SizeofXfrmAddress], msg[:])
+}
+
+func (msg *XfrmAddress) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmAddress)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmAddressSafe(b []byte) *XfrmAddress {
+	var msg = XfrmAddress{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmAddress]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmAddressDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmAddress)
+	rand.Read(orig)
+	safemsg := deserializeXfrmAddressSafe(orig)
+	msg := DeserializeXfrmAddress(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmSelector) write(b []byte) {
+	const AddrEnd = SizeofXfrmAddress * 2
+	native := NativeEndian()
+	msg.Daddr.write(b[0:SizeofXfrmAddress])
+	msg.Saddr.write(b[SizeofXfrmAddress:AddrEnd])
+	native.PutUint16(b[AddrEnd:AddrEnd+2], msg.Dport)
+	native.PutUint16(b[AddrEnd+2:AddrEnd+4], msg.DportMask)
+	native.PutUint16(b[AddrEnd+4:AddrEnd+6], msg.Sport)
+	native.PutUint16(b[AddrEnd+6:AddrEnd+8], msg.SportMask)
+	native.PutUint16(b[AddrEnd+8:AddrEnd+10], msg.Family)
+	b[AddrEnd+10] = msg.PrefixlenD
+	b[AddrEnd+11] = msg.PrefixlenS
+	b[AddrEnd+12] = msg.Proto
+	copy(b[AddrEnd+13:AddrEnd+16], msg.Pad[:])
+	native.PutUint32(b[AddrEnd+16:AddrEnd+20], uint32(msg.Ifindex))
+	native.PutUint32(b[AddrEnd+20:AddrEnd+24], msg.User)
+}
+
+func (msg *XfrmSelector) serializeSafe() []byte {
+	length := SizeofXfrmSelector
+	b := make([]byte, length)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmSelectorSafe(b []byte) *XfrmSelector {
+	var msg = XfrmSelector{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmSelector]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmSelectorDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmSelector)
+	rand.Read(orig)
+	safemsg := deserializeXfrmSelectorSafe(orig)
+	msg := DeserializeXfrmSelector(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmLifetimeCfg) write(b []byte) {
+	native := NativeEndian()
+	native.PutUint64(b[0:8], msg.SoftByteLimit)
+	native.PutUint64(b[8:16], msg.HardByteLimit)
+	native.PutUint64(b[16:24], msg.SoftPacketLimit)
+	native.PutUint64(b[24:32], msg.HardPacketLimit)
+	native.PutUint64(b[32:40], msg.SoftAddExpiresSeconds)
+	native.PutUint64(b[40:48], msg.HardAddExpiresSeconds)
+	native.PutUint64(b[48:56], msg.SoftUseExpiresSeconds)
+	native.PutUint64(b[56:64], msg.HardUseExpiresSeconds)
+}
+
+func (msg *XfrmLifetimeCfg) serializeSafe() []byte {
+	length := SizeofXfrmLifetimeCfg
+	b := make([]byte, length)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmLifetimeCfgSafe(b []byte) *XfrmLifetimeCfg {
+	var msg = XfrmLifetimeCfg{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCfg]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmLifetimeCfgDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmLifetimeCfg)
+	rand.Read(orig)
+	safemsg := deserializeXfrmLifetimeCfgSafe(orig)
+	msg := DeserializeXfrmLifetimeCfg(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmLifetimeCur) write(b []byte) {
+	native := NativeEndian()
+	native.PutUint64(b[0:8], msg.Bytes)
+	native.PutUint64(b[8:16], msg.Packets)
+	native.PutUint64(b[16:24], msg.AddTime)
+	native.PutUint64(b[24:32], msg.UseTime)
+}
+
+func (msg *XfrmLifetimeCur) serializeSafe() []byte {
+	length := SizeofXfrmLifetimeCur
+	b := make([]byte, length)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmLifetimeCurSafe(b []byte) *XfrmLifetimeCur {
+	var msg = XfrmLifetimeCur{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmLifetimeCur]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmLifetimeCurDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmLifetimeCur)
+	rand.Read(orig)
+	safemsg := deserializeXfrmLifetimeCurSafe(orig)
+	msg := DeserializeXfrmLifetimeCur(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmId) write(b []byte) {
+	native := NativeEndian()
+	msg.Daddr.write(b[0:SizeofXfrmAddress])
+	native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
+	b[SizeofXfrmAddress+4] = msg.Proto
+	copy(b[SizeofXfrmAddress+5:SizeofXfrmAddress+8], msg.Pad[:])
+}
+
+func (msg *XfrmId) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmId)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmIdSafe(b []byte) *XfrmId {
+	var msg = XfrmId{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmId]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmIdDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmId)
+	rand.Read(orig)
+	safemsg := deserializeXfrmIdSafe(orig)
+	msg := DeserializeXfrmId(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}

+ 120 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go

@@ -0,0 +1,120 @@
+package nl
+
+import (
+	"unsafe"
+)
+
+const (
+	SizeofXfrmUserpolicyId   = 0x40
+	SizeofXfrmUserpolicyInfo = 0xa8
+	SizeofXfrmUserTmpl       = 0x40
+)
+
+// struct xfrm_userpolicy_id {
+//   struct xfrm_selector    sel;
+//   __u32       index;
+//   __u8        dir;
+// };
+//
+
+type XfrmUserpolicyId struct {
+	Sel   XfrmSelector
+	Index uint32
+	Dir   uint8
+	Pad   [3]byte
+}
+
+func (msg *XfrmUserpolicyId) Len() int {
+	return SizeofXfrmUserpolicyId
+}
+
+func DeserializeXfrmUserpolicyId(b []byte) *XfrmUserpolicyId {
+	return (*XfrmUserpolicyId)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyId][0]))
+}
+
+func (msg *XfrmUserpolicyId) Serialize() []byte {
+	return (*(*[SizeofXfrmUserpolicyId]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_userpolicy_info {
+//   struct xfrm_selector    sel;
+//   struct xfrm_lifetime_cfg  lft;
+//   struct xfrm_lifetime_cur  curlft;
+//   __u32       priority;
+//   __u32       index;
+//   __u8        dir;
+//   __u8        action;
+// #define XFRM_POLICY_ALLOW 0
+// #define XFRM_POLICY_BLOCK 1
+//   __u8        flags;
+// #define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
+//   /* Automatically expand selector to include matching ICMP payloads. */
+// #define XFRM_POLICY_ICMP  2
+//   __u8        share;
+// };
+
+type XfrmUserpolicyInfo struct {
+	Sel      XfrmSelector
+	Lft      XfrmLifetimeCfg
+	Curlft   XfrmLifetimeCur
+	Priority uint32
+	Index    uint32
+	Dir      uint8
+	Action   uint8
+	Flags    uint8
+	Share    uint8
+	Pad      [4]byte
+}
+
+func (msg *XfrmUserpolicyInfo) Len() int {
+	return SizeofXfrmUserpolicyInfo
+}
+
+func DeserializeXfrmUserpolicyInfo(b []byte) *XfrmUserpolicyInfo {
+	return (*XfrmUserpolicyInfo)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyInfo][0]))
+}
+
+func (msg *XfrmUserpolicyInfo) Serialize() []byte {
+	return (*(*[SizeofXfrmUserpolicyInfo]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_user_tmpl {
+//   struct xfrm_id    id;
+//   __u16     family;
+//   xfrm_address_t    saddr;
+//   __u32     reqid;
+//   __u8      mode;
+//   __u8      share;
+//   __u8      optional;
+//   __u32     aalgos;
+//   __u32     ealgos;
+//   __u32     calgos;
+// }
+
+type XfrmUserTmpl struct {
+	XfrmId   XfrmId
+	Family   uint16
+	Pad1     [2]byte
+	Saddr    XfrmAddress
+	Reqid    uint32
+	Mode     uint8
+	Share    uint8
+	Optional uint8
+	Pad2     byte
+	Aalgos   uint32
+	Ealgos   uint32
+	Calgos   uint32
+}
+
+func (msg *XfrmUserTmpl) Len() int {
+	return SizeofXfrmUserTmpl
+}
+
+func DeserializeXfrmUserTmpl(b []byte) *XfrmUserTmpl {
+	return (*XfrmUserTmpl)(unsafe.Pointer(&b[0:SizeofXfrmUserTmpl][0]))
+}
+
+func (msg *XfrmUserTmpl) Serialize() []byte {
+	return (*(*[SizeofXfrmUserTmpl]byte)(unsafe.Pointer(msg)))[:]
+}
+

+ 109 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux_test.go

@@ -0,0 +1,109 @@
+package nl
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/binary"
+	"testing"
+)
+
+func (msg *XfrmUserpolicyId) write(b []byte) {
+	native := NativeEndian()
+	msg.Sel.write(b[0:SizeofXfrmSelector])
+	native.PutUint32(b[SizeofXfrmSelector:SizeofXfrmSelector+4], msg.Index)
+	b[SizeofXfrmSelector+4] = msg.Dir
+	copy(b[SizeofXfrmSelector+5:SizeofXfrmSelector+8], msg.Pad[:])
+}
+
+func (msg *XfrmUserpolicyId) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmUserpolicyId)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmUserpolicyIdSafe(b []byte) *XfrmUserpolicyId {
+	var msg = XfrmUserpolicyId{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyId]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmUserpolicyIdDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmUserpolicyId)
+	rand.Read(orig)
+	safemsg := deserializeXfrmUserpolicyIdSafe(orig)
+	msg := DeserializeXfrmUserpolicyId(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmUserpolicyInfo) write(b []byte) {
+	const CfgEnd = SizeofXfrmSelector + SizeofXfrmLifetimeCfg
+	const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
+	native := NativeEndian()
+	msg.Sel.write(b[0:SizeofXfrmSelector])
+	msg.Lft.write(b[SizeofXfrmSelector:CfgEnd])
+	msg.Curlft.write(b[CfgEnd:CurEnd])
+	native.PutUint32(b[CurEnd:CurEnd+4], msg.Priority)
+	native.PutUint32(b[CurEnd+4:CurEnd+8], msg.Index)
+	b[CurEnd+8] = msg.Dir
+	b[CurEnd+9] = msg.Action
+	b[CurEnd+10] = msg.Flags
+	b[CurEnd+11] = msg.Share
+	copy(b[CurEnd+12:CurEnd+16], msg.Pad[:])
+}
+
+func (msg *XfrmUserpolicyInfo) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmUserpolicyInfo)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmUserpolicyInfoSafe(b []byte) *XfrmUserpolicyInfo {
+	var msg = XfrmUserpolicyInfo{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmUserpolicyInfo]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmUserpolicyInfoDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmUserpolicyInfo)
+	rand.Read(orig)
+	safemsg := deserializeXfrmUserpolicyInfoSafe(orig)
+	msg := DeserializeXfrmUserpolicyInfo(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmUserTmpl) write(b []byte) {
+	const AddrEnd = SizeofXfrmId + 4 + SizeofXfrmAddress
+	native := NativeEndian()
+	msg.XfrmId.write(b[0:SizeofXfrmId])
+	native.PutUint16(b[SizeofXfrmId:SizeofXfrmId+2], msg.Family)
+	copy(b[SizeofXfrmId+2:SizeofXfrmId+4], msg.Pad1[:])
+	msg.Saddr.write(b[SizeofXfrmId+4 : AddrEnd])
+	native.PutUint32(b[AddrEnd:AddrEnd+4], msg.Reqid)
+	b[AddrEnd+4] = msg.Mode
+	b[AddrEnd+5] = msg.Share
+	b[AddrEnd+6] = msg.Optional
+	b[AddrEnd+7] = msg.Pad2
+	native.PutUint32(b[AddrEnd+8:AddrEnd+12], msg.Aalgos)
+	native.PutUint32(b[AddrEnd+12:AddrEnd+16], msg.Ealgos)
+	native.PutUint32(b[AddrEnd+16:AddrEnd+20], msg.Calgos)
+}
+
+func (msg *XfrmUserTmpl) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmUserTmpl)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmUserTmplSafe(b []byte) *XfrmUserTmpl {
+	var msg = XfrmUserTmpl{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmUserTmpl]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmUserTmplDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmUserTmpl)
+	rand.Read(orig)
+	safemsg := deserializeXfrmUserTmplSafe(orig)
+	msg := DeserializeXfrmUserTmpl(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}

+ 222 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go

@@ -0,0 +1,222 @@
+package nl
+
+import (
+	"unsafe"
+)
+
+const (
+	SizeofXfrmUsersaId   = 0x18
+	SizeofXfrmStats      = 0x0c
+	SizeofXfrmUsersaInfo = 0xe0
+	SizeofXfrmAlgo       = 0x44
+	SizeofXfrmAlgoAuth   = 0x48
+	SizeofXfrmEncapTmpl  = 0x18
+)
+
+// struct xfrm_usersa_id {
+//   xfrm_address_t      daddr;
+//   __be32        spi;
+//   __u16       family;
+//   __u8        proto;
+// };
+
+type XfrmUsersaId struct {
+	Daddr  XfrmAddress
+	Spi    uint32 // big endian
+	Family uint16
+	Proto  uint8
+	Pad    byte
+}
+
+func (msg *XfrmUsersaId) Len() int {
+	return SizeofXfrmUsersaId
+}
+
+func DeserializeXfrmUsersaId(b []byte) *XfrmUsersaId {
+	return (*XfrmUsersaId)(unsafe.Pointer(&b[0:SizeofXfrmUsersaId][0]))
+}
+
+func (msg *XfrmUsersaId) Serialize() []byte {
+	return (*(*[SizeofXfrmUsersaId]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_stats {
+//   __u32 replay_window;
+//   __u32 replay;
+//   __u32 integrity_failed;
+// };
+
+type XfrmStats struct {
+	ReplayWindow    uint32
+	Replay          uint32
+	IntegrityFailed uint32
+}
+
+func (msg *XfrmStats) Len() int {
+	return SizeofXfrmStats
+}
+
+func DeserializeXfrmStats(b []byte) *XfrmStats {
+	return (*XfrmStats)(unsafe.Pointer(&b[0:SizeofXfrmStats][0]))
+}
+
+func (msg *XfrmStats) Serialize() []byte {
+	return (*(*[SizeofXfrmStats]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_usersa_info {
+//   struct xfrm_selector    sel;
+//   struct xfrm_id      id;
+//   xfrm_address_t      saddr;
+//   struct xfrm_lifetime_cfg  lft;
+//   struct xfrm_lifetime_cur  curlft;
+//   struct xfrm_stats   stats;
+//   __u32       seq;
+//   __u32       reqid;
+//   __u16       family;
+//   __u8        mode;   /* XFRM_MODE_xxx */
+//   __u8        replay_window;
+//   __u8        flags;
+// #define XFRM_STATE_NOECN  1
+// #define XFRM_STATE_DECAP_DSCP 2
+// #define XFRM_STATE_NOPMTUDISC 4
+// #define XFRM_STATE_WILDRECV 8
+// #define XFRM_STATE_ICMP   16
+// #define XFRM_STATE_AF_UNSPEC  32
+// #define XFRM_STATE_ALIGN4 64
+// #define XFRM_STATE_ESN    128
+// };
+//
+// #define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1
+//
+
+type XfrmUsersaInfo struct {
+	Sel          XfrmSelector
+	Id           XfrmId
+	Saddr        XfrmAddress
+	Lft          XfrmLifetimeCfg
+	Curlft       XfrmLifetimeCur
+	Stats        XfrmStats
+	Seq          uint32
+	Reqid        uint32
+	Family       uint16
+	Mode         uint8
+	ReplayWindow uint8
+	Flags        uint8
+	Pad          [7]byte
+}
+
+func (msg *XfrmUsersaInfo) Len() int {
+	return SizeofXfrmUsersaInfo
+}
+
+func DeserializeXfrmUsersaInfo(b []byte) *XfrmUsersaInfo {
+	return (*XfrmUsersaInfo)(unsafe.Pointer(&b[0:SizeofXfrmUsersaInfo][0]))
+}
+
+func (msg *XfrmUsersaInfo) Serialize() []byte {
+	return (*(*[SizeofXfrmUsersaInfo]byte)(unsafe.Pointer(msg)))[:]
+}
+
+// struct xfrm_algo {
+//   char    alg_name[64];
+//   unsigned int  alg_key_len;    /* in bits */
+//   char    alg_key[0];
+// };
+
+type XfrmAlgo struct {
+	AlgName   [64]byte
+	AlgKeyLen uint32
+	AlgKey    []byte
+}
+
+func (msg *XfrmAlgo) Len() int {
+	return SizeofXfrmAlgo + int(msg.AlgKeyLen/8)
+}
+
+func DeserializeXfrmAlgo(b []byte) *XfrmAlgo {
+	ret := XfrmAlgo{}
+	copy(ret.AlgName[:], b[0:64])
+	ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64]))
+	ret.AlgKey = b[68:ret.Len()]
+	return &ret
+}
+
+func (msg *XfrmAlgo) Serialize() []byte {
+	b := make([]byte, msg.Len())
+	copy(b[0:64], msg.AlgName[:])
+	copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:])
+	copy(b[68:msg.Len()], msg.AlgKey[:])
+	return b
+}
+
+// struct xfrm_algo_auth {
+//   char    alg_name[64];
+//   unsigned int  alg_key_len;    /* in bits */
+//   unsigned int  alg_trunc_len;  /* in bits */
+//   char    alg_key[0];
+// };
+
+type XfrmAlgoAuth struct {
+	AlgName     [64]byte
+	AlgKeyLen   uint32
+	AlgTruncLen uint32
+	AlgKey      []byte
+}
+
+func (msg *XfrmAlgoAuth) Len() int {
+	return SizeofXfrmAlgoAuth + int(msg.AlgKeyLen/8)
+}
+
+func DeserializeXfrmAlgoAuth(b []byte) *XfrmAlgoAuth {
+	ret := XfrmAlgoAuth{}
+	copy(ret.AlgName[:], b[0:64])
+	ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64]))
+	ret.AlgTruncLen = *(*uint32)(unsafe.Pointer(&b[68]))
+	ret.AlgKey = b[72:ret.Len()]
+	return &ret
+}
+
+func (msg *XfrmAlgoAuth) Serialize() []byte {
+	b := make([]byte, msg.Len())
+	copy(b[0:64], msg.AlgName[:])
+	copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:])
+	copy(b[68:72], (*(*[4]byte)(unsafe.Pointer(&msg.AlgTruncLen)))[:])
+	copy(b[72:msg.Len()], msg.AlgKey[:])
+	return b
+}
+
+// struct xfrm_algo_aead {
+//   char    alg_name[64];
+//   unsigned int  alg_key_len;  /* in bits */
+//   unsigned int  alg_icv_len;  /* in bits */
+//   char    alg_key[0];
+// }
+
+// struct xfrm_encap_tmpl {
+//   __u16   encap_type;
+//   __be16    encap_sport;
+//   __be16    encap_dport;
+//   xfrm_address_t  encap_oa;
+// };
+
+type XfrmEncapTmpl struct {
+	EncapType  uint16
+	EncapSport uint16 // big endian
+	EncapDport uint16 // big endian
+	Pad        [2]byte
+	EncapOa    XfrmAddress
+}
+
+func (msg *XfrmEncapTmpl) Len() int {
+	return SizeofXfrmEncapTmpl
+}
+
+func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl {
+	return (*XfrmEncapTmpl)(unsafe.Pointer(&b[0:SizeofXfrmEncapTmpl][0]))
+}
+
+func (msg *XfrmEncapTmpl) Serialize() []byte {
+	return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:]
+}
+

+ 207 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux_test.go

@@ -0,0 +1,207 @@
+package nl
+
+import (
+	"bytes"
+	"crypto/rand"
+	"encoding/binary"
+	"testing"
+)
+
+func (msg *XfrmUsersaId) write(b []byte) {
+	native := NativeEndian()
+	msg.Daddr.write(b[0:SizeofXfrmAddress])
+	native.PutUint32(b[SizeofXfrmAddress:SizeofXfrmAddress+4], msg.Spi)
+	native.PutUint16(b[SizeofXfrmAddress+4:SizeofXfrmAddress+6], msg.Family)
+	b[SizeofXfrmAddress+6] = msg.Proto
+	b[SizeofXfrmAddress+7] = msg.Pad
+}
+
+func (msg *XfrmUsersaId) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmUsersaId)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmUsersaIdSafe(b []byte) *XfrmUsersaId {
+	var msg = XfrmUsersaId{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaId]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmUsersaIdDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmUsersaId)
+	rand.Read(orig)
+	safemsg := deserializeXfrmUsersaIdSafe(orig)
+	msg := DeserializeXfrmUsersaId(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmStats) write(b []byte) {
+	native := NativeEndian()
+	native.PutUint32(b[0:4], msg.ReplayWindow)
+	native.PutUint32(b[4:8], msg.Replay)
+	native.PutUint32(b[8:12], msg.IntegrityFailed)
+}
+
+func (msg *XfrmStats) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmStats)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmStatsSafe(b []byte) *XfrmStats {
+	var msg = XfrmStats{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmStats]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmStatsDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmStats)
+	rand.Read(orig)
+	safemsg := deserializeXfrmStatsSafe(orig)
+	msg := DeserializeXfrmStats(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmUsersaInfo) write(b []byte) {
+	const IdEnd = SizeofXfrmSelector + SizeofXfrmId
+	const AddressEnd = IdEnd + SizeofXfrmAddress
+	const CfgEnd = AddressEnd + SizeofXfrmLifetimeCfg
+	const CurEnd = CfgEnd + SizeofXfrmLifetimeCur
+	const StatsEnd = CurEnd + SizeofXfrmStats
+	native := NativeEndian()
+	msg.Sel.write(b[0:SizeofXfrmSelector])
+	msg.Id.write(b[SizeofXfrmSelector:IdEnd])
+	msg.Saddr.write(b[IdEnd:AddressEnd])
+	msg.Lft.write(b[AddressEnd:CfgEnd])
+	msg.Curlft.write(b[CfgEnd:CurEnd])
+	msg.Stats.write(b[CurEnd:StatsEnd])
+	native.PutUint32(b[StatsEnd:StatsEnd+4], msg.Seq)
+	native.PutUint32(b[StatsEnd+4:StatsEnd+8], msg.Reqid)
+	native.PutUint16(b[StatsEnd+8:StatsEnd+10], msg.Family)
+	b[StatsEnd+10] = msg.Mode
+	b[StatsEnd+11] = msg.ReplayWindow
+	b[StatsEnd+12] = msg.Flags
+	copy(b[StatsEnd+13:StatsEnd+20], msg.Pad[:])
+}
+
+func (msg *XfrmUsersaInfo) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmUsersaInfo)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmUsersaInfoSafe(b []byte) *XfrmUsersaInfo {
+	var msg = XfrmUsersaInfo{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmUsersaInfo]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmUsersaInfoDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmUsersaInfo)
+	rand.Read(orig)
+	safemsg := deserializeXfrmUsersaInfoSafe(orig)
+	msg := DeserializeXfrmUsersaInfo(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmAlgo) write(b []byte) {
+	native := NativeEndian()
+	copy(b[0:64], msg.AlgName[:])
+	native.PutUint32(b[64:68], msg.AlgKeyLen)
+	copy(b[68:msg.Len()], msg.AlgKey[:])
+}
+
+func (msg *XfrmAlgo) serializeSafe() []byte {
+	b := make([]byte, msg.Len())
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmAlgoSafe(b []byte) *XfrmAlgo {
+	var msg = XfrmAlgo{}
+	copy(msg.AlgName[:], b[0:64])
+	binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
+	msg.AlgKey = b[68:msg.Len()]
+	return &msg
+}
+
+func TestXfrmAlgoDeserializeSerialize(t *testing.T) {
+	// use a 32 byte key len
+	var orig = make([]byte, SizeofXfrmAlgo+32)
+	rand.Read(orig)
+	// set the key len to 256 bits
+	orig[64] = 0
+	orig[65] = 1
+	orig[66] = 0
+	orig[67] = 0
+	safemsg := deserializeXfrmAlgoSafe(orig)
+	msg := DeserializeXfrmAlgo(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmAlgoAuth) write(b []byte) {
+	native := NativeEndian()
+	copy(b[0:64], msg.AlgName[:])
+	native.PutUint32(b[64:68], msg.AlgKeyLen)
+	native.PutUint32(b[68:72], msg.AlgTruncLen)
+	copy(b[72:msg.Len()], msg.AlgKey[:])
+}
+
+func (msg *XfrmAlgoAuth) serializeSafe() []byte {
+	b := make([]byte, msg.Len())
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmAlgoAuthSafe(b []byte) *XfrmAlgoAuth {
+	var msg = XfrmAlgoAuth{}
+	copy(msg.AlgName[:], b[0:64])
+	binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
+	binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgTruncLen)
+	msg.AlgKey = b[72:msg.Len()]
+	return &msg
+}
+
+func TestXfrmAlgoAuthDeserializeSerialize(t *testing.T) {
+	// use a 32 byte key len
+	var orig = make([]byte, SizeofXfrmAlgoAuth+32)
+	rand.Read(orig)
+	// set the key len to 256 bits
+	orig[64] = 0
+	orig[65] = 1
+	orig[66] = 0
+	orig[67] = 0
+	safemsg := deserializeXfrmAlgoAuthSafe(orig)
+	msg := DeserializeXfrmAlgoAuth(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}
+
+func (msg *XfrmEncapTmpl) write(b []byte) {
+	native := NativeEndian()
+	native.PutUint16(b[0:2], msg.EncapType)
+	native.PutUint16(b[2:4], msg.EncapSport)
+	native.PutUint16(b[4:6], msg.EncapDport)
+	copy(b[6:8], msg.Pad[:])
+	msg.EncapOa.write(b[8:SizeofXfrmAddress])
+}
+
+func (msg *XfrmEncapTmpl) serializeSafe() []byte {
+	b := make([]byte, SizeofXfrmEncapTmpl)
+	msg.write(b)
+	return b
+}
+
+func deserializeXfrmEncapTmplSafe(b []byte) *XfrmEncapTmpl {
+	var msg = XfrmEncapTmpl{}
+	binary.Read(bytes.NewReader(b[0:SizeofXfrmEncapTmpl]), NativeEndian(), &msg)
+	return &msg
+}
+
+func TestXfrmEncapTmplDeserializeSerialize(t *testing.T) {
+	var orig = make([]byte, SizeofXfrmEncapTmpl)
+	rand.Read(orig)
+	safemsg := deserializeXfrmEncapTmplSafe(orig)
+	msg := DeserializeXfrmEncapTmpl(orig)
+	testDeserializeSerialize(t, orig, safemsg, msg)
+}

+ 35 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/route.go

@@ -0,0 +1,35 @@
+package netlink
+
+import (
+	"fmt"
+	"net"
+	"syscall"
+)
+
+// Scope is an enum representing a route scope.
+type Scope uint8
+
+const (
+	SCOPE_UNIVERSE Scope = syscall.RT_SCOPE_UNIVERSE
+	SCOPE_SITE     Scope = syscall.RT_SCOPE_SITE
+	SCOPE_LINK     Scope = syscall.RT_SCOPE_LINK
+	SCOPE_HOST     Scope = syscall.RT_SCOPE_HOST
+	SCOPE_NOWHERE  Scope = syscall.RT_SCOPE_NOWHERE
+)
+
+// Route represents a netlink route. A route is associated with a link,
+// has a destination network, an optional source ip, and optional
+// gateway. Advanced route parameters and non-main routing tables are
+// currently not supported.
+type Route struct {
+	LinkIndex int
+	Scope     Scope
+	Dst       *net.IPNet
+	Src       net.IP
+	Gw        net.IP
+}
+
+func (r Route) String() string {
+	return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s}", r.LinkIndex, r.Dst.String(),
+		r.Src, r.Gw)
+}

+ 166 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go

@@ -0,0 +1,166 @@
+package netlink
+
+import (
+	"fmt"
+	"net"
+	"syscall"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+// RtAttr is shared so it is in netlink_linux.go
+
+// RouteAdd will add a route to the system.
+// Equivalent to: `ip route add $route`
+func RouteAdd(route *Route) error {
+	req := nl.NewNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	return routeHandle(route, req)
+}
+
+// RouteAdd will delete a route from the system.
+// Equivalent to: `ip route del $route`
+func RouteDel(route *Route) error {
+	req := nl.NewNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
+	return routeHandle(route, req)
+}
+
+func routeHandle(route *Route, req *nl.NetlinkRequest) error {
+	if route.Dst.IP == nil && route.Src == nil && route.Gw == nil {
+		return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
+	}
+
+	msg := nl.NewRtMsg()
+	msg.Scope = uint8(route.Scope)
+	family := -1
+	var rtAttrs []*nl.RtAttr
+
+	if route.Dst.IP != nil {
+		dstLen, _ := route.Dst.Mask.Size()
+		msg.Dst_len = uint8(dstLen)
+		dstFamily := nl.GetIPFamily(route.Dst.IP)
+		family = dstFamily
+		var dstData []byte
+		if dstFamily == FAMILY_V4 {
+			dstData = route.Dst.IP.To4()
+		} else {
+			dstData = route.Dst.IP.To16()
+		}
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_DST, dstData))
+	}
+
+	if route.Src != nil {
+		srcFamily := nl.GetIPFamily(route.Src)
+		if family != -1 && family != srcFamily {
+			return fmt.Errorf("source and destination ip are not the same IP family")
+		}
+		family = srcFamily
+		var srcData []byte
+		if srcFamily == FAMILY_V4 {
+			srcData = route.Src.To4()
+		} else {
+			srcData = route.Src.To16()
+		}
+		// The commonly used src ip for routes is actually PREFSRC
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_PREFSRC, srcData))
+	}
+
+	if route.Gw != nil {
+		gwFamily := nl.GetIPFamily(route.Gw)
+		if family != -1 && family != gwFamily {
+			return fmt.Errorf("gateway, source, and destination ip are not the same IP family")
+		}
+		family = gwFamily
+		var gwData []byte
+		if gwFamily == FAMILY_V4 {
+			gwData = route.Gw.To4()
+		} else {
+			gwData = route.Gw.To16()
+		}
+		rtAttrs = append(rtAttrs, nl.NewRtAttr(syscall.RTA_GATEWAY, gwData))
+	}
+
+	msg.Family = uint8(family)
+
+	req.AddData(msg)
+	for _, attr := range rtAttrs {
+		req.AddData(attr)
+	}
+
+	var (
+		b      = make([]byte, 4)
+		native = nl.NativeEndian()
+	)
+	native.PutUint32(b, uint32(route.LinkIndex))
+
+	req.AddData(nl.NewRtAttr(syscall.RTA_OIF, b))
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// RouteList gets a list of routes in the system.
+// Equivalent to: `ip route show`.
+// The list can be filtered by link and ip family.
+func RouteList(link Link, family int) ([]Route, error) {
+	req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
+	msg := nl.NewIfInfomsg(family)
+	req.AddData(msg)
+
+	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
+	if err != nil {
+		return nil, err
+	}
+
+	index := 0
+	if link != nil {
+		base := link.Attrs()
+		ensureIndex(base)
+		index = base.Index
+	}
+
+	native := nl.NativeEndian()
+	res := make([]Route, 0)
+	for _, m := range msgs {
+		msg := nl.DeserializeRtMsg(m)
+
+		if msg.Flags&syscall.RTM_F_CLONED != 0 {
+			// Ignore cloned routes
+			continue
+		}
+
+		if msg.Table != syscall.RT_TABLE_MAIN {
+			// Ignore non-main tables
+			continue
+		}
+
+		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+		if err != nil {
+			return nil, err
+		}
+
+		route := Route{Scope: Scope(msg.Scope)}
+		for _, attr := range attrs {
+			switch attr.Attr.Type {
+			case syscall.RTA_GATEWAY:
+				route.Gw = net.IP(attr.Value)
+			case syscall.RTA_PREFSRC:
+				route.Src = net.IP(attr.Value)
+			case syscall.RTA_DST:
+				route.Dst = &net.IPNet{
+					IP:   attr.Value,
+					Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
+				}
+			case syscall.RTA_OIF:
+				routeIndex := int(native.Uint32(attr.Value[0:4]))
+				if link != nil && routeIndex != index {
+					// Ignore routes from other interfaces
+					continue
+				}
+				route.LinkIndex = routeIndex
+			}
+		}
+		res = append(res, route)
+	}
+
+	return res, nil
+}

+ 53 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/route_test.go

@@ -0,0 +1,53 @@
+package netlink
+
+import (
+	"net"
+	"testing"
+)
+
+func TestRouteAddDel(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	// get loopback interface
+	link, err := LinkByName("lo")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// bring the interface up
+	if err = LinkSetUp(link); err != nil {
+		t.Fatal(err)
+	}
+
+	// add a gateway route
+	_, dst, err := net.ParseCIDR("192.168.0.0/24")
+
+	ip := net.ParseIP("127.1.1.1")
+	route := Route{LinkIndex: link.Attrs().Index, Dst: dst, Src: ip}
+	err = RouteAdd(&route)
+	if err != nil {
+		t.Fatal(err)
+	}
+	routes, err := RouteList(link, FAMILY_V4)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(routes) != 1 {
+		t.Fatal("Link not removed properly")
+	}
+
+	err = RouteDel(&route)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	routes, err = RouteList(link, FAMILY_V4)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(routes) != 0 {
+		t.Fatal("Route not removed properly")
+	}
+
+}

+ 64 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go

@@ -0,0 +1,64 @@
+package netlink
+
+import (
+	"fmt"
+	"syscall"
+)
+
+// Proto is an enum representing an ipsec protocol.
+type Proto uint8
+
+const (
+	XFRM_PROTO_ROUTE2    Proto = syscall.IPPROTO_ROUTING
+	XFRM_PROTO_ESP       Proto = syscall.IPPROTO_ESP
+	XFRM_PROTO_AH        Proto = syscall.IPPROTO_AH
+	XFRM_PROTO_HAO       Proto = syscall.IPPROTO_DSTOPTS
+	XFRM_PROTO_COMP      Proto = syscall.IPPROTO_COMP
+	XFRM_PROTO_IPSEC_ANY Proto = syscall.IPPROTO_RAW
+)
+
+func (p Proto) String() string {
+	switch p {
+	case XFRM_PROTO_ROUTE2:
+		return "route2"
+	case XFRM_PROTO_ESP:
+		return "esp"
+	case XFRM_PROTO_AH:
+		return "ah"
+	case XFRM_PROTO_HAO:
+		return "hao"
+	case XFRM_PROTO_COMP:
+		return "comp"
+	case XFRM_PROTO_IPSEC_ANY:
+		return "ipsec-any"
+	}
+	return fmt.Sprintf("%d", p)
+}
+
+// Mode is an enum representing an ipsec transport.
+type Mode uint8
+
+const (
+	XFRM_MODE_TRANSPORT         Mode = iota
+	XFRM_MODE_TUNNEL            Mode = iota
+	XFRM_MODE_ROUTEOPTIMIZATION Mode = iota
+	XFRM_MODE_IN_TRIGGER        Mode = iota
+	XFRM_MODE_BEET              Mode = iota
+	XFRM_MODE_MAX               Mode = iota
+)
+
+func (m Mode) String() string {
+	switch m {
+	case XFRM_MODE_TRANSPORT:
+		return "transport"
+	case XFRM_MODE_TUNNEL:
+		return "tunnel"
+	case XFRM_MODE_ROUTEOPTIMIZATION:
+		return "ro"
+	case XFRM_MODE_IN_TRIGGER:
+		return "in_trigger"
+	case XFRM_MODE_BEET:
+		return "beet"
+	}
+	return fmt.Sprintf("%d", m)
+}

+ 59 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go

@@ -0,0 +1,59 @@
+package netlink
+
+import (
+	"fmt"
+	"net"
+)
+
+// Dir is an enum representing an ipsec template direction.
+type Dir uint8
+
+const (
+	XFRM_DIR_IN     Dir = iota
+	XFRM_DIR_OUT    Dir = iota
+	XFRM_DIR_FWD    Dir = iota
+	XFRM_SOCKET_IN  Dir = iota
+	XFRM_SOCKET_OUT Dir = iota
+	XFRM_SOCKET_FWD Dir = iota
+)
+
+func (d Dir) String() string {
+	switch d {
+	case XFRM_DIR_IN:
+		return "dir in"
+	case XFRM_DIR_OUT:
+		return "dir out"
+	case XFRM_DIR_FWD:
+		return "dir fwd"
+	case XFRM_SOCKET_IN:
+		return "socket in"
+	case XFRM_SOCKET_OUT:
+		return "socket out"
+	case XFRM_SOCKET_FWD:
+		return "socket fwd"
+	}
+	return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN)
+}
+
+// XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec
+// policy. These rules are matched with XfrmState to determine encryption
+// and authentication algorithms.
+type XfrmPolicyTmpl struct {
+	Dst   net.IP
+	Src   net.IP
+	Proto Proto
+	Mode  Mode
+	Reqid int
+}
+
+// XfrmPolicy represents an ipsec policy. It represents the overlay network
+// and has a list of XfrmPolicyTmpls representing the base addresses of
+// the policy.
+type XfrmPolicy struct {
+	Dst      *net.IPNet
+	Src      *net.IPNet
+	Dir      Dir
+	Priority int
+	Index    int
+	Tmpls    []XfrmPolicyTmpl
+}

+ 127 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go

@@ -0,0 +1,127 @@
+package netlink
+
+import (
+	"syscall"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) {
+	sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP))
+	sel.Daddr.FromIP(policy.Dst.IP)
+	sel.Saddr.FromIP(policy.Src.IP)
+	prefixlenD, _ := policy.Dst.Mask.Size()
+	sel.PrefixlenD = uint8(prefixlenD)
+	prefixlenS, _ := policy.Src.Mask.Size()
+	sel.PrefixlenS = uint8(prefixlenS)
+}
+
+// XfrmPolicyAdd will add an xfrm policy to the system.
+// Equivalent to: `ip xfrm policy add $policy`
+func XfrmPolicyAdd(policy *XfrmPolicy) error {
+	req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWPOLICY, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+
+	msg := &nl.XfrmUserpolicyInfo{}
+	selFromPolicy(&msg.Sel, policy)
+	msg.Priority = uint32(policy.Priority)
+	msg.Index = uint32(policy.Index)
+	msg.Dir = uint8(policy.Dir)
+	msg.Lft.SoftByteLimit = nl.XFRM_INF
+	msg.Lft.HardByteLimit = nl.XFRM_INF
+	msg.Lft.SoftPacketLimit = nl.XFRM_INF
+	msg.Lft.HardPacketLimit = nl.XFRM_INF
+	req.AddData(msg)
+
+	tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls))
+	for i, tmpl := range policy.Tmpls {
+		start := i * nl.SizeofXfrmUserTmpl
+		userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl])
+		userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst)
+		userTmpl.Saddr.FromIP(tmpl.Src)
+		userTmpl.XfrmId.Proto = uint8(tmpl.Proto)
+		userTmpl.Mode = uint8(tmpl.Mode)
+		userTmpl.Reqid = uint32(tmpl.Reqid)
+		userTmpl.Aalgos = ^uint32(0)
+		userTmpl.Ealgos = ^uint32(0)
+		userTmpl.Calgos = ^uint32(0)
+	}
+	if len(tmplData) > 0 {
+		tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData)
+		req.AddData(tmpls)
+	}
+
+	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+	return err
+}
+
+// XfrmPolicyDel will delete an xfrm policy from the system. Note that
+// the Tmpls are ignored when matching the policy to delete.
+// Equivalent to: `ip xfrm policy del $policy`
+func XfrmPolicyDel(policy *XfrmPolicy) error {
+	req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELPOLICY, syscall.NLM_F_ACK)
+
+	msg := &nl.XfrmUserpolicyId{}
+	selFromPolicy(&msg.Sel, policy)
+	msg.Index = uint32(policy.Index)
+	msg.Dir = uint8(policy.Dir)
+	req.AddData(msg)
+
+	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+	return err
+}
+
+// XfrmPolicyList gets a list of xfrm policies in the system.
+// Equivalent to: `ip xfrm policy show`.
+// The list can be filtered by ip family.
+func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
+	req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP)
+
+	msg := nl.NewIfInfomsg(family)
+	req.AddData(msg)
+
+	msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY)
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]XfrmPolicy, 0)
+	for _, m := range msgs {
+		msg := nl.DeserializeXfrmUserpolicyInfo(m)
+
+		if family != FAMILY_ALL && family != int(msg.Sel.Family) {
+			continue
+		}
+
+		var policy XfrmPolicy
+
+		policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD)
+		policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS)
+		policy.Priority = int(msg.Priority)
+		policy.Index = int(msg.Index)
+		policy.Dir = Dir(msg.Dir)
+
+		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+		if err != nil {
+			return nil, err
+		}
+
+		for _, attr := range attrs {
+			switch attr.Attr.Type {
+			case nl.XFRMA_TMPL:
+				max := len(attr.Value)
+				for i := 0; i < max; i += nl.SizeofXfrmUserTmpl {
+					var resTmpl XfrmPolicyTmpl
+					tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl])
+					resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP()
+					resTmpl.Src = tmpl.Saddr.ToIP()
+					resTmpl.Proto = Proto(tmpl.XfrmId.Proto)
+					resTmpl.Mode = Mode(tmpl.Mode)
+					resTmpl.Reqid = int(tmpl.Reqid)
+					policy.Tmpls = append(policy.Tmpls, resTmpl)
+				}
+			}
+		}
+		res = append(res, policy)
+	}
+	return res, nil
+}

+ 49 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_test.go

@@ -0,0 +1,49 @@
+package netlink
+
+import (
+	"net"
+	"testing"
+)
+
+func TestXfrmPolicyAddDel(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	src, _ := ParseIPNet("127.1.1.1/32")
+	dst, _ := ParseIPNet("127.1.1.2/32")
+	policy := XfrmPolicy{
+		Src: src,
+		Dst: dst,
+		Dir: XFRM_DIR_OUT,
+	}
+	tmpl := XfrmPolicyTmpl{
+		Src:   net.ParseIP("127.0.0.1"),
+		Dst:   net.ParseIP("127.0.0.2"),
+		Proto: XFRM_PROTO_ESP,
+		Mode:  XFRM_MODE_TUNNEL,
+	}
+	policy.Tmpls = append(policy.Tmpls, tmpl)
+	if err := XfrmPolicyAdd(&policy); err != nil {
+		t.Fatal(err)
+	}
+	policies, err := XfrmPolicyList(FAMILY_ALL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(policies) != 1 {
+		t.Fatal("Policy not added properly")
+	}
+
+	if err = XfrmPolicyDel(&policy); err != nil {
+		t.Fatal(err)
+	}
+
+	policies, err = XfrmPolicyList(FAMILY_ALL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(policies) != 0 {
+		t.Fatal("Policy not removed properly")
+	}
+}

+ 54 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go

@@ -0,0 +1,54 @@
+package netlink
+
+import (
+	"net"
+)
+
+// XfrmStateAlgo represents the algorithm to use for the ipsec encryption.
+type XfrmStateAlgo struct {
+	Name        string
+	Key         []byte
+	TruncateLen int // Auth only
+}
+
+// EncapType is an enum representing an ipsec template direction.
+type EncapType uint8
+
+const (
+	_                                    = iota
+	XFRM_ENCAP_ESPINUDP_NONIKE EncapType = iota
+	XFRM_ENCAP_ESPINUDP        EncapType = iota
+)
+
+func (e EncapType) String() string {
+	switch e {
+	case XFRM_ENCAP_ESPINUDP_NONIKE:
+		return "espinudp-nonike"
+	case XFRM_ENCAP_ESPINUDP:
+		return "espinudp"
+	}
+	return "unknown"
+}
+
+// XfrmEncap represents the encapsulation to use for the ipsec encryption.
+type XfrmStateEncap struct {
+	Type            EncapType
+	SrcPort         int
+	DstPort         int
+	OriginalAddress net.IP
+}
+
+// XfrmState represents the state of an ipsec policy. It optionally
+// contains an XfrmStateAlgo for encryption and one for authentication.
+type XfrmState struct {
+	Dst          net.IP
+	Src          net.IP
+	Proto        Proto
+	Mode         Mode
+	Spi          int
+	Reqid        int
+	ReplayWindow int
+	Auth         *XfrmStateAlgo
+	Crypt        *XfrmStateAlgo
+	Encap        *XfrmStateEncap
+}

+ 181 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go

@@ -0,0 +1,181 @@
+package netlink
+
+import (
+	"fmt"
+	"syscall"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+func writeStateAlgo(a *XfrmStateAlgo) []byte {
+	algo := nl.XfrmAlgo{
+		AlgKeyLen: uint32(len(a.Key) * 8),
+		AlgKey:    a.Key,
+	}
+	end := len(a.Name)
+	if end > 64 {
+		end = 64
+	}
+	copy(algo.AlgName[:end], a.Name)
+	return algo.Serialize()
+}
+
+func writeStateAlgoAuth(a *XfrmStateAlgo) []byte {
+	algo := nl.XfrmAlgoAuth{
+		AlgKeyLen:   uint32(len(a.Key) * 8),
+		AlgTruncLen: uint32(a.TruncateLen),
+		AlgKey:      a.Key,
+	}
+	end := len(a.Name)
+	if end > 64 {
+		end = 64
+	}
+	copy(algo.AlgName[:end], a.Name)
+	return algo.Serialize()
+}
+
+// XfrmStateAdd will add an xfrm state to the system.
+// Equivalent to: `ip xfrm state add $state`
+func XfrmStateAdd(state *XfrmState) error {
+	// A state with spi 0 can't be deleted so don't allow it to be set
+	if state.Spi == 0 {
+		return fmt.Errorf("Spi must be set when adding xfrm state.")
+	}
+	req := nl.NewNetlinkRequest(nl.XFRM_MSG_NEWSA, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+
+	msg := &nl.XfrmUsersaInfo{}
+	msg.Family = uint16(nl.GetIPFamily(state.Dst))
+	msg.Id.Daddr.FromIP(state.Dst)
+	msg.Saddr.FromIP(state.Src)
+	msg.Id.Proto = uint8(state.Proto)
+	msg.Mode = uint8(state.Mode)
+	msg.Id.Spi = nl.Swap32(uint32(state.Spi))
+	msg.Reqid = uint32(state.Reqid)
+	msg.ReplayWindow = uint8(state.ReplayWindow)
+	msg.Lft.SoftByteLimit = nl.XFRM_INF
+	msg.Lft.HardByteLimit = nl.XFRM_INF
+	msg.Lft.SoftPacketLimit = nl.XFRM_INF
+	msg.Lft.HardPacketLimit = nl.XFRM_INF
+	req.AddData(msg)
+
+	if state.Auth != nil {
+		out := nl.NewRtAttr(nl.XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth))
+		req.AddData(out)
+	}
+	if state.Crypt != nil {
+		out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt))
+		req.AddData(out)
+	}
+	if state.Encap != nil {
+		encapData := make([]byte, nl.SizeofXfrmEncapTmpl)
+		encap := nl.DeserializeXfrmEncapTmpl(encapData)
+		encap.EncapType = uint16(state.Encap.Type)
+		encap.EncapSport = nl.Swap16(uint16(state.Encap.SrcPort))
+		encap.EncapDport = nl.Swap16(uint16(state.Encap.DstPort))
+		encap.EncapOa.FromIP(state.Encap.OriginalAddress)
+		out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData)
+		req.AddData(out)
+	}
+
+	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+	return err
+}
+
+// XfrmStateDel will delete an xfrm state from the system. Note that
+// the Algos are ignored when matching the state to delete.
+// Equivalent to: `ip xfrm state del $state`
+func XfrmStateDel(state *XfrmState) error {
+	req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELSA, syscall.NLM_F_ACK)
+
+	msg := &nl.XfrmUsersaId{}
+	msg.Daddr.FromIP(state.Dst)
+	msg.Family = uint16(nl.GetIPFamily(state.Dst))
+	msg.Proto = uint8(state.Proto)
+	msg.Spi = nl.Swap32(uint32(state.Spi))
+	req.AddData(msg)
+
+	saddr := nl.XfrmAddress{}
+	saddr.FromIP(state.Src)
+	srcdata := nl.NewRtAttr(nl.XFRMA_SRCADDR, saddr.Serialize())
+
+	req.AddData(srcdata)
+
+	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+	return err
+}
+
+// XfrmStateList gets a list of xfrm states in the system.
+// Equivalent to: `ip xfrm state show`.
+// The list can be filtered by ip family.
+func XfrmStateList(family int) ([]XfrmState, error) {
+	req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
+
+	msg := nl.NewIfInfomsg(family)
+	req.AddData(msg)
+
+	msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]XfrmState, 0)
+	for _, m := range msgs {
+		msg := nl.DeserializeXfrmUsersaInfo(m)
+
+		if family != FAMILY_ALL && family != int(msg.Family) {
+			continue
+		}
+
+		var state XfrmState
+
+		state.Dst = msg.Id.Daddr.ToIP()
+		state.Src = msg.Saddr.ToIP()
+		state.Proto = Proto(msg.Id.Proto)
+		state.Mode = Mode(msg.Mode)
+		state.Spi = int(nl.Swap32(msg.Id.Spi))
+		state.Reqid = int(msg.Reqid)
+		state.ReplayWindow = int(msg.ReplayWindow)
+
+		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+		if err != nil {
+			return nil, err
+		}
+
+		for _, attr := range attrs {
+			switch attr.Attr.Type {
+			case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT:
+				var resAlgo *XfrmStateAlgo
+				if attr.Attr.Type == nl.XFRMA_ALG_AUTH {
+					if state.Auth == nil {
+						state.Auth = new(XfrmStateAlgo)
+					}
+					resAlgo = state.Auth
+				} else {
+					state.Crypt = new(XfrmStateAlgo)
+					resAlgo = state.Crypt
+				}
+				algo := nl.DeserializeXfrmAlgo(attr.Value[:])
+				(*resAlgo).Name = nl.BytesToString(algo.AlgName[:])
+				(*resAlgo).Key = algo.AlgKey
+			case nl.XFRMA_ALG_AUTH_TRUNC:
+				if state.Auth == nil {
+					state.Auth = new(XfrmStateAlgo)
+				}
+				algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:])
+				state.Auth.Name = nl.BytesToString(algo.AlgName[:])
+				state.Auth.Key = algo.AlgKey
+				state.Auth.TruncateLen = int(algo.AlgTruncLen)
+			case nl.XFRMA_ENCAP:
+				encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:])
+				state.Encap = new(XfrmStateEncap)
+				state.Encap.Type = EncapType(encap.EncapType)
+				state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport))
+				state.Encap.DstPort = int(nl.Swap16(encap.EncapDport))
+				state.Encap.OriginalAddress = encap.EncapOa.ToIP()
+			}
+
+		}
+		res = append(res, state)
+	}
+	return res, nil
+}

+ 50 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_test.go

@@ -0,0 +1,50 @@
+package netlink
+
+import (
+	"net"
+	"testing"
+)
+
+func TestXfrmStateAddDel(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	state := XfrmState{
+		Src:   net.ParseIP("127.0.0.1"),
+		Dst:   net.ParseIP("127.0.0.2"),
+		Proto: XFRM_PROTO_ESP,
+		Mode:  XFRM_MODE_TUNNEL,
+		Spi:   1,
+		Auth: &XfrmStateAlgo{
+			Name: "hmac(sha256)",
+			Key:  []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
+		},
+		Crypt: &XfrmStateAlgo{
+			Name: "cbc(aes)",
+			Key:  []byte("abcdefghijklmnopqrstuvwzyzABCDEF"),
+		},
+	}
+	if err := XfrmStateAdd(&state); err != nil {
+		t.Fatal(err)
+	}
+	policies, err := XfrmStateList(FAMILY_ALL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(policies) != 1 {
+		t.Fatal("State not added properly")
+	}
+
+	if err = XfrmStateDel(&state); err != nil {
+		t.Fatal(err)
+	}
+
+	policies, err = XfrmStateList(FAMILY_ALL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(policies) != 0 {
+		t.Fatal("State not removed properly")
+	}
+}

+ 192 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/LICENSE

@@ -0,0 +1,192 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2014 Vishvananda Ishaya.
+   Copyright 2014 Docker, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 49 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/README.md

@@ -0,0 +1,49 @@
+# netns - network namespaces in go #
+
+The netns package provides an ultra-simple interface for handling
+network namespaces in go. Changing namespaces requires elevated
+privileges, so in most cases this code needs to be run as root.
+
+## Local Build and Test ##
+
+You can use go get command:
+
+    go get github.com/vishvananda/netns
+
+Testing (requires root):
+
+    sudo -E go test github.com/vishvananda/netns
+
+## Example ##
+
+```go
+package main
+
+import (
+    "net"
+    "runtime"
+    "github.com/vishvananada/netns"
+)
+
+func main() {
+    // Lock the OS Thread so we don't accidentally switch namespaces
+    runtime.LockOSThread()
+    defer runtime.UnlockOSThread()
+
+    // Save the current network namespace
+    origns, _ := netns.Get()
+    defer origns.Close()
+
+    // Create a new network namespace
+    newns, _ := netns.New()
+    defer newns.Close()
+
+    // Do something with tne network namespace
+    ifaces, _ := net.Interfaces()
+    fmt.Printf("Interfaces: %v\n", ifaces)
+
+    // Switch back to the original namespace
+    netns.Set(origns)
+}
+
+```

+ 242 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux.go

@@ -0,0 +1,242 @@
+// Package netns allows ultra-simple network namespace handling. NsHandles
+// can be retrieved and set. Note that the current namespace is thread
+// local so actions that set and reset namespaces should use LockOSThread
+// to make sure the namespace doesn't change due to a goroutine switch.
+// It is best to close NsHandles when you are done with them. This can be
+// accomplished via a `defer ns.Close()` on the handle. Changing namespaces
+// requires elevated privileges, so in most cases this code needs to be run
+// as root.
+package netns
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+)
+
+const (
+	// These constants belong in the syscall library but have not been
+	// added yet.
+	CLONE_NEWUTS  = 0x04000000 /* New utsname group? */
+	CLONE_NEWIPC  = 0x08000000 /* New ipcs */
+	CLONE_NEWUSER = 0x10000000 /* New user namespace */
+	CLONE_NEWPID  = 0x20000000 /* New pid namespace */
+	CLONE_NEWNET  = 0x40000000 /* New network namespace */
+	CLONE_IO      = 0x80000000 /* Get io context */
+)
+
+// Setns sets namespace using syscall. Note that this should be a method
+// in syscall but it has not been added.
+func Setns(ns NsHandle, nstype int) (err error) {
+	_, _, e1 := syscall.Syscall(SYS_SETNS, uintptr(ns), uintptr(nstype), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// NsHandle is a handle to a network namespace. It can be cast directly
+// to an int and used as a file descriptor.
+type NsHandle int
+
+// Equal determines if two network handles refer to the same network
+// namespace. This is done by comparing the device and inode that the
+// file descripors point to.
+func (ns NsHandle) Equal(other NsHandle) bool {
+	var s1, s2 syscall.Stat_t
+	if err := syscall.Fstat(int(ns), &s1); err != nil {
+		return false
+	}
+	if err := syscall.Fstat(int(other), &s2); err != nil {
+		return false
+	}
+	return (s1.Dev == s2.Dev) && (s1.Ino == s2.Ino)
+}
+
+// String shows the file descriptor number and its dev and inode.
+func (ns NsHandle) String() string {
+	var s syscall.Stat_t
+	if err := syscall.Fstat(int(ns), &s); err != nil {
+		return fmt.Sprintf("NS(%d: unknown)", ns)
+	}
+	return fmt.Sprintf("NS(%d: %d, %d)", ns, s.Dev, s.Ino)
+}
+
+// IsOpen returns true if Close() has not been called.
+func (ns NsHandle) IsOpen() bool {
+	return ns != -1
+}
+
+// Close closes the NsHandle and resets its file descriptor to -1.
+// It is not safe to use an NsHandle after Close() is called.
+func (ns *NsHandle) Close() error {
+	if err := syscall.Close(int(*ns)); err != nil {
+		return err
+	}
+	(*ns) = -1
+	return nil
+}
+
+// Set sets the current network namespace to the namespace represented
+// by NsHandle.
+func Set(ns NsHandle) (err error) {
+	return Setns(ns, CLONE_NEWNET)
+}
+
+// New creates a new network namespace and returns a handle to it.
+func New() (ns NsHandle, err error) {
+	if err := syscall.Unshare(CLONE_NEWNET); err != nil {
+		return -1, err
+	}
+	return Get()
+}
+
+// Get gets a handle to the current threads network namespace.
+func Get() (NsHandle, error) {
+	return GetFromPid(os.Getpid())
+}
+
+// GetFromName gets a handle to a named network namespace such as one
+// created by `ip netns add`.
+func GetFromName(name string) (NsHandle, error) {
+	fd, err := syscall.Open(fmt.Sprintf("/var/run/netns/%s", name), syscall.O_RDONLY, 0)
+	if err != nil {
+		return -1, err
+	}
+	return NsHandle(fd), nil
+}
+
+// GetFromName gets a handle to the network namespace of a given pid.
+func GetFromPid(pid int) (NsHandle, error) {
+	fd, err := syscall.Open(fmt.Sprintf("/proc/%d/ns/net", pid), syscall.O_RDONLY, 0)
+	if err != nil {
+		return -1, err
+	}
+	return NsHandle(fd), nil
+}
+
+// GetFromName gets a handle to the network namespace of a docker container.
+// Id is prefixed matched against the running docker containers, so a short
+// identifier can be used as long as it isn't ambiguous.
+func GetFromDocker(id string) (NsHandle, error) {
+	pid, err := getPidForContainer(id)
+	if err != nil {
+		return -1, err
+	}
+	return GetFromPid(pid)
+}
+
+// borrowed from docker/utils/utils.go
+func findCgroupMountpoint(cgroupType string) (string, error) {
+	output, err := ioutil.ReadFile("/proc/mounts")
+	if err != nil {
+		return "", err
+	}
+
+	// /proc/mounts has 6 fields per line, one mount per line, e.g.
+	// cgroup /sys/fs/cgroup/devices cgroup rw,relatime,devices 0 0
+	for _, line := range strings.Split(string(output), "\n") {
+		parts := strings.Split(line, " ")
+		if len(parts) == 6 && parts[2] == "cgroup" {
+			for _, opt := range strings.Split(parts[3], ",") {
+				if opt == cgroupType {
+					return parts[1], nil
+				}
+			}
+		}
+	}
+
+	return "", fmt.Errorf("cgroup mountpoint not found for %s", cgroupType)
+}
+
+// Returns the relative path to the cgroup docker is running in.
+// borrowed from docker/utils/utils.go
+// modified to get the docker pid instead of using /proc/self
+func getThisCgroup(cgroupType string) (string, error) {
+	dockerpid, err := ioutil.ReadFile("/var/run/docker.pid")
+	if err != nil {
+		return "", err
+	}
+	result := strings.Split(string(dockerpid), "\n")
+	if len(result) == 0 || len(result[0]) == 0 {
+		return "", fmt.Errorf("docker pid not found in /var/run/docker.pid")
+	}
+	pid, err := strconv.Atoi(result[0])
+
+	output, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cgroup", pid))
+	if err != nil {
+		return "", err
+	}
+	for _, line := range strings.Split(string(output), "\n") {
+		parts := strings.Split(line, ":")
+		// any type used by docker should work
+		if parts[1] == cgroupType {
+			return parts[2], nil
+		}
+	}
+	return "", fmt.Errorf("cgroup '%s' not found in /proc/%d/cgroup", cgroupType, pid)
+}
+
+// Returns the first pid in a container.
+// borrowed from docker/utils/utils.go
+// modified to only return the first pid
+// modified to glob with id
+func getPidForContainer(id string) (int, error) {
+	pid := 0
+
+	// memory is chosen randomly, any cgroup used by docker works
+	cgroupType := "memory"
+
+	cgroupRoot, err := findCgroupMountpoint(cgroupType)
+	if err != nil {
+		return pid, err
+	}
+
+	cgroupThis, err := getThisCgroup(cgroupType)
+	if err != nil {
+		return pid, err
+	}
+
+	id += "*"
+
+	filename := filepath.Join(cgroupRoot, cgroupThis, id, "tasks")
+	filenames, _ := filepath.Glob(filename)
+	if len(filenames) > 1 {
+		return pid, fmt.Errorf("Ambiguous id supplied: %v", filenames)
+	} else if len(filenames) == 1 {
+		filename = filenames[0]
+	}
+	if _, err := os.Stat(filename); os.IsNotExist(err) {
+		// With more recent lxc versions use, cgroup will be in lxc/
+		filename = filepath.Join(cgroupRoot, cgroupThis, "lxc", id, "tasks")
+		filenames, _ = filepath.Glob(filename)
+		if len(filenames) > 1 {
+			return pid, fmt.Errorf("Ambiguous id supplied: %v", filenames)
+		} else if len(filenames) == 1 {
+			filename = filenames[0]
+		} else {
+			return pid, fmt.Errorf("Unable to find container: %v", id[:len(id)-1])
+		}
+	}
+
+	output, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return pid, err
+	}
+
+	result := strings.Split(string(output), "\n")
+	if len(result) == 0 || len(result[0]) == 0 {
+		return pid, fmt.Errorf("No pid found for container")
+	}
+
+	pid, err = strconv.Atoi(result[0])
+	if err != nil {
+		return pid, fmt.Errorf("Invalid pid '%s': %s", result[0], err)
+	}
+
+	return pid, nil
+}

+ 5 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux_386.go

@@ -0,0 +1,5 @@
+package netns
+
+const (
+	SYS_SETNS = 346
+)

+ 5 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux_amd.go

@@ -0,0 +1,5 @@
+package netns
+
+const (
+	SYS_SETNS = 308
+)

+ 5 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/netns_linux_arm.go

@@ -0,0 +1,5 @@
+package netns
+
+const (
+	SYS_SETNS = 374
+)

+ 37 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/netns_test.go

@@ -0,0 +1,37 @@
+package netns
+
+import (
+	"runtime"
+	"testing"
+)
+
+func TestGetNewSetDelete(t *testing.T) {
+	runtime.LockOSThread()
+	defer runtime.UnlockOSThread()
+
+	origns, err := Get()
+	if err != nil {
+		t.Fatal(err)
+	}
+	newns, err := New()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if origns.Equal(newns) {
+		t.Fatal("New ns failed")
+	}
+	if err := Set(origns); err != nil {
+		t.Fatal(err)
+	}
+	newns.Close()
+	if newns.IsOpen() {
+		t.Fatal("newns still open after close", newns)
+	}
+	ns, err := Get()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !ns.Equal(origns) {
+		t.Fatal("Reset ns failed", origns, newns, ns)
+	}
+}

+ 35 - 0
Godeps/_workspace/src/github.com/vishvananda/netns/netns_unspecified.go

@@ -0,0 +1,35 @@
+// +build !linux
+
+package netns
+
+import (
+	"errors"
+)
+
+var (
+	ErrNotImplemented = errors.New("not implemented")
+)
+
+func Set(ns Namespace) (err error) {
+	return ErrNotImplemented
+}
+
+func New() (ns Namespace, err error) {
+	return -1, ErrNotImplemented
+}
+
+func Get() (Namespace, error) {
+	return -1, ErrNotImplemented
+}
+
+func GetFromName(name string) (Namespace, error) {
+	return -1, ErrNotImplemented
+}
+
+func GetFromPid(pid int) (Namespace, error) {
+	return -1, ErrNotImplemented
+}
+
+func GetFromDocker(id string) (Namespace, error) {
+	return -1, ErrNotImplemented
+}

+ 15 - 14
backend/udp/udp.go

@@ -9,7 +9,7 @@ import (
 	"sync"
 	"syscall"
 
-	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/docker/libcontainer/netlink"
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink"
 	log "github.com/coreos/flannel/Godeps/_workspace/src/github.com/golang/glog"
 
 	"github.com/coreos/flannel/backend"
@@ -90,7 +90,6 @@ func (m *UdpBackend) Init(extIface *net.Interface, extIP net.IP, ipMasq bool) (*
 		return nil, fmt.Errorf("failed to start listening on UDP socket: %v", err)
 	}
 
-
 	m.ctl, m.ctl2, err = newCtlSockets()
 	if err != nil {
 		return nil, fmt.Errorf("failed to create control socket: %v", err)
@@ -169,30 +168,33 @@ func (m *UdpBackend) initTun(ipMasq bool) error {
 }
 
 func configureIface(ifname string, ipn ip.IP4Net, mtu int) error {
-	iface, err := net.InterfaceByName(ifname)
+	iface, err := netlink.LinkByName(ifname)
 	if err != nil {
 		return fmt.Errorf("failed to lookup interface %v", ifname)
 	}
 
-	n := ipn.ToIPNet()
-	err = netlink.NetworkLinkAddIp(iface, n.IP, n)
+	err = netlink.AddrAdd(iface, &netlink.Addr{ipn.ToIPNet(), ""})
 	if err != nil {
-		return fmt.Errorf("failed to add IP address %v to %v: %v", n.IP, ifname, err)
+		return fmt.Errorf("failed to add IP address %v to %v: %v", ipn.String(), ifname, err)
 	}
 
-	err = netlink.NetworkSetMTU(iface, mtu)
+	err = netlink.LinkSetMTU(iface, mtu)
 	if err != nil {
 		return fmt.Errorf("failed to set MTU for %v: %v", ifname, err)
 	}
 
-	err = netlink.NetworkLinkUp(iface)
+	err = netlink.LinkSetUp(iface)
 	if err != nil {
 		return fmt.Errorf("failed to set interface %v to UP state: %v", ifname, err)
 	}
 
 	// explicitly add a route since there might be a route for a subnet already
 	// installed by Docker and then it won't get auto added
-	err = netlink.AddRoute(ipn.Network().String(), "", "", ifname)
+	err = netlink.RouteAdd(&netlink.Route{
+		LinkIndex: iface.Attrs().Index,
+		Scope:     netlink.SCOPE_UNIVERSE,
+		Dst:       ipn.Network().ToIPNet(),
+	})
 	if err != nil && err != syscall.EEXIST {
 		return fmt.Errorf("Failed to add route (%v -> %v): %v", ipn.Network().String(), ifname, err)
 	}
@@ -213,13 +215,12 @@ func setupIpMasq(ipn ip.IP4Net, iface string) error {
 
 	rules := [][]string{
 		// This rule makes sure we don't NAT traffic within overlay network (e.g. coming out of docker0)
-		[]string{ "FLANNEL", "-d", ipn.String(), "-j", "ACCEPT" },
+		[]string{"FLANNEL", "-d", ipn.String(), "-j", "ACCEPT"},
 		// This rule makes sure we don't NAT multicast traffic within overlay network
-		[]string{ "FLANNEL", "-d", "224.0.0.0/4", "-j", "ACCEPT" },
-		// This rule will NAT everything originating from our overlay network and 
-		[]string{ "FLANNEL", "!", "-o", iface, "-j", "MASQUERADE" },
+		[]string{"FLANNEL", "-d", "224.0.0.0/4", "-j", "ACCEPT"}, // This rule will NAT everything originating from our overlay network and
+		[]string{"FLANNEL", "!", "-o", iface, "-j", "MASQUERADE"},
 		// This rule will take everything coming from overlay and sent it to FLANNEL chain
-		[]string{ "POSTROUTING", "-s", ipn.String(), "-j", "FLANNEL" },
+		[]string{"POSTROUTING", "-s", ipn.String(), "-j", "FLANNEL"},
 	}
 
 	for _, args := range rules {

+ 6 - 5
pkg/ip/iface.go

@@ -3,8 +3,9 @@ package ip
 import (
 	"errors"
 	"net"
+	"syscall"
 
-	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/docker/libcontainer/netlink"
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink"
 )
 
 func GetIfaceIP4Addr(iface *net.Interface) (net.IP, error) {
@@ -46,17 +47,17 @@ func GetIfaceIP4AddrMatch(iface *net.Interface, matchAddr net.IP) error {
 }
 
 func GetDefaultGatewayIface() (*net.Interface, error) {
-	routes, err := netlink.NetworkGetRoutes()
+	routes, err := netlink.RouteList(nil, syscall.AF_INET)
 	if err != nil {
 		return nil, err
 	}
 
 	for _, route := range routes {
-		if route.Default {
-			if route.Iface == nil {
+		if route.Dst == nil || route.Dst.String() == "0.0.0.0/0" {
+			if route.LinkIndex <= 0 {
 				return nil, errors.New("Found default route but could not determine interface")
 			}
-			return route.Iface, nil
+			return net.InterfaceByIndex(route.LinkIndex)
 		}
 	}
 

+ 4 - 5
pkg/ip/tun.go

@@ -6,16 +6,15 @@ import (
 	"os"
 	"syscall"
 	"unsafe"
-
-	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/docker/libcontainer/netlink"
 )
 
 const (
-	tunDevice = "/dev/net/tun"
+	tunDevice  = "/dev/net/tun"
+	ifnameSize = 16
 )
 
 type ifreqFlags struct {
-	IfrnName  [netlink.IFNAMSIZ]byte
+	IfrnName  [ifnameSize]byte
 	IfruFlags uint16
 }
 
@@ -46,6 +45,6 @@ func OpenTun(name string) (*os.File, string, error) {
 		return nil, "", err
 	}
 
-	ifname := fromZeroTerm(ifr.IfrnName[:netlink.IFNAMSIZ])
+	ifname := fromZeroTerm(ifr.IfrnName[:ifnameSize])
 	return tun, ifname, nil
 }