From 00bf437d84ac1aec5ce24ffc5f1b7dbb6309263b Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Tue, 3 Sep 2024 12:35:36 +0100 Subject: [PATCH 1/2] Add nlutil functions to retry on netlink EINTR A recent change to the vishvananda/netlink package exposes NLM_F_DUMP_INTR in some netlink responses as an EINTR (with no data). Retry the requests when that happens, up to five times, before returning the error. The limit of five is arbitrary, on most systems a single retry will be rare but, there's no guarantee that a retry will succeed. So, on a very busy or misbehaving system the error may still be returned. In most cases, this will lead to failure of the operation being attempted (which may lead to daemon startup failure, network initialisation failure etc). Signed-off-by: Rob Murray --- daemon/cluster/listen_addr_linux.go | 5 +- daemon/daemon_unix.go | 3 +- .../docker_cli_network_unix_test.go | 7 +- integration-cli/docker_cli_swarm_test.go | 3 +- internal/nlwrap/nlwrap_linux.go | 172 ++++++++++++++++++ libnetwork/drivers/bridge/bridge_linux.go | 9 +- .../drivers/bridge/bridge_linux_test.go | 3 +- libnetwork/drivers/bridge/interface_linux.go | 5 +- .../drivers/bridge/interface_linux_test.go | 7 +- .../drivers/bridge/network_linux_test.go | 6 +- .../drivers/bridge/setup_device_linux_test.go | 12 +- .../drivers/bridge/setup_ip_tables_linux.go | 4 +- .../bridge/setup_ip_tables_linux_test.go | 8 +- .../drivers/bridge/setup_ipv4_linux_test.go | 7 +- .../drivers/bridge/setup_ipv6_linux_test.go | 5 +- .../drivers/bridge/setup_verify_linux_test.go | 3 +- libnetwork/drivers/overlay/ov_network.go | 3 +- libnetwork/drivers/overlay/ov_utils.go | 3 +- libnetwork/iptables/conntrack.go | 9 +- libnetwork/libnetwork_linux_test.go | 4 +- libnetwork/netutils/utils_linux.go | 13 +- libnetwork/ns/init_linux.go | 8 +- libnetwork/osl/interface_linux.go | 23 +-- libnetwork/osl/namespace_linux.go | 11 +- libnetwork/osl/sandbox_linux_test.go | 5 +- 25 files changed, 263 insertions(+), 75 deletions(-) create mode 100644 internal/nlwrap/nlwrap_linux.go diff --git a/daemon/cluster/listen_addr_linux.go b/daemon/cluster/listen_addr_linux.go index 62e4f61a6534f..e8e2bddadcd84 100644 --- a/daemon/cluster/listen_addr_linux.go +++ b/daemon/cluster/listen_addr_linux.go @@ -3,13 +3,14 @@ package cluster // import "github.com/docker/docker/daemon/cluster" import ( "net" + "github.com/docker/docker/internal/nlwrap" "github.com/vishvananda/netlink" ) func (c *Cluster) resolveSystemAddr() (net.IP, error) { // Use the system's only device IP address, or fail if there are // multiple addresses to choose from. - interfaces, err := netlink.LinkList() + interfaces, err := nlwrap.LinkList() if err != nil { return nil, err } @@ -26,7 +27,7 @@ func (c *Cluster) resolveSystemAddr() (net.IP, error) { continue } - addrs, err := netlink.AddrList(intf, netlink.FAMILY_ALL) + addrs, err := nlwrap.AddrList(intf, netlink.FAMILY_ALL) if err != nil { continue } diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 10ab139245a53..408dd53cb5b00 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -27,6 +27,7 @@ import ( "github.com/docker/docker/daemon/config" "github.com/docker/docker/daemon/initlayer" "github.com/docker/docker/errdefs" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libcontainerd/remote" "github.com/docker/docker/libnetwork" nwconfig "github.com/docker/docker/libnetwork/config" @@ -1065,7 +1066,7 @@ func initBridgeDriver(controller *libnetwork.Controller, cfg config.BridgeConfig // Remove default bridge interface if present (--bridge=none use case) func removeDefaultBridgeInterface() { - if lnk, err := netlink.LinkByName(bridge.DefaultBridgeName); err == nil { + if lnk, err := nlwrap.LinkByName(bridge.DefaultBridgeName); err == nil { if err := netlink.LinkDel(lnk); err != nil { log.G(context.TODO()).Warnf("Failed to remove bridge interface (%s): %v", bridge.DefaultBridgeName, err) } diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go index a81da8a6de5ec..825caffb76d3b 100644 --- a/integration-cli/docker_cli_network_unix_test.go +++ b/integration-cli/docker_cli_network_unix_test.go @@ -18,6 +18,7 @@ import ( "github.com/docker/docker/api/types/network" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/daemon" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/driverapi" remoteapi "github.com/docker/docker/libnetwork/drivers/remote/api" "github.com/docker/docker/libnetwork/ipamapi" @@ -120,7 +121,7 @@ func setupRemoteNetworkDrivers(t *testing.T, mux *http.ServeMux, url, netDrv, ip mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", plugins.VersionMimetype) - if link, err := netlink.LinkByName("cnt0"); err == nil { + if link, err := nlwrap.LinkByName("cnt0"); err == nil { err = netlink.LinkDel(link) assert.NilError(t, err) } @@ -1778,7 +1779,7 @@ func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *testing.T) { cli.DockerCmd(c, "run", "-d", "--name", "client", "--net=host", "busybox", "sh", "-c", cmd) // Get all the flows using netlink - flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) + flows, err := nlwrap.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) assert.NilError(c, err) var flowMatch int for _, flow := range flows { @@ -1796,7 +1797,7 @@ func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *testing.T) { cli.DockerCmd(c, "rm", "-fv", "server") // Fetch again all the flows and validate that there is no server flow in the conntrack laying around - flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) + flows, err = nlwrap.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET) assert.NilError(c, err) flowMatch = 0 for _, flow := range flows { diff --git a/integration-cli/docker_cli_swarm_test.go b/integration-cli/docker_cli_swarm_test.go index 1420f1a8ed72c..a32ddc035dd3b 100644 --- a/integration-cli/docker_cli_swarm_test.go +++ b/integration-cli/docker_cli_swarm_test.go @@ -22,6 +22,7 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/daemon" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/driverapi" "github.com/docker/docker/libnetwork/ipamapi" remoteipam "github.com/docker/docker/libnetwork/ipams/remote/api" @@ -718,7 +719,7 @@ func setupRemoteGlobalNetworkPlugin(t *testing.T, mux *http.ServeMux, url, netDr mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", plugins.VersionMimetype) - if link, err := netlink.LinkByName("cnt0"); err == nil { + if link, err := nlwrap.LinkByName("cnt0"); err == nil { err := netlink.LinkDel(link) assert.NilError(t, err) } diff --git a/internal/nlwrap/nlwrap_linux.go b/internal/nlwrap/nlwrap_linux.go new file mode 100644 index 0000000000000..cda5e25a7af80 --- /dev/null +++ b/internal/nlwrap/nlwrap_linux.go @@ -0,0 +1,172 @@ +// Package nlwrap wraps vishvandanda/netlink functions that may return EINTR. +// +// A Handle instantiated using [NewHandle] or [NewHandleAt] can be used in place +// of a netlink.Handle, it's a wrapper that replaces methods that need to be +// wrapped. Functions that use the package handle need to be called as "nlwrap.X" +// instead of "netlink.X". +// +// The wrapped functions currently return EINTR when NLM_F_DUMP_INTR flagged +// in a netlink response, meaning something changed during the dump so results +// may be incomplete or inconsistent. +// +// At present, the possibly incomplete/inconsistent results are not returned +// by netlink functions along with the EINTR. So, it's not possible to do +// anything but retry. After maxAttempts the EINTR will be returned to the +// caller. +package nlwrap + +import ( + "context" + "errors" + + "github.com/containerd/log" + "github.com/vishvananda/netlink" + "github.com/vishvananda/netns" + "golang.org/x/sys/unix" +) + +// Arbitrary limit on max attempts at netlink calls if they are repeatedly interrupted. +const maxAttempts = 5 + +type Handle struct { + *netlink.Handle +} + +func NewHandle(nlFamilies ...int) (Handle, error) { + nlh, err := netlink.NewHandle(nlFamilies...) + if err != nil { + return Handle{}, err + } + return Handle{nlh}, nil +} + +func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (Handle, error) { + nlh, err := netlink.NewHandleAt(ns, nlFamilies...) + if err != nil { + return Handle{}, err + } + return Handle{nlh}, nil +} + +func (h Handle) Close() { + if h.Handle != nil { + h.Handle.Close() + } +} + +func retryOnIntr(f func() error) { + for attempt := 0; attempt < maxAttempts; attempt += 1 { + if err := f(); !errors.Is(err, unix.EINTR) { + return + } + } + log.G(context.TODO()).Infof("netlink call interrupted after %d attempts", maxAttempts) +} + +// AddrList calls nlh.LinkList, retrying if necessary. +func (nlh Handle) AddrList(link netlink.Link, family int) (addrs []netlink.Addr, err error) { + retryOnIntr(func() error { + addrs, err = nlh.Handle.AddrList(link, family) + return err + }) + return addrs, err +} + +// AddrList calls netlink.LinkList, retrying if necessary. +func AddrList(link netlink.Link, family int) (addrs []netlink.Addr, err error) { + retryOnIntr(func() error { + addrs, err = netlink.AddrList(link, family) + return err + }) + return addrs, err +} + +// ConntrackDeleteFilters calls nlh.ConntrackDeleteFilters, retrying if necessary. +func (nlh Handle) ConntrackDeleteFilters( + table netlink.ConntrackTableType, + family netlink.InetFamily, + filters ...netlink.CustomConntrackFilter, +) (matched uint, err error) { + retryOnIntr(func() error { + matched, err = nlh.Handle.ConntrackDeleteFilters(table, family, filters...) + return err + }) + return matched, err +} + +// ConntrackTableList calls netlink.ConntrackTableList, retrying if necessary. +func ConntrackTableList( + table netlink.ConntrackTableType, + family netlink.InetFamily, +) (flows []*netlink.ConntrackFlow, err error) { + retryOnIntr(func() error { + flows, err = netlink.ConntrackTableList(table, family) + return err + }) + return flows, err +} + +// LinkByName calls nlh.LinkByName, retrying if necessary. The netlink function +// doesn't normally ask the kernel for a dump of links. But, on an old kernel, it +// will do as a fallback and that dump may get inconsistent results. +func (nlh Handle) LinkByName(name string) (link netlink.Link, err error) { + retryOnIntr(func() error { + link, err = nlh.Handle.LinkByName(name) + return err + }) + return link, err +} + +// LinkByName calls netlink.LinkByName, retrying if necessary. The netlink +// function doesn't normally ask the kernel for a dump of links. But, on an old +// kernel, it will do as a fallback and that dump may get inconsistent results. +func LinkByName(name string) (link netlink.Link, err error) { + retryOnIntr(func() error { + link, err = netlink.LinkByName(name) + return err + }) + return link, err +} + +// LinkList calls nlh.LinkList, retrying if necessary. +func (nlh Handle) LinkList() (links []netlink.Link, err error) { + retryOnIntr(func() error { + links, err = nlh.Handle.LinkList() + return err + }) + return links, err +} + +// LinkList calls netlink.LinkList, retrying if necessary. +func LinkList() (links []netlink.Link, err error) { + retryOnIntr(func() error { + links, err = netlink.LinkList() + return err + }) + return links, err +} + +// RouteList calls nlh.RouteList, retrying if necessary. +func (nlh Handle) RouteList(link netlink.Link, family int) (routes []netlink.Route, err error) { + retryOnIntr(func() error { + routes, err = nlh.Handle.RouteList(link, family) + return err + }) + return routes, err +} + +func (nlh Handle) XfrmPolicyList(family int) (policies []netlink.XfrmPolicy, err error) { + retryOnIntr(func() error { + policies, err = nlh.Handle.XfrmPolicyList(family) + return err + }) + return policies, err +} + +func (nlh Handle) XfrmStateList(family int) (states []netlink.XfrmState, err error) { + retryOnIntr(func() error { + states, err = nlh.Handle.XfrmStateList(family) + return err + }) + return states, err +} diff --git a/libnetwork/drivers/bridge/bridge_linux.go b/libnetwork/drivers/bridge/bridge_linux.go index 0057344e56ea2..06d96638bd4c9 100644 --- a/libnetwork/drivers/bridge/bridge_linux.go +++ b/libnetwork/drivers/bridge/bridge_linux.go @@ -12,6 +12,7 @@ import ( "github.com/containerd/log" "github.com/docker/docker/errdefs" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/datastore" "github.com/docker/docker/libnetwork/driverapi" "github.com/docker/docker/libnetwork/drivers/bridge/internal/rlkclient" @@ -155,7 +156,7 @@ type driver struct { isolationChain2V6 *iptables.ChainInfo networks map[string]*bridgeNetwork store *datastore.Store - nlh *netlink.Handle + nlh nlwrap.Handle portDriverClient portDriverClient configNetwork sync.Mutex sync.Mutex @@ -808,7 +809,7 @@ func (d *driver) checkConflict(config *networkConfiguration) error { func (d *driver) createNetwork(config *networkConfiguration) (err error) { // Initialize handle when needed d.Lock() - if d.nlh == nil { + if d.nlh.Handle == nil { d.nlh = ns.NlHandle() } d.Unlock() @@ -1018,7 +1019,7 @@ func (d *driver) deleteNetwork(nid string) error { return d.storeDelete(config) } -func addToBridge(ctx context.Context, nlh *netlink.Handle, ifaceName, bridgeName string) error { +func addToBridge(ctx context.Context, nlh nlwrap.Handle, ifaceName, bridgeName string) error { ctx, span := otel.Tracer("").Start(ctx, "libnetwork.drivers.bridge.addToBridge", trace.WithAttributes( attribute.String("ifaceName", ifaceName), attribute.String("bridgeName", bridgeName))) @@ -1035,7 +1036,7 @@ func addToBridge(ctx context.Context, nlh *netlink.Handle, ifaceName, bridgeName return nil } -func setHairpinMode(nlh *netlink.Handle, link netlink.Link, enable bool) error { +func setHairpinMode(nlh nlwrap.Handle, link netlink.Link, enable bool) error { err := nlh.LinkSetHairpin(link, enable) if err != nil { return fmt.Errorf("unable to set hairpin mode on %s via netlink: %v", diff --git a/libnetwork/drivers/bridge/bridge_linux_test.go b/libnetwork/drivers/bridge/bridge_linux_test.go index ba1671b8f4bb8..208bcdaf7aa02 100644 --- a/libnetwork/drivers/bridge/bridge_linux_test.go +++ b/libnetwork/drivers/bridge/bridge_linux_test.go @@ -11,6 +11,7 @@ import ( "strconv" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/docker/docker/libnetwork/driverapi" "github.com/docker/docker/libnetwork/internal/netiputil" @@ -1226,7 +1227,7 @@ func TestCreateWithExistingBridge(t *testing.T) { t.Fatalf("Failed to delete network %s: %v", brName, err) } - if _, err := netlink.LinkByName(brName); err != nil { + if _, err := nlwrap.LinkByName(brName); err != nil { t.Fatal("Deleting bridge network that using existing bridge interface unexpectedly deleted the bridge interface") } } diff --git a/libnetwork/drivers/bridge/interface_linux.go b/libnetwork/drivers/bridge/interface_linux.go index 4ed940e646a95..48ef59bb79e32 100644 --- a/libnetwork/drivers/bridge/interface_linux.go +++ b/libnetwork/drivers/bridge/interface_linux.go @@ -8,6 +8,7 @@ import ( "github.com/containerd/log" "github.com/docker/docker/errdefs" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/internal/netiputil" "github.com/vishvananda/netlink" ) @@ -25,14 +26,14 @@ type bridgeInterface struct { bridgeIPv6 *net.IPNet gatewayIPv4 net.IP gatewayIPv6 net.IP - nlh *netlink.Handle + nlh nlwrap.Handle } // newInterface creates a new bridge interface structure. It attempts to find // an already existing device identified by the configuration BridgeName field, // or the default bridge name when unspecified, but doesn't attempt to create // one when missing -func newInterface(nlh *netlink.Handle, config *networkConfiguration) (*bridgeInterface, error) { +func newInterface(nlh nlwrap.Handle, config *networkConfiguration) (*bridgeInterface, error) { var err error i := &bridgeInterface{nlh: nlh} diff --git a/libnetwork/drivers/bridge/interface_linux_test.go b/libnetwork/drivers/bridge/interface_linux_test.go index a661d09379ef6..832554be34a69 100644 --- a/libnetwork/drivers/bridge/interface_linux_test.go +++ b/libnetwork/drivers/bridge/interface_linux_test.go @@ -5,6 +5,7 @@ import ( "sort" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/vishvananda/netlink" "golang.org/x/sys/unix" @@ -28,7 +29,7 @@ func addAddr(t *testing.T, link netlink.Link, addr string) { func prepTestBridge(t *testing.T, nc *networkConfiguration) *bridgeInterface { t.Helper() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() assert.Assert(t, err) i, err := newInterface(nh, nc) assert.Assert(t, err) @@ -40,7 +41,7 @@ func prepTestBridge(t *testing.T, nc *networkConfiguration) *bridgeInterface { func TestInterfaceDefaultName(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -60,7 +61,7 @@ func TestAddressesNoInterface(t *testing.T) { func TestAddressesEmptyInterface(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() assert.NilError(t, err) inf, err := newInterface(nh, &networkConfiguration{}) diff --git a/libnetwork/drivers/bridge/network_linux_test.go b/libnetwork/drivers/bridge/network_linux_test.go index e5827ebb81367..f1a664a941af4 100644 --- a/libnetwork/drivers/bridge/network_linux_test.go +++ b/libnetwork/drivers/bridge/network_linux_test.go @@ -4,10 +4,10 @@ import ( "context" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/docker/docker/libnetwork/driverapi" "github.com/docker/docker/libnetwork/netlabel" - "github.com/vishvananda/netlink" ) func TestLinkCreate(t *testing.T) { @@ -55,7 +55,7 @@ func TestLinkCreate(t *testing.T) { } // Verify sbox endpoint interface inherited MTU value from bridge config - sboxLnk, err := netlink.LinkByName(te.iface.srcName) + sboxLnk, err := nlwrap.LinkByName(te.iface.srcName) if err != nil { t.Fatal(err) } @@ -75,7 +75,7 @@ func TestLinkCreate(t *testing.T) { t.Fatal("Invalid Dstname returned") } - _, err = netlink.LinkByName(te.iface.srcName) + _, err = nlwrap.LinkByName(te.iface.srcName) if err != nil { t.Fatalf("Could not find source link %s: %v", te.iface.srcName, err) } diff --git a/libnetwork/drivers/bridge/setup_device_linux_test.go b/libnetwork/drivers/bridge/setup_device_linux_test.go index 05f3513314885..41edf97c5d82e 100644 --- a/libnetwork/drivers/bridge/setup_device_linux_test.go +++ b/libnetwork/drivers/bridge/setup_device_linux_test.go @@ -6,16 +6,16 @@ import ( "syscall" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/docker/docker/libnetwork/netutils" - "github.com/vishvananda/netlink" "gotest.tools/v3/assert" ) func TestSetupNewBridge(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -41,7 +41,7 @@ func TestSetupNewBridge(t *testing.T) { func TestSetupNewNonDefaultBridge(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -63,7 +63,7 @@ func TestSetupNewNonDefaultBridge(t *testing.T) { func TestSetupDeviceUp(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -98,7 +98,7 @@ func TestGenerateRandomMAC(t *testing.T) { func TestMTUBiggerThan1500(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -114,7 +114,7 @@ func TestMTUBiggerThan1500(t *testing.T) { func TestMTUBiggerThan64K(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } diff --git a/libnetwork/drivers/bridge/setup_ip_tables_linux.go b/libnetwork/drivers/bridge/setup_ip_tables_linux.go index dd8810fbbd8a0..ad7be89416460 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables_linux.go +++ b/libnetwork/drivers/bridge/setup_ip_tables_linux.go @@ -9,9 +9,9 @@ import ( "github.com/containerd/log" "github.com/docker/docker/errdefs" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/iptables" "github.com/docker/docker/libnetwork/types" - "github.com/vishvananda/netlink" ) // DockerChain: DOCKER iptable chain name @@ -482,7 +482,7 @@ func setupInternalNetworkRules(bridgeIface string, addr *net.IPNet, icc, insert // As such, we need to flush all those conntrack entries to make sure NAT rules // are correctly applied to all packets. // See: #8795, #44688 & #44742. -func clearConntrackEntries(nlh *netlink.Handle, ep *bridgeEndpoint) { +func clearConntrackEntries(nlh nlwrap.Handle, ep *bridgeEndpoint) { var ipv4List []net.IP var ipv6List []net.IP var udpPorts []uint16 diff --git a/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go b/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go index 440286cd73476..cff66608c44ec 100644 --- a/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go +++ b/libnetwork/drivers/bridge/setup_ip_tables_linux_test.go @@ -4,11 +4,11 @@ import ( "net" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/docker/docker/libnetwork/driverapi" "github.com/docker/docker/libnetwork/iptables" "github.com/docker/docker/libnetwork/netlabel" - "github.com/vishvananda/netlink" "gotest.tools/v3/assert" ) @@ -38,7 +38,7 @@ func TestProgramIPTable(t *testing.T) { // Create a test bridge with a basic bridge configuration (name + IPv4). defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -68,7 +68,7 @@ func TestSetupIPChains(t *testing.T) { // Create a test bridge with a basic bridge configuration (name + IPv4). defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -193,7 +193,7 @@ func TestSetupIP6TablesWithHostIPv4(t *testing.T) { AddressIPv6: &net.IPNet{IP: net.ParseIP("2001:db8::1"), Mask: net.CIDRMask(64, 128)}, HostIPv4: net.ParseIP("192.0.2.2"), } - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } diff --git a/libnetwork/drivers/bridge/setup_ipv4_linux_test.go b/libnetwork/drivers/bridge/setup_ipv4_linux_test.go index 6b191b3745b9a..024306687027a 100644 --- a/libnetwork/drivers/bridge/setup_ipv4_linux_test.go +++ b/libnetwork/drivers/bridge/setup_ipv4_linux_test.go @@ -4,11 +4,12 @@ import ( "net" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/vishvananda/netlink" ) -func setupTestInterface(t *testing.T, nh *netlink.Handle) (*networkConfiguration, *bridgeInterface) { +func setupTestInterface(t *testing.T, nh nlwrap.Handle) (*networkConfiguration, *bridgeInterface) { config := &networkConfiguration{ BridgeName: DefaultBridgeName, } @@ -28,7 +29,7 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) { t.Fatalf("Failed to parse bridge IPv4: %v", err) } - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -61,7 +62,7 @@ func TestSetupBridgeIPv4Fixed(t *testing.T) { func TestSetupGatewayIPv4(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } diff --git a/libnetwork/drivers/bridge/setup_ipv6_linux_test.go b/libnetwork/drivers/bridge/setup_ipv6_linux_test.go index 8c9f8c7645afc..cfd97f50d3479 100644 --- a/libnetwork/drivers/bridge/setup_ipv6_linux_test.go +++ b/libnetwork/drivers/bridge/setup_ipv6_linux_test.go @@ -7,6 +7,7 @@ import ( "os" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/vishvananda/netlink" ) @@ -14,7 +15,7 @@ import ( func TestSetupIPv6(t *testing.T) { defer netnsutils.SetupTestOSContext(t)() - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } @@ -66,7 +67,7 @@ func TestSetupGatewayIPv6(t *testing.T) { DefaultGatewayIPv6: gw, } - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } diff --git a/libnetwork/drivers/bridge/setup_verify_linux_test.go b/libnetwork/drivers/bridge/setup_verify_linux_test.go index 045f3a16812e4..08013d8ba6749 100644 --- a/libnetwork/drivers/bridge/setup_verify_linux_test.go +++ b/libnetwork/drivers/bridge/setup_verify_linux_test.go @@ -4,12 +4,13 @@ import ( "net" "testing" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/vishvananda/netlink" ) func setupVerifyTest(t *testing.T) *bridgeInterface { - nh, err := netlink.NewHandle() + nh, err := nlwrap.NewHandle() if err != nil { t.Fatal(err) } diff --git a/libnetwork/drivers/overlay/ov_network.go b/libnetwork/drivers/overlay/ov_network.go index 3d170d74899d3..8a50b8e5ad508 100644 --- a/libnetwork/drivers/overlay/ov_network.go +++ b/libnetwork/drivers/overlay/ov_network.go @@ -15,6 +15,7 @@ import ( "sync" "github.com/containerd/log" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/driverapi" "github.com/docker/docker/libnetwork/drivers/overlay/overlayutils" "github.com/docker/docker/libnetwork/netlabel" @@ -351,7 +352,7 @@ func populateVNITbl() { } defer n.Close() - nlh, err := netlink.NewHandleAt(n, unix.NETLINK_ROUTE) + nlh, err := nlwrap.NewHandleAt(n, unix.NETLINK_ROUTE) if err != nil { log.G(context.TODO()).Errorf("Could not open netlink handle during vni population for ns %s: %v", path, err) return nil diff --git a/libnetwork/drivers/overlay/ov_utils.go b/libnetwork/drivers/overlay/ov_utils.go index 1ef14ecfc2222..76a5bcef01731 100644 --- a/libnetwork/drivers/overlay/ov_utils.go +++ b/libnetwork/drivers/overlay/ov_utils.go @@ -9,6 +9,7 @@ import ( "syscall" "github.com/containerd/log" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/drivers/overlay/overlayutils" "github.com/docker/docker/libnetwork/netutils" "github.com/docker/docker/libnetwork/ns" @@ -110,7 +111,7 @@ func deleteVxlanByVNI(path string, vni uint32) error { } defer ns.Close() - nlh, err = netlink.NewHandleAt(ns, syscall.NETLINK_ROUTE) + nlh, err = nlwrap.NewHandleAt(ns, syscall.NETLINK_ROUTE) if err != nil { return fmt.Errorf("failed to get netlink handle for ns %s: %v", path, err) } diff --git a/libnetwork/iptables/conntrack.go b/libnetwork/iptables/conntrack.go index 37fd91528a4e0..b3e91a3065844 100644 --- a/libnetwork/iptables/conntrack.go +++ b/libnetwork/iptables/conntrack.go @@ -9,13 +9,14 @@ import ( "syscall" "github.com/containerd/log" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/types" "github.com/vishvananda/netlink" ) // checkConntrackProgrammable checks if the handle supports the // NETLINK_NETFILTER and the base modules are loaded. -func checkConntrackProgrammable(nlh *netlink.Handle) error { +func checkConntrackProgrammable(nlh nlwrap.Handle) error { if !nlh.SupportsNetlinkFamily(syscall.NETLINK_NETFILTER) { return errors.New("conntrack is not available") } @@ -24,7 +25,7 @@ func checkConntrackProgrammable(nlh *netlink.Handle) error { // DeleteConntrackEntries deletes all the conntrack connections on the host for the specified IP // Returns the number of flows deleted for IPv4, IPv6 else error -func DeleteConntrackEntries(nlh *netlink.Handle, ipv4List []net.IP, ipv6List []net.IP) error { +func DeleteConntrackEntries(nlh nlwrap.Handle, ipv4List []net.IP, ipv6List []net.IP) error { if err := checkConntrackProgrammable(nlh); err != nil { return err } @@ -56,7 +57,7 @@ func DeleteConntrackEntries(nlh *netlink.Handle, ipv4List []net.IP, ipv6List []n return nil } -func DeleteConntrackEntriesByPort(nlh *netlink.Handle, proto types.Protocol, ports []uint16) error { +func DeleteConntrackEntriesByPort(nlh nlwrap.Handle, proto types.Protocol, ports []uint16) error { if err := checkConntrackProgrammable(nlh); err != nil { return err } @@ -95,7 +96,7 @@ func DeleteConntrackEntriesByPort(nlh *netlink.Handle, proto types.Protocol, por return nil } -func purgeConntrackState(nlh *netlink.Handle, family netlink.InetFamily, ipAddress net.IP) (uint, error) { +func purgeConntrackState(nlh nlwrap.Handle, family netlink.InetFamily, ipAddress net.IP) (uint, error) { filter := &netlink.ConntrackFilter{} // NOTE: doing the flush using the ipAddress is safe because today there cannot be multiple networks with the same subnet // so it will not be possible to flush flows that are of other containers diff --git a/libnetwork/libnetwork_linux_test.go b/libnetwork/libnetwork_linux_test.go index d6401bef16302..ed1cdee08dfc1 100644 --- a/libnetwork/libnetwork_linux_test.go +++ b/libnetwork/libnetwork_linux_test.go @@ -17,6 +17,7 @@ import ( "testing" "github.com/containerd/log" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/docker/docker/libnetwork" "github.com/docker/docker/libnetwork/config" @@ -32,7 +33,6 @@ import ( "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/reexec" "github.com/pkg/errors" - "github.com/vishvananda/netlink" "github.com/vishvananda/netns" "golang.org/x/sync/errgroup" "gotest.tools/v3/assert" @@ -1490,7 +1490,7 @@ func checkSandbox(t *testing.T, info libnetwork.EndpointInfo) { } defer sbNs.Close() - nh, err := netlink.NewHandleAt(sbNs) + nh, err := nlwrap.NewHandleAt(sbNs) if err != nil { t.Fatal(err) } diff --git a/libnetwork/netutils/utils_linux.go b/libnetwork/netutils/utils_linux.go index 51630e1e95286..50fdec43e2de5 100644 --- a/libnetwork/netutils/utils_linux.go +++ b/libnetwork/netutils/utils_linux.go @@ -8,6 +8,7 @@ import ( "os" "slices" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/internal/netiputil" "github.com/docker/docker/libnetwork/ns" "github.com/docker/docker/libnetwork/resolvconf" @@ -99,17 +100,17 @@ func queryOnLinkRoutes() []netip.Prefix { // GenerateIfaceName returns an interface name using the passed in // prefix and the length of random bytes. The api ensures that the // there are is no interface which exists with that name. -func GenerateIfaceName(nlh *netlink.Handle, prefix string, len int) (string, error) { - linkByName := netlink.LinkByName - if nlh != nil { - linkByName = nlh.LinkByName - } +func GenerateIfaceName(nlh nlwrap.Handle, prefix string, len int) (string, error) { for i := 0; i < 3; i++ { name, err := GenerateRandomName(prefix, len) if err != nil { return "", err } - _, err = linkByName(name) + if nlh.Handle == nil { + _, err = nlwrap.LinkByName(name) + } else { + _, err = nlh.LinkByName(name) + } if err != nil { if errors.As(err, &netlink.LinkNotFoundError{}) { return name, nil diff --git a/libnetwork/ns/init_linux.go b/libnetwork/ns/init_linux.go index 66bc67c603beb..b2d945e885448 100644 --- a/libnetwork/ns/init_linux.go +++ b/libnetwork/ns/init_linux.go @@ -10,13 +10,13 @@ import ( "time" "github.com/containerd/log" - "github.com/vishvananda/netlink" + "github.com/docker/docker/internal/nlwrap" "github.com/vishvananda/netns" ) var ( initNs netns.NsHandle - initNl *netlink.Handle + initNl nlwrap.Handle initOnce sync.Once // NetlinkSocketsTimeout represents the default timeout duration for the sockets NetlinkSocketsTimeout = 3 * time.Second @@ -29,7 +29,7 @@ func Init() { if err != nil { log.G(context.TODO()).Errorf("could not get initial namespace: %v", err) } - initNl, err = netlink.NewHandle(getSupportedNlFamilies()...) + initNl, err = nlwrap.NewHandle(getSupportedNlFamilies()...) if err != nil { log.G(context.TODO()).Errorf("could not create netlink handle on initial namespace: %v", err) } @@ -51,7 +51,7 @@ func getHandler() netns.NsHandle { } // NlHandle returns the netlink handler -func NlHandle() *netlink.Handle { +func NlHandle() nlwrap.Handle { initOnce.Do(Init) return initNl } diff --git a/libnetwork/osl/interface_linux.go b/libnetwork/osl/interface_linux.go index 28e1ac32fa113..0370d4f0bd787 100644 --- a/libnetwork/osl/interface_linux.go +++ b/libnetwork/osl/interface_linux.go @@ -11,6 +11,7 @@ import ( "time" "github.com/containerd/log" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/libnetwork/ns" "github.com/docker/docker/libnetwork/types" "github.com/pkg/errors" @@ -162,7 +163,7 @@ func (n *Namespace) findDst(srcName string, isBridge bool) string { return "" } -func moveLink(ctx context.Context, nlhHost *netlink.Handle, iface netlink.Link, i *Interface, path string) error { +func moveLink(ctx context.Context, nlhHost nlwrap.Handle, iface netlink.Link, i *Interface, path string) error { ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.moveLink", trace.WithAttributes( attribute.String("ifaceName", i.DstName()))) defer span.End() @@ -340,14 +341,14 @@ func (n *Namespace) RemoveInterface(i *Interface) error { return nil } -func (n *Namespace) configureInterface(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func (n *Namespace) configureInterface(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.configureInterface", trace.WithAttributes( attribute.String("ifaceName", iface.Attrs().Name))) defer span.End() ifaceName := iface.Attrs().Name ifaceConfigurators := []struct { - Fn func(context.Context, *netlink.Handle, netlink.Link, *Interface) error + Fn func(context.Context, nlwrap.Handle, netlink.Link, *Interface) error ErrMessage string }{ {setInterfaceName, fmt.Sprintf("error renaming interface %q to %q", ifaceName, i.DstName())}, @@ -371,7 +372,7 @@ func (n *Namespace) configureInterface(ctx context.Context, nlh *netlink.Handle, return nil } -func setInterfaceMaster(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func setInterfaceMaster(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { if i.DstMaster() == "" { return nil } @@ -386,7 +387,7 @@ func setInterfaceMaster(ctx context.Context, nlh *netlink.Handle, iface netlink. }) } -func setInterfaceMAC(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func setInterfaceMAC(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { if i.MacAddress() == nil { return nil } @@ -399,7 +400,7 @@ func setInterfaceMAC(ctx context.Context, nlh *netlink.Handle, iface netlink.Lin return nlh.LinkSetHardwareAddr(iface, i.MacAddress()) } -func setInterfaceIP(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func setInterfaceIP(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { if i.Address() == nil { return nil } @@ -416,7 +417,7 @@ func setInterfaceIP(ctx context.Context, nlh *netlink.Handle, iface netlink.Link return nlh.AddrAdd(iface, ipAddr) } -func setInterfaceIPv6(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func setInterfaceIPv6(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { addr := i.AddressIPv6() ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.setInterfaceIPv6", trace.WithAttributes( attribute.String("i.SrcName", i.SrcName()), @@ -443,7 +444,7 @@ func setInterfaceIPv6(ctx context.Context, nlh *netlink.Handle, iface netlink.Li return nlh.AddrAdd(iface, nlAddr) } -func setInterfaceLinkLocalIPs(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func setInterfaceLinkLocalIPs(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.setInterfaceLinkLocalIPs", trace.WithAttributes( attribute.String("i.SrcName", i.SrcName()), attribute.String("i.DstName", i.DstName()))) @@ -498,7 +499,7 @@ func (n *Namespace) setSysctls(ctx context.Context, ifName string, sysctls []str return nil } -func setInterfaceName(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func setInterfaceName(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.setInterfaceName", trace.WithAttributes( attribute.String("ifaceName", iface.Attrs().Name))) defer span.End() @@ -506,7 +507,7 @@ func setInterfaceName(ctx context.Context, nlh *netlink.Handle, iface netlink.Li return nlh.LinkSetName(iface, i.DstName()) } -func setInterfaceRoutes(ctx context.Context, nlh *netlink.Handle, iface netlink.Link, i *Interface) error { +func setInterfaceRoutes(ctx context.Context, nlh nlwrap.Handle, iface netlink.Link, i *Interface) error { ctx, span := otel.Tracer("").Start(ctx, "libnetwork.osl.setInterfaceRoutes", trace.WithAttributes( attribute.String("i.SrcName", i.SrcName()), attribute.String("i.DstName", i.DstName()))) @@ -525,7 +526,7 @@ func setInterfaceRoutes(ctx context.Context, nlh *netlink.Handle, iface netlink. return nil } -func checkRouteConflict(nlh *netlink.Handle, address *net.IPNet, family int) error { +func checkRouteConflict(nlh nlwrap.Handle, address *net.IPNet, family int) error { routes, err := nlh.RouteList(nil, family) if err != nil { return err diff --git a/libnetwork/osl/namespace_linux.go b/libnetwork/osl/namespace_linux.go index 2f3995ff0cc7a..efbed92af1f87 100644 --- a/libnetwork/osl/namespace_linux.go +++ b/libnetwork/osl/namespace_linux.go @@ -15,6 +15,7 @@ import ( "time" "github.com/containerd/log" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/unshare" "github.com/docker/docker/libnetwork/ns" "github.com/docker/docker/libnetwork/osl/kernel" @@ -198,7 +199,7 @@ func NewSandbox(key string, osCreate, isRestore bool) (*Namespace, error) { } defer sboxNs.Close() - n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) + n.nlHandle, err = nlwrap.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) if err != nil { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } @@ -241,7 +242,7 @@ func GetSandboxForExternalKey(basePath string, key string) (*Namespace, error) { } defer sboxNs.Close() - n.nlHandle, err = netlink.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) + n.nlHandle, err = nlwrap.NewHandleAt(sboxNs, syscall.NETLINK_ROUTE) if err != nil { return nil, fmt.Errorf("failed to create a netlink handle: %v", err) } @@ -320,7 +321,7 @@ type Namespace struct { isDefault bool ipv6LoEnabledOnce sync.Once ipv6LoEnabledCached bool - nlHandle *netlink.Handle + nlHandle nlwrap.Handle mu sync.Mutex } @@ -456,9 +457,7 @@ func (n *Namespace) Key() string { // Destroy destroys the sandbox. func (n *Namespace) Destroy() error { - if n.nlHandle != nil { - n.nlHandle.Close() - } + n.nlHandle.Handle.Close() // Assuming no running process is executing in this network namespace, // unmounting is sufficient to destroy it. if err := syscall.Unmount(n.path, syscall.MNT_DETACH); err != nil { diff --git a/libnetwork/osl/sandbox_linux_test.go b/libnetwork/osl/sandbox_linux_test.go index 6b599736d2ac6..b998512a41198 100644 --- a/libnetwork/osl/sandbox_linux_test.go +++ b/libnetwork/osl/sandbox_linux_test.go @@ -13,6 +13,7 @@ import ( "testing" "time" + "github.com/docker/docker/internal/nlwrap" "github.com/docker/docker/internal/testutils/netnsutils" "github.com/docker/docker/libnetwork/ns" "github.com/docker/docker/libnetwork/types" @@ -59,7 +60,7 @@ func newKey(t *testing.T) (string, error) { return name, nil } -func newInfo(t *testing.T, hnd *netlink.Handle) (*Namespace, error) { +func newInfo(t *testing.T, hnd nlwrap.Handle) (*Namespace, error) { t.Helper() err := hnd.LinkAdd(&netlink.Veth{ LinkAttrs: netlink.LinkAttrs{Name: vethName1, TxQLen: 0}, @@ -130,7 +131,7 @@ func verifySandbox(t *testing.T, ns *Namespace, ifaceSuffixes []string) { } defer sbNs.Close() - nh, err := netlink.NewHandleAt(sbNs) + nh, err := nlwrap.NewHandleAt(sbNs) if err != nil { t.Fatal(err) } From edaa0eb56d7e749df81bd3dcc2945b81e911b52e Mon Sep 17 00:00:00 2001 From: Rob Murray Date: Tue, 3 Sep 2024 18:06:26 +0100 Subject: [PATCH 2/2] Add linting rules to spot use of un-wrapped netlink functions. Spot netlink functions that may return EINTR because network configuration changed during a state dump, and point at the nlutil wrappers. Signed-off-by: Rob Murray --- .golangci.yml | 6 ++++++ internal/nlwrap/nlwrap_linux.go | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 627958db13fdc..a2196bcca84ca 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -37,6 +37,12 @@ linters-settings: - pkg: ^sync/atomic$ p: ^atomic\.(Add|CompareAndSwap|Load|Store|Swap). msg: Go 1.19 atomic types should be used instead. + - pkg: github.com/vishvananda/netlink$ + p: ^netlink\.(Handle\.)?(AddrList|BridgeVlanList|ChainList|ClassList|ConntrackTableList|ConntrackDeleteFilter$|ConntrackDeleteFilters|DevLinkGetDeviceList|DevLinkGetAllPortList|DevlinkGetDeviceParams|FilterList|FouList|GenlFamilyList|GTPPDPList|LinkByName|LinkByAlias|LinkList|LinkSubscribeWithOptions|NeighList$|NeighProxyList|NeighListExecute|NeighSubscribeWithOptions|LinkGetProtinfo|QdiscList|RdmaLinkList|RdmaLinkByName|RdmaLinkDel|RouteList|RouteListFilteredIter|RuleListFiltered$|RouteSubscribeWithOptions|RuleList$|RuleListFiltered|SocketGet|SocketDiagTCPInfo|SocketDiagTCP|SocketDiagUDPInfo|SocketDiagUDP|UnixSocketDiagInfo|UnixSocketDiag|VDPAGetDevConfigList|VDPAGetDevList|VDPAGetMGMTDevList|XfrmPolicyList|XfrmStateList) + msg: Use internal nlwrap package for EINTR handling. + - pkg: github.com/docker/docker/internal/nlwrap$ + p: ^nlwrap.Handle.(BridgeVlanList|ChainList|ClassList|ConntrackDeleteFilter$|DevLinkGetDeviceList|DevLinkGetAllPortList|DevlinkGetDeviceParams|FilterList|FouList|GenlFamilyList|GTPPDPList|LinkByAlias|LinkSubscribeWithOptions|NeighList$|NeighProxyList|NeighListExecute|NeighSubscribeWithOptions|LinkGetProtinfo|QdiscList|RdmaLinkList|RdmaLinkByName|RdmaLinkDel|RouteListFilteredIter|RuleListFiltered$|RouteSubscribeWithOptions|RuleList$|RuleListFiltered|SocketGet|SocketDiagTCPInfo|SocketDiagTCP|SocketDiagUDPInfo|SocketDiagUDP|UnixSocketDiagInfo|UnixSocketDiag|VDPAGetDevConfigList|VDPAGetDevList|VDPAGetMGMTDevList) + msg: Add a wrapper to nlwrap.Handle for EINTR handling and update the list in .golangci.yml. analyze-types: true importas: # Do not allow unaliased imports of aliased packages. diff --git a/internal/nlwrap/nlwrap_linux.go b/internal/nlwrap/nlwrap_linux.go index cda5e25a7af80..8f874de7b0407 100644 --- a/internal/nlwrap/nlwrap_linux.go +++ b/internal/nlwrap/nlwrap_linux.go @@ -66,7 +66,7 @@ func retryOnIntr(f func() error) { // AddrList calls nlh.LinkList, retrying if necessary. func (nlh Handle) AddrList(link netlink.Link, family int) (addrs []netlink.Addr, err error) { retryOnIntr(func() error { - addrs, err = nlh.Handle.AddrList(link, family) + addrs, err = nlh.Handle.AddrList(link, family) //nolint:forbidigo return err }) return addrs, err @@ -75,7 +75,7 @@ func (nlh Handle) AddrList(link netlink.Link, family int) (addrs []netlink.Addr, // AddrList calls netlink.LinkList, retrying if necessary. func AddrList(link netlink.Link, family int) (addrs []netlink.Addr, err error) { retryOnIntr(func() error { - addrs, err = netlink.AddrList(link, family) + addrs, err = netlink.AddrList(link, family) //nolint:forbidigo return err }) return addrs, err @@ -88,7 +88,7 @@ func (nlh Handle) ConntrackDeleteFilters( filters ...netlink.CustomConntrackFilter, ) (matched uint, err error) { retryOnIntr(func() error { - matched, err = nlh.Handle.ConntrackDeleteFilters(table, family, filters...) + matched, err = nlh.Handle.ConntrackDeleteFilters(table, family, filters...) //nolint:forbidigo return err }) return matched, err @@ -100,7 +100,7 @@ func ConntrackTableList( family netlink.InetFamily, ) (flows []*netlink.ConntrackFlow, err error) { retryOnIntr(func() error { - flows, err = netlink.ConntrackTableList(table, family) + flows, err = netlink.ConntrackTableList(table, family) //nolint:forbidigo return err }) return flows, err @@ -111,7 +111,7 @@ func ConntrackTableList( // will do as a fallback and that dump may get inconsistent results. func (nlh Handle) LinkByName(name string) (link netlink.Link, err error) { retryOnIntr(func() error { - link, err = nlh.Handle.LinkByName(name) + link, err = nlh.Handle.LinkByName(name) //nolint:forbidigo return err }) return link, err @@ -122,7 +122,7 @@ func (nlh Handle) LinkByName(name string) (link netlink.Link, err error) { // kernel, it will do as a fallback and that dump may get inconsistent results. func LinkByName(name string) (link netlink.Link, err error) { retryOnIntr(func() error { - link, err = netlink.LinkByName(name) + link, err = netlink.LinkByName(name) //nolint:forbidigo return err }) return link, err @@ -131,7 +131,7 @@ func LinkByName(name string) (link netlink.Link, err error) { // LinkList calls nlh.LinkList, retrying if necessary. func (nlh Handle) LinkList() (links []netlink.Link, err error) { retryOnIntr(func() error { - links, err = nlh.Handle.LinkList() + links, err = nlh.Handle.LinkList() //nolint:forbidigo return err }) return links, err @@ -140,7 +140,7 @@ func (nlh Handle) LinkList() (links []netlink.Link, err error) { // LinkList calls netlink.LinkList, retrying if necessary. func LinkList() (links []netlink.Link, err error) { retryOnIntr(func() error { - links, err = netlink.LinkList() + links, err = netlink.LinkList() //nolint:forbidigo return err }) return links, err @@ -149,7 +149,7 @@ func LinkList() (links []netlink.Link, err error) { // RouteList calls nlh.RouteList, retrying if necessary. func (nlh Handle) RouteList(link netlink.Link, family int) (routes []netlink.Route, err error) { retryOnIntr(func() error { - routes, err = nlh.Handle.RouteList(link, family) + routes, err = nlh.Handle.RouteList(link, family) //nolint:forbidigo return err }) return routes, err @@ -157,7 +157,7 @@ func (nlh Handle) RouteList(link netlink.Link, family int) (routes []netlink.Rou func (nlh Handle) XfrmPolicyList(family int) (policies []netlink.XfrmPolicy, err error) { retryOnIntr(func() error { - policies, err = nlh.Handle.XfrmPolicyList(family) + policies, err = nlh.Handle.XfrmPolicyList(family) //nolint:forbidigo return err }) return policies, err @@ -165,7 +165,7 @@ func (nlh Handle) XfrmPolicyList(family int) (policies []netlink.XfrmPolicy, err func (nlh Handle) XfrmStateList(family int) (states []netlink.XfrmState, err error) { retryOnIntr(func() error { - states, err = nlh.Handle.XfrmStateList(family) + states, err = nlh.Handle.XfrmStateList(family) //nolint:forbidigo return err }) return states, err