From a2dddf030d78d189e1570bc83a3b45609cde2ba7 Mon Sep 17 00:00:00 2001 From: Eugene Yakubovich Date: Tue, 28 Oct 2014 14:37:55 -0700 Subject: [PATCH] Fallback to dumping ifaces when name lookup fails Older kernels don't support looking up interface by name (via netlink). In these cases, fallback to dumping all interfaces. This patch just pulls in latest netlink library. Fixes #66 --- Godeps/Godeps.json | 2 +- .../github.com/vishvananda/netlink/README.md | 6 ++-- .../vishvananda/netlink/link_linux.go | 33 +++++++++++++++++-- .../vishvananda/netlink/link_test.go | 5 ++- .../vishvananda/netlink/neigh_test.go | 15 +++++---- .../vishvananda/netlink/nl/addr_linux.go | 1 - .../vishvananda/netlink/nl/nl_linux.go | 4 +-- .../vishvananda/netlink/nl/route_linux.go | 1 - .../netlink/nl/xfrm_policy_linux.go | 1 - .../netlink/nl/xfrm_state_linux.go | 1 - 10 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index d3f8278d05..aecd1a0091 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -21,7 +21,7 @@ }, { "ImportPath": "github.com/vishvananda/netlink", - "Rev": "dd2d5f17ae986599e165402a77c7e85fea606bec" + "Rev": "2187ba67a244c1c32f53bf88876e766bbbbcd5e6" } ] } diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md b/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md index bc74032281..2f4c0727ac 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/README.md @@ -1,5 +1,7 @@ # netlink - netlink library for go # +[![Build Status](https://travis-ci.org/vishvananda/netlink.png?branch=master)](https://travis-ci.org/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 the kernel. It can be used to add and remove interfaces, set ip addresses @@ -41,8 +43,8 @@ import ( ) func main() { - mybridge := &netlink.Link{Name: "mybridge", Type: "bridge"} - netlink, _ := netlink.LinkAdd(mybridge) + mybridge := &netlink.Bridge{netlink.LinkAttrs{Name: "foo"}} + _ := netlink.LinkAdd(mybridge) eth1, _ := netlink.LinkByName("eth1") netlink.LinkSetMaster(eth1, mybridge) } diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go index 06e9bddc66..b1c77c42a3 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_linux.go @@ -11,6 +11,7 @@ import ( ) var native = nl.NativeEndian() +var lookupByDump = false func ensureIndex(link *LinkAttrs) { if link != nil && link.Index == 0 { @@ -177,7 +178,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 { @@ -226,7 +227,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) @@ -314,8 +315,26 @@ func LinkDel(link Link) error { return err } +func linkByNameDump(name string) (Link, error) { + links, err := LinkList() + if err != nil { + return nil, err + } + + for _, link := range links { + if link.Attrs().Name == name { + return link, nil + } + } + return nil, fmt.Errorf("Link %s not found", name) +} + // LinkByName finds a link by name and returns a pointer to the object. func LinkByName(name string) (Link, error) { + if lookupByDump { + return linkByNameDump(name) + } + req := nl.NewNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_UNSPEC) @@ -324,7 +343,15 @@ func LinkByName(name string) (Link, error) { nameData := nl.NewRtAttr(syscall.IFLA_IFNAME, nl.ZeroTerminated(name)) req.AddData(nameData) - return execGetLink(req) + link, err := execGetLink(req) + 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) + } + + return link, err } // LinkByIndex finds a link by index and returns a pointer to the object. diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go index 7c718bb845..65b7b2b6c8 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/link_test.go @@ -349,7 +349,7 @@ func TestLinkAddDelVxlan(t *testing.T) { LinkAttrs: LinkAttrs{ Name: "bar", }, - VxlanId: 10, + VxlanId: 10, VtepDevIndex: parent.Index, Learning: true, L2miss: true, @@ -363,6 +363,9 @@ func TestLinkAddDelVxlan(t *testing.T) { } func TestLinkByIndex(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + dummy := &Dummy{LinkAttrs{Name: "dummy"}} if err := LinkAdd(dummy); err != nil { t.Fatal(err) diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go index 510f012b76..3b84162e3c 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/neigh_test.go @@ -20,7 +20,7 @@ func parseMAC(s string) net.HardwareAddr { func dumpContains(dump []Neigh, e arpEntry) bool { for _, n := range dump { - if n.IP.Equal(e.ip) && (n.State & NUD_INCOMPLETE) == 0 { + if n.IP.Equal(e.ip) && (n.State&NUD_INCOMPLETE) == 0 { return true } } @@ -28,6 +28,9 @@ func dumpContains(dump []Neigh, e arpEntry) bool { } func TestNeighAddDel(t *testing.T) { + tearDown := setUpNetlinkTest(t) + defer tearDown() + dummy := Dummy{LinkAttrs{Name: "neigh0"}} if err := LinkAdd(&dummy); err != nil { t.Fatal(err) @@ -36,11 +39,11 @@ func TestNeighAddDel(t *testing.T) { ensureIndex(dummy.Attrs()) arpTable := []arpEntry{ - { net.ParseIP("10.99.0.1"), parseMAC("aa:bb:cc:dd:00:01") }, - { net.ParseIP("10.99.0.2"), parseMAC("aa:bb:cc:dd:00:02") }, - { net.ParseIP("10.99.0.3"), parseMAC("aa:bb:cc:dd:00:03") }, - { net.ParseIP("10.99.0.4"), parseMAC("aa:bb:cc:dd:00:04") }, - { net.ParseIP("10.99.0.5"), parseMAC("aa:bb:cc:dd:00:05") }, + {net.ParseIP("10.99.0.1"), parseMAC("aa:bb:cc:dd:00:01")}, + {net.ParseIP("10.99.0.2"), parseMAC("aa:bb:cc:dd:00:02")}, + {net.ParseIP("10.99.0.3"), parseMAC("aa:bb:cc:dd:00:03")}, + {net.ParseIP("10.99.0.4"), parseMAC("aa:bb:cc:dd:00:04")}, + {net.ParseIP("10.99.0.5"), parseMAC("aa:bb:cc:dd:00:05")}, } // Add the arpTable diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go index 12870421ad..17088fa0c0 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/addr_linux.go @@ -45,4 +45,3 @@ func (msg *IfAddrmsg) Serialize() []byte { func (msg *IfAddrmsg) Len() int { return syscall.SizeofIfAddrmsg } - diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go index ee2533bcfe..9c2499e60f 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/nl_linux.go @@ -4,8 +4,8 @@ package nl import ( "bytes" "encoding/binary" - "net" "fmt" + "net" "sync/atomic" "syscall" "unsafe" @@ -304,7 +304,7 @@ func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) { s.lsa.Family = syscall.AF_NETLINK for _, g := range groups { - s.lsa.Groups |= (1 << (g-1)) + s.lsa.Groups |= (1 << (g - 1)) } if err := syscall.Bind(fd, &s.lsa); err != nil { diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go index de54609eb3..5dde998e96 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/route_linux.go @@ -31,4 +31,3 @@ func DeserializeRtMsg(b []byte) *RtMsg { func (msg *RtMsg) Serialize() []byte { return (*(*[syscall.SizeofRtMsg]byte)(unsafe.Pointer(msg)))[:] } - diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go index e1d186bcaf..66f7e03d2d 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_policy_linux.go @@ -117,4 +117,3 @@ func DeserializeXfrmUserTmpl(b []byte) *XfrmUserTmpl { func (msg *XfrmUserTmpl) Serialize() []byte { return (*(*[SizeofXfrmUserTmpl]byte)(unsafe.Pointer(msg)))[:] } - diff --git a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go index 74da3325d9..4876ce4583 100644 --- a/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go +++ b/Godeps/_workspace/src/github.com/vishvananda/netlink/nl/xfrm_state_linux.go @@ -219,4 +219,3 @@ func DeserializeXfrmEncapTmpl(b []byte) *XfrmEncapTmpl { func (msg *XfrmEncapTmpl) Serialize() []byte { return (*(*[SizeofXfrmEncapTmpl]byte)(unsafe.Pointer(msg)))[:] } -