Browse Source

Merge pull request #1173 from aboch/vndnl

Vendoring vishvananda/netlink f9bc7a684edbe780a09b87689db6cb1706bf327f
Jana Radhakrishnan 9 năm trước cách đây
mục cha
commit
4fb3e998f6
29 tập tin đã thay đổi với 1588 bổ sung385 xóa
  1. 3 4
      libnetwork/Godeps/Godeps.json
  2. 1 1
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile
  3. 134 48
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go
  4. 60 0
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go
  5. 6 6
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class.go
  6. 49 15
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class_linux.go
  7. 59 9
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go
  8. 173 52
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go
  9. 86 0
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/handle.go
  10. 32 2
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link.go
  11. 217 60
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go
  12. 45 6
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go
  13. 1 1
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go
  14. 58 6
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go
  15. 64 5
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go
  16. 18 0
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go
  17. 27 6
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go
  18. 6 2
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go
  19. 26 21
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go
  20. 44 11
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go
  21. 4 4
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go
  22. 40 8
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go
  23. 21 3
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go
  24. 10 0
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go
  25. 14 0
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go
  26. 170 46
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy_linux.go
  27. 19 3
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go
  28. 200 64
      libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state_linux.go
  29. 1 2
      libnetwork/drivers/overlay/ov_utils.go

+ 3 - 4
libnetwork/Godeps/Godeps.json

@@ -1,7 +1,6 @@
 {
 	"ImportPath": "github.com/docker/libnetwork",
-	"GoVersion": "go1.5",
-	"GodepVersion": "v62",
+	"GoVersion": "go1.6",
 	"Packages": [
 		"./..."
 	],
@@ -384,11 +383,11 @@
 		},
 		{
 			"ImportPath": "github.com/vishvananda/netlink",
-			"Rev": "631962935bff4f3d20ff32a72e8944f6d2836a26"
+			"Rev": "f9bc7a684edbe780a09b87689db6cb1706bf327f"
 		},
 		{
 			"ImportPath": "github.com/vishvananda/netlink/nl",
-			"Rev": "631962935bff4f3d20ff32a72e8944f6d2836a26"
+			"Rev": "f9bc7a684edbe780a09b87689db6cb1706bf327f"
 		},
 		{
 			"ImportPath": "github.com/vishvananda/netns",

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

@@ -11,7 +11,7 @@ goroot = $(addprefix ../../../,$(1))
 unroot = $(subst ../../../,,$(1))
 fmt = $(addprefix fmt-,$(1))
 
-all: fmt test
+all: test
 
 $(call goroot,$(DEPS)):
 	go get $(call unroot,$@)

+ 134 - 48
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go

@@ -2,6 +2,7 @@ package netlink
 
 import (
 	"fmt"
+	"log"
 	"net"
 	"strings"
 	"syscall"
@@ -15,24 +16,35 @@ const IFA_FLAGS = 0x8
 // AddrAdd will add an IP address to a link device.
 // Equivalent to: `ip addr add $addr dev $link`
 func AddrAdd(link Link, addr *Addr) error {
+	return pkgHandle.AddrAdd(link, addr)
+}
 
-	req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
-	return addrHandle(link, addr, req)
+// AddrAdd will add an IP address to a link device.
+// Equivalent to: `ip addr add $addr dev $link`
+func (h *Handle) AddrAdd(link Link, addr *Addr) error {
+	req := h.newNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	return h.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)
+	return pkgHandle.AddrDel(link, addr)
+}
+
+// AddrDel will delete an IP address from a link device.
+// Equivalent to: `ip addr del $addr dev $link`
+func (h *Handle) AddrDel(link Link, addr *Addr) error {
+	req := h.newNetlinkRequest(syscall.RTM_DELADDR, syscall.NLM_F_ACK)
+	return h.addrHandle(link, addr, req)
 }
 
-func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
+func (h *Handle) 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)
+	h.ensureIndex(base)
 
 	family := nl.GetIPFamily(addr.IP)
 
@@ -57,10 +69,14 @@ func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
 	req.AddData(addressData)
 
 	if addr.Flags != 0 {
-		b := make([]byte, 4)
-		native.PutUint32(b, uint32(addr.Flags))
-		flagsData := nl.NewRtAttr(IFA_FLAGS, b)
-		req.AddData(flagsData)
+		if addr.Flags <= 0xff {
+			msg.IfAddrmsg.Flags = uint8(addr.Flags)
+		} else {
+			b := make([]byte, 4)
+			native.PutUint32(b, uint32(addr.Flags))
+			flagsData := nl.NewRtAttr(IFA_FLAGS, b)
+			req.AddData(flagsData)
+		}
 	}
 
 	if addr.Label != "" {
@@ -76,7 +92,14 @@ func addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error {
 // 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)
+	return pkgHandle.AddrList(link, family)
+}
+
+// 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 (h *Handle) AddrList(link Link, family int) ([]Addr, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETADDR, syscall.NLM_F_DUMP)
 	msg := nl.NewIfInfomsg(family)
 	req.AddData(msg)
 
@@ -85,62 +108,125 @@ func AddrList(link Link, family int) ([]Addr, error) {
 		return nil, err
 	}
 
-	index := 0
+	indexFilter := 0
 	if link != nil {
 		base := link.Attrs()
-		ensureIndex(base)
-		index = base.Index
+		h.ensureIndex(base)
+		indexFilter = base.Index
 	}
 
 	var res []Addr
 	for _, m := range msgs {
-		msg := nl.DeserializeIfAddrmsg(m)
+		addr, msgFamily, ifindex, err := parseAddr(m)
+		if err != nil {
+			return res, err
+		}
 
-		if link != nil && msg.Index != uint32(index) {
+		if link != nil && ifindex != indexFilter {
 			// Ignore messages from other interfaces
 			continue
 		}
 
-		if family != FAMILY_ALL && msg.Family != uint8(family) {
+		if family != FAMILY_ALL && msgFamily != family {
 			continue
 		}
 
-		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
-		if err != nil {
-			return nil, err
-		}
+		res = append(res, addr)
+	}
 
-		var local, dst *net.IPNet
-		var addr Addr
-		for _, attr := range attrs {
-			switch attr.Attr.Type {
-			case syscall.IFA_ADDRESS:
-				dst = &net.IPNet{
-					IP:   attr.Value,
-					Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
-				}
-			case syscall.IFA_LOCAL:
-				local = &net.IPNet{
-					IP:   attr.Value,
-					Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
-				}
-			case syscall.IFA_LABEL:
-				addr.Label = string(attr.Value[:len(attr.Value)-1])
-			case IFA_FLAGS:
-				addr.Flags = int(native.Uint32(attr.Value[0:4]))
+	return res, nil
+}
+
+func parseAddr(m []byte) (addr Addr, family, index int, err error) {
+	msg := nl.DeserializeIfAddrmsg(m)
+
+	family = -1
+	index = -1
+
+	attrs, err1 := nl.ParseRouteAttr(m[msg.Len():])
+	if err1 != nil {
+		err = err1
+		return
+	}
+
+	family = int(msg.Family)
+	index = int(msg.Index)
+
+	var local, dst *net.IPNet
+	for _, attr := range attrs {
+		switch attr.Attr.Type {
+		case syscall.IFA_ADDRESS:
+			dst = &net.IPNet{
+				IP:   attr.Value,
+				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
 			}
+		case syscall.IFA_LOCAL:
+			local = &net.IPNet{
+				IP:   attr.Value,
+				Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
+			}
+		case syscall.IFA_LABEL:
+			addr.Label = string(attr.Value[:len(attr.Value)-1])
+		case IFA_FLAGS:
+			addr.Flags = int(native.Uint32(attr.Value[0:4]))
 		}
+	}
 
-		// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
-		if local != nil {
-			addr.IPNet = local
-		} else {
-			addr.IPNet = dst
-		}
-		addr.Scope = int(msg.Scope)
+	// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
+	if local != nil {
+		addr.IPNet = local
+	} else {
+		addr.IPNet = dst
+	}
+	addr.Scope = int(msg.Scope)
 
-		res = append(res, addr)
+	return
+}
+
+type AddrUpdate struct {
+	LinkAddress net.IPNet
+	LinkIndex   int
+	NewAddr     bool // true=added false=deleted
+}
+
+// AddrSubscribe takes a chan down which notifications will be sent
+// when addresses change.  Close the 'done' chan to stop subscription.
+func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error {
+	s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_IPV4_IFADDR, syscall.RTNLGRP_IPV6_IFADDR)
+	if err != nil {
+		return err
 	}
+	if done != nil {
+		go func() {
+			<-done
+			s.Close()
+		}()
+	}
+	go func() {
+		defer close(ch)
+		for {
+			msgs, err := s.Receive()
+			if err != nil {
+				log.Printf("netlink.AddrSubscribe: Receive() error: %v", err)
+				return
+			}
+			for _, m := range msgs {
+				msgType := m.Header.Type
+				if msgType != syscall.RTM_NEWADDR && msgType != syscall.RTM_DELADDR {
+					log.Printf("netlink.AddrSubscribe: bad message type: %d", msgType)
+					continue
+				}
 
-	return res, nil
+				addr, _, ifindex, err := parseAddr(m.Data)
+				if err != nil {
+					log.Printf("netlink.AddrSubscribe: could not parse address: %v", err)
+					continue
+				}
+
+				ch <- AddrUpdate{LinkAddress: *addr.IPNet, LinkIndex: ifindex, NewAddr: msgType == syscall.RTM_NEWADDR}
+			}
+		}
+	}()
+
+	return nil
 }

+ 60 - 0
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/bpf_linux.go

@@ -0,0 +1,60 @@
+package netlink
+
+/*
+#include <asm/types.h>
+#include <asm/unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+
+static int load_simple_bpf(int prog_type) {
+#ifdef __NR_bpf
+	// { return 1; }
+	__u64 __attribute__((aligned(8))) insns[] = {
+		0x00000001000000b7ull,
+		0x0000000000000095ull,
+	};
+	__u8 __attribute__((aligned(8))) license[] = "ASL2";
+	// Copied from a header file since libc is notoriously slow to update.
+	// The call will succeed or fail and that will be our indication on
+	// whether or not it is supported.
+	struct {
+		__u32 prog_type;
+		__u32 insn_cnt;
+		__u64 insns;
+		__u64 license;
+		__u32 log_level;
+		__u32 log_size;
+		__u64 log_buf;
+		__u32 kern_version;
+	} __attribute__((aligned(8))) attr = {
+		.prog_type = prog_type,
+		.insn_cnt = 2,
+		.insns = (uintptr_t)&insns,
+		.license = (uintptr_t)&license,
+	};
+	return syscall(__NR_bpf, 5, &attr, sizeof(attr));
+#else
+	errno = EINVAL;
+	return -1;
+#endif
+}
+*/
+import "C"
+
+type BpfProgType C.int
+
+const (
+	BPF_PROG_TYPE_UNSPEC BpfProgType = iota
+	BPF_PROG_TYPE_SOCKET_FILTER
+	BPF_PROG_TYPE_KPROBE
+	BPF_PROG_TYPE_SCHED_CLS
+	BPF_PROG_TYPE_SCHED_ACT
+)
+
+// loadSimpleBpf loads a trivial bpf program for testing purposes
+func loadSimpleBpf(progType BpfProgType) (int, error) {
+	fd, err := C.load_simple_bpf(C.int(progType))
+	return int(fd), err
+}

+ 6 - 6
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class.go

@@ -9,7 +9,7 @@ type Class interface {
 	Type() string
 }
 
-// Class represents a netlink class. A filter is associated with a link,
+// ClassAttrs represents a netlink class. A filter is associated with a link,
 // has a handle and a parent. The root filter of a device should have a
 // parent == HANDLE_ROOT.
 type ClassAttrs struct {
@@ -20,7 +20,7 @@ type ClassAttrs struct {
 }
 
 func (q ClassAttrs) String() string {
-	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf)
+	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf)
 }
 
 type HtbClassAttrs struct {
@@ -38,7 +38,7 @@ func (q HtbClassAttrs) String() string {
 	return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer)
 }
 
-// Htb class
+// HtbClass represents an Htb class
 type HtbClass struct {
 	ClassAttrs
 	Rate    uint64
@@ -87,11 +87,11 @@ func (q HtbClass) String() string {
 	return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer)
 }
 
-func (class *HtbClass) Attrs() *ClassAttrs {
-	return &class.ClassAttrs
+func (q *HtbClass) Attrs() *ClassAttrs {
+	return &q.ClassAttrs
 }
 
-func (class *HtbClass) Type() string {
+func (q *HtbClass) Type() string {
 	return "htb"
 }
 

+ 49 - 15
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/class_linux.go

@@ -10,15 +10,27 @@ import (
 // ClassDel will delete a class from the system.
 // Equivalent to: `tc class del $class`
 func ClassDel(class Class) error {
-	return classModify(syscall.RTM_DELTCLASS, 0, class)
+	return pkgHandle.ClassDel(class)
+}
+
+// ClassDel will delete a class from the system.
+// Equivalent to: `tc class del $class`
+func (h *Handle) ClassDel(class Class) error {
+	return h.classModify(syscall.RTM_DELTCLASS, 0, class)
 }
 
 // ClassChange will change a class in place
 // Equivalent to: `tc class change $class`
 // The parent and handle MUST NOT be changed.
-
 func ClassChange(class Class) error {
-	return classModify(syscall.RTM_NEWTCLASS, 0, class)
+	return pkgHandle.ClassChange(class)
+}
+
+// ClassChange will change a class in place
+// Equivalent to: `tc class change $class`
+// The parent and handle MUST NOT be changed.
+func (h *Handle) ClassChange(class Class) error {
+	return h.classModify(syscall.RTM_NEWTCLASS, 0, class)
 }
 
 // ClassReplace will replace a class to the system.
@@ -27,21 +39,36 @@ func ClassChange(class Class) error {
 // If a class already exist with this parent/handle pair, the class is changed.
 // If a class does not already exist with this parent/handle, a new class is created.
 func ClassReplace(class Class) error {
-	return classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class)
+	return pkgHandle.ClassReplace(class)
+}
+
+// ClassReplace will replace a class to the system.
+// quivalent to: `tc class replace $class`
+// The handle MAY be changed.
+// If a class already exist with this parent/handle pair, the class is changed.
+// If a class does not already exist with this parent/handle, a new class is created.
+func (h *Handle) ClassReplace(class Class) error {
+	return h.classModify(syscall.RTM_NEWTCLASS, syscall.NLM_F_CREATE, class)
 }
 
 // ClassAdd will add a class to the system.
 // Equivalent to: `tc class add $class`
 func ClassAdd(class Class) error {
-	return classModify(
+	return pkgHandle.ClassAdd(class)
+}
+
+// ClassAdd will add a class to the system.
+// Equivalent to: `tc class add $class`
+func (h *Handle) ClassAdd(class Class) error {
+	return h.classModify(
 		syscall.RTM_NEWTCLASS,
 		syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
 		class,
 	)
 }
 
-func classModify(cmd, flags int, class Class) error {
-	req := nl.NewNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
+func (h *Handle) classModify(cmd, flags int, class Class) error {
+	req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
 	base := class.Attrs()
 	msg := &nl.TcMsg{
 		Family:  nl.FAMILY_ALL,
@@ -73,20 +100,20 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
 		opt.Prio = htb.Prio
 		// TODO: Handle Debug properly. For now default to 0
 		/* Calculate {R,C}Tab and set Rate and Ceil */
-		cell_log := -1
-		ccell_log := -1
+		cellLog := -1
+		ccellLog := -1
 		linklayer := nl.LINKLAYER_ETHERNET
 		mtu := 1600
 		var rtab [256]uint32
 		var ctab [256]uint32
 		tcrate := nl.TcRateSpec{Rate: uint32(htb.Rate)}
-		if CalcRtable(&tcrate, rtab, cell_log, uint32(mtu), linklayer) < 0 {
-			return errors.New("HTB: failed to calculate rate table.")
+		if CalcRtable(&tcrate, rtab, cellLog, uint32(mtu), linklayer) < 0 {
+			return errors.New("HTB: failed to calculate rate table")
 		}
 		opt.Rate = tcrate
 		tcceil := nl.TcRateSpec{Rate: uint32(htb.Ceil)}
-		if CalcRtable(&tcceil, ctab, ccell_log, uint32(mtu), linklayer) < 0 {
-			return errors.New("HTB: failed to calculate ceil rate table.")
+		if CalcRtable(&tcceil, ctab, ccellLog, uint32(mtu), linklayer) < 0 {
+			return errors.New("HTB: failed to calculate ceil rate table")
 		}
 		opt.Ceil = tcceil
 		nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize())
@@ -101,14 +128,21 @@ func classPayload(req *nl.NetlinkRequest, class Class) error {
 // Equivalent to: `tc class show`.
 // Generally returns nothing if link and parent are not specified.
 func ClassList(link Link, parent uint32) ([]Class, error) {
-	req := nl.NewNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP)
+	return pkgHandle.ClassList(link, parent)
+}
+
+// ClassList gets a list of classes in the system.
+// Equivalent to: `tc class show`.
+// Generally returns nothing if link and parent are not specified.
+func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETTCLASS, syscall.NLM_F_DUMP)
 	msg := &nl.TcMsg{
 		Family: nl.FAMILY_ALL,
 		Parent: parent,
 	}
 	if link != nil {
 		base := link.Attrs()
-		ensureIndex(base)
+		h.ensureIndex(base)
 		msg.Ifindex = int32(base.Index)
 	}
 	req.AddData(msg)

+ 59 - 9
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter.go

@@ -11,7 +11,7 @@ type Filter interface {
 	Type() string
 }
 
-// Filter represents a netlink filter. A filter is associated with a link,
+// FilterAttrs represents a netlink filter. A filter is associated with a link,
 // has a handle and a parent. The root filter of a device should have a
 // parent == HANDLE_ROOT.
 type FilterAttrs struct {
@@ -26,11 +26,45 @@ func (q FilterAttrs) String() string {
 	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Priority: %d, Protocol: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Priority, q.Protocol)
 }
 
+// Action represents an action in any supported filter.
+type Action interface {
+	Type() string
+}
+
+type BpfAction struct {
+	nl.TcActBpf
+	Fd   int
+	Name string
+}
+
+func (action *BpfAction) Type() string {
+	return "bpf"
+}
+
+type MirredAction struct {
+	nl.TcMirred
+}
+
+func (action *MirredAction) Type() string {
+	return "mirred"
+}
+
+func NewMirredAction(redirIndex int) *MirredAction {
+	return &MirredAction{
+		TcMirred: nl.TcMirred{
+			TcGen:   nl.TcGen{Action: nl.TC_ACT_STOLEN},
+			Eaction: nl.TCA_EGRESS_REDIR,
+			Ifindex: uint32(redirIndex),
+		},
+	}
+}
+
 // U32 filters on many packet related properties
 type U32 struct {
 	FilterAttrs
-	// Currently only supports redirecting to another interface
+	ClassId    uint32
 	RedirIndex int
+	Actions    []Action
 }
 
 func (filter *U32) Attrs() *FilterAttrs {
@@ -57,7 +91,7 @@ type FilterFwAttrs struct {
 	LinkLayer int
 }
 
-// FwFilter filters on firewall marks
+// Fw filter filters on firewall marks
 type Fw struct {
 	FilterAttrs
 	ClassId uint32
@@ -73,8 +107,8 @@ type Fw struct {
 func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
 	var rtab [256]uint32
 	var ptab [256]uint32
-	rcell_log := -1
-	pcell_log := -1
+	rcellLog := -1
+	pcellLog := -1
 	avrate := fattrs.AvRate / 8
 	police := nl.TcPolice{}
 	police.Rate.Rate = fattrs.Rate / 8
@@ -90,8 +124,8 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
 	if police.Rate.Rate != 0 {
 		police.Rate.Mpu = fattrs.Mpu
 		police.Rate.Overhead = fattrs.Overhead
-		if CalcRtable(&police.Rate, rtab, rcell_log, fattrs.Mtu, linklayer) < 0 {
-			return nil, errors.New("TBF: failed to calculate rate table.")
+		if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 {
+			return nil, errors.New("TBF: failed to calculate rate table")
 		}
 		police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer)))
 	}
@@ -99,8 +133,8 @@ func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) {
 	if police.PeakRate.Rate != 0 {
 		police.PeakRate.Mpu = fattrs.Mpu
 		police.PeakRate.Overhead = fattrs.Overhead
-		if CalcRtable(&police.PeakRate, ptab, pcell_log, fattrs.Mtu, linklayer) < 0 {
-			return nil, errors.New("POLICE: failed to calculate peak rate table.")
+		if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 {
+			return nil, errors.New("POLICE: failed to calculate peak rate table")
 		}
 	}
 
@@ -124,6 +158,22 @@ func (filter *Fw) Type() string {
 	return "fw"
 }
 
+type BpfFilter struct {
+	FilterAttrs
+	ClassId      uint32
+	Fd           int
+	Name         string
+	DirectAction bool
+}
+
+func (filter *BpfFilter) Type() string {
+	return "bpf"
+}
+
+func (filter *BpfFilter) Attrs() *FilterAttrs {
+	return &filter.FilterAttrs
+}
+
 // GenericFilter filters represent types that are not currently understood
 // by this netlink library.
 type GenericFilter struct {

+ 173 - 52
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/filter_linux.go

@@ -12,7 +12,13 @@ import (
 // FilterDel will delete a filter from the system.
 // Equivalent to: `tc filter del $filter`
 func FilterDel(filter Filter) error {
-	req := nl.NewNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK)
+	return pkgHandle.FilterDel(filter)
+}
+
+// FilterDel will delete a filter from the system.
+// Equivalent to: `tc filter del $filter`
+func (h *Handle) FilterDel(filter Filter) error {
+	req := h.newNetlinkRequest(syscall.RTM_DELTFILTER, syscall.NLM_F_ACK)
 	base := filter.Attrs()
 	msg := &nl.TcMsg{
 		Family:  nl.FAMILY_ALL,
@@ -30,8 +36,14 @@ func FilterDel(filter Filter) error {
 // FilterAdd will add a filter to the system.
 // Equivalent to: `tc filter add $filter`
 func FilterAdd(filter Filter) error {
+	return pkgHandle.FilterAdd(filter)
+}
+
+// FilterAdd will add a filter to the system.
+// Equivalent to: `tc filter add $filter`
+func (h *Handle) FilterAdd(filter Filter) error {
 	native = nl.NativeEndian()
-	req := nl.NewNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	req := h.newNetlinkRequest(syscall.RTM_NEWTFILTER, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
 	base := filter.Attrs()
 	msg := &nl.TcMsg{
 		Family:  nl.FAMILY_ALL,
@@ -52,17 +64,17 @@ func FilterAdd(filter Filter) error {
 		}
 		sel.Keys = append(sel.Keys, nl.TcU32Key{})
 		nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize())
-		actions := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
-		table := nl.NewRtAttrChild(actions, nl.TCA_ACT_TAB, nil)
-		nl.NewRtAttrChild(table, nl.TCA_KIND, nl.ZeroTerminated("mirred"))
-		// redirect to other interface
-		mir := nl.TcMirred{
-			Action:  nl.TC_ACT_STOLEN,
-			Eaction: nl.TCA_EGRESS_REDIR,
-			Ifindex: uint32(u32.RedirIndex),
+		if u32.ClassId != 0 {
+			nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(u32.ClassId))
+		}
+		actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil)
+		// backwards compatibility
+		if u32.RedirIndex != 0 {
+			u32.Actions = append([]Action{NewMirredAction(u32.RedirIndex)}, u32.Actions...)
+		}
+		if err := encodeActions(actionsAttr, u32.Actions); err != nil {
+			return err
 		}
-		aopts := nl.NewRtAttrChild(table, nl.TCA_OPTIONS, nil)
-		nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mir.Serialize())
 	} else if fw, ok := filter.(*Fw); ok {
 		if fw.Mask != 0 {
 			b := make([]byte, 4)
@@ -90,6 +102,21 @@ func FilterAdd(filter Filter) error {
 			native.PutUint32(b, fw.ClassId)
 			nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b)
 		}
+	} else if bpf, ok := filter.(*BpfFilter); ok {
+		var bpfFlags uint32
+		if bpf.ClassId != 0 {
+			nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(bpf.ClassId))
+		}
+		if bpf.Fd >= 0 {
+			nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(bpf.Fd))))
+		}
+		if bpf.Name != "" {
+			nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(bpf.Name))
+		}
+		if bpf.DirectAction {
+			bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
+		}
+		nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
 	}
 
 	req.AddData(options)
@@ -101,14 +128,21 @@ func FilterAdd(filter Filter) error {
 // Equivalent to: `tc filter show`.
 // Generally retunrs nothing if link and parent are not specified.
 func FilterList(link Link, parent uint32) ([]Filter, error) {
-	req := nl.NewNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP)
+	return pkgHandle.FilterList(link, parent)
+}
+
+// FilterList gets a list of filters in the system.
+// Equivalent to: `tc filter show`.
+// Generally retunrs nothing if link and parent are not specified.
+func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETTFILTER, syscall.NLM_F_DUMP)
 	msg := &nl.TcMsg{
 		Family: nl.FAMILY_ALL,
 		Parent: parent,
 	}
 	if link != nil {
 		base := link.Attrs()
-		ensureIndex(base)
+		h.ensureIndex(base)
 		msg.Ifindex = int32(base.Index)
 	}
 	req.AddData(msg)
@@ -147,26 +181,29 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
 					filter = &U32{}
 				case "fw":
 					filter = &Fw{}
+				case "bpf":
+					filter = &BpfFilter{}
 				default:
 					filter = &GenericFilter{FilterType: filterType}
 				}
 			case nl.TCA_OPTIONS:
+				data, err := nl.ParseRouteAttr(attr.Value)
+				if err != nil {
+					return nil, err
+				}
 				switch filterType {
 				case "u32":
-					data, err := nl.ParseRouteAttr(attr.Value)
-					if err != nil {
-						return nil, err
-					}
 					detailed, err = parseU32Data(filter, data)
 					if err != nil {
 						return nil, err
 					}
 				case "fw":
-					data, err := nl.ParseRouteAttr(attr.Value)
+					detailed, err = parseFwData(filter, data)
 					if err != nil {
 						return nil, err
 					}
-					detailed, err = parseFwData(filter, data)
+				case "bpf":
+					detailed, err = parseBpfData(filter, data)
 					if err != nil {
 						return nil, err
 					}
@@ -183,6 +220,85 @@ func FilterList(link Link, parent uint32) ([]Filter, error) {
 	return res, nil
 }
 
+func encodeActions(attr *nl.RtAttr, actions []Action) error {
+	tabIndex := int(nl.TCA_ACT_TAB)
+
+	for _, action := range actions {
+		switch action := action.(type) {
+		default:
+			return fmt.Errorf("unknown action type %s", action.Type())
+		case *MirredAction:
+			table := nl.NewRtAttrChild(attr, tabIndex, nil)
+			tabIndex++
+			nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
+			aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+			nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, action.Serialize())
+		case *BpfAction:
+			table := nl.NewRtAttrChild(attr, tabIndex, nil)
+			tabIndex++
+			nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
+			aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil)
+			nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, action.Serialize())
+			nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
+			nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
+		}
+	}
+	return nil
+}
+
+func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
+	var actions []Action
+	for _, table := range tables {
+		var action Action
+		var actionType string
+		aattrs, err := nl.ParseRouteAttr(table.Value)
+		if err != nil {
+			return nil, err
+		}
+	nextattr:
+		for _, aattr := range aattrs {
+			switch aattr.Attr.Type {
+			case nl.TCA_KIND:
+				actionType = string(aattr.Value[:len(aattr.Value)-1])
+				// only parse if the action is mirred or bpf
+				switch actionType {
+				case "mirred":
+					action = &MirredAction{}
+				case "bpf":
+					action = &BpfAction{}
+				default:
+					break nextattr
+				}
+			case nl.TCA_OPTIONS:
+				adata, err := nl.ParseRouteAttr(aattr.Value)
+				if err != nil {
+					return nil, err
+				}
+				for _, adatum := range adata {
+					switch actionType {
+					case "mirred":
+						switch adatum.Attr.Type {
+						case nl.TCA_MIRRED_PARMS:
+							action.(*MirredAction).TcMirred = *nl.DeserializeTcMirred(adatum.Value)
+						}
+					case "bpf":
+						switch adatum.Attr.Type {
+						case nl.TCA_ACT_BPF_PARMS:
+							action.(*BpfAction).TcActBpf = *nl.DeserializeTcActBpf(adatum.Value)
+						case nl.TCA_ACT_BPF_FD:
+							action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4]))
+						case nl.TCA_ACT_BPF_NAME:
+							action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
+						}
+					}
+				}
+			}
+		}
+		actions = append(actions, action)
+	}
+	return actions, nil
+}
+
 func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
 	native = nl.NativeEndian()
 	u32 := filter.(*U32)
@@ -197,34 +313,17 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error)
 				return detailed, nil
 			}
 		case nl.TCA_U32_ACT:
-			table, err := nl.ParseRouteAttr(datum.Value)
+			tables, err := nl.ParseRouteAttr(datum.Value)
 			if err != nil {
 				return detailed, err
 			}
-			if len(table) != 1 || table[0].Attr.Type != nl.TCA_ACT_TAB {
-				return detailed, fmt.Errorf("Action table not formed properly")
+			u32.Actions, err = parseActions(tables)
+			if err != nil {
+				return detailed, err
 			}
-			aattrs, err := nl.ParseRouteAttr(table[0].Value)
-			for _, aattr := range aattrs {
-				switch aattr.Attr.Type {
-				case nl.TCA_KIND:
-					actionType := string(aattr.Value[:len(aattr.Value)-1])
-					// only parse if the action is mirred
-					if actionType != "mirred" {
-						return detailed, nil
-					}
-				case nl.TCA_OPTIONS:
-					adata, err := nl.ParseRouteAttr(aattr.Value)
-					if err != nil {
-						return detailed, err
-					}
-					for _, adatum := range adata {
-						switch adatum.Attr.Type {
-						case nl.TCA_MIRRED_PARMS:
-							mir := nl.DeserializeTcMirred(adatum.Value)
-							u32.RedirIndex = int(mir.Ifindex)
-						}
-					}
+			for _, action := range u32.Actions {
+				if action, ok := action.(*MirredAction); ok {
+					u32.RedirIndex = int(action.Ifindex)
 				}
 			}
 		}
@@ -261,6 +360,28 @@ func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
 	return detailed, nil
 }
 
+func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
+	native = nl.NativeEndian()
+	bpf := filter.(*BpfFilter)
+	detailed := true
+	for _, datum := range data {
+		switch datum.Attr.Type {
+		case nl.TCA_BPF_FD:
+			bpf.Fd = int(native.Uint32(datum.Value[0:4]))
+		case nl.TCA_BPF_NAME:
+			bpf.Name = string(datum.Value[:len(datum.Value)-1])
+		case nl.TCA_BPF_CLASSID:
+			bpf.ClassId = native.Uint32(datum.Value[0:4])
+		case nl.TCA_BPF_FLAGS:
+			flags := native.Uint32(datum.Value[0:4])
+			if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 {
+				bpf.DirectAction = true
+			}
+		}
+	}
+	return detailed, nil
+}
+
 func AlignToAtm(size uint) uint {
 	var linksize, cells int
 	cells = int(size / nl.ATM_CELL_PAYLOAD)
@@ -283,27 +404,27 @@ func AdjustSize(sz uint, mpu uint, linklayer int) uint {
 	}
 }
 
-func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cell_log int, mtu uint32, linklayer int) int {
+func CalcRtable(rate *nl.TcRateSpec, rtab [256]uint32, cellLog int, mtu uint32, linklayer int) int {
 	bps := rate.Rate
 	mpu := rate.Mpu
 	var sz uint
 	if mtu == 0 {
 		mtu = 2047
 	}
-	if cell_log < 0 {
-		cell_log = 0
-		for (mtu >> uint(cell_log)) > 255 {
-			cell_log++
+	if cellLog < 0 {
+		cellLog = 0
+		for (mtu >> uint(cellLog)) > 255 {
+			cellLog++
 		}
 	}
 	for i := 0; i < 256; i++ {
-		sz = AdjustSize(uint((i+1)<<uint32(cell_log)), uint(mpu), linklayer)
+		sz = AdjustSize(uint((i+1)<<uint32(cellLog)), uint(mpu), linklayer)
 		rtab[i] = uint32(Xmittime(uint64(bps), uint32(sz)))
 	}
 	rate.CellAlign = -1
-	rate.CellLog = uint8(cell_log)
+	rate.CellLog = uint8(cellLog)
 	rate.Linklayer = uint8(linklayer & nl.TC_LINKLAYER_MASK)
-	return cell_log
+	return cellLog
 }
 
 func DeserializeRtab(b []byte) [256]uint32 {

+ 86 - 0
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/handle.go

@@ -0,0 +1,86 @@
+package netlink
+
+import (
+	"sync/atomic"
+	"syscall"
+
+	"github.com/vishvananda/netlink/nl"
+	"github.com/vishvananda/netns"
+)
+
+// Empty handle used by the netlink package methods
+var pkgHandle = &Handle{}
+
+// Handle is an handle for the netlink requests
+// on a specific network namespace. All the requests
+// share the same netlink socket, which gets released
+// when the handle is deleted.
+type Handle struct {
+	seq          uint32
+	routeSocket  *nl.NetlinkSocket
+	xfrmSocket   *nl.NetlinkSocket
+	lookupByDump bool
+}
+
+// NewHandle returns a netlink handle on the current network namespace.
+func NewHandle() (*Handle, error) {
+	return newHandle(netns.None(), netns.None())
+}
+
+// NewHandle returns a netlink handle on the network namespace
+// specified by ns. If ns=netns.None(), current network namespace
+// will be assumed
+func NewHandleAt(ns netns.NsHandle) (*Handle, error) {
+	return newHandle(ns, netns.None())
+}
+
+// NewHandleAtFrom works as NewHandle but allows client to specify the
+// new and the origin netns Handle.
+func NewHandleAtFrom(newNs, curNs netns.NsHandle) (*Handle, error) {
+	return newHandle(newNs, curNs)
+}
+
+func newHandle(newNs, curNs netns.NsHandle) (*Handle, error) {
+	var (
+		err     error
+		rSocket *nl.NetlinkSocket
+		xSocket *nl.NetlinkSocket
+	)
+	rSocket, err = nl.GetNetlinkSocketAt(newNs, curNs, syscall.NETLINK_ROUTE)
+	if err != nil {
+		return nil, err
+	}
+	xSocket, err = nl.GetNetlinkSocketAt(newNs, curNs, syscall.NETLINK_XFRM)
+	if err != nil {
+		return nil, err
+	}
+	return &Handle{routeSocket: rSocket, xfrmSocket: xSocket}, nil
+}
+
+// Delete releases the resources allocated to this handle
+func (h *Handle) Delete() {
+	if h.routeSocket != nil {
+		h.routeSocket.Close()
+	}
+	if h.xfrmSocket != nil {
+		h.xfrmSocket.Close()
+	}
+	h.routeSocket, h.xfrmSocket = nil, nil
+}
+
+func (h *Handle) newNetlinkRequest(proto, flags int) *nl.NetlinkRequest {
+	// Do this so that package API still use nl package variable nextSeqNr
+	if h.routeSocket == nil {
+		return nl.NewNetlinkRequest(proto, flags)
+	}
+	return &nl.NetlinkRequest{
+		NlMsghdr: syscall.NlMsghdr{
+			Len:   uint32(syscall.SizeofNlMsghdr),
+			Type:  uint16(proto),
+			Flags: syscall.NLM_F_REQUEST | uint16(flags),
+			Seq:   atomic.AddUint32(&h.seq, 1),
+		},
+		RouteSocket: h.routeSocket,
+		XfmrSocket:  h.xfrmSocket,
+	}
+}

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

@@ -31,6 +31,7 @@ type LinkAttrs struct {
 	MasterIndex  int         // must be the index of a bridge
 	Namespace    interface{} // nil | NsPid | NsFd
 	Alias        string
+	Statistics   *LinkStatistics
 }
 
 // NewLinkAttrs returns LinkAttrs structure filled with default values
@@ -40,6 +41,35 @@ func NewLinkAttrs() LinkAttrs {
 	}
 }
 
+/*
+Ref: struct rtnl_link_stats {...}
+*/
+type LinkStatistics struct {
+	RxPackets         uint32
+	TxPackets         uint32
+	RxBytes           uint32
+	TxBytes           uint32
+	RxErrors          uint32
+	TxErrors          uint32
+	RxDropped         uint32
+	TxDropped         uint32
+	Multicast         uint32
+	Collisions        uint32
+	RxLengthErrors    uint32
+	RxOverErrors      uint32
+	RxCrcErrors       uint32
+	RxFrameErrors     uint32
+	RxFifoErrors      uint32
+	RxMissedErrors    uint32
+	TxAbortedErrors   uint32
+	TxCarrierErrors   uint32
+	TxFifoErrors      uint32
+	TxHeartbeatErrors uint32
+	TxWindowErrors    uint32
+	RxCompressed      uint32
+	TxCompressed      uint32
+}
+
 // Device links cannot be created via netlink. These links
 // are links created by udev like 'lo' and 'etho0'
 type Device struct {
@@ -425,7 +455,7 @@ const (
 	BOND_AD_SELECT_COUNT
 )
 
-// BondAdInfo
+// BondAdInfo represents ad info for bond
 type BondAdInfo struct {
 	AggregatorId int
 	NumPorts     int
@@ -526,7 +556,7 @@ func (bond *Bond) Type() string {
 	return "bond"
 }
 
-// GreTap devices must specify LocalIP and RemoteIP on create
+// Gretap devices must specify LocalIP and RemoteIP on create
 type Gretap struct {
 	LinkAttrs
 	IKey       uint32

+ 217 - 60
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go

@@ -12,6 +12,8 @@ import (
 	"github.com/vishvananda/netlink/nl"
 )
 
+const SizeofLinkStats = 0x5c
+
 var native = nl.NativeEndian()
 var lookupByDump = false
 
@@ -33,12 +35,27 @@ func ensureIndex(link *LinkAttrs) {
 	}
 }
 
+func (h *Handle) ensureIndex(link *LinkAttrs) {
+	if link != nil && link.Index == 0 {
+		newlink, _ := h.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 {
+	return pkgHandle.LinkSetUp(link)
+}
+
+// LinkSetUp enables the link device.
+// Equivalent to: `ip link set $link up`
+func (h *Handle) LinkSetUp(link Link) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Change = syscall.IFF_UP
@@ -53,9 +70,15 @@ func LinkSetUp(link Link) error {
 // LinkSetDown disables link device.
 // Equivalent to: `ip link set $link down`
 func LinkSetDown(link Link) error {
+	return pkgHandle.LinkSetDown(link)
+}
+
+// LinkSetDown disables link device.
+// Equivalent to: `ip link set $link down`
+func (h *Handle) LinkSetDown(link Link) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Change = syscall.IFF_UP
@@ -70,9 +93,15 @@ func LinkSetDown(link Link) error {
 // LinkSetMTU sets the mtu of the link device.
 // Equivalent to: `ip link set $link mtu $mtu`
 func LinkSetMTU(link Link, mtu int) error {
+	return pkgHandle.LinkSetMTU(link, mtu)
+}
+
+// LinkSetMTU sets the mtu of the link device.
+// Equivalent to: `ip link set $link mtu $mtu`
+func (h *Handle) LinkSetMTU(link Link, mtu int) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -91,9 +120,15 @@ func LinkSetMTU(link Link, mtu int) error {
 // LinkSetName sets the name of the link device.
 // Equivalent to: `ip link set $link name $name`
 func LinkSetName(link Link, name string) error {
+	return pkgHandle.LinkSetName(link, name)
+}
+
+// LinkSetName sets the name of the link device.
+// Equivalent to: `ip link set $link name $name`
+func (h *Handle) LinkSetName(link Link, name string) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -109,9 +144,15 @@ func LinkSetName(link Link, name string) error {
 // LinkSetAlias sets the alias of the link device.
 // Equivalent to: `ip link set dev $link alias $name`
 func LinkSetAlias(link Link, name string) error {
+	return pkgHandle.LinkSetAlias(link, name)
+}
+
+// LinkSetAlias sets the alias of the link device.
+// Equivalent to: `ip link set dev $link alias $name`
+func (h *Handle) LinkSetAlias(link Link, name string) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -127,9 +168,15 @@ func LinkSetAlias(link Link, name string) error {
 // LinkSetHardwareAddr sets the hardware address of the link device.
 // Equivalent to: `ip link set $link address $hwaddr`
 func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
+	return pkgHandle.LinkSetHardwareAddr(link, hwaddr)
+}
+
+// LinkSetHardwareAddr sets the hardware address of the link device.
+// Equivalent to: `ip link set $link address $hwaddr`
+func (h *Handle) LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -145,9 +192,15 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
 // LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
 // Equivalent to: `ip link set $link vf $vf mac $hwaddr`
 func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
+	return pkgHandle.LinkSetVfHardwareAddr(link, vf, hwaddr)
+}
+
+// LinkSetVfHardwareAddr sets the hardware address of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf mac $hwaddr`
+func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -169,9 +222,15 @@ func LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAddr) error {
 // LinkSetVfVlan sets the vlan of a vf for the link.
 // Equivalent to: `ip link set $link vf $vf vlan $vlan`
 func LinkSetVfVlan(link Link, vf, vlan int) error {
+	return pkgHandle.LinkSetVfVlan(link, vf, vlan)
+}
+
+// LinkSetVfVlan sets the vlan of a vf for the link.
+// Equivalent to: `ip link set $link vf $vf vlan $vlan`
+func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -193,30 +252,48 @@ func LinkSetVfVlan(link Link, vf, vlan int) error {
 // LinkSetMaster sets the master of the link device.
 // Equivalent to: `ip link set $link master $master`
 func LinkSetMaster(link Link, master *Bridge) error {
+	return pkgHandle.LinkSetMaster(link, master)
+}
+
+// LinkSetMaster sets the master of the link device.
+// Equivalent to: `ip link set $link master $master`
+func (h *Handle) LinkSetMaster(link Link, master *Bridge) error {
 	index := 0
 	if master != nil {
 		masterBase := master.Attrs()
-		ensureIndex(masterBase)
+		h.ensureIndex(masterBase)
 		index = masterBase.Index
 	}
 	if index <= 0 {
 		return fmt.Errorf("Device does not exist")
 	}
-	return LinkSetMasterByIndex(link, index)
+	return h.LinkSetMasterByIndex(link, index)
 }
 
 // LinkSetNoMaster removes the master of the link device.
 // Equivalent to: `ip link set $link nomaster`
 func LinkSetNoMaster(link Link) error {
-	return LinkSetMasterByIndex(link, 0)
+	return pkgHandle.LinkSetNoMaster(link)
+}
+
+// LinkSetNoMaster removes the master of the link device.
+// Equivalent to: `ip link set $link nomaster`
+func (h *Handle) LinkSetNoMaster(link Link) error {
+	return h.LinkSetMasterByIndex(link, 0)
 }
 
 // LinkSetMasterByIndex sets the master of the link device.
 // Equivalent to: `ip link set $link master $master`
 func LinkSetMasterByIndex(link Link, masterIndex int) error {
+	return pkgHandle.LinkSetMasterByIndex(link, masterIndex)
+}
+
+// LinkSetMasterByIndex sets the master of the link device.
+// Equivalent to: `ip link set $link master $master`
+func (h *Handle) LinkSetMasterByIndex(link Link, masterIndex int) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -236,9 +313,16 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
 // pid must be a pid of a running process.
 // Equivalent to: `ip link set $link netns $pid`
 func LinkSetNsPid(link Link, nspid int) error {
+	return pkgHandle.LinkSetNsPid(link, nspid)
+}
+
+// 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 (h *Handle) LinkSetNsPid(link Link, nspid int) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -258,9 +342,16 @@ func LinkSetNsPid(link Link, nspid int) error {
 // 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 {
+	return pkgHandle.LinkSetNsFd(link, fd)
+}
+
+// LinkSetNsFd puts the device into a new network namespace. The
+// fd must be an open file descriptor to a network namespace.
+// Similar to: `ip link set $link netns $ns`
+func (h *Handle) LinkSetNsFd(link Link, fd int) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -340,7 +431,7 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
 		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)))
+		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port)))
 	}
 	if vxlan.PortLow > 0 || vxlan.PortHigh > 0 {
 		pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)}
@@ -434,9 +525,16 @@ func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) {
 }
 
 // LinkAdd adds a new link device. The type and features of the device
-// are taken fromt the parameters in the link object.
+// are taken from the parameters in the link object.
 // Equivalent to: `ip link add $link`
 func LinkAdd(link Link) error {
+	return pkgHandle.LinkAdd(link)
+}
+
+// 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 (h *Handle) LinkAdd(link Link) error {
 	// TODO: set mtu and hardware address
 	// TODO: support extra data for macvlan
 	base := link.Attrs()
@@ -473,17 +571,17 @@ func LinkAdd(link Link) error {
 		if errno != 0 {
 			return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno)
 		}
-		ensureIndex(base)
+		h.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 h.LinkSetMasterByIndex(link, base.MasterIndex)
 		}
 		return nil
 	}
 
-	req := nl.NewNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	req := h.newNetlinkRequest(syscall.RTM_NEWLINK, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	// TODO: make it shorter
@@ -588,12 +686,12 @@ func LinkAdd(link Link) error {
 		return err
 	}
 
-	ensureIndex(base)
+	h.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 h.LinkSetMasterByIndex(link, base.MasterIndex)
 	}
 	return nil
 }
@@ -602,11 +700,18 @@ func LinkAdd(link Link) error {
 // the link object for it to be deleted. The other values are ignored.
 // Equivalent to: `ip link del $link`
 func LinkDel(link Link) error {
+	return pkgHandle.LinkDel(link)
+}
+
+// LinkDel deletes 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 (h *Handle) LinkDel(link Link) error {
 	base := link.Attrs()
 
-	ensureIndex(base)
+	h.ensureIndex(base)
 
-	req := nl.NewNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
+	req := h.newNetlinkRequest(syscall.RTM_DELLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(base.Index)
@@ -616,8 +721,8 @@ func LinkDel(link Link) error {
 	return err
 }
 
-func linkByNameDump(name string) (Link, error) {
-	links, err := LinkList()
+func (h *Handle) linkByNameDump(name string) (Link, error) {
+	links, err := h.LinkList()
 	if err != nil {
 		return nil, err
 	}
@@ -630,8 +735,8 @@ func linkByNameDump(name string) (Link, error) {
 	return nil, fmt.Errorf("Link %s not found", name)
 }
 
-func linkByAliasDump(alias string) (Link, error) {
-	links, err := LinkList()
+func (h *Handle) linkByAliasDump(alias string) (Link, error) {
+	links, err := h.LinkList()
 	if err != nil {
 		return nil, err
 	}
@@ -646,11 +751,16 @@ func linkByAliasDump(alias string) (Link, error) {
 
 // LinkByName finds a link by name and returns a pointer to the object.
 func LinkByName(name string) (Link, error) {
-	if lookupByDump {
-		return linkByNameDump(name)
+	return pkgHandle.LinkByName(name)
+}
+
+// LinkByName finds a link by name and returns a pointer to the object.
+func (h *Handle) LinkByName(name string) (Link, error) {
+	if h.lookupByDump {
+		return h.linkByNameDump(name)
 	}
 
-	req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
+	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	req.AddData(msg)
@@ -662,8 +772,8 @@ func LinkByName(name string) (Link, error) {
 	if err == syscall.EINVAL {
 		// older kernels don't support looking up via IFLA_IFNAME
 		// so fall back to dumping all links
-		lookupByDump = true
-		return linkByNameDump(name)
+		h.lookupByDump = true
+		return h.linkByNameDump(name)
 	}
 
 	return link, err
@@ -672,11 +782,17 @@ func LinkByName(name string) (Link, error) {
 // LinkByAlias finds a link by its alias and returns a pointer to the object.
 // If there are multiple links with the alias it returns the first one
 func LinkByAlias(alias string) (Link, error) {
-	if lookupByDump {
-		return linkByAliasDump(alias)
+	return pkgHandle.LinkByAlias(alias)
+}
+
+// LinkByAlias finds a link by its alias and returns a pointer to the object.
+// If there are multiple links with the alias it returns the first one
+func (h *Handle) LinkByAlias(alias string) (Link, error) {
+	if h.lookupByDump {
+		return h.linkByAliasDump(alias)
 	}
 
-	req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
+	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	req.AddData(msg)
@@ -688,8 +804,8 @@ func LinkByAlias(alias string) (Link, error) {
 	if err == syscall.EINVAL {
 		// older kernels don't support looking up via IFLA_IFALIAS
 		// so fall back to dumping all links
-		lookupByDump = true
-		return linkByAliasDump(alias)
+		h.lookupByDump = true
+		return h.linkByAliasDump(alias)
 	}
 
 	return link, err
@@ -697,7 +813,12 @@ func LinkByAlias(alias string) (Link, error) {
 
 // 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)
+	return pkgHandle.LinkByIndex(index)
+}
+
+// LinkByIndex finds a link by index and returns a pointer to the object.
+func (h *Handle) LinkByIndex(index int) (Link, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	msg.Index = int32(index)
@@ -824,6 +945,8 @@ func linkDeserialize(m []byte) (Link, error) {
 			base.TxQLen = int(native.Uint32(attr.Value[0:4]))
 		case syscall.IFLA_IFALIAS:
 			base.Alias = string(attr.Value[:len(attr.Value)-1])
+		case syscall.IFLA_STATS:
+			base.Statistics = parseLinkStats(attr.Value[:])
 		}
 	}
 	// Links that don't have IFLA_INFO_KIND are hardware devices
@@ -838,9 +961,15 @@ func linkDeserialize(m []byte) (Link, error) {
 // LinkList gets a list of link devices.
 // Equivalent to: `ip link show`
 func LinkList() ([]Link, error) {
+	return pkgHandle.LinkList()
+}
+
+// LinkList gets a list of link devices.
+// Equivalent to: `ip link show`
+func (h *Handle) 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)
+	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
 
 	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
 	req.AddData(msg)
@@ -904,33 +1033,57 @@ func LinkSubscribe(ch chan<- LinkUpdate, done <-chan struct{}) error {
 }
 
 func LinkSetHairpin(link Link, mode bool) error {
-	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE)
+	return pkgHandle.LinkSetHairpin(link, mode)
+}
+
+func (h *Handle) LinkSetHairpin(link Link, mode bool) error {
+	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE)
 }
 
 func LinkSetGuard(link Link, mode bool) error {
-	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD)
+	return pkgHandle.LinkSetGuard(link, mode)
+}
+
+func (h *Handle) LinkSetGuard(link Link, mode bool) error {
+	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD)
 }
 
 func LinkSetFastLeave(link Link, mode bool) error {
-	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE)
+	return pkgHandle.LinkSetFastLeave(link, mode)
+}
+
+func (h *Handle) LinkSetFastLeave(link Link, mode bool) error {
+	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE)
 }
 
 func LinkSetLearning(link Link, mode bool) error {
-	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
+	return pkgHandle.LinkSetLearning(link, mode)
+}
+
+func (h *Handle) LinkSetLearning(link Link, mode bool) error {
+	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
 }
 
 func LinkSetRootBlock(link Link, mode bool) error {
-	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT)
+	return pkgHandle.LinkSetRootBlock(link, mode)
+}
+
+func (h *Handle) LinkSetRootBlock(link Link, mode bool) error {
+	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT)
 }
 
 func LinkSetFlood(link Link, mode bool) error {
-	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
+	return pkgHandle.LinkSetFlood(link, mode)
+}
+
+func (h *Handle) LinkSetFlood(link Link, mode bool) error {
+	return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
 }
 
-func setProtinfoAttr(link Link, mode bool, attr int) error {
+func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error {
 	base := link.Attrs()
-	ensureIndex(base)
-	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+	h.ensureIndex(base)
+	req := h.newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
 
 	msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
 	msg.Index = int32(base.Index)
@@ -996,7 +1149,7 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
 		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]))
+			vxlan.Port = int(ntohs(datum.Value[0:2]))
 		case nl.IFLA_VXLAN_PORT_RANGE:
 			buf := bytes.NewBuffer(datum.Value[0:4])
 			var pr vxlanPortRange
@@ -1211,3 +1364,7 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) {
 		}
 	}
 }
+
+func parseLinkStats(data []byte) *LinkStatistics {
+	return (*LinkStatistics)(unsafe.Pointer(&data[0:SizeofLinkStats][0]))
+}

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

@@ -67,30 +67,62 @@ func (msg *Ndmsg) Len() int {
 // 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)
+	return pkgHandle.NeighAdd(neigh)
+}
+
+// NeighAdd will add an IP to MAC mapping to the ARP table
+// Equivalent to: `ip neigh add ....`
+func (h *Handle) NeighAdd(neigh *Neigh) error {
+	return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL)
 }
 
 // NeighSet 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|syscall.NLM_F_REPLACE)
+	return pkgHandle.NeighSet(neigh)
+}
+
+// NeighSet will add or replace an IP to MAC mapping to the ARP table
+// Equivalent to: `ip neigh replace....`
+func (h *Handle) NeighSet(neigh *Neigh) error {
+	return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE)
 }
 
 // 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)
+	return pkgHandle.NeighAppend(neigh)
 }
 
+// NeighAppend will append an entry to FDB
+// Equivalent to: `bridge fdb append...`
+func (h *Handle) NeighAppend(neigh *Neigh) error {
+	return h.neighAdd(neigh, syscall.NLM_F_CREATE|syscall.NLM_F_APPEND)
+}
+
+// NeighAppend will append an entry to FDB
+// Equivalent to: `bridge fdb append...`
 func neighAdd(neigh *Neigh, mode int) error {
-	req := nl.NewNetlinkRequest(syscall.RTM_NEWNEIGH, mode|syscall.NLM_F_ACK)
+	return pkgHandle.neighAdd(neigh, mode)
+}
+
+// NeighAppend will append an entry to FDB
+// Equivalent to: `bridge fdb append...`
+func (h *Handle) neighAdd(neigh *Neigh, mode int) error {
+	req := h.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 pkgHandle.NeighDel(neigh)
+}
+
+// NeighDel will delete an IP address from a link device.
+// Equivalent to: `ip addr del $addr dev $link`
+func (h *Handle) NeighDel(neigh *Neigh) error {
+	req := h.newNetlinkRequest(syscall.RTM_DELNEIGH, syscall.NLM_F_ACK)
 	return neighHandle(neigh, req)
 }
 
@@ -130,7 +162,14 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error {
 // 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)
+	return pkgHandle.NeighList(linkIndex, family)
+}
+
+// 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 (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETNEIGH, syscall.NLM_F_DUMP)
 	msg := Ndmsg{
 		Family: uint8(family),
 		Index:  uint32(linkIndex),

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

@@ -14,8 +14,8 @@ import (
 	"github.com/vishvananda/netlink/nl"
 )
 
+// Family type definitions
 const (
-	// Family type definitions
 	FAMILY_ALL = nl.FAMILY_ALL
 	FAMILY_V4  = nl.FAMILY_V4
 	FAMILY_V6  = nl.FAMILY_V6

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

@@ -6,9 +6,12 @@ import (
 	"encoding/binary"
 	"fmt"
 	"net"
+	"runtime"
 	"sync/atomic"
 	"syscall"
 	"unsafe"
+
+	"github.com/vishvananda/netns"
 )
 
 const (
@@ -171,7 +174,9 @@ func (a *RtAttr) Serialize() []byte {
 
 type NetlinkRequest struct {
 	syscall.NlMsghdr
-	Data []NetlinkRequestData
+	Data        []NetlinkRequestData
+	RouteSocket *NetlinkSocket
+	XfmrSocket  *NetlinkSocket
 }
 
 // Serialize the Netlink Request into a byte array
@@ -206,11 +211,29 @@ func (req *NetlinkRequest) AddData(data NetlinkRequestData) {
 // 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
+	var (
+		s   *NetlinkSocket
+		err error
+	)
+
+	switch sockType {
+	case syscall.NETLINK_XFRM:
+		s = req.XfmrSocket
+	case syscall.NETLINK_ROUTE:
+		s = req.RouteSocket
+	default:
+		return nil, fmt.Errorf("Socket type %d is not handled", sockType)
+	}
+
+	sharedSocket := s != nil
+
+	if s == nil {
+		s, err = getNetlinkSocket(sockType)
+		if err != nil {
+			return nil, err
+		}
+		defer s.Close()
 	}
-	defer s.Close()
 
 	if err := s.Send(req); err != nil {
 		return nil, err
@@ -231,7 +254,10 @@ done:
 		}
 		for _, m := range msgs {
 			if m.Header.Seq != req.Seq {
-				return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
+				if sharedSocket {
+					continue
+				}
+				return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq)
 			}
 			if m.Header.Pid != pid {
 				return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
@@ -295,6 +321,32 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
 	return s, nil
 }
 
+// GetNetlinkSocketAt opens a netlink socket in the network namespace newNs
+// and positions the thread back into the network namespace specified by curNs,
+// when done. If curNs is close, the function derives the current namespace and
+// moves back into it when done. If newNs is close, the socket will be opened
+// in the current network namespace.
+func GetNetlinkSocketAt(newNs, curNs netns.NsHandle, protocol int) (*NetlinkSocket, error) {
+	var err error
+
+	if newNs.IsOpen() {
+		runtime.LockOSThread()
+		defer runtime.UnlockOSThread()
+		if !curNs.IsOpen() {
+			if curNs, err = netns.Get(); err != nil {
+				return nil, fmt.Errorf("could not get current namespace while creating netlink socket: %v", err)
+			}
+			defer curNs.Close()
+		}
+		if err := netns.Set(newNs); err != nil {
+			return nil, fmt.Errorf("failed to set into network namespace %d while creating netlink socket: %v", newNs, err)
+		}
+		defer netns.Set(curNs)
+	}
+
+	return getNetlinkSocket(protocol)
+}
+
 // 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 which Receive() method can be called

+ 64 - 5
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/tc_linux.go

@@ -49,6 +49,15 @@ const (
 	TCAA_MAX    = 1
 )
 
+const (
+	TCA_ACT_UNSPEC = iota
+	TCA_ACT_KIND
+	TCA_ACT_OPTIONS
+	TCA_ACT_INDEX
+	TCA_ACT_STATS
+	TCA_ACT_MAX
+)
+
 const (
 	TCA_PRIO_UNSPEC = iota
 	TCA_PRIO_MQ
@@ -69,6 +78,7 @@ const (
 	SizeofTcHtbGlob      = 0x14
 	SizeofTcU32Key       = 0x10
 	SizeofTcU32Sel       = 0x10 // without keys
+	SizeofTcActBpf       = 0x14
 	SizeofTcMirred       = 0x1c
 	SizeofTcPolice       = 2*SizeofTcRateSpec + 0x20
 )
@@ -533,9 +543,34 @@ const (
 	TC_ACT_STOLEN     = 4
 	TC_ACT_QUEUED     = 5
 	TC_ACT_REPEAT     = 6
+	TC_ACT_REDIRECT   = 7
 	TC_ACT_JUMP       = 0x10000000
 )
 
+type TcGen struct {
+	Index   uint32
+	Capab   uint32
+	Action  int32
+	Refcnt  int32
+	Bindcnt int32
+}
+
+type TcActBpf struct {
+	TcGen
+}
+
+func (msg *TcActBpf) Len() int {
+	return SizeofTcActBpf
+}
+
+func DeserializeTcActBpf(b []byte) *TcActBpf {
+	return (*TcActBpf)(unsafe.Pointer(&b[0:SizeofTcActBpf][0]))
+}
+
+func (x *TcActBpf) Serialize() []byte {
+	return (*(*[SizeofTcActBpf]byte)(unsafe.Pointer(x)))[:]
+}
+
 // #define tc_gen \
 //   __u32                 index; \
 //   __u32                 capab; \
@@ -549,11 +584,7 @@ const (
 // };
 
 type TcMirred struct {
-	Index   uint32
-	Capab   uint32
-	Action  int32
-	Refcnt  int32
-	Bindcnt int32
+	TcGen
 	Eaction int32
 	Ifindex uint32
 }
@@ -625,3 +656,31 @@ const (
 	TCA_FW_MASK
 	TCA_FW_MAX = TCA_FW_MASK
 )
+
+const (
+	TCA_BPF_FLAG_ACT_DIRECT uint32 = 1 << iota
+)
+
+const (
+	TCA_BPF_UNSPEC = iota
+	TCA_BPF_ACT
+	TCA_BPF_POLICE
+	TCA_BPF_CLASSID
+	TCA_BPF_OPS_LEN
+	TCA_BPF_OPS
+	TCA_BPF_FD
+	TCA_BPF_NAME
+	TCA_BPF_FLAGS
+	TCA_BPF_MAX = TCA_BPF_FLAGS
+)
+
+const (
+	TCA_ACT_BPF_UNSPEC = iota
+	TCA_ACT_BPF_TM
+	TCA_ACT_BPF_PARMS
+	TCA_ACT_BPF_OPS_LEN
+	TCA_ACT_BPF_OPS
+	TCA_ACT_BPF_FD
+	TCA_ACT_BPF_NAME
+	TCA_ACT_BPF_MAX = TCA_ACT_BPF_NAME
+)

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

@@ -78,6 +78,7 @@ const (
 	SizeofXfrmLifetimeCfg = 0x40
 	SizeofXfrmLifetimeCur = 0x20
 	SizeofXfrmId          = 0x18
+	SizeofXfrmMark        = 0x08
 )
 
 // typedef union {
@@ -256,3 +257,20 @@ func DeserializeXfrmId(b []byte) *XfrmId {
 func (msg *XfrmId) Serialize() []byte {
 	return (*(*[SizeofXfrmId]byte)(unsafe.Pointer(msg)))[:]
 }
+
+type XfrmMark struct {
+	Value uint32
+	Mask  uint32
+}
+
+func (msg *XfrmMark) Len() int {
+	return SizeofXfrmMark
+}
+
+func DeserializeXfrmMark(b []byte) *XfrmMark {
+	return (*XfrmMark)(unsafe.Pointer(&b[0:SizeofXfrmMark][0]))
+}
+
+func (msg *XfrmMark) Serialize() []byte {
+	return (*(*[SizeofXfrmMark]byte)(unsafe.Pointer(msg)))[:]
+}

+ 27 - 6
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go

@@ -5,12 +5,13 @@ import (
 )
 
 const (
-	SizeofXfrmUsersaId   = 0x18
-	SizeofXfrmStats      = 0x0c
-	SizeofXfrmUsersaInfo = 0xe0
-	SizeofXfrmAlgo       = 0x44
-	SizeofXfrmAlgoAuth   = 0x48
-	SizeofXfrmEncapTmpl  = 0x18
+	SizeofXfrmUsersaId    = 0x18
+	SizeofXfrmStats       = 0x0c
+	SizeofXfrmUsersaInfo  = 0xe0
+	SizeofXfrmAlgo        = 0x44
+	SizeofXfrmAlgoAuth    = 0x48
+	SizeofXfrmEncapTmpl   = 0x18
+	SizeofXfrmUsersaFlush = 0x8
 )
 
 // struct xfrm_usersa_id {
@@ -219,3 +220,23 @@ func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl {
 func (msg *XfrmEncapTmpl) Serialize() []byte {
 	return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:]
 }
+
+// struct xfrm_usersa_flush {
+//    __u8 proto;
+// };
+
+type XfrmUsersaFlush struct {
+	Proto uint8
+}
+
+func (msg *XfrmUsersaFlush) Len() int {
+	return SizeofXfrmUsersaFlush
+}
+
+func DeserializeXfrmUsersaFlush(b []byte) *XfrmUsersaFlush {
+	return (*XfrmUsersaFlush)(unsafe.Pointer(&b[0:SizeofXfrmUsersaFlush][0]))
+}
+
+func (msg *XfrmUsersaFlush) Serialize() []byte {
+	return (*(*[SizeofXfrmUsersaFlush]byte)(unsafe.Pointer(msg)))[:]
+}

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

@@ -8,10 +8,14 @@ import (
 )
 
 func LinkGetProtinfo(link Link) (Protinfo, error) {
+	return pkgHandle.LinkGetProtinfo(link)
+}
+
+func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) {
 	base := link.Attrs()
-	ensureIndex(base)
+	h.ensureIndex(base)
 	var pi Protinfo
-	req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
+	req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
 	msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
 	req.AddData(msg)
 	msgs, err := req.Execute(syscall.NETLINK_ROUTE, 0)

+ 26 - 21
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc.go

@@ -8,16 +8,21 @@ import (
 const (
 	HANDLE_NONE      = 0
 	HANDLE_INGRESS   = 0xFFFFFFF1
+	HANDLE_CLSACT    = HANDLE_INGRESS
 	HANDLE_ROOT      = 0xFFFFFFFF
 	PRIORITY_MAP_LEN = 16
 )
+const (
+	HANDLE_MIN_INGRESS = 0xFFFFFFF2
+	HANDLE_MIN_EGRESS  = 0xFFFFFFF3
+)
 
 type Qdisc interface {
 	Attrs() *QdiscAttrs
 	Type() string
 }
 
-// Qdisc represents a netlink qdisc. A qdisc is associated with a link,
+// QdiscAttrs represents a netlink qdisc. A qdisc is associated with a link,
 // has a handle, a parent and a refcnt. The root qdisc of a device should
 // have parent == HANDLE_ROOT.
 type QdiscAttrs struct {
@@ -28,7 +33,7 @@ type QdiscAttrs struct {
 }
 
 func (q QdiscAttrs) String() string {
-	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %s}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
+	return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Refcnt: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Refcnt)
 }
 
 func MakeHandle(major, minor uint16) uint32 {
@@ -149,7 +154,7 @@ type NetemQdiscAttrs struct {
 
 func (q NetemQdiscAttrs) String() string {
 	return fmt.Sprintf(
-		"{Latency: %d, Limit: %d, Loss: %d, Gap: %d, Duplicate: %d, Jitter: %d}",
+		"{Latency: %d, Limit: %d, Loss: %f, Gap: %d, Duplicate: %f, Jitter: %d}",
 		q.Latency, q.Limit, q.Loss, q.Gap, q.Duplicate, q.Jitter,
 	)
 }
@@ -173,9 +178,9 @@ type Netem struct {
 
 func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
 	var limit uint32 = 1000
-	var loss_corr, delay_corr, duplicate_corr uint32
-	var reorder_prob, reorder_corr uint32
-	var corrupt_prob, corrupt_corr uint32
+	var lossCorr, delayCorr, duplicateCorr uint32
+	var reorderProb, reorderCorr uint32
+	var corruptProb, corruptCorr uint32
 
 	latency := nattrs.Latency
 	loss := Percentage2u32(nattrs.Loss)
@@ -185,13 +190,13 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
 
 	// Correlation
 	if latency > 0 && jitter > 0 {
-		delay_corr = Percentage2u32(nattrs.DelayCorr)
+		delayCorr = Percentage2u32(nattrs.DelayCorr)
 	}
 	if loss > 0 {
-		loss_corr = Percentage2u32(nattrs.LossCorr)
+		lossCorr = Percentage2u32(nattrs.LossCorr)
 	}
 	if duplicate > 0 {
-		duplicate_corr = Percentage2u32(nattrs.DuplicateCorr)
+		duplicateCorr = Percentage2u32(nattrs.DuplicateCorr)
 	}
 	// FIXME should validate values(like loss/duplicate are percentages...)
 	latency = time2Tick(latency)
@@ -204,34 +209,34 @@ func NewNetem(attrs QdiscAttrs, nattrs NetemQdiscAttrs) *Netem {
 		jitter = time2Tick(jitter)
 	}
 
-	reorder_prob = Percentage2u32(nattrs.ReorderProb)
-	reorder_corr = Percentage2u32(nattrs.ReorderCorr)
+	reorderProb = Percentage2u32(nattrs.ReorderProb)
+	reorderCorr = Percentage2u32(nattrs.ReorderCorr)
 
-	if reorder_prob > 0 {
+	if reorderProb > 0 {
 		// ERROR if lantency == 0
 		if gap == 0 {
 			gap = 1
 		}
 	}
 
-	corrupt_prob = Percentage2u32(nattrs.CorruptProb)
-	corrupt_corr = Percentage2u32(nattrs.CorruptCorr)
+	corruptProb = Percentage2u32(nattrs.CorruptProb)
+	corruptCorr = Percentage2u32(nattrs.CorruptCorr)
 
 	return &Netem{
 		QdiscAttrs:    attrs,
 		Latency:       latency,
-		DelayCorr:     delay_corr,
+		DelayCorr:     delayCorr,
 		Limit:         limit,
 		Loss:          loss,
-		LossCorr:      loss_corr,
+		LossCorr:      lossCorr,
 		Gap:           gap,
 		Duplicate:     duplicate,
-		DuplicateCorr: duplicate_corr,
+		DuplicateCorr: duplicateCorr,
 		Jitter:        jitter,
-		ReorderProb:   reorder_prob,
-		ReorderCorr:   reorder_corr,
-		CorruptProb:   corrupt_prob,
-		CorruptCorr:   corrupt_corr,
+		ReorderProb:   reorderProb,
+		ReorderCorr:   reorderCorr,
+		CorruptProb:   corruptProb,
+		CorruptCorr:   corruptCorr,
 	}
 }
 

+ 44 - 11
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/qdisc_linux.go

@@ -13,21 +13,41 @@ import (
 // QdiscDel will delete a qdisc from the system.
 // Equivalent to: `tc qdisc del $qdisc`
 func QdiscDel(qdisc Qdisc) error {
-	return qdiscModify(syscall.RTM_DELQDISC, 0, qdisc)
+	return pkgHandle.QdiscDel(qdisc)
+}
+
+// QdiscDel will delete a qdisc from the system.
+// Equivalent to: `tc qdisc del $qdisc`
+func (h *Handle) QdiscDel(qdisc Qdisc) error {
+	return h.qdiscModify(syscall.RTM_DELQDISC, 0, qdisc)
 }
 
 // QdiscChange will change a qdisc in place
 // Equivalent to: `tc qdisc change $qdisc`
 // The parent and handle MUST NOT be changed.
 func QdiscChange(qdisc Qdisc) error {
-	return qdiscModify(syscall.RTM_NEWQDISC, 0, qdisc)
+	return pkgHandle.QdiscChange(qdisc)
+}
+
+// QdiscChange will change a qdisc in place
+// Equivalent to: `tc qdisc change $qdisc`
+// The parent and handle MUST NOT be changed.
+func (h *Handle) QdiscChange(qdisc Qdisc) error {
+	return h.qdiscModify(syscall.RTM_NEWQDISC, 0, qdisc)
 }
 
 // QdiscReplace will replace a qdisc to the system.
 // Equivalent to: `tc qdisc replace $qdisc`
 // The handle MUST change.
 func QdiscReplace(qdisc Qdisc) error {
-	return qdiscModify(
+	return pkgHandle.QdiscReplace(qdisc)
+}
+
+// QdiscReplace will replace a qdisc to the system.
+// Equivalent to: `tc qdisc replace $qdisc`
+// The handle MUST change.
+func (h *Handle) QdiscReplace(qdisc Qdisc) error {
+	return h.qdiscModify(
 		syscall.RTM_NEWQDISC,
 		syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE,
 		qdisc)
@@ -36,14 +56,20 @@ func QdiscReplace(qdisc Qdisc) error {
 // QdiscAdd will add a qdisc to the system.
 // Equivalent to: `tc qdisc add $qdisc`
 func QdiscAdd(qdisc Qdisc) error {
-	return qdiscModify(
+	return pkgHandle.QdiscAdd(qdisc)
+}
+
+// QdiscAdd will add a qdisc to the system.
+// Equivalent to: `tc qdisc add $qdisc`
+func (h *Handle) QdiscAdd(qdisc Qdisc) error {
+	return h.qdiscModify(
 		syscall.RTM_NEWQDISC,
 		syscall.NLM_F_CREATE|syscall.NLM_F_EXCL,
 		qdisc)
 }
 
-func qdiscModify(cmd, flags int, qdisc Qdisc) error {
-	req := nl.NewNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
+func (h *Handle) qdiscModify(cmd, flags int, qdisc Qdisc) error {
+	req := h.newNetlinkRequest(cmd, flags|syscall.NLM_F_ACK)
 	base := qdisc.Attrs()
 	msg := &nl.TcMsg{
 		Family:  nl.FAMILY_ALL,
@@ -139,11 +165,18 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error {
 // Equivalent to: `tc qdisc show`.
 // The list can be filtered by link.
 func QdiscList(link Link) ([]Qdisc, error) {
-	req := nl.NewNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP)
+	return pkgHandle.QdiscList(link)
+}
+
+// QdiscList gets a list of qdiscs in the system.
+// Equivalent to: `tc qdisc show`.
+// The list can be filtered by link.
+func (h *Handle) QdiscList(link Link) ([]Qdisc, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETQDISC, syscall.NLM_F_DUMP)
 	index := int32(0)
 	if link != nil {
 		base := link.Attrs()
-		ensureIndex(base)
+		h.ensureIndex(base)
 		index = int32(base.Index)
 	}
 	msg := &nl.TcMsg{
@@ -334,9 +367,9 @@ const (
 )
 
 var (
-	tickInUsec  float64 = 0.0
-	clockFactor float64 = 0.0
-	hz          float64 = 0.0
+	tickInUsec  float64
+	clockFactor float64
+	hz          float64
 )
 
 func initClock() {

+ 4 - 4
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/route.go

@@ -41,8 +41,8 @@ type Route struct {
 }
 
 func (r Route) String() string {
-	return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s Flags: %s}", r.LinkIndex, r.Dst,
-		r.Src, r.Gw, r.ListFlags())
+	return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s Flags: %s Table: %d}", r.LinkIndex, r.Dst,
+		r.Src, r.Gw, r.ListFlags(), r.Table)
 }
 
 func (r *Route) SetFlag(flag NextHopFlag) {
@@ -59,8 +59,8 @@ type flagString struct {
 }
 
 var testFlags = []flagString{
-	flagString{f: FLAG_ONLINK, s: "onlink"},
-	flagString{f: FLAG_PERVASIVE, s: "pervasive"},
+	{f: FLAG_ONLINK, s: "onlink"},
+	{f: FLAG_PERVASIVE, s: "pervasive"},
 }
 
 func (r *Route) ListFlags() []string {

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

@@ -26,18 +26,30 @@ const (
 // 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, nl.NewRtMsg())
+	return pkgHandle.RouteAdd(route)
+}
+
+// RouteAdd will add a route to the system.
+// Equivalent to: `ip route add $route`
+func (h *Handle) RouteAdd(route *Route) error {
+	req := h.newNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	return h.routeHandle(route, req, nl.NewRtMsg())
 }
 
 // RouteDel 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, nl.NewRtDelMsg())
+	return pkgHandle.RouteDel(route)
 }
 
-func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
+// RouteDel will delete a route from the system.
+// Equivalent to: `ip route del $route`
+func (h *Handle) RouteDel(route *Route) error {
+	req := h.newNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
+	return h.routeHandle(route, req, nl.NewRtDelMsg())
+}
+
+func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
 	if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil {
 		return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
 	}
@@ -116,6 +128,7 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
 		msg.Type = uint8(route.Type)
 	}
 
+	msg.Flags = uint32(route.Flags)
 	msg.Scope = uint8(route.Scope)
 	msg.Family = uint8(family)
 	req.AddData(msg)
@@ -139,19 +152,32 @@ func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
 // Equivalent to: `ip route show`.
 // The list can be filtered by link and ip family.
 func RouteList(link Link, family int) ([]Route, error) {
+	return pkgHandle.RouteList(link, family)
+}
+
+// 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 (h *Handle) RouteList(link Link, family int) ([]Route, error) {
 	var routeFilter *Route
 	if link != nil {
 		routeFilter = &Route{
 			LinkIndex: link.Attrs().Index,
 		}
 	}
-	return RouteListFiltered(family, routeFilter, RT_FILTER_OIF)
+	return h.RouteListFiltered(family, routeFilter, RT_FILTER_OIF)
 }
 
 // RouteListFiltered gets a list of routes in the system filtered with specified rules.
 // All rules must be defined in RouteFilter struct
 func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
-	req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
+	return pkgHandle.RouteListFiltered(family, filter, filterMask)
+}
+
+// RouteListFiltered gets a list of routes in the system filtered with specified rules.
+// All rules must be defined in RouteFilter struct
+func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_DUMP)
 	infmsg := nl.NewIfInfomsg(family)
 	req.AddData(infmsg)
 
@@ -257,7 +283,13 @@ func deserializeRoute(m []byte) (Route, error) {
 // RouteGet gets a route to a specific destination from the host system.
 // Equivalent to: 'ip route get'.
 func RouteGet(destination net.IP) ([]Route, error) {
-	req := nl.NewNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
+	return pkgHandle.RouteGet(destination)
+}
+
+// RouteGet gets a route to a specific destination from the host system.
+// Equivalent to: 'ip route get'.
+func (h *Handle) RouteGet(destination net.IP) ([]Route, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETROUTE, syscall.NLM_F_REQUEST)
 	family := nl.GetIPFamily(destination)
 	var destinationData []byte
 	var bitlen uint8

+ 21 - 3
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/rule_linux.go

@@ -11,14 +11,26 @@ import (
 // RuleAdd adds a rule to the system.
 // Equivalent to: ip rule add
 func RuleAdd(rule *Rule) error {
-	req := nl.NewNetlinkRequest(syscall.RTM_NEWRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	return pkgHandle.RuleAdd(rule)
+}
+
+// RuleAdd adds a rule to the system.
+// Equivalent to: ip rule add
+func (h *Handle) RuleAdd(rule *Rule) error {
+	req := h.newNetlinkRequest(syscall.RTM_NEWRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
 	return ruleHandle(rule, req)
 }
 
 // RuleDel deletes a rule from the system.
 // Equivalent to: ip rule del
 func RuleDel(rule *Rule) error {
-	req := nl.NewNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
+	return pkgHandle.RuleDel(rule)
+}
+
+// RuleDel deletes a rule from the system.
+// Equivalent to: ip rule del
+func (h *Handle) RuleDel(rule *Rule) error {
+	req := h.newNetlinkRequest(syscall.RTM_DELRULE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
 	return ruleHandle(rule, req)
 }
 
@@ -128,7 +140,13 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error {
 // RuleList lists rules in the system.
 // Equivalent to: ip rule list
 func RuleList(family int) ([]Rule, error) {
-	req := nl.NewNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST)
+	return pkgHandle.RuleList(family)
+}
+
+// RuleList lists rules in the system.
+// Equivalent to: ip rule list
+func (h *Handle) RuleList(family int) ([]Rule, error) {
+	req := h.newNetlinkRequest(syscall.RTM_GETRULE, syscall.NLM_F_DUMP|syscall.NLM_F_REQUEST)
 	msg := nl.NewIfInfomsg(family)
 	req.AddData(msg)
 

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

@@ -62,3 +62,13 @@ func (m Mode) String() string {
 	}
 	return fmt.Sprintf("%d", m)
 }
+
+// XfrmMark represents the mark associated to the state or policy
+type XfrmMark struct {
+	Value uint32
+	Mask  uint32
+}
+
+func (m *XfrmMark) String() string {
+	return fmt.Sprintf("(0x%x,0x%x)", m.Value, m.Mask)
+}

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

@@ -46,14 +46,28 @@ type XfrmPolicyTmpl struct {
 	Reqid int
 }
 
+func (t XfrmPolicyTmpl) String() string {
+	return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, Mode: %s, Reqid: 0x%x}",
+		t.Dst, t.Src, t.Proto, t.Mode, t.Reqid)
+}
+
 // 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
+	Proto    Proto
+	DstPort  int
+	SrcPort  int
 	Dir      Dir
 	Priority int
 	Index    int
+	Mark     *XfrmMark
 	Tmpls    []XfrmPolicyTmpl
 }
+
+func (p XfrmPolicy) String() string {
+	return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Mark: %s, Tmpls: %s}",
+		p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Mark, p.Tmpls)
+}

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

@@ -7,19 +7,51 @@ import (
 )
 
 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)
+	sel.Family = uint16(nl.FAMILY_V4)
+	if policy.Dst != nil {
+		sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP))
+		sel.Daddr.FromIP(policy.Dst.IP)
+		prefixlenD, _ := policy.Dst.Mask.Size()
+		sel.PrefixlenD = uint8(prefixlenD)
+	}
+	if policy.Src != nil {
+		sel.Saddr.FromIP(policy.Src.IP)
+		prefixlenS, _ := policy.Src.Mask.Size()
+		sel.PrefixlenS = uint8(prefixlenS)
+	}
+	sel.Proto = uint8(policy.Proto)
+	sel.Dport = nl.Swap16(uint16(policy.DstPort))
+	sel.Sport = nl.Swap16(uint16(policy.SrcPort))
+	sel.DportMask = ^uint16(0)
+	sel.SportMask = ^uint16(0)
 }
 
 // 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)
+	return pkgHandle.XfrmPolicyAdd(policy)
+}
+
+// XfrmPolicyAdd will add an xfrm policy to the system.
+// Equivalent to: `ip xfrm policy add $policy`
+func (h *Handle) XfrmPolicyAdd(policy *XfrmPolicy) error {
+	return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_NEWPOLICY)
+}
+
+// XfrmPolicyUpdate will update an xfrm policy to the system.
+// Equivalent to: `ip xfrm policy update $policy`
+func XfrmPolicyUpdate(policy *XfrmPolicy) error {
+	return pkgHandle.XfrmPolicyUpdate(policy)
+}
+
+// XfrmPolicyUpdate will update an xfrm policy to the system.
+// Equivalent to: `ip xfrm policy update $policy`
+func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error {
+	return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_UPDPOLICY)
+}
+
+func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error {
+	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
 
 	msg := &nl.XfrmUserpolicyInfo{}
 	selFromPolicy(&msg.Sel, policy)
@@ -49,6 +81,10 @@ func XfrmPolicyAdd(policy *XfrmPolicy) error {
 		tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData)
 		req.AddData(tmpls)
 	}
+	if policy.Mark != nil {
+		out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark))
+		req.AddData(out)
+	}
 
 	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
 	return err
@@ -58,15 +94,14 @@ func XfrmPolicyAdd(policy *XfrmPolicy) error {
 // 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)
+	return pkgHandle.XfrmPolicyDel(policy)
+}
 
-	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+// 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 (h *Handle) XfrmPolicyDel(policy *XfrmPolicy) error {
+	_, err := h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_DELPOLICY)
 	return err
 }
 
@@ -74,7 +109,14 @@ func XfrmPolicyDel(policy *XfrmPolicy) error {
 // 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)
+	return pkgHandle.XfrmPolicyList(family)
+}
+
+// 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 (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) {
+	req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP)
 
 	msg := nl.NewIfInfomsg(family)
 	req.AddData(msg)
@@ -86,42 +128,124 @@ func XfrmPolicyList(family int) ([]XfrmPolicy, error) {
 
 	var res []XfrmPolicy
 	for _, m := range msgs {
-		msg := nl.DeserializeXfrmUserpolicyInfo(m)
-
-		if family != FAMILY_ALL && family != int(msg.Sel.Family) {
+		if policy, err := parseXfrmPolicy(m, family); err == nil {
+			res = append(res, *policy)
+		} else if err == familyError {
 			continue
+		} else {
+			return nil, err
 		}
+	}
+	return res, nil
+}
 
-		var policy XfrmPolicy
+// XfrmPolicyGet gets a the policy described by the index or selector, if found.
+// Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`.
+func XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) {
+	return pkgHandle.XfrmPolicyGet(policy)
+}
 
-		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)
+// XfrmPolicyGet gets a the policy described by the index or selector, if found.
+// Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`.
+func (h *Handle) XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) {
+	return h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_GETPOLICY)
+}
 
-		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
-		if err != nil {
-			return nil, err
-		}
+// XfrmPolicyFlush will flush the policies on the system.
+// Equivalent to: `ip xfrm policy flush`
+func XfrmPolicyFlush() error {
+	return pkgHandle.XfrmPolicyFlush()
+}
 
-		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)
-				}
+// XfrmPolicyFlush will flush the policies on the system.
+// Equivalent to: `ip xfrm policy flush`
+func (h *Handle) XfrmPolicyFlush() error {
+	req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, syscall.NLM_F_ACK)
+	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+	return err
+}
+
+func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) {
+	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
+
+	msg := &nl.XfrmUserpolicyId{}
+	selFromPolicy(&msg.Sel, policy)
+	msg.Index = uint32(policy.Index)
+	msg.Dir = uint8(policy.Dir)
+	req.AddData(msg)
+
+	if policy.Mark != nil {
+		out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark))
+		req.AddData(out)
+	}
+
+	resType := nl.XFRM_MSG_NEWPOLICY
+	if nlProto == nl.XFRM_MSG_DELPOLICY {
+		resType = 0
+	}
+
+	msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
+	if err != nil {
+		return nil, err
+	}
+
+	if nlProto == nl.XFRM_MSG_DELPOLICY {
+		return nil, err
+	}
+
+	p, err := parseXfrmPolicy(msgs[0], FAMILY_ALL)
+	if err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) {
+	msg := nl.DeserializeXfrmUserpolicyInfo(m)
+
+	// This is mainly for the policy dump
+	if family != FAMILY_ALL && family != int(msg.Sel.Family) {
+		return nil, familyError
+	}
+
+	var policy XfrmPolicy
+
+	policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD)
+	policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS)
+	policy.Proto = Proto(msg.Sel.Proto)
+	policy.DstPort = int(nl.Swap16(msg.Sel.Dport))
+	policy.SrcPort = int(nl.Swap16(msg.Sel.Sport))
+	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)
 			}
+		case nl.XFRMA_MARK:
+			mark := nl.DeserializeXfrmMark(attr.Value[:])
+			policy.Mark = new(XfrmMark)
+			policy.Mark.Value = mark.Value
+			policy.Mark.Mask = mark.Mask
 		}
-		res = append(res, policy)
 	}
-	return res, nil
+
+	return &policy, nil
 }

+ 19 - 3
libnetwork/Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go

@@ -1,6 +1,7 @@
 package netlink
 
 import (
+	"fmt"
 	"net"
 )
 
@@ -11,7 +12,11 @@ type XfrmStateAlgo struct {
 	TruncateLen int // Auth only
 }
 
-// EncapType is an enum representing an ipsec template direction.
+func (a XfrmStateAlgo) String() string {
+	return fmt.Sprintf("{Name: %s, Key: 0x%x, TruncateLen: %d}", a.Name, a.Key, a.TruncateLen)
+}
+
+// EncapType is an enum representing the optional packet encapsulation.
 type EncapType uint8
 
 const (
@@ -22,14 +27,14 @@ const (
 func (e EncapType) String() string {
 	switch e {
 	case XFRM_ENCAP_ESPINUDP_NONIKE:
-		return "espinudp-nonike"
+		return "espinudp-non-ike"
 	case XFRM_ENCAP_ESPINUDP:
 		return "espinudp"
 	}
 	return "unknown"
 }
 
-// XfrmEncap represents the encapsulation to use for the ipsec encryption.
+// XfrmStateEncap represents the encapsulation to use for the ipsec encryption.
 type XfrmStateEncap struct {
 	Type            EncapType
 	SrcPort         int
@@ -37,6 +42,11 @@ type XfrmStateEncap struct {
 	OriginalAddress net.IP
 }
 
+func (e XfrmStateEncap) String() string {
+	return fmt.Sprintf("{Type: %s, Srcport: %d, DstPort: %d, OriginalAddress: %v}",
+		e.Type, e.SrcPort, e.DstPort, e.OriginalAddress)
+}
+
 // XfrmState represents the state of an ipsec policy. It optionally
 // contains an XfrmStateAlgo for encryption and one for authentication.
 type XfrmState struct {
@@ -47,7 +57,13 @@ type XfrmState struct {
 	Spi          int
 	Reqid        int
 	ReplayWindow int
+	Mark         *XfrmMark
 	Auth         *XfrmStateAlgo
 	Crypt        *XfrmStateAlgo
 	Encap        *XfrmStateEncap
 }
+
+func (sa XfrmState) String() string {
+	return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Encap: %v",
+		sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Encap)
+}

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

@@ -34,14 +34,47 @@ func writeStateAlgoAuth(a *XfrmStateAlgo) []byte {
 	return algo.Serialize()
 }
 
+func writeMark(m *XfrmMark) []byte {
+	mark := &nl.XfrmMark{
+		Value: m.Value,
+		Mask:  m.Mask,
+	}
+	if mark.Mask == 0 {
+		mark.Mask = ^uint32(0)
+	}
+	return mark.Serialize()
+}
+
 // XfrmStateAdd will add an xfrm state to the system.
 // Equivalent to: `ip xfrm state add $state`
 func XfrmStateAdd(state *XfrmState) error {
+	return pkgHandle.XfrmStateAdd(state)
+}
+
+// XfrmStateAdd will add an xfrm state to the system.
+// Equivalent to: `ip xfrm state add $state`
+func (h *Handle) XfrmStateAdd(state *XfrmState) error {
+	return h.xfrmStateAddOrUpdate(state, nl.XFRM_MSG_NEWSA)
+}
+
+// XfrmStateUpdate will update an xfrm state to the system.
+// Equivalent to: `ip xfrm state update $state`
+func XfrmStateUpdate(state *XfrmState) error {
+	return pkgHandle.XfrmStateUpdate(state)
+}
+
+// XfrmStateUpdate will update an xfrm state to the system.
+// Equivalent to: `ip xfrm state update $state`
+func (h *Handle) XfrmStateUpdate(state *XfrmState) error {
+	return h.xfrmStateAddOrUpdate(state, nl.XFRM_MSG_UPDSA)
+}
+
+func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) 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)
+	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
 
 	msg := &nl.XfrmUsersaInfo{}
 	msg.Family = uint16(nl.GetIPFamily(state.Dst))
@@ -76,6 +109,10 @@ func XfrmStateAdd(state *XfrmState) error {
 		out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData)
 		req.AddData(out)
 	}
+	if state.Mark != nil {
+		out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
+		req.AddData(out)
+	}
 
 	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
 	return err
@@ -85,30 +122,29 @@ func XfrmStateAdd(state *XfrmState) error {
 // 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)
+	return pkgHandle.XfrmStateDel(state)
+}
 
-	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+// 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 (h *Handle) XfrmStateDel(state *XfrmState) error {
+	_, err := h.xfrmStateGetOrDelete(state, nl.XFRM_MSG_DELSA)
 	return err
 }
 
 // XfrmStateList gets a list of xfrm states in the system.
-// Equivalent to: `ip xfrm state show`.
+// Equivalent to: `ip [-4|-6] 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)
+	return pkgHandle.XfrmStateList(family)
+}
+
+// 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 (h *Handle) XfrmStateList(family int) ([]XfrmState, error) {
+	req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
 
 	msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
 	if err != nil {
@@ -117,62 +153,162 @@ func XfrmStateList(family int) ([]XfrmState, error) {
 
 	var res []XfrmState
 	for _, m := range msgs {
-		msg := nl.DeserializeXfrmUsersaInfo(m)
-
-		if family != FAMILY_ALL && family != int(msg.Family) {
+		if state, err := parseXfrmState(m, family); err == nil {
+			res = append(res, *state)
+		} else if err == familyError {
 			continue
+		} else {
+			return nil, err
 		}
+	}
+	return res, nil
+}
 
-		var state XfrmState
+// XfrmStateGet gets the xfrm state described by the ID, if found.
+// Equivalent to: `ip xfrm state get ID [ mark MARK [ mask MASK ] ]`.
+// Only the fields which constitue the SA ID must be filled in:
+// ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]
+// mark is optional
+func XfrmStateGet(state *XfrmState) (*XfrmState, error) {
+	return pkgHandle.XfrmStateGet(state)
+}
 
-		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)
+// XfrmStateGet gets the xfrm state described by the ID, if found.
+// Equivalent to: `ip xfrm state get ID [ mark MARK [ mask MASK ] ]`.
+// Only the fields which constitue the SA ID must be filled in:
+// ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]
+// mark is optional
+func (h *Handle) XfrmStateGet(state *XfrmState) (*XfrmState, error) {
+	return h.xfrmStateGetOrDelete(state, nl.XFRM_MSG_GETSA)
+}
 
-		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
-		if err != nil {
-			return nil, err
-		}
+func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) {
+	req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
 
-		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:
+	msg := &nl.XfrmUsersaId{}
+	msg.Family = uint16(nl.GetIPFamily(state.Dst))
+	msg.Daddr.FromIP(state.Dst)
+	msg.Proto = uint8(state.Proto)
+	msg.Spi = nl.Swap32(uint32(state.Spi))
+	req.AddData(msg)
+
+	if state.Mark != nil {
+		out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
+		req.AddData(out)
+	}
+	if state.Src != nil {
+		out := nl.NewRtAttr(nl.XFRMA_SRCADDR, state.Src)
+		req.AddData(out)
+	}
+
+	resType := nl.XFRM_MSG_NEWSA
+	if nlProto == nl.XFRM_MSG_DELSA {
+		resType = 0
+	}
+
+	msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
+	if err != nil {
+		return nil, err
+	}
+
+	if nlProto == nl.XFRM_MSG_DELSA {
+		return nil, nil
+	}
+
+	s, err := parseXfrmState(msgs[0], FAMILY_ALL)
+	if err != nil {
+		return nil, err
+	}
+
+	return s, nil
+}
+
+var familyError = fmt.Errorf("family error")
+
+func parseXfrmState(m []byte, family int) (*XfrmState, error) {
+	msg := nl.DeserializeXfrmUsersaInfo(m)
+
+	// This is mainly for the state dump
+	if family != FAMILY_ALL && family != int(msg.Family) {
+		return nil, familyError
+	}
+
+	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[nl.SizeofXfrmUsersaInfo:])
+	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)
 				}
-				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()
+				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()
+		case nl.XFRMA_MARK:
+			mark := nl.DeserializeXfrmMark(attr.Value[:])
+			state.Mark = new(XfrmMark)
+			state.Mark.Value = mark.Value
+			state.Mark.Mask = mark.Mask
 		}
-		res = append(res, state)
 	}
-	return res, nil
+
+	return &state, nil
+}
+
+// XfrmStateFlush will flush the xfrm state on the system.
+// proto = 0 means any transformation protocols
+// Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]`
+func XfrmStateFlush(proto Proto) error {
+	return pkgHandle.XfrmStateFlush(proto)
+}
+
+// XfrmStateFlush will flush the xfrm state on the system.
+// proto = 0 means any transformation protocols
+// Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]`
+func (h *Handle) XfrmStateFlush(proto Proto) error {
+	req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, syscall.NLM_F_ACK)
+
+	req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
+
+	_, err := req.Execute(syscall.NETLINK_XFRM, 0)
+	if err != nil {
+		return err
+	}
+
+	return nil
 }

+ 1 - 2
libnetwork/drivers/overlay/ov_utils.go

@@ -6,7 +6,6 @@ import (
 	"github.com/docker/libnetwork/netutils"
 	"github.com/docker/libnetwork/osl"
 	"github.com/vishvananda/netlink"
-	"github.com/vishvananda/netlink/nl"
 )
 
 func validateID(nid, eid string) error {
@@ -54,7 +53,7 @@ func createVxlan(name string, vni uint32) error {
 		LinkAttrs: netlink.LinkAttrs{Name: name},
 		VxlanId:   int(vni),
 		Learning:  true,
-		Port:      int(nl.Swap16(vxlanPort)), //network endian order
+		Port:      vxlanPort,
 		Proxy:     true,
 		L3miss:    true,
 		L2miss:    true,