Signed-off-by: Rob Murray <rob.murray@docker.com>
| ... | ... |
@@ -734,6 +734,7 @@ func testLiveRestoreVolumeReferences(t *testing.T) {
|
| 734 | 734 |
|
| 735 | 735 |
func testLiveRestoreUserChainsSetup(t *testing.T) {
|
| 736 | 736 |
skip.If(t, testEnv.IsRootless(), "rootless daemon uses it's own network namespace") |
| 737 |
+ skip.If(t, testEnv.FirewallBackendDriver() == "nftables", "nftables enabled, skipping iptables test") |
|
| 737 | 738 |
|
| 738 | 739 |
t.Parallel() |
| 739 | 740 |
ctx := testutil.StartSpan(baseContext, t) |
| ... | ... |
@@ -306,17 +306,30 @@ func TestFilterForwardPolicy(t *testing.T) {
|
| 306 | 306 |
) |
| 307 | 307 |
host := l3.Hosts[hostname] |
| 308 | 308 |
|
| 309 |
- getFwdPolicy := func(cmd string) string {
|
|
| 309 |
+ getFwdPolicy := func(usingNftables bool, fam string) string {
|
|
| 310 | 310 |
t.Helper() |
| 311 |
- out := host.MustRun(t, cmd, "-S", "FORWARD") |
|
| 312 |
- if strings.HasPrefix(out, "-P FORWARD ACCEPT") {
|
|
| 313 |
- return "ACCEPT" |
|
| 314 |
- } |
|
| 315 |
- if strings.HasPrefix(out, "-P FORWARD DROP") {
|
|
| 316 |
- return "DROP" |
|
| 311 |
+ if usingNftables {
|
|
| 312 |
+ out := host.MustRun(t, "nft", "list chain "+fam+" docker-bridges filter-FORWARD") |
|
| 313 |
+ if strings.Contains(out, "policy accept") {
|
|
| 314 |
+ return "ACCEPT" |
|
| 315 |
+ } |
|
| 316 |
+ if strings.Contains(out, "policy drop") {
|
|
| 317 |
+ return "DROP" |
|
| 318 |
+ } |
|
| 319 |
+ t.Fatalf("Failed to determine nftables filter-FORWARD policy: %s", out)
|
|
| 320 |
+ return "" |
|
| 321 |
+ } else {
|
|
| 322 |
+ cmd := fam + "tables" |
|
| 323 |
+ out := host.MustRun(t, cmd, "-S", "FORWARD") |
|
| 324 |
+ if strings.HasPrefix(out, "-P FORWARD ACCEPT") {
|
|
| 325 |
+ return "ACCEPT" |
|
| 326 |
+ } |
|
| 327 |
+ if strings.HasPrefix(out, "-P FORWARD DROP") {
|
|
| 328 |
+ return "DROP" |
|
| 329 |
+ } |
|
| 330 |
+ t.Fatalf("Failed to determine %s FORWARD policy: %s", cmd, out)
|
|
| 331 |
+ return "" |
|
| 317 | 332 |
} |
| 318 |
- t.Fatalf("Failed to determine %s FORWARD policy: %s", cmd, out)
|
|
| 319 |
- return "" |
|
| 320 | 333 |
} |
| 321 | 334 |
|
| 322 | 335 |
type sysctls struct{ v4, v6def, v6all string }
|
| ... | ... |
@@ -342,21 +355,22 @@ func TestFilterForwardPolicy(t *testing.T) {
|
| 342 | 342 |
d.StartWithBusybox(ctx, t, tc.daemonArgs...) |
| 343 | 343 |
t.Cleanup(func() { d.Stop(t) })
|
| 344 | 344 |
}) |
| 345 |
+ usingNftables := d.FirewallBackendDriver(t) == "nftables" |
|
| 345 | 346 |
c := d.NewClientT(t) |
| 346 | 347 |
t.Cleanup(func() { c.Close() })
|
| 347 | 348 |
|
| 348 | 349 |
// If necessary, the IPv4 policy should have been updated when the default bridge network was created. |
| 349 |
- assert.Check(t, is.Equal(getFwdPolicy("iptables"), tc.expPolicy))
|
|
| 350 |
+ assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip"), tc.expPolicy)) |
|
| 350 | 351 |
// IPv6 policy should not have been updated yet. |
| 351 |
- assert.Check(t, is.Equal(getFwdPolicy("ip6tables"), "ACCEPT"))
|
|
| 352 |
+ assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip6"), "ACCEPT")) |
|
| 352 | 353 |
assert.Check(t, is.Equal(getSysctls(), sysctls{tc.expForwarding, tc.initForwarding, tc.initForwarding}))
|
| 353 | 354 |
|
| 354 | 355 |
// If necessary, creating an IPv6 network should update the sysctls and policy. |
| 355 | 356 |
const netName = "testnetffp" |
| 356 | 357 |
network.CreateNoError(ctx, t, c, netName, network.WithIPv6()) |
| 357 | 358 |
t.Cleanup(func() { network.RemoveNoError(ctx, t, c, netName) })
|
| 358 |
- assert.Check(t, is.Equal(getFwdPolicy("iptables"), tc.expPolicy))
|
|
| 359 |
- assert.Check(t, is.Equal(getFwdPolicy("ip6tables"), tc.expPolicy))
|
|
| 359 |
+ assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip"), tc.expPolicy)) |
|
| 360 |
+ assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip6"), tc.expPolicy)) |
|
| 360 | 361 |
assert.Check(t, is.Equal(getSysctls(), sysctls{tc.expForwarding, tc.expForwarding, tc.expForwarding}))
|
| 361 | 362 |
}) |
| 362 | 363 |
} |
| ... | ... |
@@ -217,6 +217,7 @@ var iptCmds = map[iptCmdType][]string{
|
| 217 | 217 |
func TestBridgeIptablesDoc(t *testing.T) {
|
| 218 | 218 |
skip.If(t, networking.FirewalldRunning(), "can't document iptables rules, running under firewalld") |
| 219 | 219 |
skip.If(t, testEnv.IsRootless) |
| 220 |
+ skip.If(t, testEnv.FirewallBackendDriver() == "nftables") |
|
| 220 | 221 |
ctx := setupTest(t) |
| 221 | 222 |
|
| 222 | 223 |
// Get the full path for "bundles/TestBridgeIptablesDoc". |
| ... | ... |
@@ -93,7 +93,14 @@ func TestHostIPv4BridgeLabel(t *testing.T) {
|
| 93 | 93 |
assert.NilError(t, err) |
| 94 | 94 |
assert.Assert(t, len(out.IPAM.Config) > 0) |
| 95 | 95 |
// Make sure the SNAT rule exists |
| 96 |
- testutil.RunCommand(ctx, "iptables", "-t", "nat", "-C", "POSTROUTING", "-s", out.IPAM.Config[0].Subnet, "!", "-o", bridgeName, "-j", "SNAT", "--to-source", ipv4SNATAddr).Assert(t, icmd.Success) |
|
| 96 |
+ if testEnv.FirewallBackendDriver() == "nftables" {
|
|
| 97 |
+ chain := testutil.RunCommand(ctx, "nft", "--stateless", "list", "chain", "ip", "docker-bridges", "nat-postrouting-out__hostIPv4Bridge").Combined() |
|
| 98 |
+ exp := fmt.Sprintf(`oifname != "hostIPv4Bridge" ip saddr %s counter snat to %s comment "SNAT"`, |
|
| 99 |
+ out.IPAM.Config[0].Subnet, ipv4SNATAddr) |
|
| 100 |
+ assert.Check(t, is.Contains(chain, exp)) |
|
| 101 |
+ } else {
|
|
| 102 |
+ testutil.RunCommand(ctx, "iptables", "-t", "nat", "-C", "POSTROUTING", "-s", out.IPAM.Config[0].Subnet, "!", "-o", bridgeName, "-j", "SNAT", "--to-source", ipv4SNATAddr).Assert(t, icmd.Success) |
|
| 103 |
+ } |
|
| 97 | 104 |
} |
| 98 | 105 |
|
| 99 | 106 |
func TestDefaultNetworkOpts(t *testing.T) {
|
| ... | ... |
@@ -510,23 +510,26 @@ func TestRoutedAccessToPublishedPort(t *testing.T) {
|
| 510 | 510 |
ctx := setupTest(t) |
| 511 | 511 |
|
| 512 | 512 |
testcases := []struct {
|
| 513 |
- name string |
|
| 514 |
- userlandProxy bool |
|
| 515 |
- skipINC bool |
|
| 516 |
- expResponse bool |
|
| 513 |
+ name string |
|
| 514 |
+ userlandProxy bool |
|
| 515 |
+ skipINC bool |
|
| 516 |
+ expResponseIptables bool |
|
| 517 |
+ expResponseNftables bool |
|
| 517 | 518 |
}{
|
| 518 | 519 |
{
|
| 519 |
- name: "proxy=true/skipICC=false", |
|
| 520 |
- userlandProxy: true, |
|
| 521 |
- expResponse: true, |
|
| 520 |
+ name: "proxy=true/skipINC=false", |
|
| 521 |
+ userlandProxy: true, |
|
| 522 |
+ expResponseIptables: true, |
|
| 523 |
+ expResponseNftables: true, |
|
| 522 | 524 |
}, |
| 523 | 525 |
{
|
| 524 |
- name: "proxy=false/skipICC=false", |
|
| 526 |
+ name: "proxy=false/skipINC=false", |
|
| 527 |
+ expResponseNftables: true, |
|
| 525 | 528 |
}, |
| 526 | 529 |
{
|
| 527 |
- name: "proxy=false/skipICC=true", |
|
| 528 |
- skipINC: true, |
|
| 529 |
- expResponse: true, |
|
| 530 |
+ name: "proxy=false/skipINC=true", |
|
| 531 |
+ skipINC: true, |
|
| 532 |
+ expResponseIptables: true, |
|
| 530 | 533 |
}, |
| 531 | 534 |
} |
| 532 | 535 |
|
| ... | ... |
@@ -535,6 +538,10 @@ func TestRoutedAccessToPublishedPort(t *testing.T) {
|
| 535 | 535 |
d := daemon.New(t) |
| 536 | 536 |
d.StartWithBusybox(ctx, t, "--ipv6", "--userland-proxy="+strconv.FormatBool(tc.userlandProxy)) |
| 537 | 537 |
defer d.Stop(t) |
| 538 |
+ usingNftables := d.FirewallBackendDriver(t) == "nftables" |
|
| 539 |
+ if usingNftables && tc.skipINC {
|
|
| 540 |
+ t.Skip("Skipping iptables skip-INC test, using nftables")
|
|
| 541 |
+ } |
|
| 538 | 542 |
|
| 539 | 543 |
c := d.NewClientT(t) |
| 540 | 544 |
defer c.Close() |
| ... | ... |
@@ -603,7 +610,7 @@ func TestRoutedAccessToPublishedPort(t *testing.T) {
|
| 603 | 603 |
container.WithNetworkMode(routedNetName), |
| 604 | 604 |
container.WithCmd("wget", "-O-", "-T3", url),
|
| 605 | 605 |
) |
| 606 |
- if tc.expResponse {
|
|
| 606 |
+ if (usingNftables && tc.expResponseNftables) || (!usingNftables && tc.expResponseIptables) {
|
|
| 607 | 607 |
// 404 Not Found means the server responded, but it's got nothing to serve. |
| 608 | 608 |
assert.Check(t, is.Contains(res.Stderr.String(), "404 Not Found"), "url: %s", url) |
| 609 | 609 |
} else {
|
| ... | ... |
@@ -1032,16 +1039,23 @@ func TestNoIP6Tables(t *testing.T) {
|
| 1032 | 1032 |
id := container.Run(ctx, t, c, container.WithNetworkMode(netName)) |
| 1033 | 1033 |
defer c.ContainerRemove(ctx, id, containertypes.RemoveOptions{Force: true})
|
| 1034 | 1034 |
|
| 1035 |
- res, err := exec.Command("/usr/sbin/ip6tables-save").CombinedOutput()
|
|
| 1035 |
+ var cmd *exec.Cmd |
|
| 1036 |
+ if d.FirewallBackendDriver(t) == "nftables" {
|
|
| 1037 |
+ cmd = exec.Command("nft", "list", "table", "ip6", "docker-bridges")
|
|
| 1038 |
+ } else {
|
|
| 1039 |
+ cmd = exec.Command("/usr/sbin/ip6tables-save")
|
|
| 1040 |
+ } |
|
| 1041 |
+ res, err := cmd.CombinedOutput() |
|
| 1036 | 1042 |
assert.NilError(t, err) |
| 1043 |
+ dump := string(res) |
|
| 1037 | 1044 |
if tc.expIPTables {
|
| 1038 |
- assert.Check(t, is.Contains(string(res), subnet)) |
|
| 1039 |
- assert.Check(t, is.Contains(string(res), bridgeName)) |
|
| 1045 |
+ assert.Check(t, is.Contains(dump, subnet)) |
|
| 1046 |
+ assert.Check(t, is.Contains(dump, bridgeName)) |
|
| 1040 | 1047 |
} else {
|
| 1041 |
- assert.Check(t, !strings.Contains(string(res), subnet), |
|
| 1042 |
- fmt.Sprintf("Didn't expect to find '%s' in '%s'", subnet, string(res)))
|
|
| 1043 |
- assert.Check(t, !strings.Contains(string(res), bridgeName), |
|
| 1044 |
- fmt.Sprintf("Didn't expect to find '%s' in '%s'", bridgeName, string(res)))
|
|
| 1048 |
+ assert.Check(t, !strings.Contains(dump, subnet), |
|
| 1049 |
+ fmt.Sprintf("Didn't expect to find '%s' in '%s'", subnet, dump))
|
|
| 1050 |
+ assert.Check(t, !strings.Contains(dump, bridgeName), |
|
| 1051 |
+ fmt.Sprintf("Didn't expect to find '%s' in '%s'", bridgeName, dump))
|
|
| 1045 | 1052 |
} |
| 1046 | 1053 |
}) |
| 1047 | 1054 |
} |
| ... | ... |
@@ -1690,6 +1704,8 @@ func TestNetworkInspectGateway(t *testing.T) {
|
| 1690 | 1690 |
func TestDropInForwardChain(t *testing.T) {
|
| 1691 | 1691 |
skip.If(t, networking.FirewalldRunning(), "can't use firewalld in host netns to add rules in L3Segment") |
| 1692 | 1692 |
skip.If(t, testEnv.IsRootless, "rootless has its own netns") |
| 1693 |
+ skip.If(t, !strings.Contains(testEnv.FirewallBackendDriver(), "iptables"), |
|
| 1694 |
+ "test is iptables specific, and iptables isn't in use") |
|
| 1693 | 1695 |
|
| 1694 | 1696 |
// Run the test in its own netns, to avoid interfering with iptables on the test host. |
| 1695 | 1697 |
const l3SegHost = "difc" |
| ... | ... |
@@ -1228,6 +1228,8 @@ func getContainerStdout(t *testing.T, ctx context.Context, c *client.Client, ctr |
| 1228 | 1228 |
// See https://github.com/moby/moby/issues/49557 |
| 1229 | 1229 |
func TestSkipRawRules(t *testing.T) {
|
| 1230 | 1230 |
skip.If(t, networking.FirewalldRunning(), "can't use firewalld in host netns to add rules in L3Segment") |
| 1231 |
+ skip.If(t, !strings.Contains(testEnv.FirewallBackendDriver(), "iptables"), |
|
| 1232 |
+ "test is iptables specific, and iptables isn't in use") |
|
| 1231 | 1233 |
skip.If(t, testEnv.IsRootless, "can't use L3Segment, or check iptables rules") |
| 1232 | 1234 |
|
| 1233 | 1235 |
testcases := []struct {
|
| ... | ... |
@@ -184,6 +184,7 @@ func TestSwarmScopedNetFromConfig(t *testing.T) {
|
| 184 | 184 |
func TestDockerIngressChainPosition(t *testing.T) {
|
| 185 | 185 |
skip.If(t, testEnv.IsRemoteDaemon) |
| 186 | 186 |
skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode") |
| 187 |
+ skip.If(t, testEnv.FirewallBackendDriver() == "nftables") |
|
| 187 | 188 |
skip.If(t, networking.FirewalldRunning(), "can't use firewalld in host netns to add rules in L3Segment") |
| 188 | 189 |
ctx := setupTest(t) |
| 189 | 190 |
|
| ... | ... |
@@ -232,3 +232,12 @@ func (e *Execution) GitHubActions() bool {
|
| 232 | 232 |
func (e *Execution) NotAmd64() bool {
|
| 233 | 233 |
return e.DaemonVersion.Arch != "amd64" |
| 234 | 234 |
} |
| 235 |
+ |
|
| 236 |
+// FirewallBackendDriver returns the value of FirewallBackend.Driver from |
|
| 237 |
+// system Info if set, else the empty string. |
|
| 238 |
+func (e *Execution) FirewallBackendDriver() string {
|
|
| 239 |
+ if e.DaemonInfo.FirewallBackend == nil {
|
|
| 240 |
+ return "" |
|
| 241 |
+ } |
|
| 242 |
+ return e.DaemonInfo.FirewallBackend.Driver |
|
| 243 |
+} |