Skip to content

Commit d505152

Browse files
drewhlicopybara-github
authored andcommitted
Remove unnecessary extra ip route calls when checking for routes to add and delete in network module.
Currently, the `ip route` check happens twice -- once when checking if there are missing routes and extra routes, and another time when we actually add missing routes/remove extra routes. This optimization makes it so that we store the extra/missing routes upon the first check, and use those for the actual route setup instead of checking again. PiperOrigin-RevId: 874856285
1 parent 69dff6c commit d505152

File tree

10 files changed

+287
-61
lines changed

10 files changed

+287
-61
lines changed

cmd/core_plugin/network/manager_linux.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,12 @@ func managerSetup(ctx context.Context, nics []*nic.Configuration, networkChanged
6161
}
6262

6363
// Attempt to setup the routes.
64-
if err := routeSetup(ctx, opts); err != nil {
65-
return fmt.Errorf("failed to setup routes: %w", err)
64+
if networkChanged.routes {
65+
if err := routeSetup(ctx, &networkChanged.routeSetupOptions); err != nil {
66+
return fmt.Errorf("failed to setup routes: %w", err)
67+
}
68+
} else {
69+
galog.Debugf("No routes to setup.")
6670
}
6771

6872
galog.Infof("Finished linux network management module setup.")

cmd/core_plugin/network/manager_linux_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/GoogleCloudPlatform/google-guest-agent/internal/cfg"
2525
"github.com/GoogleCloudPlatform/google-guest-agent/internal/network/ethernet"
2626
"github.com/GoogleCloudPlatform/google-guest-agent/internal/network/nic"
27+
"github.com/GoogleCloudPlatform/google-guest-agent/internal/network/route"
2728
"github.com/GoogleCloudPlatform/google-guest-agent/internal/network/service"
2829
"github.com/google/go-cmp/cmp"
2930
)
@@ -467,15 +468,15 @@ func TestNetworkInterfacesSetupDisabled(t *testing.T) {
467468
t.Cleanup(func() {
468469
routeSetup = oldRouteSetup
469470
})
470-
routeSetup = func(ctx context.Context, opts *service.Options) error {
471+
routeSetup = func(ctx context.Context, opts *route.SetupOptions) error {
471472
routeSetupCalled = true
472473
return nil
473474
}
474475

475476
testOpts := service.NewOptions(nil, []*nic.Configuration{
476477
{Index: 1},
477478
})
478-
if err := managerSetup(ctx, testOpts.NICConfigs(), networkChanged{true, false}); err != nil {
479+
if err := managerSetup(ctx, testOpts.NICConfigs(), networkChanged{true, true, route.SetupOptions{}}); err != nil {
479480
t.Errorf("managerSetup(ctx, %+v) = %v, want nil", testOpts, err)
480481
}
481482

@@ -579,7 +580,7 @@ func TestManagerSetup(t *testing.T) {
579580
defaultLinuxManagers = oldManagers
580581
})
581582

582-
err := managerSetup(ctx, tc.opts.NICConfigs(), networkChanged{true, false})
583+
err := managerSetup(ctx, tc.opts.NICConfigs(), networkChanged{true, false, route.SetupOptions{ServiceOptions: tc.opts}})
583584
if (err == nil) == tc.wantError {
584585
t.Errorf("runManagerSetup(ctx, %+v) = %v, want error", tc.opts, err)
585586
}

cmd/core_plugin/network/network.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,15 @@ func (mod *module) networkSetup(ctx context.Context, config *cfg.Sections, mds *
155155
// If the metadata has not changed then we return early to avoid unnecessary
156156
// work.
157157
metadataChanged := mod.networkMetadataChanged(mds, config)
158-
routeChanged := mod.routeChanged(ctx, nicConfigs)
158+
routeChanged, setupOptions := mod.routeChanged(ctx, nicConfigs)
159159
if !metadataChanged && !routeChanged && !mod.failedConfiguration {
160160
return true, nil
161161
}
162162

163163
galog.V(1).Debugf("Network metadata has changed or failed configuration, setting up network interfaces.")
164164

165165
// Forward the network configuration to the platform's network manager.
166-
if err := managerSetup(ctx, nicConfigs, networkChanged{networkInterfaces: metadataChanged, routes: routeChanged}); err != nil {
166+
if err := managerSetup(ctx, nicConfigs, networkChanged{networkInterfaces: metadataChanged, routes: routeChanged, routeSetupOptions: setupOptions}); err != nil {
167167
failedSetup = true
168168
return false, fmt.Errorf("failed to setup network interfaces: %v", err)
169169
}
@@ -178,6 +178,8 @@ type networkChanged struct {
178178
networkInterfaces bool
179179
// routes indicates if the routes have changed.
180180
routes bool
181+
// routeSetupOptions is the route setup options.
182+
routeSetupOptions route.SetupOptions
181183
}
182184

183185
// networkMetadataChanged returns true if the metadata has changed or if it's being
@@ -213,26 +215,36 @@ func (mod *module) networkMetadataChanged(mds *metadata.Descriptor, config *cfg.
213215
// routeChanged returns true if the route metadata has changed, or if the routes
214216
// present on the system have changed from what is expected based on the network
215217
// interfaces configuration.
216-
func (mod *module) routeChanged(ctx context.Context, nicConfigs []*nic.Configuration) bool {
218+
func (mod *module) routeChanged(ctx context.Context, nicConfigs []*nic.Configuration) (bool, route.SetupOptions) {
219+
missingRoutes := make(map[string][]route.Handle)
220+
extraRoutes := make(map[string][]route.Handle)
221+
222+
var foundChanged bool
217223
for _, nic := range nicConfigs {
218224
if nic.Invalid || nic.Interface == nil {
219225
continue
220226
}
221227
wantedRoutes := nic.ExtraAddresses.MergedMap()
222228

223-
if missing, err := route.MissingRoutes(ctx, nic.Interface.Name(), wantedRoutes); err != nil {
229+
missing, err := route.MissingRoutes(ctx, nic.Interface.Name(), wantedRoutes)
230+
if err != nil {
224231
galog.V(2).Debugf("Failed to get missing routes for interface %q: %v", nic.Interface.Name(), err)
225-
continue
226232
} else if len(missing) > 0 {
227-
return true
233+
foundChanged = true
234+
missingRoutes[nic.Interface.Name()] = missing
228235
}
229236

230-
if extra, err := route.ExtraRoutes(ctx, nic.Interface.Name(), wantedRoutes); err != nil {
237+
extra, err := route.ExtraRoutes(ctx, nic.Interface.Name(), wantedRoutes)
238+
if err != nil {
231239
galog.V(2).Debugf("Failed to get extra routes for interface %q: %v", nic.Interface.Name(), err)
232-
continue
233240
} else if len(extra) > 0 {
234-
return true
241+
foundChanged = true
242+
extraRoutes[nic.Interface.Name()] = extra
235243
}
236244
}
237-
return false
245+
return foundChanged, route.SetupOptions{
246+
AlreadyChecked: true,
247+
MissingRoutes: missingRoutes,
248+
ExtraRoutes: extraRoutes,
249+
}
238250
}

cmd/core_plugin/network/network_linux_test.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ func TestRouteChanged(t *testing.T) {
6363
}
6464

6565
tests := []struct {
66-
name string
67-
nicConfigs []*nic.Configuration
68-
hasExtraRoutes bool
69-
want bool
66+
name string
67+
nicConfigs []*nic.Configuration
68+
hasExtraRoutes bool
69+
want bool
70+
numExtraRoutes int
71+
numMissingRoutes int
7072
}{
7173
{
7274
name: "no-change-empty-extra-addresses",
@@ -125,7 +127,8 @@ func TestRouteChanged(t *testing.T) {
125127
ExtraAddresses: address.NewExtraAddresses(desc.Instance().NetworkInterfaces()[0], cfg.Retrieve(), nil),
126128
},
127129
},
128-
want: true,
130+
want: true,
131+
numMissingRoutes: 2,
129132
},
130133
{
131134
name: "change-extra-route",
@@ -139,6 +142,7 @@ func TestRouteChanged(t *testing.T) {
139142
},
140143
hasExtraRoutes: true,
141144
want: true,
145+
numExtraRoutes: 2,
142146
},
143147
}
144148

@@ -151,10 +155,18 @@ func TestRouteChanged(t *testing.T) {
151155
})
152156

153157
mod := &module{}
154-
got := mod.routeChanged(context.Background(), test.nicConfigs)
158+
got, opts := mod.routeChanged(context.Background(), test.nicConfigs)
155159
if got != test.want {
156160
t.Errorf("routeChanged(%v) = %t, want %t", test.nicConfigs, got, test.want)
157161
}
162+
163+
if len(opts.ExtraRoutes["eth0"]) != test.numExtraRoutes {
164+
t.Errorf("routeChanged(%v) = %v, want %d extra routes", test.nicConfigs, opts.ExtraRoutes, test.numExtraRoutes)
165+
}
166+
167+
if len(opts.MissingRoutes["eth0"]) != test.numMissingRoutes {
168+
t.Errorf("routeChanged(%v) = %v, want %d missing routes", test.nicConfigs, opts.MissingRoutes, test.numMissingRoutes)
169+
}
158170
})
159171
}
160172
}

cmd/core_plugin/network/network_windows_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestRouteChanged(t *testing.T) {
4242
}
4343

4444
mod := &module{}
45-
got := mod.routeChanged(context.Background(), nicConfigs)
45+
got, _ := mod.routeChanged(context.Background(), nicConfigs)
4646
if got {
4747
t.Errorf("routeChanged(%v) = %t, want false", nicConfigs, got)
4848
}

cmd/ggactl/commands/routes/routes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func setupRoutes(cmd *cobra.Command, args []string) error {
7171
opts := service.NewOptions(nil, nicConfigs)
7272

7373
// Add the routes, if any.
74-
if err := route.Setup(ctx, opts); err != nil {
74+
if err := route.Setup(ctx, &route.SetupOptions{ServiceOptions: opts}); err != nil {
7575
return fmt.Errorf("failed to setup routes: %v", err)
7676
}
7777
return nil

internal/network/route/route.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ type Options struct {
8383
Device string
8484
}
8585

86+
// SetupOptions wraps route setup options.
87+
type SetupOptions struct {
88+
// ServiceOptions contains the NIC configurations for route setup.
89+
ServiceOptions *service.Options
90+
// AlreadyChecked indicates whether missing and extra routes have already
91+
// been checked.
92+
AlreadyChecked bool
93+
// MissingRoutes contains the routes that are missing from the system. This
94+
// is only relevant if AlreadyChecked is true.
95+
MissingRoutes map[string][]Handle
96+
// ExtraRoutes contains the routes that are extra to the system. This is only
97+
// relevant if AlreadyChecked is true.
98+
ExtraRoutes map[string][]Handle
99+
}
100+
86101
// routeOperations is the interface for a route backend.
87102
type routeOperations interface {
88103
// Add adds a route to the system.
@@ -103,7 +118,7 @@ type routeOperations interface {
103118
// interface.
104119
RemoveRoutes(ctx context.Context, iface string) error
105120
// Setup sets up the routes for the network interfaces.
106-
Setup(ctx context.Context, opts *service.Options) error
121+
Setup(ctx context.Context, opts *SetupOptions) error
107122
}
108123

109124
// Add adds a route to the system.
@@ -133,7 +148,7 @@ func MissingRoutes(ctx context.Context, iface string, wantedRoutes address.IPAdd
133148
}
134149

135150
// Setup sets up the routes for the network interfaces.
136-
func Setup(ctx context.Context, opts *service.Options) error {
151+
func Setup(ctx context.Context, opts *SetupOptions) error {
137152
return client.Setup(ctx, opts)
138153
}
139154

internal/network/route/route_linux.go

Lines changed: 73 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/GoogleCloudPlatform/galog"
2626
"github.com/GoogleCloudPlatform/google-guest-agent/internal/cfg"
2727
"github.com/GoogleCloudPlatform/google-guest-agent/internal/network/address"
28-
"github.com/GoogleCloudPlatform/google-guest-agent/internal/network/service"
2928
"github.com/GoogleCloudPlatform/google-guest-agent/internal/run"
3029
"golang.org/x/exp/maps"
3130
)
@@ -398,16 +397,40 @@ func (lc *linuxClient) RemoveRoutes(ctx context.Context, iface string) error {
398397

399398
// SetupRoutes sets up the routes for the network interfaces. This uses ip route
400399
// commands to delete extra routes and add missing routes.
401-
func (lc *linuxClient) Setup(ctx context.Context, opts *service.Options) error {
402-
nicConfigs := opts.FilteredNICConfigs()
400+
func (lc *linuxClient) Setup(ctx context.Context, opts *SetupOptions) error {
401+
if opts == nil {
402+
galog.Debugf("No setup options provided.")
403+
return nil
404+
}
405+
galog.Debugf("Running ip route setup.")
406+
407+
if opts.AlreadyChecked {
408+
if len(opts.MissingRoutes) == 0 && len(opts.ExtraRoutes) == 0 {
409+
galog.Debugf("No routes to setup.")
410+
return nil
411+
}
412+
413+
for iface, routes := range opts.ExtraRoutes {
414+
lc.deleteExtraRoutes(ctx, iface, routes)
415+
}
416+
for iface, routes := range opts.MissingRoutes {
417+
lc.addMissingRoutes(ctx, iface, routes)
418+
}
419+
return nil
420+
}
421+
422+
if opts.ServiceOptions == nil {
423+
galog.Debugf("No service options provided.")
424+
return nil
425+
}
426+
nicConfigs := opts.ServiceOptions.FilteredNICConfigs()
403427
if len(nicConfigs) == 0 {
404428
galog.Debugf("No NICs to setup routes for.")
405429
return nil
406430
}
407-
galog.Debugf("Running ip route setup.")
408431

409432
// Fallback route setup uses ip commands.
410-
for _, nic := range opts.FilteredNICConfigs() {
433+
for _, nic := range nicConfigs {
411434
if nic.Interface == nil {
412435
galog.Debugf("Skipping route setup for interface index %d: interface is nil", nic.Index)
413436
continue
@@ -418,44 +441,60 @@ func (lc *linuxClient) Setup(ctx context.Context, opts *service.Options) error {
418441
}
419442

420443
// Find extra routes to delete.
421-
extraAddrs := nic.ExtraAddresses.MergedMap()
422-
extraRoutes, err := lc.ExtraRoutes(ctx, nic.Interface.Name(), extraAddrs)
423-
if err != nil {
424-
return fmt.Errorf("failed to get extra routes for interface %q: %w", nic.Interface.Name(), err)
425-
}
426-
427-
if len(extraRoutes) == 0 {
428-
galog.Debugf("No extra routes to delete for interface %q", nic.Interface.Name())
444+
var extraAddrs address.IPAddressMap
445+
var extraRoutes []Handle
446+
var err error
447+
if opts.AlreadyChecked {
448+
extraRoutes = opts.ExtraRoutes[nic.Interface.Name()]
429449
} else {
430-
galog.Infof("Deleting extra routes %v for interface %q", extraRoutes, nic.Interface.Name())
431-
for _, r := range extraRoutes {
432-
if err = lc.Delete(ctx, r); err != nil {
433-
// Continue to delete the rest of the routes, and only log the error.
434-
galog.Errorf("Failed to delete route %q for interface %q: %v", r.Destination.String(), nic.Interface.Name(), err)
435-
}
450+
extraAddrs = nic.ExtraAddresses.MergedMap()
451+
extraRoutes, err = lc.ExtraRoutes(ctx, nic.Interface.Name(), extraAddrs)
452+
if err != nil {
453+
return fmt.Errorf("failed to get extra routes for interface %q: %w", nic.Interface.Name(), err)
436454
}
437455
}
456+
lc.deleteExtraRoutes(ctx, nic.Interface.Name(), extraRoutes)
438457

439458
// Find missing routes for the given interface.
440-
missingRoutes, err := lc.MissingRoutes(ctx, nic.Interface.Name(), extraAddrs)
441-
if err != nil {
442-
return fmt.Errorf("failed to get missing routes for interface %q: %w", nic.Interface.Name(), err)
459+
var missingRoutes []Handle
460+
if opts.AlreadyChecked {
461+
missingRoutes = opts.MissingRoutes[nic.Interface.Name()]
462+
} else {
463+
missingRoutes, err = lc.MissingRoutes(ctx, nic.Interface.Name(), extraAddrs)
464+
if err != nil {
465+
return fmt.Errorf("failed to get missing routes for interface %q: %w", nic.Interface.Name(), err)
466+
}
443467
}
468+
lc.addMissingRoutes(ctx, nic.Interface.Name(), missingRoutes)
469+
}
470+
galog.Debugf("Finished ip route setup.")
471+
return nil
472+
}
444473

445-
if len(missingRoutes) == 0 {
446-
galog.Debugf("No missing routes to add for interface %q", nic.Interface.Name())
447-
continue
474+
func (lc *linuxClient) deleteExtraRoutes(ctx context.Context, iface string, extraRoutes []Handle) {
475+
if len(extraRoutes) == 0 {
476+
galog.Debugf("No extra routes to delete for interface %q", iface)
477+
return
478+
}
479+
galog.Infof("Deleting extra routes %v for interface %q", extraRoutes, iface)
480+
for _, r := range extraRoutes {
481+
if err := lc.Delete(ctx, r); err != nil {
482+
// Continue to delete the rest of the routes, and only log the error.
483+
galog.Errorf("Failed to delete route %q for interface %q: %v", r.Destination.String(), iface, err)
448484
}
449-
galog.Infof("Adding routes %v for interface %q", missingRoutes, nic.Interface.Name())
485+
}
486+
}
450487

451-
// Add the missing routes.
452-
for _, r := range missingRoutes {
453-
if err = lc.Add(ctx, r); err != nil {
454-
// Continue to add the rest of the routes, and only log the error.
455-
galog.Errorf("Failed to add route %q for interface %q: %v", r.Destination.String(), nic.Interface.Name(), err)
456-
}
488+
func (lc *linuxClient) addMissingRoutes(ctx context.Context, iface string, missingRoutes []Handle) {
489+
if len(missingRoutes) == 0 {
490+
galog.Debugf("No missing routes to add for interface %q", iface)
491+
return
492+
}
493+
galog.Infof("Adding routes %v for interface %q", missingRoutes, iface)
494+
for _, r := range missingRoutes {
495+
if err := lc.Add(ctx, r); err != nil {
496+
// Continue to add the rest of the routes, and only log the error.
497+
galog.Errorf("Failed to add route %q for interface %q: %v", r.Destination.String(), iface, err)
457498
}
458499
}
459-
galog.Debugf("Finished ip route setup.")
460-
return nil
461500
}

0 commit comments

Comments
 (0)