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

sbr: Add rule for outbound interface when there is a single interface IP #1144

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
28 changes: 20 additions & 8 deletions plugins/meta/sbr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,18 @@ func doRoutes(ipCfgs []*current.IPConfig, iface string) error {

linkIndex := link.Attrs().Index

// Add an interface rule, only if there is a single IP address configured on the interface
if len(ipCfgs) == 1 {
interfaceRule := netlink.NewRule()
interfaceRule.Table = table
log.Printf("Interface to use %s", iface)
interfaceRule.OifName = iface

if err = netlink.RuleAdd(interfaceRule); err != nil {
return fmt.Errorf("Failed to add interface rule: %v", err)
}
}

// Get all routes for the interface in the default routing table
routes, err = netlink.RouteList(link, netlink.FAMILY_ALL)
if err != nil {
Expand All @@ -239,9 +251,9 @@ func doRoutes(ipCfgs []*current.IPConfig, iface string) error {

// Loop through setting up source based rules and default routes.
for _, ipCfg := range ipCfgs {
log.Printf("Set rule for source %s", ipCfg.String())
rule := netlink.NewRule()
rule.Table = table
log.Printf("Set src and interface rules for source %s", ipCfg.String())
srcRule := netlink.NewRule()
srcRule.Table = table

// Source must be restricted to a single IP, not a full subnet
var src net.IPNet
Expand All @@ -253,10 +265,10 @@ func doRoutes(ipCfgs []*current.IPConfig, iface string) error {
}

log.Printf("Source to use %s", src.String())
rule.Src = &src
srcRule.Src = &src

if err = netlink.RuleAdd(rule); err != nil {
return fmt.Errorf("Failed to add rule: %v", err)
if err = netlink.RuleAdd(srcRule); err != nil {
return fmt.Errorf("Failed to add src rule: %v", err)
}

// Add a default route, since this may have been removed by previous
Expand Down Expand Up @@ -425,12 +437,12 @@ func tidyRules(iface string, table *int) error {
RULE_LOOP:
for _, rule := range rules {
log.Printf("Check rule: %v", rule)
if rule.Src == nil {
if rule.Src == nil && rule.OifName == "" {
continue
}

for _, addr := range addrs {
if rule.Src.IP.Equal(addr.IP) {
if rule.OifName == iface || rule.Src.IP.Equal(addr.IP) {
log.Printf("Delete rule %v", rule)
err := netlink.RuleDel(&rule)
if err != nil {
Expand Down
23 changes: 17 additions & 6 deletions plugins/meta/sbr/sbr_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ var _ = Describe("sbr test", func() {

// Check results. We expect all the routes on net1 to have moved to
// table 100 except for local routes (table 255); a new default gateway
// route to have been created; and a single rule to exist.
// route to have been created; and two rules to exist.
expNet1 := oldStatus.Devices[0]
expEth0 := oldStatus.Devices[1]
for i := range expNet1.Routes {
Expand All @@ -303,9 +303,14 @@ var _ = Describe("sbr test", func() {
LinkIndex: expNet1.Routes[0].LinkIndex,
})

Expect(newStatus.Rules).To(HaveLen(1))
Expect(newStatus.Rules).To(HaveLen(2))

Expect(newStatus.Rules[0].Table).To(Equal(100))
Expect(newStatus.Rules[0].Src.String()).To(Equal("192.168.1.209/32"))

Expect(newStatus.Rules[1].Table).To(Equal(100))
Expect(newStatus.Rules[1].OifName).To(Equal("net1"))

devNet1 := newStatus.Devices[0]
devEth0 := newStatus.Devices[1]
Expect(equalRoutes(expNet1.Routes, devNet1.Routes)).To(BeTrue())
Expand Down Expand Up @@ -392,7 +397,7 @@ var _ = Describe("sbr test", func() {

// Check results. We expect all the routes on net1 to have moved to
// table 100 except for local routes (table 255); a new default gateway
// route to have been created; and a single rule to exist.
// route to have been created; and two rules to exist.
expNet1 := oldStatus.Devices[0]
expEth0 := oldStatus.Devices[1]
for i := range expNet1.Routes {
Expand All @@ -401,9 +406,14 @@ var _ = Describe("sbr test", func() {
}
}

Expect(newStatus.Rules).To(HaveLen(1))
Expect(newStatus.Rules).To(HaveLen(2))

Expect(newStatus.Rules[0].Table).To(Equal(100))
Expect(newStatus.Rules[0].Src.String()).To(Equal("192.168.1.209/32"))

Expect(newStatus.Rules[1].Table).To(Equal(100))
Expect(newStatus.Rules[1].OifName).To(Equal("net1"))

devNet1 := newStatus.Devices[0]
devEth0 := newStatus.Devices[1]
Expect(equalRoutes(expEth0.Routes, devEth0.Routes)).To(BeTrue())
Expand Down Expand Up @@ -472,7 +482,9 @@ var _ = Describe("sbr test", func() {

// Check results. We expect all the routes on net1 to have moved to
// table 100 except for local routes (table 255); a new default gateway
// route to have been created; and 2 rules to exist.
// route to have been created; and 2 rules to exist. There will be no
// interface rules, because they don't make sense when there are multiple
// IPs for a single interface
expNet1 := oldStatus.Devices[0]
expEth0 := oldStatus.Devices[1]

Expand Down Expand Up @@ -520,7 +532,6 @@ var _ = Describe("sbr test", func() {
Expect(newStatus.Rules[0].Table).To(Equal(101))
Expect(newStatus.Rules[0].Src.String()).To(Equal("192.168.101.209/32"))

// Second entry corresponds to first table (100)
Expect(newStatus.Rules[1].Table).To(Equal(100))
Expect(newStatus.Rules[1].Src.String()).To(Equal("192.168.1.209/32"))

Expand Down