Browse Source

update vendored netlink

Fixes #168
Eugene Yakubovich 9 years ago
parent
commit
3740b01fa0
26 changed files with 906 additions and 127 deletions
  1. 1 1
      Godeps/Godeps.json
  2. 3 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/.travis.yml
  3. 29 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile
  4. 3 3
      Godeps/_workspace/src/github.com/vishvananda/netlink/README.md
  5. 16 2
      Godeps/_workspace/src/github.com/vishvananda/netlink/addr_linux.go
  6. 46 7
      Godeps/_workspace/src/github.com/vishvananda/netlink/link.go
  7. 181 8
      Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go
  8. 177 23
      Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go
  9. 10 10
      Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_linux.go
  10. 12 13
      Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go
  11. 2 2
      Godeps/_workspace/src/github.com/vishvananda/netlink/netlink.go
  12. 2 1
      Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_test.go
  13. 24 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/netlink_unspecified.go
  14. 72 32
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go
  15. 6 3
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go
  16. 2 2
      Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_linux.go
  17. 53 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo.go
  18. 60 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_linux.go
  19. 98 0
      Godeps/_workspace/src/github.com/vishvananda/netlink/protinfo_test.go
  20. 1 1
      Godeps/_workspace/src/github.com/vishvananda/netlink/route.go
  21. 61 2
      Godeps/_workspace/src/github.com/vishvananda/netlink/route_linux.go
  22. 32 1
      Godeps/_workspace/src/github.com/vishvananda/netlink/route_test.go
  23. 6 6
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm.go
  24. 6 6
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_policy.go
  25. 2 3
      Godeps/_workspace/src/github.com/vishvananda/netlink/xfrm_state.go
  26. 1 1
      backend/vxlan/device.go

+ 1 - 1
Godeps/Godeps.json

@@ -33,7 +33,7 @@
 		},
 		{
 			"ImportPath": "github.com/vishvananda/netlink",
-			"Rev": "2187ba67a244c1c32f53bf88876e766bbbbcd5e6"
+			"Rev": "991a7a2fa7c073968fb27f36669df199b1fdf412"
 		}
 	]
 }

+ 3 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/.travis.yml

@@ -0,0 +1,3 @@
+language: go
+install:
+      - go get github.com/vishvananda/netns

+ 29 - 0
Godeps/_workspace/src/github.com/vishvananda/netlink/Makefile

@@ -0,0 +1,29 @@
+DIRS := \
+	. \
+	nl
+
+DEPS = \
+	github.com/vishvananda/netns
+
+uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
+testdirs = $(call uniq,$(foreach d,$(1),$(dir $(wildcard $(d)/*_test.go))))
+goroot = $(addprefix ../../../,$(1))
+unroot = $(subst ../../../,,$(1))
+fmt = $(addprefix fmt-,$(1))
+
+all: fmt
+
+$(call goroot,$(DEPS)):
+	go get $(call unroot,$@)
+
+.PHONY: $(call testdirs,$(DIRS))
+$(call testdirs,$(DIRS)):
+	sudo -E go test -v github.com/vishvananda/netlink/$@
+
+$(call fmt,$(call testdirs,$(DIRS))):
+	! gofmt -l $(subst fmt-,,$@)/*.go | grep ''
+
+.PHONY: fmt
+fmt: $(call fmt,$(call testdirs,$(DIRS)))
+
+test: fmt $(call goroot,$(DEPS)) $(call testdirs,$(DIRS))

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

@@ -1,6 +1,6 @@
 # netlink - netlink library for go #
 
-[![Build Status](https://travis-ci.org/vishvananda/netlink.png?branch=master)](https://travis-ci.org/vishvananda/netlink)
+[![Build Status](https://travis-ci.org/vishvananda/netlink.png?branch=master)](https://travis-ci.org/vishvananda/netlink) [![GoDoc](https://godoc.org/github.com/vishvananda/netlink?status.svg)](https://godoc.org/github.com/vishvananda/netlink)
 
 The netlink package provides a simple netlink library for go. Netlink
 is the interface a user-space program in linux uses to communicate with
@@ -39,7 +39,7 @@ package main
 
 import (
     "net"
-    "github.com/vishvananada/netlink"
+    "github.com/vishvananda/netlink"
 )
 
 func main() {
@@ -58,7 +58,7 @@ package main
 
 import (
     "net"
-    "github.com/vishvananada/netlink"
+    "github.com/vishvananda/netlink"
 )
 
 func main() {

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

@@ -10,7 +10,7 @@ import (
 )
 
 // AddrAdd will add an IP address to a link device.
-// Equivalent to: `ip addr del $addr dev $link`
+// Equivalent to: `ip addr add $addr dev $link`
 func AddrAdd(link Link, addr *Addr) error {
 
 	req := nl.NewNetlinkRequest(syscall.RTM_NEWADDR, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
@@ -95,11 +95,17 @@ func AddrList(link Link, family int) ([]Addr, error) {
 			return nil, err
 		}
 
+		var local, dst *net.IPNet
 		var addr Addr
 		for _, attr := range attrs {
 			switch attr.Attr.Type {
 			case syscall.IFA_ADDRESS:
-				addr.IPNet = &net.IPNet{
+				dst = &net.IPNet{
+					IP:   attr.Value,
+					Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
+				}
+			case syscall.IFA_LOCAL:
+				local = &net.IPNet{
 					IP:   attr.Value,
 					Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)),
 				}
@@ -107,6 +113,14 @@ func AddrList(link Link, family int) ([]Addr, error) {
 				addr.Label = string(attr.Value[:len(attr.Value)-1])
 			}
 		}
+
+		// IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS
+		if local != nil {
+			addr.IPNet = local
+		} else {
+			addr.IPNet = dst
+		}
+
 		res = append(res, addr)
 	}
 

+ 46 - 7
Godeps/_workspace/src/github.com/vishvananda/netlink/link.go

@@ -1,8 +1,6 @@
 package netlink
 
-import (
-	"net"
-)
+import "net"
 
 // Link represents a link device from netlink. Shared link attributes
 // like name may be retrieved using the Attrs() method. Unique data
@@ -12,15 +10,22 @@ type Link interface {
 	Type() string
 }
 
+type (
+	NsPid int
+	NsFd  int
+)
+
 // LinkAttrs represents data shared by most link types
 type LinkAttrs struct {
 	Index        int
 	MTU          int
+	TxQLen       uint32 // Transmit Queue Length
 	Name         string
 	HardwareAddr net.HardwareAddr
 	Flags        net.Flags
-	ParentIndex  int // index of the parent link device
-	MasterIndex  int // must be the index of a bridge
+	ParentIndex  int         // index of the parent link device
+	MasterIndex  int         // must be the index of a bridge
+	Namespace    interface{} // nil | NsPid | NsFd
 }
 
 // Device links cannot be created via netlink. These links
@@ -77,9 +82,21 @@ func (vlan *Vlan) Type() string {
 	return "vlan"
 }
 
+type MacvlanMode uint16
+
+const (
+	MACVLAN_MODE_DEFAULT MacvlanMode = iota
+	MACVLAN_MODE_PRIVATE
+	MACVLAN_MODE_VEPA
+	MACVLAN_MODE_BRIDGE
+	MACVLAN_MODE_PASSTHRU
+	MACVLAN_MODE_SOURCE
+)
+
 // Macvlan links have ParentIndex set in their Attrs()
 type Macvlan struct {
 	LinkAttrs
+	Mode MacvlanMode
 }
 
 func (macvlan *Macvlan) Attrs() *LinkAttrs {
@@ -148,7 +165,29 @@ func (vxlan *Vxlan) Type() string {
 	return "vxlan"
 }
 
+type IPVlanMode uint16
+
+const (
+	IPVLAN_MODE_L2 IPVlanMode = iota
+	IPVLAN_MODE_L3
+	IPVLAN_MODE_MAX
+)
+
+type IPVlan struct {
+	LinkAttrs
+	Mode IPVlanMode
+}
+
+func (ipvlan *IPVlan) Attrs() *LinkAttrs {
+	return &ipvlan.LinkAttrs
+}
+
+func (ipvlan *IPVlan) Type() string {
+	return "ipvlan"
+}
+
 // iproute2 supported devices;
 // vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
-// can | bridge | bond | ipoib | ip6tnl | ipip | sit |
-// vxlan | gre | gretap | ip6gre | ip6gretap | vti
+// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |
+// gre | gretap | ip6gre | ip6gretap | vti | nlmon |
+// bond_slave | ipvlan

+ 181 - 8
Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go

@@ -13,6 +13,15 @@ import (
 var native = nl.NativeEndian()
 var lookupByDump = false
 
+var macvlanModes = [...]uint32{
+	0,
+	nl.MACVLAN_MODE_PRIVATE,
+	nl.MACVLAN_MODE_VEPA,
+	nl.MACVLAN_MODE_BRIDGE,
+	nl.MACVLAN_MODE_PASSTHRU,
+	nl.MACVLAN_MODE_SOURCE,
+}
+
 func ensureIndex(link *LinkAttrs) {
 	if link != nil && link.Index == 0 {
 		newlink, _ := LinkByName(link.Name)
@@ -67,7 +76,7 @@ func LinkSetMTU(link Link, mtu int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_MTU
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -80,6 +89,48 @@ func LinkSetMTU(link Link, mtu int) error {
 	return err
 }
 
+// LinkSetName sets the name of the link device.
+// Equivalent to: `ip link set $link name $name`
+func LinkSetName(link Link, name string) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(base.Index)
+	msg.Change = syscall.IFLA_IFNAME
+	req.AddData(msg)
+
+	data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
+// 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 {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(base.Index)
+	msg.Change = syscall.IFLA_ADDRESS
+	req.AddData(msg)
+
+	data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
+	req.AddData(data)
+
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	return err
+}
+
 // LinkSetMaster sets the master of the link device.
 // Equivalent to: `ip link set $link master $master`
 func LinkSetMaster(link Link, master *Bridge) error {
@@ -103,7 +154,7 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_MASTER
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -128,7 +179,7 @@ func LinkSetNsPid(link Link, nspid int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = syscall.IFLA_NET_NS_PID
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -141,7 +192,7 @@ func LinkSetNsPid(link Link, nspid int) error {
 	return err
 }
 
-// LinkSetNsPid puts the device into a new network namespace. The
+// LinkSetNsFd puts the device into a new network namespace. The
 // fd must be an open file descriptor to a network namespace.
 // Similar to: `ip link set $link netns $ns`
 func LinkSetNsFd(link Link, fd int) error {
@@ -153,7 +204,7 @@ func LinkSetNsFd(link Link, fd int) error {
 	msg.Type = syscall.RTM_SETLINK
 	msg.Flags = syscall.NLM_F_REQUEST
 	msg.Index = int32(base.Index)
-	msg.Change = nl.DEFAULT_CHANGE
+	msg.Change = nl.IFLA_NET_NS_FD
 	req.AddData(msg)
 
 	b := make([]byte, 4)
@@ -178,7 +229,7 @@ type vxlanPortRange struct {
 	Lo, Hi uint16
 }
 
-func addVxlanAttrs(vxlan* Vxlan, linkInfo *nl.RtAttr) {
+func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
 	data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
 	nl.NewRtAttrChild(data, nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId)))
 	if vxlan.VtepDevIndex != 0 {
@@ -227,7 +278,7 @@ func addVxlanAttrs(vxlan* Vxlan, linkInfo *nl.RtAttr) {
 		nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, nl.Uint16Attr(uint16(vxlan.Port)))
 	}
 	if vxlan.PortLow > 0 || vxlan.PortHigh > 0 {
-		pr := vxlanPortRange{ uint16(vxlan.PortLow), uint16(vxlan.PortHigh) }
+		pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)}
 
 		buf := new(bytes.Buffer)
 		binary.Write(buf, binary.BigEndian, &pr)
@@ -258,14 +309,37 @@ func LinkAdd(link Link) error {
 		native.PutUint32(b, uint32(base.ParentIndex))
 		data := nl.NewRtAttr(syscall.IFLA_LINK, b)
 		req.AddData(data)
+	} else if link.Type() == "ipvlan" {
+		return fmt.Errorf("Can't create ipvlan link without ParentIndex")
 	}
 
 	nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(base.Name))
 	req.AddData(nameData)
 
+	if base.MTU > 0 {
+		mtu := nl.NewRtAttr(syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
+		req.AddData(mtu)
+	}
+
+	if base.Namespace != nil {
+		var attr *nl.RtAttr
+		switch base.Namespace.(type) {
+		case NsPid:
+			val := nl.Uint32Attr(uint32(base.Namespace.(NsPid)))
+			attr = nl.NewRtAttr(syscall.IFLA_NET_NS_PID, val)
+		case NsFd:
+			val := nl.Uint32Attr(uint32(base.Namespace.(NsFd)))
+			attr = nl.NewRtAttr(nl.IFLA_NET_NS_FD, val)
+		}
+
+		req.AddData(attr)
+	}
+
 	linkInfo := nl.NewRtAttr(syscall.IFLA_LINKINFO, nil)
 	nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type()))
 
+	nl.NewRtAttrChild(linkInfo, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
+
 	if vlan, ok := link.(*Vlan); ok {
 		b := make([]byte, 2)
 		native.PutUint16(b, uint16(vlan.VlanId))
@@ -276,8 +350,20 @@ func LinkAdd(link Link) error {
 		peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil)
 		nl.NewIfInfomsgChild(peer, syscall.AF_UNSPEC)
 		nl.NewRtAttrChild(peer, syscall.IFLA_IFNAME, nl.ZeroTerminated(veth.PeerName))
+		nl.NewRtAttrChild(peer, syscall.IFLA_TXQLEN, nl.Uint32Attr(base.TxQLen))
+		if base.MTU > 0 {
+			nl.NewRtAttrChild(peer, syscall.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU)))
+		}
 	} else if vxlan, ok := link.(*Vxlan); ok {
 		addVxlanAttrs(vxlan, linkInfo)
+	} else if ipv, ok := link.(*IPVlan); ok {
+		data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+		nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(ipv.Mode)))
+	} else if macv, ok := link.(*Macvlan); ok {
+		if macv.Mode != MACVLAN_MODE_DEFAULT {
+			data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil)
+			nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[macv.Mode]))
+		}
 	}
 
 	req.AddData(linkInfo)
@@ -297,7 +383,7 @@ func LinkAdd(link Link) error {
 	return nil
 }
 
-// LinkAdd adds a new link device. Either Index or Name must be set in
+// 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 LinkDel(link Link) error {
@@ -423,6 +509,10 @@ func linkDeserialize(m []byte) (Link, error) {
 						link = &Veth{}
 					case "vxlan":
 						link = &Vxlan{}
+					case "ipvlan":
+						link = &IPVlan{}
+					case "macvlan":
+						link = &Macvlan{}
 					default:
 						link = &Generic{LinkType: linkType}
 					}
@@ -436,6 +526,10 @@ func linkDeserialize(m []byte) (Link, error) {
 						parseVlanData(link, data)
 					case "vxlan":
 						parseVxlanData(link, data)
+					case "ipvlan":
+						parseIPVlanData(link, data)
+					case "macvlan":
+						parseMacvlanData(link, data)
 					}
 				}
 			}
@@ -457,6 +551,8 @@ func linkDeserialize(m []byte) (Link, error) {
 			base.ParentIndex = int(native.Uint32(attr.Value[0:4]))
 		case syscall.IFLA_MASTER:
 			base.MasterIndex = int(native.Uint32(attr.Value[0:4]))
+		case syscall.IFLA_TXQLEN:
+			base.TxQLen = native.Uint32(attr.Value[0:4])
 		}
 	}
 	// Links that don't have IFLA_INFO_KIND are hardware devices
@@ -496,6 +592,52 @@ func LinkList() ([]Link, error) {
 	return res, nil
 }
 
+func LinkSetHairpin(link Link, mode bool) error {
+	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_MODE)
+}
+
+func LinkSetGuard(link Link, mode bool) error {
+	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_GUARD)
+}
+
+func LinkSetFastLeave(link Link, mode bool) error {
+	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_FAST_LEAVE)
+}
+
+func LinkSetLearning(link Link, mode bool) error {
+	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
+}
+
+func LinkSetRootBlock(link Link, mode bool) error {
+	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_PROTECT)
+}
+
+func LinkSetFlood(link Link, mode bool) error {
+	return setProtinfoAttr(link, mode, nl.IFLA_BRPORT_UNICAST_FLOOD)
+}
+
+func setProtinfoAttr(link Link, mode bool, attr int) error {
+	base := link.Attrs()
+	ensureIndex(base)
+	req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
+
+	msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
+	msg.Type = syscall.RTM_SETLINK
+	msg.Flags = syscall.NLM_F_REQUEST
+	msg.Index = int32(base.Index)
+	msg.Change = syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED
+	req.AddData(msg)
+
+	br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
+	nl.NewRtAttrChild(br, attr, boolToByte(mode))
+	req.AddData(br)
+	_, err := req.Execute(syscall.NETLINK_ROUTE, 0)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
 	vlan := link.(*Vlan)
 	for _, datum := range data {
@@ -554,6 +696,37 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
 	}
 }
 
+func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) {
+	ipv := link.(*IPVlan)
+	for _, datum := range data {
+		if datum.Attr.Type == nl.IFLA_IPVLAN_MODE {
+			ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4]))
+			return
+		}
+	}
+}
+
+func parseMacvlanData(link Link, data []syscall.NetlinkRouteAttr) {
+	macv := link.(*Macvlan)
+	for _, datum := range data {
+		if datum.Attr.Type == nl.IFLA_MACVLAN_MODE {
+			switch native.Uint32(datum.Value[0:4]) {
+			case nl.MACVLAN_MODE_PRIVATE:
+				macv.Mode = MACVLAN_MODE_PRIVATE
+			case nl.MACVLAN_MODE_VEPA:
+				macv.Mode = MACVLAN_MODE_VEPA
+			case nl.MACVLAN_MODE_BRIDGE:
+				macv.Mode = MACVLAN_MODE_BRIDGE
+			case nl.MACVLAN_MODE_PASSTHRU:
+				macv.Mode = MACVLAN_MODE_PASSTHRU
+			case nl.MACVLAN_MODE_SOURCE:
+				macv.Mode = MACVLAN_MODE_SOURCE
+			}
+			return
+		}
+	}
+}
+
 // copied from pkg/net_linux.go
 func linkFlags(rawFlags uint32) net.Flags {
 	var f net.Flags

+ 177 - 23
Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go

@@ -1,10 +1,15 @@
 package netlink
 
 import (
-	"github.com/vishvananda/netns"
+	"bytes"
+	"net"
 	"testing"
+
+	"github.com/vishvananda/netns"
 )
 
+const testTxQLen uint32 = 100
+
 func testLinkAddDel(t *testing.T, link Link) {
 	links, err := LinkList()
 	if err != nil {
@@ -46,13 +51,24 @@ func testLinkAddDel(t *testing.T, link Link) {
 	}
 
 	if veth, ok := link.(*Veth); ok {
+		if veth.TxQLen != testTxQLen {
+			t.Fatalf("TxQLen is %d, should be %d", veth.TxQLen, testTxQLen)
+		}
+		if rBase.MTU != base.MTU {
+			t.Fatalf("MTU is %d, should be %d", rBase.MTU, base.MTU)
+		}
+
 		if veth.PeerName != "" {
+			var peer *Veth
 			other, err := LinkByName(veth.PeerName)
 			if err != nil {
-				t.Fatal("Peer %s not created", veth.PeerName)
+				t.Fatalf("Peer %s not created", veth.PeerName)
+			}
+			if peer, ok = other.(*Veth); !ok {
+				t.Fatalf("Peer %s is incorrect type", veth.PeerName)
 			}
-			if _, ok = other.(*Veth); !ok {
-				t.Fatal("Peer %s is incorrect type", veth.PeerName)
+			if peer.TxQLen != testTxQLen {
+				t.Fatalf("TxQLen of peer is %d, should be %d", peer.TxQLen, testTxQLen)
 			}
 		}
 	}
@@ -65,6 +81,26 @@ func testLinkAddDel(t *testing.T, link Link) {
 		compareVxlan(t, vxlan, other)
 	}
 
+	if ipv, ok := link.(*IPVlan); ok {
+		other, ok := result.(*IPVlan)
+		if !ok {
+			t.Fatal("Result of create is not a ipvlan")
+		}
+		if ipv.Mode != other.Mode {
+			t.Fatalf("Got unexpected mode: %d, expected: %d", other.Mode, ipv.Mode)
+		}
+	}
+
+	if macv, ok := link.(*Macvlan); ok {
+		other, ok := result.(*Macvlan)
+		if !ok {
+			t.Fatal("Result of create is not a macvlan")
+		}
+		if macv.Mode != other.Mode {
+			t.Fatalf("Got unexpected mode: %d, expected: %d", other.Mode, macv.Mode)
+		}
+	}
+
 	if err = LinkDel(link); err != nil {
 		t.Fatal(err)
 	}
@@ -82,54 +118,54 @@ func testLinkAddDel(t *testing.T, link Link) {
 func compareVxlan(t *testing.T, expected, actual *Vxlan) {
 
 	if actual.VxlanId != expected.VxlanId {
-		t.Fatalf("Vxlan.VxlanId doesn't match")
+		t.Fatal("Vxlan.VxlanId doesn't match")
 	}
 	if expected.SrcAddr != nil && !actual.SrcAddr.Equal(expected.SrcAddr) {
-		t.Fatalf("Vxlan.SrcAddr doesn't match")
+		t.Fatal("Vxlan.SrcAddr doesn't match")
 	}
 	if expected.Group != nil && !actual.Group.Equal(expected.Group) {
-		t.Fatalf("Vxlan.Group doesn't match")
+		t.Fatal("Vxlan.Group doesn't match")
 	}
 	if expected.TTL != -1 && actual.TTL != expected.TTL {
-		t.Fatalf("Vxlan.TTL doesn't match")
+		t.Fatal("Vxlan.TTL doesn't match")
 	}
 	if expected.TOS != -1 && actual.TOS != expected.TOS {
-		t.Fatalf("Vxlan.TOS doesn't match")
+		t.Fatal("Vxlan.TOS doesn't match")
 	}
 	if actual.Learning != expected.Learning {
-		t.Fatalf("Vxlan.Learning doesn't match")
+		t.Fatal("Vxlan.Learning doesn't match")
 	}
 	if actual.Proxy != expected.Proxy {
-		t.Fatalf("Vxlan.Proxy doesn't match")
+		t.Fatal("Vxlan.Proxy doesn't match")
 	}
 	if actual.RSC != expected.RSC {
-		t.Fatalf("Vxlan.RSC doesn't match", actual, expected)
+		t.Fatal("Vxlan.RSC doesn't match")
 	}
 	if actual.L2miss != expected.L2miss {
-		t.Fatalf("Vxlan.L2miss doesn't match")
+		t.Fatal("Vxlan.L2miss doesn't match")
 	}
 	if actual.L3miss != expected.L3miss {
-		t.Fatalf("Vxlan.L3miss doesn't match")
+		t.Fatal("Vxlan.L3miss doesn't match")
 	}
 	if expected.NoAge {
 		if !actual.NoAge {
-			t.Fatalf("Vxlan.NoAge doesn't match")
+			t.Fatal("Vxlan.NoAge doesn't match")
 		}
 	} else if expected.Age > 0 && actual.Age != expected.Age {
-		t.Fatalf("Vxlan.Age doesn't match")
+		t.Fatal("Vxlan.Age doesn't match")
 	}
 	if expected.Limit > 0 && actual.Limit != expected.Limit {
-		t.Fatalf("Vxlan.Limit doesn't match")
+		t.Fatal("Vxlan.Limit doesn't match")
 	}
 	if expected.Port > 0 && actual.Port != expected.Port {
-		t.Fatalf("Vxlan.Port doesn't match")
+		t.Fatal("Vxlan.Port doesn't match")
 	}
 	if expected.PortLow > 0 || expected.PortHigh > 0 {
 		if actual.PortLow != expected.PortLow {
-			t.Fatalf("Vxlan.PortLow doesn't match")
+			t.Fatal("Vxlan.PortLow doesn't match")
 		}
 		if actual.PortHigh != expected.PortHigh {
-			t.Fatalf("Vxlan.PortHigh doesn't match")
+			t.Fatal("Vxlan.PortHigh doesn't match")
 		}
 	}
 }
@@ -145,7 +181,7 @@ func TestLinkAddDelBridge(t *testing.T) {
 	tearDown := setUpNetlinkTest(t)
 	defer tearDown()
 
-	testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo"}})
+	testLinkAddDel(t, &Bridge{LinkAttrs{Name: "foo", MTU: 1400}})
 }
 
 func TestLinkAddDelVlan(t *testing.T) {
@@ -173,7 +209,10 @@ func TestLinkAddDelMacvlan(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	testLinkAddDel(t, &Macvlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}})
+	testLinkAddDel(t, &Macvlan{
+		LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
+		Mode:      MACVLAN_MODE_PRIVATE,
+	})
 
 	if err := LinkDel(parent); err != nil {
 		t.Fatal(err)
@@ -184,7 +223,7 @@ func TestLinkAddDelVeth(t *testing.T) {
 	tearDown := setUpNetlinkTest(t)
 	defer tearDown()
 
-	testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo"}, "bar"})
+	testLinkAddDel(t, &Veth{LinkAttrs{Name: "foo", TxQLen: testTxQLen, MTU: 1400}, "bar"})
 }
 
 func TestLinkAddDelBridgeMaster(t *testing.T) {
@@ -362,6 +401,63 @@ func TestLinkAddDelVxlan(t *testing.T) {
 	}
 }
 
+func TestLinkAddDelIPVlanL2(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+	parent := &Dummy{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(parent); err != nil {
+		t.Fatal(err)
+	}
+
+	ipv := IPVlan{
+		LinkAttrs: LinkAttrs{
+			Name:        "bar",
+			ParentIndex: parent.Index,
+		},
+		Mode: IPVLAN_MODE_L2,
+	}
+
+	testLinkAddDel(t, &ipv)
+}
+
+func TestLinkAddDelIPVlanL3(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+	parent := &Dummy{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(parent); err != nil {
+		t.Fatal(err)
+	}
+
+	ipv := IPVlan{
+		LinkAttrs: LinkAttrs{
+			Name:        "bar",
+			ParentIndex: parent.Index,
+		},
+		Mode: IPVLAN_MODE_L3,
+	}
+
+	testLinkAddDel(t, &ipv)
+}
+
+func TestLinkAddDelIPVlanNoParent(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	ipv := IPVlan{
+		LinkAttrs: LinkAttrs{
+			Name: "bar",
+		},
+		Mode: IPVLAN_MODE_L3,
+	}
+	err := LinkAdd(&ipv)
+	if err == nil {
+		t.Fatal("Add should fail if ipvlan creating without ParentIndex")
+	}
+	if err.Error() != "Can't create ipvlan link without ParentIndex" {
+		t.Fatalf("Error should be about missing ParentIndex, got %q", err)
+	}
+}
+
 func TestLinkByIndex(t *testing.T) {
 	tearDown := setUpNetlinkTest(t)
 	defer tearDown()
@@ -388,3 +484,61 @@ func TestLinkByIndex(t *testing.T) {
 		t.Fatalf("LinkByIndex(%v) found deleted link", err)
 	}
 }
+
+func TestLinkSet(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	iface := &Dummy{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(iface); err != nil {
+		t.Fatal(err)
+	}
+
+	link, err := LinkByName("foo")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = LinkSetName(link, "bar")
+	if err != nil {
+		t.Fatalf("Could not change interface name: %v", err)
+	}
+
+	link, err = LinkByName("bar")
+	if err != nil {
+		t.Fatalf("Interface name not changed: %v", err)
+	}
+
+	err = LinkSetMTU(link, 1400)
+	if err != nil {
+		t.Fatalf("Could not set MTU: %v", err)
+	}
+
+	link, err = LinkByName("bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if link.Attrs().MTU != 1400 {
+		t.Fatal("MTU not changed!")
+	}
+
+	addr, err := net.ParseMAC("00:12:34:56:78:AB")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = LinkSetHardwareAddr(link, addr)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	link, err = LinkByName("bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !bytes.Equal(link.Attrs().HardwareAddr, addr) {
+		t.Fatalf("hardware address not changed!")
+	}
+}

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

@@ -9,16 +9,16 @@ import (
 )
 
 const (
-	NDA_UNSPEC    = iota
-	NDA_DST       = iota
-	NDA_LLADDR    = iota
-	NDA_CACHEINFO = iota
-	NDA_PROBES    = iota
-	NDA_VLAN      = iota
-	NDA_PORT      = iota
-	NDA_VNI       = iota
-	NDA_IFINDEX   = iota
-	NDA_MAX       = NDA_IFINDEX
+	NDA_UNSPEC = iota
+	NDA_DST
+	NDA_LLADDR
+	NDA_CACHEINFO
+	NDA_PROBES
+	NDA_VLAN
+	NDA_PORT
+	NDA_VNI
+	NDA_IFINDEX
+	NDA_MAX = NDA_IFINDEX
 )
 
 // Neighbor Cache Entry States.

+ 12 - 13
Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go

@@ -72,8 +72,6 @@ func TestNeighAddDel(t *testing.T) {
 		}
 	}
 
-	return
-
 	// Delete the arpTable
 	for _, entry := range arpTable {
 		err := NeighDel(&Neigh{
@@ -87,17 +85,18 @@ func TestNeighAddDel(t *testing.T) {
 		}
 	}
 
-	// Dump and see that none of deleted entries are there
-	dump, err = NeighList(dummy.Index, 0)
-	if err != nil {
-		t.Errorf("Failed to NeighList: %v", err)
-	}
-
-	for _, entry := range arpTable {
-		if dumpContains(dump, entry) {
-			t.Errorf("Dump contains: %v", entry)
-		}
-	}
+	// TODO: seems not working because of cache
+	//// Dump and see that none of deleted entries are there
+	//dump, err = NeighList(dummy.Index, 0)
+	//if err != nil {
+	//t.Errorf("Failed to NeighList: %v", err)
+	//}
+
+	//for _, entry := range arpTable {
+	//if dumpContains(dump, entry) {
+	//t.Errorf("Dump contains: %v", entry)
+	//}
+	//}
 
 	if err := LinkDel(&dummy); err != nil {
 		t.Fatal(err)

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

@@ -30,10 +30,10 @@ func ParseIPNet(s string) (*net.IPNet, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &net.IPNet{ip, ipNet.Mask}, nil
+	return &net.IPNet{IP: ip, Mask: ipNet.Mask}, nil
 }
 
 // NewIPNet generates an IPNet from an ip address using a netmask of 32.
 func NewIPNet(ip net.IP) *net.IPNet {
-	return &net.IPNet{ip, net.CIDRMask(32, 32)}
+	return &net.IPNet{IP: ip, Mask: net.CIDRMask(32, 32)}
 }

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

@@ -1,11 +1,12 @@
 package netlink
 
 import (
-	"github.com/vishvananda/netns"
 	"log"
 	"os"
 	"runtime"
 	"testing"
+
+	"github.com/vishvananda/netns"
 )
 
 type tearDownNetlinkTest func()

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

@@ -42,6 +42,30 @@ func LinkDel(link *Link) error {
 	return ErrNotImplemented
 }
 
+func SetHairpin(link Link, mode bool) error {
+	return ErrNotImplemented
+}
+
+func SetGuard(link Link, mode bool) error {
+	return ErrNotImplemented
+}
+
+func SetFastLeave(link Link, mode bool) error {
+	return ErrNotImplemented
+}
+
+func SetLearning(link Link, mode bool) error {
+	return ErrNotImplemented
+}
+
+func SetRootBlock(link Link, mode bool) error {
+	return ErrNotImplemented
+}
+
+func SetFlood(link Link, mode bool) error {
+	return ErrNotImplemented
+}
+
 func LinkList() ([]Link, error) {
 	return nil, ErrNotImplemented
 }

+ 72 - 32
Godeps/_workspace/src/github.com/vishvananda/netlink/nl/link_linux.go

@@ -6,51 +6,91 @@ const (
 
 const (
 	IFLA_INFO_UNSPEC = iota
-	IFLA_INFO_KIND   = iota
-	IFLA_INFO_DATA   = iota
-	IFLA_INFO_XSTATS = iota
-	IFLA_INFO_MAX    = IFLA_INFO_XSTATS
+	IFLA_INFO_KIND
+	IFLA_INFO_DATA
+	IFLA_INFO_XSTATS
+	IFLA_INFO_MAX = IFLA_INFO_XSTATS
 )
 
 const (
-	IFLA_VLAN_UNSPEC      = iota
-	IFLA_VLAN_ID          = iota
-	IFLA_VLAN_FLAGS       = iota
-	IFLA_VLAN_EGRESS_QOS  = iota
-	IFLA_VLAN_INGRESS_QOS = iota
-	IFLA_VLAN_PROTOCOL    = iota
-	IFLA_VLAN_MAX         = IFLA_VLAN_PROTOCOL
+	IFLA_VLAN_UNSPEC = iota
+	IFLA_VLAN_ID
+	IFLA_VLAN_FLAGS
+	IFLA_VLAN_EGRESS_QOS
+	IFLA_VLAN_INGRESS_QOS
+	IFLA_VLAN_PROTOCOL
+	IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL
 )
 
 const (
 	VETH_INFO_UNSPEC = iota
-	VETH_INFO_PEER   = iota
-	VETH_INFO_MAX    = VETH_INFO_PEER
+	VETH_INFO_PEER
+	VETH_INFO_MAX = VETH_INFO_PEER
 )
 
 const (
-	IFLA_VXLAN_UNSPEC     = iota
-	IFLA_VXLAN_ID         = iota
-	IFLA_VXLAN_GROUP      = iota
-	IFLA_VXLAN_LINK       = iota
-	IFLA_VXLAN_LOCAL      = iota
-	IFLA_VXLAN_TTL        = iota
-	IFLA_VXLAN_TOS        = iota
-	IFLA_VXLAN_LEARNING   = iota
-	IFLA_VXLAN_AGEING     = iota
-	IFLA_VXLAN_LIMIT      = iota
-	IFLA_VXLAN_PORT_RANGE = iota
-	IFLA_VXLAN_PROXY      = iota
-	IFLA_VXLAN_RSC        = iota
-	IFLA_VXLAN_L2MISS     = iota
-	IFLA_VXLAN_L3MISS     = iota
-	IFLA_VXLAN_PORT       = iota
-	IFLA_VXLAN_GROUP6     = iota
-	IFLA_VXLAN_LOCAL6     = iota
-	IFLA_VXLAN_MAX        = IFLA_VXLAN_LOCAL6
+	IFLA_VXLAN_UNSPEC = iota
+	IFLA_VXLAN_ID
+	IFLA_VXLAN_GROUP
+	IFLA_VXLAN_LINK
+	IFLA_VXLAN_LOCAL
+	IFLA_VXLAN_TTL
+	IFLA_VXLAN_TOS
+	IFLA_VXLAN_LEARNING
+	IFLA_VXLAN_AGEING
+	IFLA_VXLAN_LIMIT
+	IFLA_VXLAN_PORT_RANGE
+	IFLA_VXLAN_PROXY
+	IFLA_VXLAN_RSC
+	IFLA_VXLAN_L2MISS
+	IFLA_VXLAN_L3MISS
+	IFLA_VXLAN_PORT
+	IFLA_VXLAN_GROUP6
+	IFLA_VXLAN_LOCAL6
+	IFLA_VXLAN_MAX = IFLA_VXLAN_LOCAL6
+)
+
+const (
+	BRIDGE_MODE_UNSPEC = iota
+	BRIDGE_MODE_HAIRPIN
+)
+
+const (
+	IFLA_BRPORT_UNSPEC = iota
+	IFLA_BRPORT_STATE
+	IFLA_BRPORT_PRIORITY
+	IFLA_BRPORT_COST
+	IFLA_BRPORT_MODE
+	IFLA_BRPORT_GUARD
+	IFLA_BRPORT_PROTECT
+	IFLA_BRPORT_FAST_LEAVE
+	IFLA_BRPORT_LEARNING
+	IFLA_BRPORT_UNICAST_FLOOD
+	IFLA_BRPORT_MAX = IFLA_BRPORT_UNICAST_FLOOD
+)
+
+const (
+	IFLA_IPVLAN_UNSPEC = iota
+	IFLA_IPVLAN_MODE
+	IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE
 )
 
 const (
 	// not defined in syscall
 	IFLA_NET_NS_FD = 28
 )
+
+const (
+	IFLA_MACVLAN_UNSPEC = iota
+	IFLA_MACVLAN_MODE
+	IFLA_MACVLAN_FLAGS
+	IFLA_MACVLAN_MAX = IFLA_MACVLAN_FLAGS
+)
+
+const (
+	MACVLAN_MODE_PRIVATE  = 1
+	MACVLAN_MODE_VEPA     = 2
+	MACVLAN_MODE_BRIDGE   = 4
+	MACVLAN_MODE_PASSTHRU = 8
+	MACVLAN_MODE_SOURCE   = 16
+)

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

@@ -222,7 +222,7 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro
 
 done:
 	for {
-		msgs, err := s.Recieve()
+		msgs, err := s.Receive()
 		if err != nil {
 			return nil, err
 		}
@@ -248,6 +248,9 @@ done:
 				continue
 			}
 			res = append(res, m.Data)
+			if m.Header.Flags&syscall.NLM_F_MULTI == 0 {
+				break done
+			}
 		}
 	}
 	return res, nil
@@ -291,7 +294,7 @@ func getNetlinkSocket(protocol int) (*NetlinkSocket, error) {
 
 // Create a netlink socket with a given protocol (e.g. NETLINK_ROUTE)
 // and subscribe it to multicast groups passed in variable argument list.
-// Returns the netlink socket on whic hReceive() method can be called
+// Returns the netlink socket on which Receive() method can be called
 // to retrieve the messages from the kernel.
 func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
 	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, protocol)
@@ -326,7 +329,7 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error {
 	return nil
 }
 
-func (s *NetlinkSocket) Recieve() ([]syscall.NetlinkMessage, error) {
+func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) {
 	rb := make([]byte, syscall.Getpagesize())
 	nr, _, err := syscall.Recvfrom(s.fd, rb, 0)
 	if err != nil {

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

@@ -103,9 +103,9 @@ func (x *XfrmAddress) ToIP() net.IP {
 func (x *XfrmAddress) ToIPNet(prefixlen uint8) *net.IPNet {
 	ip := x.ToIP()
 	if GetIPFamily(ip) == FAMILY_V4 {
-		return &net.IPNet{ip, net.CIDRMask(int(prefixlen), 32)}
+		return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 32)}
 	} else {
-		return &net.IPNet{ip, net.CIDRMask(int(prefixlen), 128)}
+		return &net.IPNet{IP: ip, Mask: net.CIDRMask(int(prefixlen), 128)}
 	}
 }
 

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

@@ -0,0 +1,53 @@
+package netlink
+
+import (
+	"strings"
+)
+
+// Protinfo represents bridge flags from netlink.
+type Protinfo struct {
+	Hairpin   bool
+	Guard     bool
+	FastLeave bool
+	RootBlock bool
+	Learning  bool
+	Flood     bool
+}
+
+// String returns a list of enabled flags
+func (prot *Protinfo) String() string {
+	boolStrings := make([]string, 0)
+	if prot.Hairpin {
+		boolStrings = append(boolStrings, "Hairpin")
+	}
+	if prot.Guard {
+		boolStrings = append(boolStrings, "Guard")
+	}
+	if prot.FastLeave {
+		boolStrings = append(boolStrings, "FastLeave")
+	}
+	if prot.RootBlock {
+		boolStrings = append(boolStrings, "RootBlock")
+	}
+	if prot.Learning {
+		boolStrings = append(boolStrings, "Learning")
+	}
+	if prot.Flood {
+		boolStrings = append(boolStrings, "Flood")
+	}
+	return strings.Join(boolStrings, " ")
+}
+
+func boolToByte(x bool) []byte {
+	if x {
+		return []byte{1}
+	}
+	return []byte{0}
+}
+
+func byteToBool(x byte) bool {
+	if uint8(x) != 0 {
+		return true
+	}
+	return false
+}

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

@@ -0,0 +1,60 @@
+package netlink
+
+import (
+	"fmt"
+	"syscall"
+
+	"github.com/coreos/flannel/Godeps/_workspace/src/github.com/vishvananda/netlink/nl"
+)
+
+func LinkGetProtinfo(link Link) (Protinfo, error) {
+	base := link.Attrs()
+	ensureIndex(base)
+	var pi Protinfo
+	req := nl.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)
+	if err != nil {
+		return pi, err
+	}
+
+	for _, m := range msgs {
+		ans := nl.DeserializeIfInfomsg(m)
+		if int(ans.Index) != base.Index {
+			continue
+		}
+		attrs, err := nl.ParseRouteAttr(m[ans.Len():])
+		if err != nil {
+			return pi, err
+		}
+		for _, attr := range attrs {
+			if attr.Attr.Type != syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED {
+				continue
+			}
+			infos, err := nl.ParseRouteAttr(attr.Value)
+			if err != nil {
+				return pi, err
+			}
+			var pi Protinfo
+			for _, info := range infos {
+				switch info.Attr.Type {
+				case nl.IFLA_BRPORT_MODE:
+					pi.Hairpin = byteToBool(info.Value[0])
+				case nl.IFLA_BRPORT_GUARD:
+					pi.Guard = byteToBool(info.Value[0])
+				case nl.IFLA_BRPORT_FAST_LEAVE:
+					pi.FastLeave = byteToBool(info.Value[0])
+				case nl.IFLA_BRPORT_PROTECT:
+					pi.RootBlock = byteToBool(info.Value[0])
+				case nl.IFLA_BRPORT_LEARNING:
+					pi.Learning = byteToBool(info.Value[0])
+				case nl.IFLA_BRPORT_UNICAST_FLOOD:
+					pi.Flood = byteToBool(info.Value[0])
+				}
+			}
+			return pi, nil
+		}
+	}
+	return pi, fmt.Errorf("Device with index %d not found", base.Index)
+}

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

@@ -0,0 +1,98 @@
+package netlink
+
+import "testing"
+
+func TestProtinfo(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+	master := &Bridge{LinkAttrs{Name: "foo"}}
+	if err := LinkAdd(master); err != nil {
+		t.Fatal(err)
+	}
+	iface1 := &Dummy{LinkAttrs{Name: "bar1", MasterIndex: master.Index}}
+	iface2 := &Dummy{LinkAttrs{Name: "bar2", MasterIndex: master.Index}}
+	iface3 := &Dummy{LinkAttrs{Name: "bar3"}}
+
+	if err := LinkAdd(iface1); err != nil {
+		t.Fatal(err)
+	}
+	if err := LinkAdd(iface2); err != nil {
+		t.Fatal(err)
+	}
+	if err := LinkAdd(iface3); err != nil {
+		t.Fatal(err)
+	}
+
+	oldpi1, err := LinkGetProtinfo(iface1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	oldpi2, err := LinkGetProtinfo(iface2)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := LinkSetHairpin(iface1, true); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := LinkSetRootBlock(iface1, true); err != nil {
+		t.Fatal(err)
+	}
+
+	pi1, err := LinkGetProtinfo(iface1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !pi1.Hairpin {
+		t.Fatalf("Hairpin mode is not enabled for %s, but should", iface1.Name)
+	}
+	if !pi1.RootBlock {
+		t.Fatalf("RootBlock is not enabled for %s, but should", iface1.Name)
+	}
+	if pi1.Guard != oldpi1.Guard {
+		t.Fatalf("Guard field was changed for %s but shouldn't", iface1.Name)
+	}
+	if pi1.FastLeave != oldpi1.FastLeave {
+		t.Fatalf("FastLeave field was changed for %s but shouldn't", iface1.Name)
+	}
+	if pi1.Learning != oldpi1.Learning {
+		t.Fatalf("Learning field was changed for %s but shouldn't", iface1.Name)
+	}
+	if pi1.Flood != oldpi1.Flood {
+		t.Fatalf("Flood field was changed for %s but shouldn't", iface1.Name)
+	}
+
+	if err := LinkSetGuard(iface2, true); err != nil {
+		t.Fatal(err)
+	}
+	if err := LinkSetLearning(iface2, false); err != nil {
+		t.Fatal(err)
+	}
+	pi2, err := LinkGetProtinfo(iface2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if pi2.Hairpin {
+		t.Fatalf("Hairpin mode is enabled for %s, but shouldn't", iface2.Name)
+	}
+	if !pi2.Guard {
+		t.Fatalf("Guard is not enabled for %s, but should", iface2.Name)
+	}
+	if pi2.Learning {
+		t.Fatalf("Learning is enabled for %s, but shouldn't", iface2.Name)
+	}
+	if pi2.RootBlock != oldpi2.RootBlock {
+		t.Fatalf("RootBlock field was changed for %s but shouldn't", iface2.Name)
+	}
+	if pi2.FastLeave != oldpi2.FastLeave {
+		t.Fatalf("FastLeave field was changed for %s but shouldn't", iface2.Name)
+	}
+	if pi2.Flood != oldpi2.Flood {
+		t.Fatalf("Flood field was changed for %s but shouldn't", iface2.Name)
+	}
+
+	if err := LinkSetHairpin(iface3, true); err == nil || err.Error() != "operation not supported" {
+		t.Fatalf("Set protinfo attrs for link without master is not supported, but err: %s", err)
+	}
+}

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

@@ -30,6 +30,6 @@ type Route struct {
 }
 
 func (r Route) String() string {
-	return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s}", r.LinkIndex, r.Dst.String(),
+	return fmt.Sprintf("{Ifindex: %d Dst: %s Src: %s Gw: %s}", r.LinkIndex, r.Dst,
 		r.Src, r.Gw)
 }

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

@@ -25,7 +25,7 @@ func RouteDel(route *Route) error {
 }
 
 func routeHandle(route *Route, req *nl.NetlinkRequest) error {
-	if route.Dst.IP == nil && route.Src == nil && route.Gw == nil {
+	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")
 	}
 
@@ -34,7 +34,7 @@ func routeHandle(route *Route, req *nl.NetlinkRequest) error {
 	family := -1
 	var rtAttrs []*nl.RtAttr
 
-	if route.Dst.IP != nil {
+	if route.Dst != nil && route.Dst.IP != nil {
 		dstLen, _ := route.Dst.Mask.Size()
 		msg.Dst_len = uint8(dstLen)
 		dstFamily := nl.GetIPFamily(route.Dst.IP)
@@ -164,3 +164,62 @@ func RouteList(link Link, family int) ([]Route, error) {
 
 	return res, nil
 }
+
+// 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)
+	family := nl.GetIPFamily(destination)
+	var destinationData []byte
+	var bitlen uint8
+	if family == FAMILY_V4 {
+		destinationData = destination.To4()
+		bitlen = 32
+	} else {
+		destinationData = destination.To16()
+		bitlen = 128
+	}
+	msg := &nl.RtMsg{}
+	msg.Family = uint8(family)
+	msg.Dst_len = bitlen
+	req.AddData(msg)
+
+	rtaDst := nl.NewRtAttr(syscall.RTA_DST, destinationData)
+	req.AddData(rtaDst)
+
+	msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWROUTE)
+	if err != nil {
+		return nil, err
+	}
+
+	native := nl.NativeEndian()
+	res := make([]Route, 0)
+	for _, m := range msgs {
+		msg := nl.DeserializeRtMsg(m)
+		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
+		if err != nil {
+			return nil, err
+		}
+
+		route := Route{}
+		for _, attr := range attrs {
+			switch attr.Attr.Type {
+			case syscall.RTA_GATEWAY:
+				route.Gw = net.IP(attr.Value)
+			case syscall.RTA_PREFSRC:
+				route.Src = net.IP(attr.Value)
+			case syscall.RTA_DST:
+				route.Dst = &net.IPNet{
+					IP:   attr.Value,
+					Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)),
+				}
+			case syscall.RTA_OIF:
+				routeIndex := int(native.Uint32(attr.Value[0:4]))
+				route.LinkIndex = routeIndex
+			}
+		}
+		res = append(res, route)
+	}
+	return res, nil
+
+}

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

@@ -34,7 +34,17 @@ func TestRouteAddDel(t *testing.T) {
 		t.Fatal(err)
 	}
 	if len(routes) != 1 {
-		t.Fatal("Link not removed properly")
+		t.Fatal("Link not added properly")
+	}
+
+	dstIP := net.ParseIP("192.168.0.42")
+	routeToDstIP, err := RouteGet(dstIP)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if len(routeToDstIP) == 0 {
+		t.Fatal("Default route not present")
 	}
 
 	err = RouteDel(&route)
@@ -51,3 +61,24 @@ func TestRouteAddDel(t *testing.T) {
 	}
 
 }
+
+func TestRouteAddIncomplete(t *testing.T) {
+	tearDown := setUpNetlinkTest(t)
+	defer tearDown()
+
+	// get loopback interface
+	link, err := LinkByName("lo")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// bring the interface up
+	if err = LinkSetUp(link); err != nil {
+		t.Fatal(err)
+	}
+
+	route := Route{LinkIndex: link.Attrs().Index}
+	if err := RouteAdd(&route); err == nil {
+		t.Fatal("Adding incomplete route should fail")
+	}
+}

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

@@ -39,12 +39,12 @@ func (p Proto) String() string {
 type Mode uint8
 
 const (
-	XFRM_MODE_TRANSPORT         Mode = iota
-	XFRM_MODE_TUNNEL            Mode = iota
-	XFRM_MODE_ROUTEOPTIMIZATION Mode = iota
-	XFRM_MODE_IN_TRIGGER        Mode = iota
-	XFRM_MODE_BEET              Mode = iota
-	XFRM_MODE_MAX               Mode = iota
+	XFRM_MODE_TRANSPORT Mode = iota
+	XFRM_MODE_TUNNEL
+	XFRM_MODE_ROUTEOPTIMIZATION
+	XFRM_MODE_IN_TRIGGER
+	XFRM_MODE_BEET
+	XFRM_MODE_MAX
 )
 
 func (m Mode) String() string {

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

@@ -9,12 +9,12 @@ import (
 type Dir uint8
 
 const (
-	XFRM_DIR_IN     Dir = iota
-	XFRM_DIR_OUT    Dir = iota
-	XFRM_DIR_FWD    Dir = iota
-	XFRM_SOCKET_IN  Dir = iota
-	XFRM_SOCKET_OUT Dir = iota
-	XFRM_SOCKET_FWD Dir = iota
+	XFRM_DIR_IN Dir = iota
+	XFRM_DIR_OUT
+	XFRM_DIR_FWD
+	XFRM_SOCKET_IN
+	XFRM_SOCKET_OUT
+	XFRM_SOCKET_FWD
 )
 
 func (d Dir) String() string {

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

@@ -15,9 +15,8 @@ type XfrmStateAlgo struct {
 type EncapType uint8
 
 const (
-	_                                    = iota
-	XFRM_ENCAP_ESPINUDP_NONIKE EncapType = iota
-	XFRM_ENCAP_ESPINUDP        EncapType = iota
+	XFRM_ENCAP_ESPINUDP_NONIKE EncapType = iota + 1
+	XFRM_ENCAP_ESPINUDP
 )
 
 func (e EncapType) String() string {

+ 1 - 1
backend/vxlan/device.go

@@ -161,7 +161,7 @@ func (dev *vxlanDevice) MonitorMisses(misses chan *netlink.Neigh) {
 	}
 
 	for {
-		msgs, err := nlsock.Recieve()
+		msgs, err := nlsock.Receive()
 		if err != nil {
 			log.Errorf("Failed to receive from netlink: %v ", err)