Skip to content

Commit

Permalink
Wait for carrier before announcing IPs via GARP/NA
Browse files Browse the repository at this point in the history
After setting up the interface, it might take a bit for kernel to detect
carrier. If we then already send the GARP/NA packets, they are lost.

Instead, wait for up to 200 msec for the interface to get carrier. This
time is chosen somewhat arbitrarily. We don't want to block the process
too long, but we also need to wait long enough, that kernel and driver
has time to detect carrier. Also, while busy waiting, sleep with an
exponential back-off time (growth factor 1.5).

Fixes: c241dcb ('Send IPv4 GARP and IPv6 Unsolicited NA in "cmdAdd"')

See-also: https://issues.redhat.com/browse/OCPBUGS-30549

Signed-off-by: Thomas Haller <[email protected]>
  • Loading branch information
thom311 committed May 30, 2024
1 parent b482f4b commit 37ac7e3
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 3 deletions.
12 changes: 9 additions & 3 deletions cmd/sriov/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"runtime"
"strings"
"time"

"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
Expand Down Expand Up @@ -205,10 +206,15 @@ func cmdAdd(args *skel.CmdArgs) error {
* may be sending packets with the incorrect link-layer address. Eventually, most network stacks would send ARPs and/or Neighbor
* Solicitation packets when the connection is unreachable. This would correct the invalid cache; however this may take a significant
* amount of time to complete.
*
* The error is ignored here because enabling this feature is only a performance enhancement.
*/
_ = utils.AnnounceIPs(args.IfName, result.IPs)

/* The interface might not yet have carrier. Wait for it for a short time. */
hasCarrier := utils.WaitForCarrier(args.IfName, 200*time.Millisecond)

/* The error is ignored here because enabling this feature is only a performance enhancement. */
err = utils.AnnounceIPs(args.IfName, result.IPs)

logging.Debug("announcing IPs", "hasCarrier", hasCarrier, "IPs", result.IPs, "announceError", err)
return nil
})
}
Expand Down
32 changes: 32 additions & 0 deletions pkg/utils/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import (
"fmt"
"net"
"syscall"
"time"

current "github.com/containernetworking/cni/pkg/types/100"
"github.com/vishvananda/netlink"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
"golang.org/x/sys/unix"
)

var (
Expand Down Expand Up @@ -196,3 +198,33 @@ func AnnounceIPs(ifName string, ipConfigs []*current.IPConfig) error {
}
return nil
}

// Blocking wait for interface ifName to have carrier (!NO_CARRIER flag).
func WaitForCarrier(ifName string, waitTime time.Duration) bool {
var sleepDuration time.Duration

myNetLink := MyNetlink{}

start := time.Now()

for time.Since(start) < waitTime {
if sleepDuration == 0 {
sleepDuration = 2 * time.Millisecond
} else {
time.Sleep(sleepDuration)
/* Grow wait time exponentionally (factor 1.5). */
sleepDuration += sleepDuration / 2
}

linkObj, err := myNetLink.LinkByName(ifName)
if err != nil {
return false
}

if linkObj.Attrs().RawFlags&unix.IFF_NO_CARRIER != 0 {
return true
}
}

return false
}

0 comments on commit 37ac7e3

Please sign in to comment.