net/netns: refactor the sync.Once usage a bit
// wgengine/router/router_linux.go.
const tailscaleBypassMark = 0x20000
-// checkIPRule runs the ipRuleAvailable check exactly once.
-var checkIPRule sync.Once
+// ipRuleOnce is the sync.Once & cached value for ipRuleAvailable.
+var ipRuleOnce struct {
+ sync.Once
+ v bool
+}
-// ipRuleAvailable is true if and only if the 'ip rule' command works.
+// ipRuleAvailable reports whether the 'ip rule' command works.
// If it doesn't, we have to use SO_BINDTODEVICE on our sockets instead.
-var ipRuleAvailable bool
+func ipRuleAvailable() bool {
+ ipRuleOnce.Do(func() {
+ ipRuleOnce.v = exec.Command("ip", "rule").Run() == nil
+ })
+ return ipRuleOnce.v
+}
// defaultRouteInterface returns the name of the network interface that owns
// the default route, not including any tailscale interfaces. We only use
@@ -98,18 +106,13 @@ func ignoreErrors() bool {
// It's intentionally the same signature as net.Dialer.Control
// and net.ListenConfig.Control.
func control(network, address string, c syscall.RawConn) error {
- checkIPRule.Do(func() {
- _, err := exec.Command("ip", "rule").Output()
- ipRuleAvailable = (err == nil)
- })
-
if skipPrivileged.Get() {
// We can't set socket marks without CAP_NET_ADMIN on linux,
// skip as requested.
return nil
}
- if ipRuleAvailable {
+ if ipRuleAvailable() {
var controlErr error
err := c.Control(func(fd uintptr) {
controlErr = unix.SetsockoptInt(int(fd),
