Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 2092501: Fixes finding default gateway for configured GW interface #1131

Merged
merged 1 commit into from Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion go-controller/pkg/node/gateway_init.go
Expand Up @@ -138,7 +138,7 @@ func getGatewayNextHops() ([]net.IP, string, error) {
}
gatewayIntf := config.Gateway.Interface
if needIPv4NextHop || needIPv6NextHop || gatewayIntf == "" {
defaultGatewayIntf, defaultGatewayNextHops, err := getDefaultGatewayInterfaceDetails()
defaultGatewayIntf, defaultGatewayNextHops, err := getDefaultGatewayInterfaceDetails(gatewayIntf)
if err != nil {
return nil, "", err
}
Expand Down
9 changes: 9 additions & 0 deletions go-controller/pkg/node/gateway_init_linux_test.go
Expand Up @@ -994,6 +994,15 @@ var _ = Describe("Gateway Init Operations", func() {
It("sets up a shared interface gateway with tagged VLAN", func() {
shareGatewayInterfaceTest(app, testNS, eth0Name, eth0MAC, eth0IP, eth0GWIP, eth0CIDR, 3000)
})

config.Gateway.Interface = eth0Name
It("sets up a shared interface gateway with predetermined gateway interface", func() {
shareGatewayInterfaceTest(app, testNS, eth0Name, eth0MAC, eth0IP, eth0GWIP, eth0CIDR, 0)
})

It("sets up a shared interface gateway with tagged VLAN + predetermined gateway interface", func() {
shareGatewayInterfaceTest(app, testNS, eth0Name, eth0MAC, eth0IP, eth0GWIP, eth0CIDR, 3000)
})
})
})

Expand Down
56 changes: 47 additions & 9 deletions go-controller/pkg/node/helper_linux.go
Expand Up @@ -16,13 +16,14 @@ import (

// getDefaultGatewayInterfaceDetails returns the interface name on
// which the default gateway (for route to 0.0.0.0) is configured.
// optionally pass the pre-determined gateway interface
// It also returns the default gateways themselves.
func getDefaultGatewayInterfaceDetails() (string, []net.IP, error) {
func getDefaultGatewayInterfaceDetails(gwIface string) (string, []net.IP, error) {
var intfName string
var gatewayIPs []net.IP

if config.IPv4Mode {
intfIPv4Name, gw, err := getDefaultGatewayInterfaceByFamily(netlink.FAMILY_V4)
intfIPv4Name, gw, err := getDefaultGatewayInterfaceByFamily(netlink.FAMILY_V4, gwIface)
if err != nil {
return "", gatewayIPs, err
}
Expand All @@ -31,7 +32,7 @@ func getDefaultGatewayInterfaceDetails() (string, []net.IP, error) {
}

if config.IPv6Mode {
intfIPv6Name, gw, err := getDefaultGatewayInterfaceByFamily(netlink.FAMILY_V6)
intfIPv6Name, gw, err := getDefaultGatewayInterfaceByFamily(netlink.FAMILY_V6, gwIface)
if err != nil {
return "", gatewayIPs, err
}
Expand All @@ -50,10 +51,29 @@ func getDefaultGatewayInterfaceDetails() (string, []net.IP, error) {
return intfName, gatewayIPs, nil
}

func getDefaultGatewayInterfaceByFamily(family int) (string, net.IP, error) {
// uses netlink to do a route lookup for default gateway
// takes IP address family and optional name of a pre-determined gateway interface
// returns name of default gateway interface, the default gateway ip, and any error
func getDefaultGatewayInterfaceByFamily(family int, gwIface string) (string, net.IP, error) {
// filter the default route to obtain the gateway
filter := &netlink.Route{Dst: nil}
routes, err := netlink.RouteListFiltered(family, filter, netlink.RT_FILTER_DST)
mask := netlink.RT_FILTER_DST
// gw interface provided
if len(gwIface) > 0 {
link, err := netlink.LinkByName(gwIface)
if err != nil {
return "", nil, fmt.Errorf("error looking up gw interface: %q, error: %w", gwIface, err)
}
if link.Attrs() == nil {
return "", nil, fmt.Errorf("no attributes found for link: %#v", link)
}
gwIfIdx := link.Attrs().Index
klog.Infof("Provided gateway interface %q, found as index: %d", gwIface, gwIfIdx)
filter.LinkIndex = gwIfIdx
mask = mask | netlink.RT_FILTER_OIF
}

routes, err := netlink.RouteListFiltered(family, filter, mask)
if err != nil {
return "", nil, errors.Wrapf(err, "failed to get routing table in node")
}
Expand All @@ -70,8 +90,17 @@ func getDefaultGatewayInterfaceByFamily(family int) (string, net.IP, error) {
klog.Warningf("Failed to get gateway for route %v : %v", r, err)
continue
}
klog.Infof("Found default gateway interface %s %s", intfLink.Attrs().Name, r.Gw.String())
return intfLink.Attrs().Name, r.Gw, nil
if intfLink.Attrs() == nil {
return "", nil, fmt.Errorf("no attributes found for link: %#v", intfLink.Attrs())
}
foundIfName := intfLink.Attrs().Name
klog.Infof("Found default gateway interface %s %s", foundIfName, r.Gw.String())
if len(gwIface) > 0 && gwIface != foundIfName {
// this should not happen, but if it did, indicates something broken with our use of the netlink lib
return "", nil, fmt.Errorf("mistmaching provided gw interface: %s and gateway found: %s",
gwIface, foundIfName)
}
return foundIfName, r.Gw, nil
}

// multipath, use the first valid entry
Expand All @@ -87,8 +116,17 @@ func getDefaultGatewayInterfaceByFamily(family int) (string, net.IP, error) {
klog.Warningf("Failed to get gateway for multipath route %v : %v", nh, err)
continue
}
klog.Infof("Found default gateway interface %s %s", intfLink.Attrs().Name, nh.Gw.String())
return intfLink.Attrs().Name, nh.Gw, nil
if intfLink.Attrs() == nil {
return "", nil, fmt.Errorf("no attributes found for link: %#v", intfLink.Attrs())
}
foundIfName := intfLink.Attrs().Name
klog.Infof("Found default gateway interface %s %s", foundIfName, nh.Gw.String())
if len(gwIface) > 0 && gwIface != foundIfName {
// this should not happen, but if it did, indicates something broken with our use of the netlink lib
return "", nil, fmt.Errorf("mistmaching provided gw interface: %q and gateway found: %q",
gwIface, foundIfName)
}
return foundIfName, nh.Gw, nil
}
}
return "", net.IP{}, fmt.Errorf("failed to get default gateway interface")
Expand Down