Use upstream netlink code
This commit is contained in:
1 parent
b1b03f3a97
commit
e230eeb486
2 files changed
+28
-104
No files matched your search
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user