Skip to content

Commit 55aee6b

Browse files
authored
Merge pull request #4835 from haytok/delete-chains-on-nat-table
fix: clean up unused iptables chains not being deleted on container r…
2 parents 35ca883 + 4f71951 commit 55aee6b

6 files changed

Lines changed: 74 additions & 40 deletions

File tree

cmd/nerdctl/container/container_remove_linux_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323
"testing"
2424
"time"
2525

26+
cniutils "github.com/containernetworking/plugins/pkg/utils"
27+
2628
"github.com/containerd/nerdctl/mod/tigron/expect"
2729
"github.com/containerd/nerdctl/mod/tigron/require"
2830
"github.com/containerd/nerdctl/mod/tigron/test"
@@ -111,10 +113,15 @@ func TestContainerRmIptables(t *testing.T) {
111113
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
112114
// Get the container ID from the label
113115
containerID := data.Labels().Get("containerID")
116+
id := fmt.Sprintf("%s-%s", testutil.Namespace, containerID)
117+
chain := cniutils.FormatChainName("bridge", id)
114118
return &test.Expected{
115119
ExitCode: expect.ExitCodeSuccess,
116-
// Verify that the iptables output does not contain the container ID
117-
Output: expect.DoesNotContain(containerID),
120+
// Verify that the iptables output does not contain the container ID and a chain name generated from the cni name, namespace, and container ID
121+
Output: expect.All(
122+
expect.DoesNotContain(containerID),
123+
expect.DoesNotContain(chain),
124+
),
118125
}
119126
},
120127
},

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ require (
152152
github.com/moby/moby/api v1.54.1 // indirect
153153
github.com/moby/sys/capability v0.4.0 // indirect
154154
go.yaml.in/yaml/v4 v4.0.0-rc.4 // indirect
155+
sigs.k8s.io/knftables v0.0.18 // indirect
155156
)
156157

157158
replace github.com/containerd/nerdctl/mod/tigron v0.0.0 => ./mod/tigron

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
186186
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
187187
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
188188
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
189+
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
190+
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
189191
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
190192
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
191193
github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs=
@@ -517,6 +519,8 @@ lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
517519
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
518520
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
519521
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
522+
sigs.k8s.io/knftables v0.0.18 h1:6Duvmu0s/HwGifKrtl6G3AyAPYlWiZqTgS8bkVMiyaE=
523+
sigs.k8s.io/knftables v0.0.18/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk=
520524
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
521525
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
522526
tags.cncf.io/container-device-interface v1.1.0 h1:RnxNhxF1JOu6CJUVpetTYvrXHdxw9j9jFYgZpI+anSY=

pkg/ocihook/ocihook.go

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ func onPostStop(opts *handlerOpts) error {
722722
// opts.cni.Remove has trouble removing network configurations when netns is empty.
723723
// Therefore, we force the deletion of iptables rules here to prevent netns exhaustion.
724724
// This is a workaround until https://github.com/containernetworking/plugins/pull/1078 is merged.
725-
if err := cleanupIptablesRules(opts.fullID); err != nil {
725+
if err := cleanupIptablesRules(opts.fullID, opts.cniNames); err != nil {
726726
log.L.WithError(err).Warnf("failed to clean up iptables rules for container %s", opts.fullID)
727727
// Don't return error here, continue with the rest of the cleanup
728728
}
@@ -755,43 +755,6 @@ func onPostStop(opts *handlerOpts) error {
755755
return nil
756756
}
757757

758-
// cleanupIptablesRules cleans up iptables rules related to the container
759-
func cleanupIptablesRules(containerID string) error {
760-
// Check if iptables command exists
761-
if _, err := exec.LookPath("iptables"); err != nil {
762-
return fmt.Errorf("iptables command not found: %w", err)
763-
}
764-
765-
// Tables to check for rules
766-
tables := []string{"nat", "filter", "mangle"}
767-
768-
for _, table := range tables {
769-
// Get all iptables rules for this table
770-
cmd := exec.Command("iptables", "-t", table, "-S")
771-
output, err := cmd.CombinedOutput()
772-
if err != nil {
773-
log.L.WithError(err).Warnf("failed to list iptables rules for table %s", table)
774-
continue
775-
}
776-
777-
// Find and delete rules related to the container
778-
rules := strings.Split(string(output), "\n")
779-
for _, rule := range rules {
780-
if strings.Contains(rule, containerID) {
781-
// Execute delete command
782-
deleteCmd := exec.Command("sh", "-c", "--", fmt.Sprintf(`iptables -t %s -D %s`, table, rule[3:]))
783-
if deleteOutput, err := deleteCmd.CombinedOutput(); err != nil {
784-
log.L.WithError(err).Warnf("failed to delete iptables rule: %s, output: %s", rule, string(deleteOutput))
785-
} else {
786-
log.L.Debugf("deleted iptables rule: %s", rule)
787-
}
788-
}
789-
}
790-
}
791-
792-
return nil
793-
}
794-
795758
// writePidFile writes the pid atomically to a file.
796759
// From https://github.com/containerd/containerd/blob/v1.7.0-rc.2/cmd/ctr/commands/commands.go#L265-L282
797760
func writePidFile(path string, pid int) error {

pkg/ocihook/ocihook_linux.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
package ocihook
1818

1919
import (
20+
"fmt"
21+
"os/exec"
22+
"strings"
23+
24+
cniutils "github.com/containernetworking/plugins/pkg/utils"
25+
2026
"github.com/containerd/containerd/v2/contrib/apparmor"
2127
"github.com/containerd/log"
2228

@@ -37,3 +43,51 @@ func loadAppArmor() {
3743
// but the profile was not actually loaded, runc will fail.
3844
}
3945
}
46+
47+
// cleanupIptablesRules cleans up iptables rules related to the container
48+
func cleanupIptablesRules(containerID string, cniNames []string) error {
49+
// Check if iptables command exists
50+
if _, err := exec.LookPath("iptables"); err != nil {
51+
return fmt.Errorf("iptables command not found: %w", err)
52+
}
53+
54+
// Tables to check for rules
55+
tables := []string{"nat", "filter", "mangle"}
56+
57+
for _, table := range tables {
58+
// Get all iptables rules for this table
59+
cmd := exec.Command("iptables", "-t", table, "-S")
60+
output, err := cmd.CombinedOutput()
61+
if err != nil {
62+
log.L.WithError(err).Warnf("failed to list iptables rules for table %s", table)
63+
continue
64+
}
65+
66+
// Find and delete rules related to the container
67+
rules := strings.Split(string(output), "\n")
68+
for _, rule := range rules {
69+
if strings.Contains(rule, containerID) {
70+
// Execute delete command
71+
deleteCmd := exec.Command("sh", "-c", "--", fmt.Sprintf(`iptables -t %s -D %s`, table, rule[3:]))
72+
if deleteOutput, err := deleteCmd.CombinedOutput(); err != nil {
73+
log.L.WithError(err).Warnf("failed to delete iptables rule: %s, output: %s", rule, string(deleteOutput))
74+
} else {
75+
log.L.Debugf("deleted iptables rule: %s", rule)
76+
}
77+
}
78+
}
79+
}
80+
81+
// Delete CNI chains related to the container
82+
for _, cniName := range cniNames {
83+
chain := cniutils.FormatChainName(cniName, containerID)
84+
deleteCmd := exec.Command("iptables", "-t", "nat", "-X", chain)
85+
if deleteOutput, err := deleteCmd.CombinedOutput(); err != nil {
86+
log.L.WithError(err).Warnf("failed to delete iptables chain: %s, output: %s", chain, string(deleteOutput))
87+
} else {
88+
log.L.Debugf("deleted iptables chain: %s", chain)
89+
}
90+
}
91+
92+
return nil
93+
}

pkg/ocihook/ocihook_nolinux.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,8 @@ package ocihook
2121
func loadAppArmor() {
2222
//noop
2323
}
24+
25+
func cleanupIptablesRules(containerID string, cniNames []string) error {
26+
//noop
27+
return nil
28+
}

0 commit comments

Comments
 (0)