Skip to content

Commit 7092060

Browse files
committed
fix(rt_tables): add path fallback logic
Ever since version v6.5.0 of iproute2, iproute2 no longer automatically creates the /etc/iproute2 files, instead preferring to add files to /usr/lib/iproute2 and then later on /usr/share/iproute2. This adds fallback path matching to kube-router so that it can find /etc/iproute2/rt_tables wherever it is defined instead of just failing. This also means people running kube-router in containers will need to change their mounts depending on where this file is located on their host OS. However, ensuring that this file is copied to `/etc/iproute2` is a legitimate way to ensure that this is consistent across a fleet of multiple OS versions.
1 parent 7f67791 commit 7092060

File tree

4 files changed

+66
-49
lines changed

4 files changed

+66
-49
lines changed

docs/dsr.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ Requirements:
2727
* `hostIPC: true` must be set for the pod
2828
* `hostPID: true` must be set for the pod
2929
* The container runtime socket must be mounted into the kube-router pod via a `hostPath` volume mount.
30-
* `/etc/iproute2/rt_tables` must be read/write mounted into the kube-router pod via a `hostPath` volume mount.
30+
* `/etc/iproute2/rt_tables` (or similar) must be read/write mounted into the kube-router pod via a `hostPath` volume
31+
mount. NOTE: since v6.5.0 of iproute2 this file has been moved underneath `/usr` in either
32+
`/usr/lib/iproute2/rt_tables` or `/usr/share/iproute2/rt_tables` instead of in `/etc` so this mount may need to be
33+
updated depending on which version of Linux you're deploying against. kube-router will check all 3 locations and
34+
use them in order of the above.
3135
* A pod network that allows for IPIP encapsulated traffic. The most notable exception to this is that Azure does not
3236
transit IPIP encapsulated packets on their network. In this scenario, the end-user may be able to get around this
3337
issue by enabling FoU (`--overlay-encap=fou`) and full overlay networking (`--overlay-type=full`) options in

pkg/controllers/proxy/linux_networking.go

+3-25
Original file line numberDiff line numberDiff line change
@@ -426,22 +426,11 @@ func (ln *linuxNetworking) ipvsAddServer(service *ipvs.Service, dest *ipvs.Desti
426426
// http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.routing_to_VIP-less_director.html
427427
// setupPolicyRoutingForDSR: setups policy routing so that FWMARKed packets are delivered locally
428428
func (ln *linuxNetworking) setupPolicyRoutingForDSR(setupIPv4, setupIPv6 bool) error {
429-
b, err := os.ReadFile("/etc/iproute2/rt_tables")
429+
err := utils.RouteTableAdd(customDSRRouteTableID, customDSRRouteTableName)
430430
if err != nil {
431431
return fmt.Errorf("failed to setup policy routing required for DSR due to %v", err)
432432
}
433433

434-
if !strings.Contains(string(b), customDSRRouteTableName) {
435-
f, err := os.OpenFile("/etc/iproute2/rt_tables", os.O_APPEND|os.O_WRONLY, 0600)
436-
if err != nil {
437-
return fmt.Errorf("failed to setup policy routing required for DSR due to %v", err)
438-
}
439-
defer utils.CloseCloserDisregardError(f)
440-
if _, err = f.WriteString(customDSRRouteTableID + " " + customDSRRouteTableName + "\n"); err != nil {
441-
return fmt.Errorf("failed to setup policy routing required for DSR due to %v", err)
442-
}
443-
}
444-
445434
if setupIPv4 {
446435
out, err := exec.Command("ip", "route", "list", "table", customDSRRouteTableID).Output()
447436
if err != nil || !strings.Contains(string(out), " lo ") {
@@ -470,20 +459,9 @@ func (ln *linuxNetworking) setupPolicyRoutingForDSR(setupIPv4, setupIPv6 bool) e
470459

471460
func (ln *linuxNetworking) setupRoutesForExternalIPForDSR(serviceInfoMap serviceInfoMap,
472461
setupIPv4, setupIPv6 bool) error {
473-
b, err := os.ReadFile("/etc/iproute2/rt_tables")
462+
err := utils.RouteTableAdd(externalIPRouteTableID, externalIPRouteTableName)
474463
if err != nil {
475-
return fmt.Errorf("failed to setup external ip routing table required for DSR due to %v", err)
476-
}
477-
478-
if !strings.Contains(string(b), externalIPRouteTableName) {
479-
f, err := os.OpenFile("/etc/iproute2/rt_tables", os.O_APPEND|os.O_WRONLY, 0600)
480-
if err != nil {
481-
return fmt.Errorf("failed setup external ip routing table required for DSR due to %v", err)
482-
}
483-
defer utils.CloseCloserDisregardError(f)
484-
if _, err = f.WriteString(externalIPRouteTableID + " " + externalIPRouteTableName + "\n"); err != nil {
485-
return fmt.Errorf("failed setup external ip routing table required for DSR due to %v", err)
486-
}
464+
return fmt.Errorf("failed to setup policy routing required for DSR due to %v", err)
487465
}
488466

489467
setupIPRulesAndRoutes := func(ipArgs []string) error {

pkg/controllers/routing/pbr.go

+2-23
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package routing
22

33
import (
44
"fmt"
5-
"os"
65
"os/exec"
76
"strings"
87

@@ -37,7 +36,7 @@ func ipRuleAbstraction(ipProtocol, ipOp, cidr string) error {
3736
// setup a custom routing table that will be used for policy based routing to ensure traffic originating
3837
// on tunnel interface only leaves through tunnel interface irrespective rp_filter enabled/disabled
3938
func (nrc *NetworkRoutingController) enablePolicyBasedRouting() error {
40-
err := rtTablesAdd(customRouteTableID, customRouteTableName)
39+
err := utils.RouteTableAdd(customRouteTableID, customRouteTableName)
4140
if err != nil {
4241
return fmt.Errorf("failed to update rt_tables file: %s", err)
4342
}
@@ -61,7 +60,7 @@ func (nrc *NetworkRoutingController) enablePolicyBasedRouting() error {
6160
}
6261

6362
func (nrc *NetworkRoutingController) disablePolicyBasedRouting() error {
64-
err := rtTablesAdd(customRouteTableID, customRouteTableName)
63+
err := utils.RouteTableAdd(customRouteTableID, customRouteTableName)
6564
if err != nil {
6665
return fmt.Errorf("failed to update rt_tables file: %s", err)
6766
}
@@ -83,23 +82,3 @@ func (nrc *NetworkRoutingController) disablePolicyBasedRouting() error {
8382

8483
return nil
8584
}
86-
87-
func rtTablesAdd(tableNumber, tableName string) error {
88-
b, err := os.ReadFile("/etc/iproute2/rt_tables")
89-
if err != nil {
90-
return fmt.Errorf("failed to read: %s", err.Error())
91-
}
92-
93-
if !strings.Contains(string(b), tableName) {
94-
f, err := os.OpenFile("/etc/iproute2/rt_tables", os.O_APPEND|os.O_WRONLY, 0600)
95-
if err != nil {
96-
return fmt.Errorf("failed to open: %s", err.Error())
97-
}
98-
defer utils.CloseCloserDisregardError(f)
99-
if _, err = f.WriteString(tableNumber + " " + tableName + "\n"); err != nil {
100-
return fmt.Errorf("failed to write: %s", err.Error())
101-
}
102-
}
103-
104-
return nil
105-
}

pkg/utils/linux_routing.go

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"strings"
7+
8+
"k8s.io/klog/v2"
9+
)
10+
11+
const (
12+
rtTablesFileName = "rt_tables"
13+
iproutePkg = "iproute2"
14+
)
15+
16+
var (
17+
rtTablesPosLoc = []string{
18+
fmt.Sprintf("/etc/%s/%s", iproutePkg, rtTablesFileName),
19+
fmt.Sprintf("/usr/lib/%s/%s", iproutePkg, rtTablesFileName),
20+
fmt.Sprintf("/usr/share/%s/%s", iproutePkg, rtTablesFileName),
21+
}
22+
)
23+
24+
// RouteTableAdd adds a new named table to iproute's rt_tables configuration file
25+
func RouteTableAdd(tableNumber, tableName string) error {
26+
var rtTablesLoc string
27+
for _, possibleLoc := range rtTablesPosLoc {
28+
_, err := os.Stat(possibleLoc)
29+
if err != nil {
30+
klog.V(2).Infof("Did not find iproute2's rt_tables in location %s", possibleLoc)
31+
continue
32+
}
33+
rtTablesLoc = possibleLoc
34+
}
35+
if rtTablesLoc == "" {
36+
return fmt.Errorf("did not find rt_tables in any of the expected locations: %s", rtTablesFileName)
37+
}
38+
39+
b, err := os.ReadFile(rtTablesLoc)
40+
if err != nil {
41+
return fmt.Errorf("failed to read: %s", err.Error())
42+
}
43+
44+
if !strings.Contains(string(b), tableName) {
45+
f, err := os.OpenFile(rtTablesLoc, os.O_APPEND|os.O_WRONLY, 0600)
46+
if err != nil {
47+
return fmt.Errorf("failed to open: %s", err.Error())
48+
}
49+
defer CloseCloserDisregardError(f)
50+
if _, err = f.WriteString(tableNumber + " " + tableName + "\n"); err != nil {
51+
return fmt.Errorf("failed to write: %s", err.Error())
52+
}
53+
}
54+
55+
return nil
56+
}

0 commit comments

Comments
 (0)