|
|
@@ -48,18 +48,12 @@ func resolveGatewayInterface(gwIP string) string {
|
|
|
return ""
|
|
|
}
|
|
|
|
|
|
-// probeRouteHealth tests reachability of a gateway or public internet host bound to a specific interface
|
|
|
-func probeRouteHealth(target string, iface string) (bool, float64, float64, error) {
|
|
|
- target = strings.TrimSpace(target)
|
|
|
- if target == "" {
|
|
|
- return false, 0, 100, fmt.Errorf("empty probe target")
|
|
|
- }
|
|
|
-
|
|
|
+func probeRouteHealthOnce(target string, iface string) (bool, float64, float64) {
|
|
|
var args []string
|
|
|
if iface != "" {
|
|
|
- args = []string{"-c", "2", "-W", "1", "-I", iface, target}
|
|
|
+ args = []string{"-c", "3", "-W", "2", "-i", "0.3", "-I", iface, target}
|
|
|
} else {
|
|
|
- args = []string{"-c", "2", "-W", "1", target}
|
|
|
+ args = []string{"-c", "3", "-W", "2", "-i", "0.3", target}
|
|
|
}
|
|
|
|
|
|
cmd := exec.Command("ping", args...)
|
|
|
@@ -67,10 +61,9 @@ func probeRouteHealth(target string, iface string) (bool, float64, float64, erro
|
|
|
cmd.Stdout = &outBuf
|
|
|
cmd.Stderr = &outBuf
|
|
|
|
|
|
- err := cmd.Run()
|
|
|
+ _ = cmd.Run()
|
|
|
output := outBuf.String()
|
|
|
|
|
|
- // Parse packet loss
|
|
|
lossPct := 100.0
|
|
|
if match := pingLossRegex.FindStringSubmatch(output); len(match) > 1 {
|
|
|
if val, err := strconv.ParseFloat(match[1], 64); err == nil {
|
|
|
@@ -78,7 +71,6 @@ func probeRouteHealth(target string, iface string) (bool, float64, float64, erro
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Parse average RTT
|
|
|
var avgRtt float64
|
|
|
if match := pingRttRegex.FindStringSubmatch(output); len(match) > 1 {
|
|
|
if val, err := strconv.ParseFloat(match[1], 64); err == nil {
|
|
|
@@ -86,8 +78,34 @@ func probeRouteHealth(target string, iface string) (bool, float64, float64, erro
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- isUp := (lossPct < 100.0) && (err == nil || lossPct < 50.0)
|
|
|
- return isUp, avgRtt, lossPct, nil
|
|
|
+ isUp := (lossPct < 100.0)
|
|
|
+ return isUp, avgRtt, lossPct
|
|
|
+}
|
|
|
+
|
|
|
+// probeRouteHealth tests reachability of a gateway or public internet host bound to a specific interface
|
|
|
+func probeRouteHealth(target string, iface string) (bool, float64, float64, error) {
|
|
|
+ target = strings.TrimSpace(target)
|
|
|
+ if target == "" {
|
|
|
+ return false, 0, 100, fmt.Errorf("empty probe target")
|
|
|
+ }
|
|
|
+
|
|
|
+ isUp, avgRtt, lossPct := probeRouteHealthOnce(target, iface)
|
|
|
+ if isUp {
|
|
|
+ return true, avgRtt, lossPct, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Secondary fallback target to avoid false failovers from CDN ICMP drops
|
|
|
+ fallbackTarget := "8.8.8.8"
|
|
|
+ if target == "8.8.8.8" || target == "8.8.4.4" {
|
|
|
+ fallbackTarget = "1.1.1.1"
|
|
|
+ }
|
|
|
+
|
|
|
+ fallbackUp, fallbackRtt, fallbackLoss := probeRouteHealthOnce(fallbackTarget, iface)
|
|
|
+ if fallbackUp {
|
|
|
+ return true, fallbackRtt, fallbackLoss, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return false, avgRtt, lossPct, nil
|
|
|
}
|
|
|
|
|
|
// startHealthCheckWorker initiates background internet connectivity probing for static routes
|
|
|
@@ -153,8 +171,8 @@ func (m *RoutingManager) checkAllRoutesHealth(now time.Time) {
|
|
|
|
|
|
// Threshold
|
|
|
threshold := r.CheckThreshold
|
|
|
- if threshold <= 0 {
|
|
|
- threshold = 3
|
|
|
+ if threshold < 5 {
|
|
|
+ threshold = 5
|
|
|
}
|
|
|
|
|
|
// Execute probe asynchronously with timeout to prevent blocking routing manager lock
|