Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions plugins/meta/vrf/vrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ func addInterface(vrf *netlink.Vrf, intf string) error {
return fmt.Errorf("interface %s has already a master set: %s", intf, master.Attrs().Name)
}

// IPV6 addresses are not maintained unless
// Global IPV6 addresses are not maintained unless
// sysctl -w net.ipv6.conf.all.keep_addr_on_down=1 is called
// so we save it, and restore it back.
beforeAddresses, err := netlink.AddrList(i, netlink.FAMILY_V6)
beforeAddresses, err := getGlobalAddresses(i, netlink.FAMILY_V6)
if err != nil {
return fmt.Errorf("failed getting ipv6 addresses for %s", intf)
return fmt.Errorf("failed getting global ipv6 addresses before slaving interface: %w", err)
}

// Save all routes that are not local and connected, before setting master,
Expand All @@ -114,19 +114,28 @@ func addInterface(vrf *netlink.Vrf, intf string) error {
Scope: netlink.SCOPE_UNIVERSE, // Exclude local and connected routes
}
filterMask := netlink.RT_FILTER_OIF | netlink.RT_FILTER_SCOPE // Filter based on link index and scope
routes, err := netlink.RouteListFiltered(netlink.FAMILY_ALL, filter, filterMask)
r, err := netlink.RouteListFiltered(netlink.FAMILY_ALL, filter, filterMask)
if err != nil {
return fmt.Errorf("failed getting all routes for %s", intf)
}

// Filter out connected IPV6 routes
globalRoutes := make([]netlink.Route, 0, len(r))
for _, route := range r {
if route.Src != nil {
globalRoutes = append(globalRoutes, route)
}
}

err = netlink.LinkSetMaster(i, vrf)
if err != nil {
return fmt.Errorf("could not set vrf %s as master of %s: %v", vrf.Name, intf, err)
}

afterAddresses, err := netlink.AddrList(i, netlink.FAMILY_V6)
// Used to identify which global IPV6 addresses are missing
afterAddresses, err := getGlobalAddresses(i, netlink.FAMILY_V6)
if err != nil {
return fmt.Errorf("failed getting ipv6 new addresses for %s: %v", intf, err)
return fmt.Errorf("failed getting global ipv6 addresses after slaving interface: %w", err)
}

// Since keeping the ipv6 address depends on net.ipv6.conf.all.keep_addr_on_down ,
Expand All @@ -144,7 +153,7 @@ CONTINUE:
return fmt.Errorf("could not restore address %s to %s @ %s: %v", toFind, intf, vrf.Name, err)
}

// Waits for local/host routes to be added by the kernel.
// Waits for global IPV6 addresses to be added by the kernel.
maxRetry := 10
for {
routesVRFTable, err := netlink.RouteListFiltered(
Expand Down Expand Up @@ -177,7 +186,7 @@ CONTINUE:
}

// Apply all saved routes for the interface that was moved to the VRF
for _, route := range routes {
for _, route := range globalRoutes {
r := route
// Modify original table to vrf one,
r.Table = int(vrf.Table)
Expand Down Expand Up @@ -218,3 +227,20 @@ func resetMaster(interfaceName string) error {
}
return nil
}

// getGlobalAddresses returns the global addresses of the given interface
func getGlobalAddresses(link netlink.Link, family int) ([]netlink.Addr, error) {
addresses, err := netlink.AddrList(link, family)
if err != nil {
return nil, fmt.Errorf("failed getting list of IP addresses for %s: %w", link.Attrs().Name, err)
}

globalAddresses := make([]netlink.Addr, 0, len(addresses))
for _, addr := range addresses {
if addr.Scope == int(netlink.SCOPE_UNIVERSE) {
globalAddresses = append(globalAddresses, addr)
}
}

return globalAddresses, nil
}
1 change: 1 addition & 0 deletions plugins/meta/vrf/vrf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ var _ = Describe("vrf plugin", func() {
// Add additional route to 10.11.10.0/24 via 10.0.0.1 gateway
r := netlink.Route{
LinkIndex: link.Attrs().Index,
Src: ipv4.IP,
Dst: routev4,
Gw: net.ParseIP("10.0.0.1"),
Priority: 100,
Expand Down