internal/socket: update zoneCache on cache misses to cover appearing interfaces

Updates golang/go#28535

Change-Id: Id653b21b4d893cc8b6b9a74b129d1ce9b7e26a9f
Reviewed-on: https://go-review.googlesource.com/c/147739
Reviewed-by: Mikio Hara <mikioh.public.networking@gmail.com>
Run-TryBot: Mikio Hara <mikioh.public.networking@gmail.com>
diff --git a/internal/socket/sys_posix.go b/internal/socket/sys_posix.go
index dc130c2..646cc2d 100644
--- a/internal/socket/sys_posix.go
+++ b/internal/socket/sys_posix.go
@@ -121,18 +121,21 @@
 	toName:  make(map[int]string),
 }
 
-func (zc *ipv6ZoneCache) update(ift []net.Interface) {
+// update refreshes the network interface information if the cache was last
+// updated more than 1 minute ago, or if force is set. It returns whether the
+// cache was updated.
+func (zc *ipv6ZoneCache) update(ift []net.Interface, force bool) (updated bool) {
 	zc.Lock()
 	defer zc.Unlock()
 	now := time.Now()
-	if zc.lastFetched.After(now.Add(-60 * time.Second)) {
-		return
+	if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
+		return false
 	}
 	zc.lastFetched = now
 	if len(ift) == 0 {
 		var err error
 		if ift, err = net.Interfaces(); err != nil {
-			return
+			return false
 		}
 	}
 	zc.toIndex = make(map[string]int, len(ift))
@@ -143,13 +146,22 @@
 			zc.toName[ifi.Index] = ifi.Name
 		}
 	}
+	return true
 }
 
 func (zc *ipv6ZoneCache) name(zone int) string {
-	zoneCache.update(nil)
+	updated := zoneCache.update(nil, false)
 	zoneCache.RLock()
-	defer zoneCache.RUnlock()
 	name, ok := zoneCache.toName[zone]
+	zoneCache.RUnlock()
+	if !ok {
+		if !updated {
+			zoneCache.update(nil, true)
+			zoneCache.RLock()
+			name, ok = zoneCache.toName[zone]
+			zoneCache.RUnlock()
+		}
+	}
 	if !ok {
 		name = strconv.Itoa(zone)
 	}
@@ -157,10 +169,18 @@
 }
 
 func (zc *ipv6ZoneCache) index(zone string) int {
-	zoneCache.update(nil)
+	updated := zoneCache.update(nil, false)
 	zoneCache.RLock()
-	defer zoneCache.RUnlock()
 	index, ok := zoneCache.toIndex[zone]
+	zoneCache.RUnlock()
+	if !ok {
+		if !updated {
+			zoneCache.update(nil, true)
+			zoneCache.RLock()
+			index, ok = zoneCache.toIndex[zone]
+			zoneCache.RUnlock()
+		}
+	}
 	if !ok {
 		index, _ = strconv.Atoi(zone)
 	}