1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.23
package environment
import (
"context"
"errors"
"maps"
"net"
"testing"
"github.com/docker/docker/internal/nlwrap"
"github.com/docker/docker/libnetwork/drivers/bridge"
"github.com/vishvananda/netlink"
"gotest.tools/v3/assert"
)
type defaultBridgeInfo struct {
bridge netlink.Link
addrs map[string]*netlink.Addr
}
var _, llSubnet, _ = net.ParseCIDR("fe80::/64")
// ProtectDefaultBridge remembers default bridge settings so that, when a test
// runs its own daemon and tramples settings of the bridge belonging to the
// CI-started bridge, the bridge is restored to its old state before the next
// test.
//
// For example, a test may enable IPv6 with a link-local fixed-cidr-v6. That's
// likely to break later tests, even if they also start their own daemon
// (because, in the absence of any specific settings, the daemon learns default
// bridge config from addresses on an existing bridge device).
func ProtectDefaultBridge(_ context.Context, t testing.TB, testEnv *Execution) {
t.Helper()
// Find the bridge - there should always be one, belonging to the daemon started by CI.
br, err := nlwrap.LinkByName(bridge.DefaultBridgeName)
if err != nil {
var lnf netlink.LinkNotFoundError
if !errors.As(err, &lnf) {
t.Fatal("Getting default bridge before test:", err)
}
return
}
testEnv.ProtectDefaultBridge(t, &defaultBridgeInfo{
bridge: br,
addrs: getAddrs(t, br),
})
}
func getAddrs(t testing.TB, br netlink.Link) map[string]*netlink.Addr {
t.Helper()
addrs, err := nlwrap.AddrList(br, netlink.FAMILY_ALL)
assert.NilError(t, err, "Getting default bridge addresses before test")
addrMap := map[string]*netlink.Addr{}
for _, addr := range addrs {
addrMap[addr.IPNet.String()] = &addr
}
return addrMap
}
// ProtectDefaultBridge stores default bridge info, to be restored on clean.
func (e *Execution) ProtectDefaultBridge(t testing.TB, info *defaultBridgeInfo) {
e.protectedElements.defaultBridgeInfo = info
}
func restoreDefaultBridge(t testing.TB, info *defaultBridgeInfo) {
t.Helper()
if info == nil {
return
}
// Re-create the bridge if the test was antisocial enough to delete it.
// Yes, I'm looking at you TestDockerDaemonSuite/TestBuildOnDisabledBridgeNetworkDaemon.
br, err := nlwrap.LinkByName(bridge.DefaultBridgeName)
if err != nil {
var lnf netlink.LinkNotFoundError
if !errors.As(err, &lnf) {
t.Fatal("Failed to find default bridge after test:", err)
}
err := netlink.LinkAdd(info.bridge)
assert.NilError(t, err, "Failed to re-create default bridge after test")
br, err = nlwrap.LinkByName(bridge.DefaultBridgeName)
assert.NilError(t, err, "Failed to find re-created default bridge after test")
}
addrs, err := nlwrap.AddrList(br, netlink.FAMILY_ALL)
assert.NilError(t, err, "Failed get default bridge addresses after test")
// Delete addresses the bridge didn't have before the test, apart from IPv6 LL
// addresses - because the bridge doesn't get a kernel-assigned LL address until
// the first veth is hooked up and, once that address is deleted, it's not
// re-added.
wantAddrs := maps.Clone(info.addrs)
for _, addr := range addrs {
if _, ok := wantAddrs[addr.IPNet.String()]; ok {
delete(wantAddrs, addr.IPNet.String())
} else if !llSubnet.Contains(addr.IP) {
err := netlink.AddrDel(br, &netlink.Addr{IPNet: addr.IPNet})
assert.NilError(t, err, "Failed to remove default bridge address '%s' after test", addr.IPNet.String())
}
}
// Add missing addresses.
for _, wantAddr := range wantAddrs {
err = netlink.AddrAdd(br, wantAddr)
assert.NilError(t, err, "Failed to add default bridge address '%s' after test", wantAddr.IPNet.String())
}
}
|