Skip to content

libnetwork: don't depend on nft when linked against libnftables - #52820

Merged
thaJeztah merged 2 commits into
moby:masterfrom
corhere:libnftables-without-nft
Jun 11, 2026
Merged

thaJeztah merged 2 commits into
moby:masterfrom
corhere:libnftables-without-nft

Conversation

@corhere

@corhere corhere commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

When the daemon is linked against libnftables it programs the kernel without invoking the nft command. Allow the nftables firewall backend to be enabled when libnftables is used, irrespective of whether nft is installed on the host.

Update the bridge network driver to clean up stale nftables tables in iptables mode without depending on the nft command.

Release notes (optional)

- Allow the nftables firewall mode to be used with a daemon that is linked against libnftables when the `nft` command is not installed on the system.

A picture of a cute animal (not mandatory but encouraged)

@corhere corhere added this to the 29.6.0 milestone Jun 10, 2026
@corhere corhere added kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. impact/changelog area/networking/firewalling Networking labels Jun 10, 2026
@github-actions github-actions Bot added the area/daemon Core Engine label Jun 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the hard dependency on the nft userspace binary when the daemon is built/linked with libnftables, so the nftables firewall backend can be enabled and stale tables can be cleaned up via libnftables APIs instead of shelling out to nft.

Changes:

  • Replace the old “nftPath found in PATH” enablement gate with a build-dependent preflight (nft required only for exec-based builds; no-op for libnftables builds).
  • Introduce RunCmd() to execute raw nftables command buffers via the selected backend (exec vs libnftables).
  • Update the bridge driver nftables cleaner to delete stale tables via nftables.RunCmd() instead of exec.Command("nft", ...).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

File Description
daemon/libnetwork/internal/nftables/nftables_linux.go Switch enablement state to a boolean, add RunCmd(), and refactor table handle management.
daemon/libnetwork/internal/nftables/nft_exec_linux.go Add exec-backend preflight for nft and refactor to a context object type.
daemon/libnetwork/internal/nftables/nft_cgo_linux.go Add libnftables-backend preflight (no nft binary dependency) and refactor to a context object type.
daemon/libnetwork/drivers/bridge/internal/nftabler/cleaner.go Use nftables.RunCmd() for cleanup instead of invoking nft directly.

Comment on lines 234 to 238
func Disable() {
nftPath = ""
enabled = false
incrementalUpdateTempl = nil
reloadTempl = nil
enableOnce = sync.Once{}
Comment on lines +23 to +25
func preflight() error {
return nil
}

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment on lines 233 to 239
// Disable undoes Enable. Intended for unit testing.
func Disable() {
nftPath = ""
enabled = false
incrementalUpdateTempl = nil
reloadTempl = nil
enableOnce = sync.Once{}
}
Comment on lines +23 to +30
var lookPathNft = sync.OnceValues(func() (string, error) {
p, err := exec.LookPath("nft")
if err != nil {
log.G(context.Background()).WithError(err).Warnf("Failed to find nft tool")
return "", fmt.Errorf("failed to find nft tool: %w", err)
}
return p, nil
})
Comment on lines 26 to 31
func tryCleanup(ctx context.Context, family nftables.Family, label string) {
cmd := exec.CommandContext(ctx, "nft", "delete", "table", string(family), dockerTable)
out, err := cmd.CombinedOutput()
err := nftables.RunCmd(ctx, fmt.Appendf(nil, "delete table %s %s", family, dockerTable))
if err != nil {
// May not exist ("Error: Could not process rule: No such file or directory")
log.G(ctx).WithFields(log.Fields{
"error": err,
"output": string(bytes.TrimRight(out, "\n ^")), // remove "^^^^^" added in nft's error message.
}).Info("Deleting nftables " + label + " rules")
log.G(ctx).WithError(err).Info("Deleting nftables " + label + " rules")
return
corhere added 2 commits June 11, 2026 10:54
Afford applying nft commands via libnftables without needing to go
through our table abstraction. Make the table abstraction responsible
for lazily allocating an nft context.

Signed-off-by: Cory Snider <csnider@mirantis.com>
When the daemon is linked against libnftables it programs the kernel
without invoking the `nft` command. Allow the nftables firewall backend
to be enabled when libnftables is used, irrespective of whether `nft` is
installed on the host.

Update the bridge network driver to clean up stale nftables tables in
iptables mode without depending on the `nft` command.

Signed-off-by: Cory Snider <csnider@mirantis.com>
@thaJeztah
thaJeztah force-pushed the libnftables-without-nft branch from b547078 to 8e3e9f4 Compare June 11, 2026 08:55
@thaJeztah

Copy link
Copy Markdown
Member

Did a quick rebase after #52822 was merged (which fixed the CI failures)

func tryCleanup(ctx context.Context, family nftables.Family, label string) {
cmd := exec.CommandContext(ctx, "nft", "delete", "table", string(family), dockerTable)
out, err := cmd.CombinedOutput()
err := nftables.RunCmd(ctx, fmt.Appendf(nil, "delete table %s %s", family, dockerTable))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting to wonder if we should change nftables.RunCmd to accept a string instead of a byte-slice

Comment on lines 34 to 35
cCmd := C.CString(string(nftCmd))
defer C.free(unsafe.Pointer(cCmd))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it would still be converted to a string here, so we'd first allocate a byte-slice, then allocate a string here?

Or was there some path where it would still benefit from passing a byte-slice around?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a []byte because that's what the original exec version of nftApply needed (now in nft_exec_linux.go) ... so it could be changed to a string.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks for the context; it looks unrelated to this PR, so not a blocker for this one!

@thaJeztah thaJeztah left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@thaJeztah

Copy link
Copy Markdown
Member

let me bring this one in so that you can rebase #52833

@thaJeztah
thaJeztah merged commit b707101 into moby:master Jun 11, 2026
573 of 580 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/daemon Core Engine area/networking/firewalling Networking impact/changelog kind/enhancement Enhancements are not bugs or new features but can improve usability or performance.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants