From e230eeb4860914add6b7607d1bb857c6c8feb5c4 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 12 Nov 2015 13:06:10 +0000 Subject: [PATCH] Use upstream netlink code --- net/if.go | 82 ++++++++++++++++++---------------------------------- net/route.go | 50 -------------------------------- 2 files changed, 28 insertions(+), 104 deletions(-) diff --git a/net/if.go b/net/if.go index b99993ec..780f4290 100644 --- a/net/if.go +++ b/net/if.go @@ -5,28 +5,33 @@ import ( "net" "syscall" - "github.com/vishvananda/netlink/nl" + "github.com/vishvananda/netlink" ) // Wait for an interface to come up. func EnsureInterface(ifaceName string) (*net.Interface, error) { - s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK) - if err != nil { - return nil, err - } - defer s.Close() - iface, err := ensureInterface(s, ifaceName) + iface, err := ensureInterface(ifaceName) if err != nil { return nil, err } return iface, err } -func ensureInterface(s *nl.NetlinkSocket, ifaceName string) (*net.Interface, error) { +func ensureInterface(ifaceName string) (*net.Interface, error) { if iface, err := findInterface(ifaceName); err == nil { return iface, nil } - netlinkReceiveUntil(s, matchIfName(ifaceName)) + ch := make(chan netlink.LinkUpdate) + done := make(chan struct{}) + defer close(done) + if err := netlink.LinkSubscribe(ch, done); err != nil { + return nil, err + } + for update := range ch { + if ifaceName == update.Link.Attrs().Name && update.IfInfomsg.Flags&syscall.IFF_UP != 0 { + break + } + } iface, err := findInterface(ifaceName) return iface, err } @@ -35,12 +40,7 @@ func ensureInterface(s *nl.NetlinkSocket, ifaceName string) (*net.Interface, err // This matches the behaviour in 'weave attach', which is the only context in which // we expect this to be called. If you change one, change the other to match. func EnsureInterfaceAndMcastRoute(ifaceName string) (*net.Interface, error) { - s, err := nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_LINK, syscall.RTNLGRP_IPV4_ROUTE) - if err != nil { - return nil, err - } - defer s.Close() - iface, err := ensureInterface(s, ifaceName) + iface, err := ensureInterface(ifaceName) if err != nil { return nil, err } @@ -48,8 +48,19 @@ func EnsureInterfaceAndMcastRoute(ifaceName string) (*net.Interface, error) { if CheckRouteExists(ifaceName, dest) { return iface, err } - netlinkReceiveUntil(s, matchRoute(ifaceName, dest)) - return iface, err + ch := make(chan netlink.RouteUpdate) + done := make(chan struct{}) + defer close(done) + if err := netlink.RouteSubscribe(ch, done); err != nil { + return nil, err + } + for update := range ch { + link, _ := netlink.LinkByIndex(update.Route.LinkIndex) + if link.Attrs().Name == ifaceName && update.Route.Dst.IP.Equal(dest) { + break + } + } + return iface, nil } func findInterface(ifaceName string) (iface *net.Interface, err error) { @@ -61,40 +72,3 @@ func findInterface(ifaceName string) (iface *net.Interface, err error) { } return } - -func netlinkReceiveUntil(s *nl.NetlinkSocket, f func(syscall.NetlinkMessage) (bool, error)) error { - for { - msgs, err := s.Receive() - if err != nil { - return err - } - for _, m := range msgs { - if done, err := f(m); done { - return err - } - } - } -} - -func matchIfName(ifaceName string) func(m syscall.NetlinkMessage) (bool, error) { - return func(m syscall.NetlinkMessage) (bool, error) { - switch m.Header.Type { - case syscall.RTM_NEWLINK: // receive this type for link 'up' - ifmsg := nl.DeserializeIfInfomsg(m.Data) - attrs, err := syscall.ParseNetlinkRouteAttr(&m) - if err != nil { - return true, err - } - name := "" - for _, attr := range attrs { - if attr.Attr.Type == syscall.IFA_LABEL { - name = string(attr.Value[:len(attr.Value)-1]) - } - } - if ifaceName == name && ifmsg.Flags&syscall.IFF_UP != 0 { - return true, nil - } - } - return false, nil - } -} diff --git a/net/route.go b/net/route.go index 560ae22e..3424826c 100644 --- a/net/route.go +++ b/net/route.go @@ -3,10 +3,8 @@ package net import ( "fmt" "net" - "syscall" "github.com/vishvananda/netlink" - "github.com/vishvananda/netlink/nl" ) // A network is considered free if it does not overlap any existing @@ -65,51 +63,3 @@ func CheckRouteExists(ifaceName string, dest net.IP) bool { }) return found } - -func matchRoute(ifaceName string, dest net.IP) func(m syscall.NetlinkMessage) (bool, error) { - return func(m syscall.NetlinkMessage) (bool, error) { - switch m.Header.Type { - case syscall.RTM_NEWROUTE: - route, err := deserializeRoute(m.Data) - if err != nil { - return true, err - } - link, _ := netlink.LinkByIndex(route.LinkIndex) - if link.Attrs().Name == ifaceName && route.Dst.IP.Equal(dest) { - return true, nil - } - } - return false, nil - } -} - -// This code proposed for addition to the vishvananda/netlink library -// deserializeRoute decodes a binary netlink message into a Route struct -func deserializeRoute(m []byte) (netlink.Route, error) { - route := netlink.Route{} - msg := nl.DeserializeRtMsg(m) - attrs, err := nl.ParseRouteAttr(m[msg.Len():]) - if err != nil { - return route, err - } - route.Scope = netlink.Scope(msg.Scope) - - native := nl.NativeEndian() - 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 - } - } - return route, nil -}