diff --git a/pkg/link/opstate.go b/pkg/link/opstate.go new file mode 100644 index 000000000..736ea4647 --- /dev/null +++ b/pkg/link/opstate.go @@ -0,0 +1,56 @@ +// Copyright 2024 CNI authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package link + +import ( + "fmt" + "time" + + "github.com/vishvananda/netlink" +) + +func WaitForOperStateUp(linkName string) (netlink.Link, error) { + var link netlink.Link + var err error + retries := []int{0, 50, 500, 1000, 1000} + for idx, sleep := range retries { + time.Sleep(time.Duration(sleep) * time.Millisecond) + + link, err = netlink.LinkByName(linkName) + if err != nil { + return nil, err + } + linkOpState := link.Attrs().OperState + if linkOpState == netlink.OperUp { + break + } + + if idx == len(retries)-1 { + return nil, fmt.Errorf("timeout waiting for %q state %q to be up", linkName, linkOpState) + } + } + return link, nil +} + +func SetUp(linkName string) error { + link, err := netlink.LinkByName(linkName) + if err != nil { + return fmt.Errorf("failed to retrieve link: %w", err) + } + if err = netlink.LinkSetUp(link); err != nil { + return fmt.Errorf("failed to set %q up: %w", linkName, err) + } + return nil +} diff --git a/plugins/main/bridge/bridge.go b/plugins/main/bridge/bridge.go index a24d2d4aa..0278ce29d 100644 --- a/plugins/main/bridge/bridge.go +++ b/plugins/main/bridge/bridge.go @@ -23,7 +23,6 @@ import ( "runtime" "sort" "syscall" - "time" "github.com/vishvananda/netlink" @@ -677,39 +676,18 @@ func cmdAdd(args *skel.CmdArgs) error { } } } else { + // If layer 2 we still need to set the container veth to up if err := netns.Do(func(_ ns.NetNS) error { - link, err := netlink.LinkByName(args.IfName) - if err != nil { - return fmt.Errorf("failed to retrieve link: %v", err) - } - // If layer 2 we still need to set the container veth to up - if err = netlink.LinkSetUp(link); err != nil { - return fmt.Errorf("failed to set %q up: %v", args.IfName, err) - } - return nil + return link.SetUp(args.IfName) }); err != nil { return err } } - var hostVeth netlink.Link - // check bridge port state - retries := []int{0, 50, 500, 1000, 1000} - for idx, sleep := range retries { - time.Sleep(time.Duration(sleep) * time.Millisecond) - - hostVeth, err = netlink.LinkByName(hostInterface.Name) - if err != nil { - return err - } - if hostVeth.Attrs().OperState == netlink.OperUp { - break - } - - if idx == len(retries)-1 { - return fmt.Errorf("bridge port in error state: %s", hostVeth.Attrs().OperState) - } + hostVeth, err := link.WaitForOperStateUp(hostInterface.Name) + if err != nil { + return fmt.Errorf("bridge port in error state %q: %v", hostVeth.Attrs().OperState, err) } // In certain circumstances, the host-side of the veth may change addrs