diff --git a/cmd/sriov/main.go b/cmd/sriov/main.go index 6f34bde0..cfd35891 100644 --- a/cmd/sriov/main.go +++ b/cmd/sriov/main.go @@ -5,6 +5,7 @@ import ( "fmt" "runtime" "strings" + "time" "github.com/containernetworking/cni/pkg/skel" "github.com/containernetworking/cni/pkg/types" @@ -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 }) } diff --git a/pkg/utils/packet.go b/pkg/utils/packet.go index 7628dc82..809b4ded 100644 --- a/pkg/utils/packet.go +++ b/pkg/utils/packet.go @@ -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 ( @@ -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 +}