|
|
@@ -928,6 +928,15 @@ func (m *RoutingManager) SetRouteState(id string, disabled bool) error {
|
|
|
return fmt.Errorf("route not found")
|
|
|
}
|
|
|
|
|
|
+func sliceContains(list []string, item string) bool {
|
|
|
+ for _, s := range list {
|
|
|
+ if s == item {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
func normalizeDst(dst string) string {
|
|
|
dst = strings.TrimSpace(dst)
|
|
|
if dst == "" || dst == "default" || dst == "0.0.0.0/0" {
|
|
|
@@ -1066,9 +1075,11 @@ func (m *RoutingManager) syncRouteGroupToKernel(dstAddress, routingTable string,
|
|
|
} else {
|
|
|
args = []string{"route", "replace", normDst}
|
|
|
iface := strings.TrimSpace(r.Interface)
|
|
|
+ hasVia := false
|
|
|
if gw != "" {
|
|
|
if net.ParseIP(gw) != nil {
|
|
|
args = append(args, "via", gw)
|
|
|
+ hasVia = true
|
|
|
} else {
|
|
|
// Gateway field contains an interface name
|
|
|
targetDev := gw
|
|
|
@@ -1077,6 +1088,7 @@ func (m *RoutingManager) syncRouteGroupToKernel(dstAddress, routingTable string,
|
|
|
}
|
|
|
if detectedGw := detectGatewayForInterface(targetDev); detectedGw != "" {
|
|
|
args = append(args, "via", detectedGw)
|
|
|
+ hasVia = true
|
|
|
} else {
|
|
|
args = append(args, "dev", targetDev)
|
|
|
}
|
|
|
@@ -1085,7 +1097,7 @@ func (m *RoutingManager) syncRouteGroupToKernel(dstAddress, routingTable string,
|
|
|
if iface != "" && (gw == "" || net.ParseIP(gw) != nil || (gw != "" && detectGatewayForInterface(gw) != "")) {
|
|
|
args = append(args, "dev", iface)
|
|
|
}
|
|
|
- if iface != "" && (gw != "" || detectGatewayForInterface(iface) != "") {
|
|
|
+ if hasVia && iface != "" {
|
|
|
args = append(args, "onlink")
|
|
|
}
|
|
|
}
|
|
|
@@ -1099,6 +1111,17 @@ func (m *RoutingManager) syncRouteGroupToKernel(dstAddress, routingTable string,
|
|
|
|
|
|
cmd := exec.Command("ip", args...)
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
+ if sliceContains(args, "onlink") {
|
|
|
+ var noOnlinkArgs []string
|
|
|
+ for _, a := range args {
|
|
|
+ if a != "onlink" {
|
|
|
+ noOnlinkArgs = append(noOnlinkArgs, a)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if _, fbErr := exec.Command("ip", noOnlinkArgs...).CombinedOutput(); fbErr == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
return fmt.Errorf("failed to apply route (%s): %s: %w", strings.Join(args, " "), string(out), err)
|
|
|
}
|
|
|
return nil
|
|
|
@@ -1121,21 +1144,38 @@ func (m *RoutingManager) syncRouteGroupToKernel(dstAddress, routingTable string,
|
|
|
if iface == "" && gw != "" && net.ParseIP(gw) == nil {
|
|
|
iface = gw
|
|
|
}
|
|
|
+ hasVia := false
|
|
|
if gw != "" && net.ParseIP(gw) != nil {
|
|
|
args = append(args, "via", gw)
|
|
|
+ hasVia = true
|
|
|
} else if iface != "" {
|
|
|
if detectedGw := detectGatewayForInterface(iface); detectedGw != "" {
|
|
|
args = append(args, "via", detectedGw)
|
|
|
+ hasVia = true
|
|
|
}
|
|
|
}
|
|
|
if iface != "" {
|
|
|
- args = append(args, "dev", iface, "onlink")
|
|
|
+ args = append(args, "dev", iface)
|
|
|
+ }
|
|
|
+ if hasVia && iface != "" {
|
|
|
+ args = append(args, "onlink")
|
|
|
}
|
|
|
args = append(args, "weight", "1")
|
|
|
}
|
|
|
|
|
|
cmd := exec.Command("ip", args...)
|
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
|
+ if sliceContains(args, "onlink") {
|
|
|
+ var noOnlinkArgs []string
|
|
|
+ for _, a := range args {
|
|
|
+ if a != "onlink" {
|
|
|
+ noOnlinkArgs = append(noOnlinkArgs, a)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if _, fbErr := exec.Command("ip", noOnlinkArgs...).CombinedOutput(); fbErr == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ }
|
|
|
return fmt.Errorf("failed to apply multipath route (%s): %s: %w", strings.Join(args, " "), string(out), err)
|
|
|
}
|
|
|
return nil
|