From 629aac1078bdeed63214c58d2110fe672d654774 Mon Sep 17 00:00:00 2001 From: yangfeiyu Date: Mon, 26 Oct 2020 20:39:05 +0800 Subject: [PATCH] kata-agent: update nic in guest reason: add linkByName and support retry of list ip link, because in some scenarios, the hardware address cannot be queried immediately after the hot plug. Signed-off-by: yangfeiyu --- network.go | 91 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/network.go b/network.go index f6e2c17..d928e2b 100644 --- a/network.go +++ b/network.go @@ -15,13 +15,14 @@ import ( "strings" "sync" "syscall" + "time" - "golang.org/x/sys/unix" agentNet "github.com/kata-containers/agent/pkg/net" "github.com/kata-containers/agent/pkg/types" pb "github.com/kata-containers/agent/protocols/grpc" "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + "golang.org/x/sys/unix" "google.golang.org/grpc/codes" grpcStatus "google.golang.org/grpc/status" ) @@ -32,6 +33,7 @@ var ( errNoLink = grpcStatus.Errorf(codes.InvalidArgument, "Need network link") errNoMAC = grpcStatus.Errorf(codes.InvalidArgument, "Need hardware address") errNoRoutes = grpcStatus.Errorf(codes.InvalidArgument, "Need network routes") + errNoName = grpcStatus.Errorf(codes.InvalidArgument, "Need network name") guestDNSFile = "/etc/resolv.conf" kataGuestSandboxDNSFile = "/run/kata-containers/sandbox/resolv.conf" ) @@ -46,6 +48,8 @@ const ( // Use the below address for ipv6 gateway once ipv6 support is added // defaultV6RouteIP = "::" + + maxLinkRetries = 10 ) // Network fully describes a sandbox network with its interfaces, routes and dns @@ -100,17 +104,36 @@ func linkByHwAddr(netHandle *netlink.Handle, hwAddr string) (netlink.Link, error return nil, grpcStatus.Errorf(codes.NotFound, "Could not find the link corresponding to HwAddr %q", hwAddr) } -func updateLink(netHandle *netlink.Handle, link netlink.Link, iface *types.Interface) error { +func linkByName(netHandle *netlink.Handle, name string) (netlink.Link, error) { if netHandle == nil { - return errNoHandle + return nil, errNoHandle } - if link == nil { - return errNoLink + if name == "" { + return nil, errNoName } - if iface == nil { - return errNoIF + links, err := netHandle.LinkList() + if err != nil { + return nil, err + } + + for _, link := range links { + if link == nil { + continue + } + + if link.Attrs() != nil && link.Attrs().Name == name { + return link, nil + } + } + + return nil, grpcStatus.Errorf(codes.NotFound, "Could not find the link corresponding to name %s", name) +} + +func updateLinkIP(netHandle *netlink.Handle, link netlink.Link, iface *types.Interface) error { + if len(iface.IPAddresses) == 0 { + return nil } // As a first step, clear out any existing addresses associated with the link: @@ -129,13 +152,6 @@ func updateLink(netHandle *netlink.Handle, link netlink.Link, iface *types.Inter netlinkAddrStr := fmt.Sprintf("%s/%s", addr.Address, addr.Mask) netlinkAddr, err := netlink.ParseAddr(netlinkAddrStr) - // With ipv6 addresses, there is a brief period during which the address is marked as "tentative" - // making it unavailable. A process called duplicate address detection(DAD) is performed during this period. - // Disble DAD so that networking is available once the container is up. The assumption is - // that it is the reponsibility of the upper stack to make sure the addresses assigned to containers - // do not conflict. A similar operation is performed by libnetwork: - // https://github.com/moby/moby/issues/18871 - if addr.GetFamily() == types.IPFamily_v6 { netlinkAddr.Flags = netlinkAddr.Flags | syscall.IFA_F_NODAD } @@ -150,14 +166,36 @@ func updateLink(netHandle *netlink.Handle, link netlink.Link, iface *types.Inter } } + return nil +} + +func updateLink(netHandle *netlink.Handle, link netlink.Link, iface *types.Interface) error { + if netHandle == nil { + return errNoHandle + } + + if link == nil { + return errNoLink + } + + if iface == nil { + return errNoIF + } + + if err := updateLinkIP(netHandle, link, iface); err != nil { + return err + } + // set the interface name: if err := netHandle.LinkSetName(link, iface.Name); err != nil { return grpcStatus.Errorf(codes.Internal, "Could not set name %s for interface %v: %v", iface.Name, link, err) } // set the interface MTU: - if err := netHandle.LinkSetMTU(link, int(iface.Mtu)); err != nil { - return grpcStatus.Errorf(codes.Internal, "Could not set MTU %d for interface %v: %v", iface.Mtu, link, err) + if iface.Mtu > 0 { + if err := netHandle.LinkSetMTU(link, int(iface.Mtu)); err != nil { + return grpcStatus.Errorf(codes.Internal, "Could not set MTU %d for interface %v: %v", iface.Mtu, link, err) + } } if iface.RawFlags&unix.IFF_NOARP == uint32(unix.IFF_NOARP) { @@ -306,8 +344,23 @@ func (s *sandbox) updateInterface(netHandle *netlink.Handle, iface *types.Interf if iface.HwAddr != "" { fieldLogger.Info("Getting interface from MAC address") - // Find the interface link from its hardware address. - link, err = linkByHwAddr(netHandle, iface.HwAddr) + // In some scenarios, the hardware address cannot be queried immediately + // after the hot plug, add a retry here. + for retry := 0; retry < maxLinkRetries; retry++ { + // Find the interface link from its hardware address. + link, err = linkByHwAddr(netHandle, iface.HwAddr) + if err != nil { + time.Sleep(100 * time.Millisecond) + continue + } + break + } + if err != nil { + return nil, grpcStatus.Errorf(codes.Internal, "updateInterface: %v", err) + } + } else if iface.Name != "" { + fieldLogger.Info("Getting interface from name") + link, err = linkByName(netHandle, iface.Name) if err != nil { return nil, grpcStatus.Errorf(codes.Internal, "updateInterface: %v", err) } @@ -487,7 +540,7 @@ func (s *sandbox) updateRoutes(netHandle *netlink.Handle, requestedRoutes *pb.Ro }() var ( - added []*types.Route + added []*types.Route removed []*types.Route ) -- 2.23.0