nftables
nftables is a subsystem of the Linux kernel's Netfilter project that provides a modern framework for packet classification, filtering, network address translation (NAT), and other packet mangling operations, serving as the successor to the older iptables, ip6tables, arptables, and ebtables utilities.[1] Introduced in Linux kernel version 3.13, released on January 19, 2014, nftables aims to offer greater flexibility, performance, and simplicity in managing network security rules compared to its predecessors.[2]
At its core, nftables employs a network-specific virtual machine that compiles user-defined rules into bytecode via the Netlink API, allowing for efficient in-kernel execution and reducing the codebase size by shifting much of the logic to userspace tools.[1] Key components include tables, which act as namespaces for organizing rules; chains, which define processing paths with hooks like prerouting, input, forward, output, and postrouting; and rules, which specify matching criteria and actions such as accept, drop, or log.[3] Additional structures like sets and maps enable dynamic, efficient lookups for IP addresses, ports, and other elements, supporting features such as rate limiting and connection tracking integration.
nftables introduces a unified syntax that works consistently across address families (e.g., ip for IPv4, ip6 for IPv6, inet for both, arp for ARP), eliminating the need for protocol-specific commands and simplifying configuration.[3] The primary userspace tool, nft, allows administrators to add, list, and flush rulesets, with configurations typically stored in files like /etc/nftables.conf and loaded via systemd services in modern distributions.[5] It also supports advanced capabilities like flow tables for accelerating packet forwarding in routers by caching flows and bypassing unnecessary hooks, as well as debugging tools such as nftrace for monitoring rule traversal.[6]
Widely adopted in enterprise environments, nftables has become the default firewall backend in distributions like Red Hat Enterprise Linux 8 and Ubuntu 20.10 onward, with migration tools like iptables-restore-translate easing the transition from legacy systems.[3][5] Its design emphasizes atomic updates to rulesets, ensuring consistency during changes, and provides a Netlink API for integration with third-party applications.[3]
Introduction
Overview
nftables is a packet classification and filtering subsystem within the Linux kernel, developed as part of the Netfilter project to succeed the legacy iptables framework. It provides a unified configuration interface for defining rules that handle network packet processing, including classification, filtering, and manipulation across various protocol families such as IPv4, IPv6, ARP, and bridge.[1] This framework replaces the disparate tools like iptables, ip6tables, arptables, and ebtables with a single, more flexible syntax, enabling efficient management of complex firewall policies.[1]
The core purpose of nftables is to allow system administrators to specify rules for incoming, outgoing, and forwarded network traffic, thereby enforcing security policies such as access control, network address translation (NAT), and packet mangling. It integrates directly with the Linux kernel's Netfilter hooks, which are predefined points in the network stack where packets can be inspected and modified before routing decisions are made.[1] This integration ensures low-overhead processing by leveraging existing Netfilter components like connection tracking and logging.[1]
nftables has been available in the Linux kernel since version 3.13, released in 2014, and is now the recommended modern tool for firewall configuration in contemporary Linux distributions.[1][2] Its adoption reflects a shift toward more scalable and performant network security mechanisms within the broader Netfilter ecosystem.[7]
Key Concepts
nftables organizes its packet filtering and classification rules into a hierarchical structure beginning with tables, which serve as top-level containers for chains, sets, maps, flowtables, and other stateful objects. Each table is identified by a unique name and must belong to a specific protocol family, such as ip for IPv4 traffic, ip6 for IPv6 traffic, or inet for handling both IPv4 and IPv6 traffic simultaneously. This family-based organization allows rules to be scoped to particular network protocols, enabling efficient management of diverse traffic types without overlap.[8]
Chains within nftables are sequences of rules contained inside tables and attached to specific points in the network packet processing pipeline, known as Netfilter hooks. Base chains are directly registered with these hooks—such as prerouting for incoming packets before routing decisions or input for packets destined to local processes—while regular chains are user-defined and invoked only via jumps from base chains. Each chain specifies a type (e.g., filter for packet acceptance or dropping, nat for address translation), a hook point, and a priority to determine processing order among multiple chains at the same hook. Chains also have a default policy, typically accept or drop, applied to packets that reach the end without matching any rule.[9]
Rules form the core of nftables configuration, residing within chains and consisting of match expressions that evaluate packet attributes followed by verdict statements that dictate actions. Match expressions filter based on criteria like source IP address (e.g., ip saddr 192.168.1.0/24), destination port (e.g., tcp dport 80), or other protocol fields, with multiple expressions combined logically from left to right until a verdict is reached. Verdicts include accept to allow the packet to proceed, drop to silently discard it, or more advanced options like jump to another chain; these actions terminate rule evaluation and influence the packet's fate in the Netfilter pipeline.[10]
Sets in nftables provide an efficient way to handle unordered collections of matchable elements, such as IP addresses or ports, stored in optimized data structures like hash tables for fast lookups. Named sets can be dynamically updated and referenced in rules (e.g., ip saddr @blacklist drop, where @blacklist contains blocked addresses), while anonymous sets are inline and non-updatable. Complementing sets, maps function as key-value stores for dynamic matching, associating packet fields (e.g., TCP destination port) with action values (e.g., port 22 to accept, port 23 to drop via tcp dport vmap { 22: accept, 23: drop }). Both sets and maps enhance scalability by reducing rule duplication and supporting runtime modifications without reloading entire rulesets.[11][12]
History and Development
Origins and Design Goals
nftables was developed to address the shortcomings of the existing iptables framework, which had fragmented tools for different protocol families, such as iptables for IPv4, ip6tables for IPv6, arptables for ARP, and ebtables for Ethernet bridging. These separate tools led to significant code duplication in the kernel, with similar extensions and protocol handling repeated across families, complicating maintenance and scalability. Additionally, iptables required atomic replacement of entire rulesets for updates, causing performance bottlenecks in dynamic environments, and its syntax was inconsistent and complex, making configuration error-prone for large-scale deployments.[1][13][14]
The primary design goals, spearheaded by Pablo Neira Ayuso, focused on creating a unified packet filtering framework with a single userspace binary called nft to simplify configuration across all protocol families. This approach aimed to shift much of the intelligence to userspace while keeping the kernel component lightweight through a simple virtual machine for packet classification. Performance improvements were targeted via native support for advanced data structures like sets and maps, enabling efficient handling of large rulesets without linear traversal, and providing a more flexible, programmable interface inspired by concepts like BPF. The framework was envisioned to support modern networking needs, such as dynamic updates for cloud environments and IP reputation systems, without the ABI stability issues posed by iptables' binary blob mechanisms.[1][14]
Early development began in 2008 with initial work by Patrick McHardy, who presented an alpha version at the Netfilter Workshop that year, but progress stalled around 2010 due to lack of community involvement. Neira Ayuso restarted the project in 2012–2013, prioritizing integration into the mainline Linux kernel and leveraging funding from organizations like Sophos/Astaro to accelerate development, including contributions from Google Summer of Code participants. A key emphasis was on reusability of the existing Netfilter core components, such as connection tracking, NAT, logging, and low-level hooks, to avoid reinventing foundational infrastructure while introducing the new classification engine.[14][13]
Timeline of Releases
The development of nftables began with an initial release by Patrick McHardy on March 18, 2009, but the project saw a significant restart in 2013 under the leadership of Pablo Neira Ayuso, who announced efforts to revive and merge the core code into the Linux kernel mainline.[15] On October 16, 2013, Ayuso submitted the nftables core pull request, leading to its integration into the Linux kernel version 3.13, released on January 19, 2014.[16] This marked the availability of nftables' basic packet filtering framework in the kernel. The initial user-space tools followed with the nftables 0.4 release on December 16, 2014, providing the first stable nft utility for configuration and management.[17]
Subsequent milestones included the nftables 0.9 release on June 8, 2018, which introduced enhanced scripting capabilities and additional verdicts such as dynamic set element removal and improved rule processing options.[17] The project reached version 1.0 on August 19, 2021, featuring a stabilized API, better performance optimizations, and expanded support for sets and maps to handle complex rule matching more efficiently.[14] In the kernel space, nftables progressed toward replacing legacy iptables modules, with legacy modules maintained for compatibility.
By the 2020s, major Linux distributions began deprecating direct iptables usage in favor of the nftables backend, exemplified by Red Hat Enterprise Linux 9 in 2022, which marked iptables-nft tools as deprecated to encourage full migration.[18] As of 2025, nftables continues to evolve with the latest user-space release, version 1.1.5 on August 27, 2025, incorporating fixes and compatibility updates. In Linux kernel 6.x series (ongoing through 2025), enhancements focus on improved hardware offloading for flowtables via SmartNIC integration and deeper eBPF compatibility for programmable packet processing, enabling higher throughput in networked environments.[17][19]
Architecture
Tables and Families
In nftables, tables serve as organizational namespaces that group related chains, sets, and maps, providing a structured way to manage firewall policies without inherent semantics of their own.[20] They are created using the command nft add table [family] [name], where the family specifies the protocol context and the name uniquely identifies the table within that family.[20] For example, nft add table inet filter establishes a table named "filter" in the inet family, which can then contain subordinate elements like chains.[21] Tables ensure that all components within them—such as chains for rule sequencing—are confined to a single scope, preventing conflicts across different policy areas.[20]
Protocol families in nftables define the type of packets the table processes and influence the available hooks and selectors for packet matching.[20] The primary families include ip for IPv4 packets, ip6 for IPv6 packets, and inet as a hybrid that handles both IPv4 and IPv6 traffic in a unified manner, reducing rule duplication by applying the same policies to both protocols.[22] Additional families are arp for IPv4 Address Resolution Protocol packets, bridge for Layer 2 Ethernet packets on bridge devices, and netdev for early ingress or egress filtering before IP processing, supporting any EtherType.[20] The choice of family determines the packet selectors (e.g., IPv4 addresses in ip versus IPv6 in ip6) and the hooks where base chains can be attached, such as prerouting, input, forward, output, postrouting for ip, ip6, and inet, or ingress/egress for netdev.[21] Using the inet family is particularly advantageous for modern networks, as it allows a single set of rules to cover both IP versions without maintaining separate tables.[22]
Tables maintain ownership over all their subordinate objects, including chains, named sets for storing match elements like IP addresses, and maps for key-value associations such as address-to-verdict mappings.[20] For instance, sets are added with nft add set [family] [table] [setname] { type [type]; }, ensuring they are scoped to the table and can be referenced in rules via @setname.[20] Similarly, maps follow the same ownership model, created as nft add map [family] [table] [mapname] { type [keytype] : [valuetype]; }.[21] This hierarchical structure promotes modularity, as deleting a table removes all its contents atomically.[20]
To maintain consistency, nftables supports atomic transactions for table operations, allowing batches of commands to be applied or rolled back as a unit via files processed with nft -f [filename], ensuring that partial failures do not leave the ruleset in an inconsistent state.[20] Tables can also include flags like dormant to defer evaluation until needed or owner to associate them with a specific process, enhancing control in dynamic environments.[21] Overall, this design enables efficient organization of complex firewall configurations while aligning with the protocol-specific needs of diverse network traffic.[22]
Chains and Hooks
In nftables, chains serve as containers for rules that process network packets at specific points in the Linux kernel's networking stack. There are two primary types of chains: base chains and regular chains. Base chains are directly attached to Netfilter hooks, allowing them to intercept packets at defined stages of the packet processing pipeline, and must specify a type, hook, and priority during creation. Regular chains, in contrast, are user-defined and not directly hooked to the kernel; they are invoked from base chains or other regular chains via jump or goto actions to organize complex rule logic.[20]
Netfilter hooks represent specific interception points in the kernel's packet journey, enabling nftables to filter, modify, or classify traffic. The standard hooks for IPv4, IPv6, and inet families include prerouting (NF_INET_PRE_ROUTING), input (NF_INET_LOCAL_IN), forward (NF_INET_FORWARD), output (NF_INET_LOCAL_OUT), and postrouting (NF_INET_POST_ROUTING). The prerouting hook occurs immediately upon packet arrival, before any routing decisions, while input applies to packets destined for the local system after routing. Forward handles transit packets between interfaces, output processes locally generated packets before routing, and postrouting finalizes packets just before transmission. The netdev family additionally supports ingress and egress hooks for layer 2 processing. Base chains attach to these hooks, and multiple base chains on the same hook are traversed in order of their priority, a signed integer value where lower numbers indicate higher precedence (e.g., -300 for raw processing or 0 for standard filtering).[20][23]
Packet flow in nftables follows the Netfilter architecture's defined traversal order. For incoming packets, processing begins at the prerouting hook, followed by connection tracking and defragmentation, then a routing decision: locally destined packets proceed to the input hook, while forwarded packets go to the forward hook. Both paths converge at the postrouting hook for final adjustments before egress. Outgoing locally generated packets start at the output hook, undergo routing, and end at postrouting. If no rule in a base chain matches a packet, the chain's policy—either accept (default, allowing the packet to continue) or drop (silently discarding it)—determines the outcome. This structure ensures orderly interception without altering the core kernel networking code.[20][23]
To create a base chain, the nft utility is used with syntax specifying the address family, table, chain name, type (e.g., filter for connection-oriented processing or nat for address translation), hook, priority, and policy. For example, the command nft add chain inet filter_table input_chain { type filter hook input priority 0 \; policy accept \; } establishes a base chain in the inet family attached to the input hook at default filter priority, accepting unmatched packets. Regular chains are simpler, as in nft add chain inet filter_table regular_chain, and reside within tables to scope their rules.[20]
Rules, Matches, and Verdicts
In nftables, rules form the core mechanism for inspecting and processing network packets within chains, which serve as ordered containers for these rules. Each rule comprises a sequence of match expressions that evaluate packet attributes—such as headers, metadata, or connection state—followed by one or more statements that dictate the packet's fate if the matches succeed. This structure allows for flexible, composable policies, where multiple matches can be combined logically using operators like conjunction (implicit AND) or disjunction (via anonymous sets). For instance, a rule might match packets from a specific IP range on a particular port: ip saddr 192.168.1.0/24 tcp dport 80.[20]
Match expressions in nftables target various packet elements to enable precise filtering. Protocol fields from IP headers, such as source and destination addresses (ip saddr, ip daddr), and transport layer details like ports ([tcp](/page/TCP) dport, [udp](/page/UDP) sport) are commonly used for basic filtering. Payload inspection extends to layer-specific data, including Ethernet addresses (ether saddr) or raw byte offsets (@th,0,16 for transport header). Additionally, meta expressions access kernel-provided information, such as the layer-4 protocol (meta l4proto [tcp](/page/TCP)) or interface indices (meta iif "eth0"). Stateful matching integrates with the connection tracking subsystem via expressions like ct state established,related or ct direction original, allowing rules to consider packet context for more sophisticated behaviors, such as permitting return traffic in established connections.[20]
Verdicts represent the terminal or control-flow decisions applied to matching packets, determining whether to allow, block, or redirect processing. Terminal verdicts include accept, which passes the packet and halts further evaluation in the current chain (though subsequent hooks may still process it); drop, which silently discards the packet without notification; reject, which discards the packet while sending an ICMP error message (e.g., port unreachable) to the sender; and queue, which enqueues the packet to userspace for custom handling, requiring an explicit accept or drop response. Non-terminal verdicts like continue proceed to the next rule in the chain, while return exits the current chain and resumes at the calling point (or applies the chain's policy if base). Control-flow verdicts such as jump chainname invoke another chain and return afterward, or goto chainname transfers without returning, enabling modular rule organization. Statements like log prefix "blocked" can precede verdicts to record events without altering flow.[20][24]
Rules are added to chains using the nft add rule command, which specifies the address family (e.g., ip, inet), table, chain, match expressions, and verdict in sequence, such as nft add rule [ip](/page/IP) filter input ip saddr 192.168.1.0/24 accept. By default, rules append to the chain's end, but insert places them at the beginning or a specific index/handle, ensuring ordered evaluation. For updates, nft replace rule enables atomic substitution of existing rules by handle, preventing inconsistent states during modifications and supporting seamless policy changes in live environments.[20]
Sets and Maps
Sets in nftables are unordered collections of elements that enable efficient bulk matching within rules, allowing multiple values to be grouped and referenced dynamically. Named sets are defined separately from rules and support runtime modifications, making them suitable for scenarios requiring frequent updates without reloading entire rule sets. For instance, a set of allowed IPv4 addresses can be created with the command nft add set ip filter allowed_ips { type ipv4_addr; elements = { 10.0.0.0/8 } }, and referenced in a rule as ip saddr @allowed_ips accept to permit traffic from those sources.[20] Sets can include flags such as dynamic to enable updates from the packet processing path, interval for storing address or port ranges (e.g., 10.0.0.0-10.0.0.255), and timeout for automatic element expiration. Interval sets support auto-merging of adjacent ranges to optimize storage and lookup efficiency.[20]
Flag sets, which handle bitmasks for fields like packet marks or TCP flags, allow compact representation of multiple bit combinations within a single set element, facilitating matches on complex flag states without enumerating every permutation. For bitmask operations, sets of type mark or similar can store flag values, enabling rules like meta mark @flag_set accept to match specific bit patterns. Concatenation extends sets to compound keys by combining multiple data types, such as an IP address and port (e.g., set type ipv4_addr . inet_service), which supports fast lookups on tuples like ip saddr . tcp dport @compound_set. This feature, introduced in Linux kernel 4.1, enhances performance for multi-field matching.[25][20]
Maps in nftables function as key-value stores, extending sets by associating data or verdicts with keys for dynamic decision-making. A verdict map, for example, can be defined as nft add map inet filter portmap { type inet_service : verdict; elements = { 22 : accept, 80 : drop } }, and used in a rule like tcp dport @portmap to apply the mapped action based on the destination port. Maps support the same types and flags as sets, including interval and dynamic options, and can output values to packet headers (e.g., for NAT) or counters. Like sets, maps permit concatenation for compound keys, such as ip saddr . tcp sport : ipv4_addr for address translation based on source tuples.[20][3]
The primary benefits of sets and maps lie in their support for runtime additions and deletions via commands like nft add element or nft delete element, avoiding the need to flush and reload rules, which reduces administrative overhead in dynamic environments. In modern Linux kernels (5.3 and later), these structures can be offloaded to hardware on compatible network interface cards, accelerating lookups and improving throughput for high-traffic scenarios by shifting processing to specialized silicon. This offload capability, particularly with flowtables, enhances overall efficiency without sacrificing flexibility.[20][26]
The nft Utility
Command Syntax
The nft command-line tool serves as the primary interface for configuring and inspecting nftables rulesets in the Linux kernel. Its basic syntax follows the structure nft [options] [subcommand] [object] [parameters], where options apply globally, the subcommand specifies the operation, the object identifies the target (such as a table or chain), and parameters provide additional details for the action.[20] This declarative syntax allows users to define rules and objects in a human-readable format, contrasting with the more procedural approach of legacy tools like iptables.[20]
Global options modify the behavior of the command across subcommands. Key options include -f or --file to read commands from a specified file (using - for standard input), -i or --interactive to enter an interactive mode for direct command entry, and -j or --json to output results in JSON format for programmatic use.[20] For debugging, the -d or --debug option enables detailed logging at specified levels, such as eval for expression evaluation or netlink for kernel communication traces, helping diagnose configuration issues.[20] Additionally, -c or --check validates syntax and semantics without applying changes to the kernel, aiding in safe testing.[20]
Subcommands dictate the core actions performed on nftables objects. Common subcommands encompass add to create new elements like tables, chains, rules, or sets; delete to remove specified objects; list to display configurations such as rulesets or tables; flush to clear contents from rulesets, tables, or chains; and monitor to observe real-time changes to the ruleset via kernel events.[20] These subcommands operate on hierarchical objects, with more specialized variants like create, insert, replace, or reset available for precise control over tables, chains, rules, sets, and maps.[20]
Object paths in commands specify the scope and location of operations using the format [family] [table] [chain] [handle], where the family (e.g., ip, ip6, inet, arp, bridge, or netdev; defaults to ip if omitted) denotes the address family, followed by the table name, optional chain name, and handle for exact identification.[20] For instance, ip mytable input targets the input chain in the mytable table for the IPv4 family.[20] Handles, numeric identifiers assigned by the kernel, enable precise manipulation of rules or elements without relying on position, and can be revealed using the -a or --handle option in listing commands.[20]
Error handling in nft relies on exit status codes and diagnostic output to indicate issues. The command exits with status 0 on successful execution; status 1 for unspecified errors, including syntax or validation failures; and status 2 for memory allocation problems.[20] Errors, such as invalid syntax or kernel rejection of rules, are reported to standard error, with the debug option providing verbose traces to facilitate troubleshooting.[20] The -c check mode further supports error detection by simulating operations without kernel modifications.[20]
Basic Operations
Basic operations in nftables involve using the nft utility to create, modify, and manage tables, chains, and rules, which form the foundational elements of a firewall configuration. These operations allow administrators to build and adjust packet filtering policies interactively or via scripts, with commands executed directly in the terminal. The syntax follows a consistent pattern: nft [operation] [family] [table] [chain] [statements], where the address family (e.g., ip for IPv4) specifies the protocol domain, and statements define matches or actions.[20]
To create a table, which serves as a container for chains and rules, the command nft add table [family] [table-name] is used. For example, to establish an IPv4 filter table named filter, the following command creates it:
nft add table ip filter
nft add table ip filter
This operation initializes the table without any chains or rules, enabling subsequent additions. Tables must be created before chains can be attached to them.[20]
Once a table exists, chains can be added to organize rules by hook points in the network stack. Base chains, which connect to kernel hooks, require specifications for type, hook, priority, and optionally a default policy. The command syntax is nft add chain [family] [table] [chain-name] { type [type] hook [hook] priority [priority] \; policy [policy] \; }. A common example for an input filter chain with a drop policy is:
nft add chain ip filter input { type filter hook input priority 0 \; policy drop \; }
nft add chain ip filter input { type filter hook input priority 0 \; policy drop \; }
This creates a chain that processes incoming packets, defaulting to dropping them unless a rule allows passage. Regular chains, lacking hook specifications, can be added for jumping from base chains but are not directly invoked by the kernel.[20]
Rules define the logic for matching packets and issuing verdicts, such as accepting or dropping them, and are appended to chains using nft add rule [family] [table] [chain] [match] [verdict]. For instance, to allow incoming traffic from a local subnet:
nft add rule ip filter input ip saddr 192.168.1.0/24 accept
nft add rule ip filter input ip saddr 192.168.1.0/24 accept
This rule matches packets with source IP addresses in the 192.168.1.0/24 range and accepts them. To insert a rule at a specific position, such as the beginning of the chain, use nft insert rule instead of add rule, which prepends the rule:
nft insert rule ip filter input ip saddr 192.168.1.0/24 accept
nft insert rule ip filter input ip saddr 192.168.1.0/24 accept
Rules can reference handles for precise management, obtained via nft list ruleset.[20]
Deleting elements ensures configurations remain current and efficient. To remove a specific rule, identify its handle (a unique numeric identifier) and use nft delete rule [family] [table] [chain] handle [handle-number]. For example:
nft delete rule ip filter input handle 5
nft delete rule ip filter input handle 5
This deletes the rule with handle 5 from the input chain. To clear all rules from a chain without removing the chain itself, employ nft flush chain [family] [table] [chain]:
nft flush chain ip filter input
nft flush chain ip filter input
Flushing resets the chain to its initial state, preserving the default policy.[20]
Configurations are typically persisted by exporting the ruleset to a file and reloading it as needed. To save the active ruleset, redirect the output of nft list ruleset to a file, such as:
nft list ruleset > /etc/nftables.conf
nft list ruleset > /etc/nftables.conf
This captures the entire configuration in a human-readable format compatible with nft syntax. To load a saved ruleset, use nft -f [filename]:
nft -f /etc/nftables.conf
nft -f /etc/nftables.conf
This command applies the rules from the file, overwriting the current ruleset; it is commonly invoked during system boot via service scripts.[20]
Monitoring and Listing
nftables provides several commands for inspecting the current state of rulesets, including tables, chains, and rules, allowing administrators to verify configurations and track packet processing. The nft list tables [family] command displays all tables defined for a specified address family, such as ip or inet, offering an overview of the organized structure of firewall policies.[20] To examine the full contents of a table, including its chains and rules, the nft list table [family] table command is used, for example, nft list table ip filter to show the standard input, output, and forward chains in the IPv4 filter table.[24] Similarly, nft list chain [family] table chain lists the rules within a specific chain, such as nft list chain ip filter input, which includes details on matches, verdicts, and associated counters.[20]
Rules displayed in listings often include byte and packet counters, which accumulate statistics on matched traffic to aid in performance analysis and troubleshooting. These counters appear in the output as packets X bytes Y, where X and Y represent the counts since the last reset.[24] To zero these counters for a fresh measurement period, the nft reset counters [family] [table [chain]] command is employed; for instance, nft reset counters [ip](/page/IP) [filter](/page/Filter) input resets only the input chain counters, while omitting arguments resets all counters system-wide.[20]
For real-time observation of nftables activity, the monitoring subcommands enable tracking of dynamic changes and packet flows. The nft monitor trace command captures packet traces, showing the path through rules and chains where matches occur, provided the meta nftrace set 1 expression is included in relevant rules to enable tracing.[24] This is particularly useful for debugging why packets are accepted, dropped, or altered, as traces reveal the exact rule hit and verdict applied.[20] Complementing this, nft monitor events listens for notifications on ruleset modifications, such as additions or deletions of tables, chains, or rules, with options to filter by family or table for targeted output.[24]
Output from listing and monitoring commands can be customized for different use cases, enhancing readability or integration with scripts. The -n option produces numeric output, displaying IP addresses, ports, and protocols without hostname or service name resolution, which speeds up processing in automated environments.[20] For programmatic handling, the -j flag outputs in JSON format, enabling parsing by tools or applications, as in nft -j list ruleset.[24] Additionally, -a includes numerical handles for each object, visible in listings like nft -a list chain ip filter input, which are essential for precise modifications or deletions in scripting workflows.[20]
Configuration Examples
Simple Firewall Setup
A simple firewall setup with nftables for a standalone host begins by creating an inet table, which supports both IPv4 and IPv6 protocols, to organize the ruleset. Base chains are then attached to the input, output, and forward hooks. The input chain uses a default drop policy to deny unsolicited incoming traffic, enhancing security for the host, while the output chain uses accept to allow all outgoing traffic. The forward chain has a drop policy to prevent routing unless explicitly allowed, with a rule restricting to local networks. Essential rules are added to permit loopback traffic, established or related connections, and access to common services like SSH.[27][28]
To implement this configuration, start by flushing any existing ruleset and creating the table:
nft flush ruleset
nft add table inet [filter](/page/Filter)
nft flush ruleset
nft add table inet [filter](/page/Filter)
Next, define the chains. The input chain processes incoming packets to the host:
nft add chain inet [filter](/page/Filter) input { type [filter](/page/Filter) hook input [priority](/page/Priority) 0; [policy](/page/Policy) [drop](/page/Drop); }
nft add chain inet [filter](/page/Filter) input { type [filter](/page/Filter) hook input [priority](/page/Priority) 0; [policy](/page/Policy) [drop](/page/Drop); }
The output chain handles outgoing packets from the host:
nft add chain inet [filter](/page/Filter) output { type [filter](/page/Filter) hook output [priority](/page/Priority) 0; [policy](/page/Policy) accept; }
nft add chain inet [filter](/page/Filter) output { type [filter](/page/Filter) hook output [priority](/page/Priority) 0; [policy](/page/Policy) accept; }
The forward chain manages packets routed through the host, assuming basic routing is enabled:
nft add chain inet filter forward { type filter hook forward priority 0; policy drop; }
nft add chain inet filter forward { type filter hook forward priority 0; policy drop; }
These chains reference the filter hook points in the network stack, where the priority 0 ensures standard processing order.[9]
Add rules to the input chain for essential allowances. Permit all loopback traffic to allow local communications:
nft add rule inet filter input iif lo accept
nft add rule inet filter input iif lo accept
Allow packets belonging to established or related connections to maintain ongoing sessions:
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input ct state established,related accept
Enable incoming SSH connections on port 22 for remote administration:
nft add rule inet filter input tcp dport 22 accept
nft add rule inet filter input tcp dport 22 accept
These rules use interface matching (iif), connection tracking (ct state), and port matching (tcp dport) to selectively accept traffic.[27]
For the forward chain, add rules to drop packets exiting on the primary interface (e.g., eth0) destined for non-local networks, preventing unintended routing to external addresses. For IPv4:
nft add rule inet [filter](/page/Filter) forward oif eth0 ip daddr != 192.168.0.0/16 drop
nft add rule inet [filter](/page/Filter) forward oif eth0 ip daddr != 192.168.0.0/16 drop
For IPv6 (assuming ULA fd00::/8 as local):
nft add rule inet [filter](/page/Filter) forward oif eth0 ip6 daddr != fd00::/8 drop
nft add rule inet [filter](/page/Filter) forward oif eth0 ip6 daddr != fd00::/8 drop
These use output interface matching (oif) and negated destination address (ip daddr != or ip6 daddr !=) to enforce local-only forwarding.[20]
To make the configuration persistent across reboots, export the ruleset to a configuration file and enable the nftables service. First, generate the file:
nft list ruleset > /etc/nftables.conf
nft list ruleset > /etc/nftables.conf
The resulting /etc/nftables.conf will contain the full ruleset in a loadable format, such as:
table inet [filter](/page/Filter) {
chain input {
type [filter](/page/Filter) hook input priority [filter](/page/Filter); policy drop;
iif "lo" accept
ct state { established, related } accept
tcp dport 22 accept
}
chain output {
type [filter](/page/Filter) hook output priority [filter](/page/Filter); policy accept;
}
chain forward {
type [filter](/page/Filter) hook forward priority [filter](/page/Filter); policy drop;
oif "eth0" ip daddr != 192.168.0.0/16 drop
oif "eth0" ip6 daddr != fd00::/8 drop
}
}
table inet [filter](/page/Filter) {
chain input {
type [filter](/page/Filter) hook input priority [filter](/page/Filter); policy drop;
iif "lo" accept
ct state { established, related } accept
tcp dport 22 accept
}
chain output {
type [filter](/page/Filter) hook output priority [filter](/page/Filter); policy accept;
}
chain forward {
type [filter](/page/Filter) hook forward priority [filter](/page/Filter); policy drop;
oif "eth0" ip daddr != 192.168.0.0/16 drop
oif "eth0" ip6 daddr != fd00::/8 drop
}
}
Then, enable and start the service using systemd:
systemctl enable nftables
systemctl start nftables
systemctl enable nftables
systemctl start nftables
This ensures the rules load automatically on boot via the service unit.[28]
Advanced Features
nftables supports advanced configurations that enhance scalability and dynamism in packet filtering through the use of sets and maps for efficient matching and decision-making. Sets allow for the creation of dynamic collections of elements, such as IP addresses in whitelists, which can be referenced in rules without modifying the rule set itself.[11] For instance, a set can be defined as follows:
nft add table ip filter
nft add set ip filter whitelist { type ipv4_addr; }
nft add table ip filter
nft add set ip filter whitelist { type ipv4_addr; }
Elements are populated using the add element command, enabling runtime additions like nft add element ip filter whitelist { 192.168.1.1, 192.168.1.2 }.[11] These sets are then referenced in rules with the @ syntax, such as nft add rule ip filter input ip saddr @whitelist accept, allowing whitelisted IPs to bypass further filtering.[11] Dynamic updates are performed via nft add element ip filter whitelist { 10.0.0.5 }, supporting real-time adjustments without rule reloading.[11]
Verdict maps extend this capability by associating packet attributes, like ports, with actions or chain jumps, facilitating port-based policy enforcement. A named verdict map is declared with nft add map ip [filter](/page/Filter) portmap { type inet_service : [verdict](/page/Verdict); }, where keys are ports and values are verdicts.[12] Elements are added as nft add element ip [filter](/page/Filter) portmap { 80 : accept, 22 : [jump](/page/Jump) ssh[chain](/page/Chain) }, mapping HTTP traffic to acceptance and SSH to a dedicated chain.[12] For more granular control, concatenation enables tuple matching since Linux kernel 4.1, such as declaring nft add map ip [filter](/page/Filter) tuplemap { type ipv4_addr . inet_service : [verdict](/page/Verdict); } (CIDR support since kernel 5.6), with rule nft add rule ip [filter](/page/Filter) input ip saddr . tcp dport map @tuplemap and element nft add element ip [filter](/page/Filter) tuplemap { 192.168.1.0/24 . 80 : accept }, combining source IP network and destination port for precise verdicts.[29][12]
Logging integrates directly into rules to capture events with customizable prefixes and levels, aiding in intrusion detection and debugging. The statement log prefix "intrusion" level info logs matching packets with the specified prefix at informational severity, as in nft add rule ip filter input tcp dport 22 log prefix "intrusion" level info drop.[20] This logs unauthorized SSH attempts without affecting performance, directing output to the kernel log or NFLOG group.[20]
Rate limiting prevents abuse through token bucket filters embedded in rules, combining with logging for controlled event capture. The syntax limit rate 5/second burst 10 restricts actions to 5 packets per second with a burst of 10, as in nft add rule ip filter input ip protocol icmp limit rate 5/second burst 10 log prefix "icmp-flood" level info drop.[30] This mitigates denial-of-service attempts by accepting initial bursts while throttling sustained traffic.[30]
Integration with kernel features like NAT, connection tracking, and acceleration broadens nftables' applicability. For NAT, masquerading dynamically alters source IPs using the outbound interface address, configured as nft add [table](/page/Table) nat; nft add [chain](/page/Chain) nat postrouting { type nat hook postrouting [priority](/page/Priority) 100; }; nft add [rule](/page/Rule) nat postrouting oifname "eth0" masquerade.[31] Conntrack helpers extend tracking for protocols like FTP or SIP, defined with nft 'add ct helper ftp { type "ftp" protocol [tcp](/page/TCP); }', enabling proper handling of related connections.[20] Since Linux kernel 5.1, eBPF offload supports flowtable acceleration, where nft add flowtable inet myft { hook ingress [priority](/page/Priority) 0; devices = { eth0 }; } offloads established flows to eBPF for reduced CPU overhead.[6] Hardware acceleration examples include offloading to Mellanox ConnectX-5 NICs via switchdev, adding flags offload; to flowtables for line-rate forwarding of up to 100 Gbps.[19]
Comparison with iptables
Structural Differences
nftables represents a significant architectural shift from iptables by adopting a unified framework that consolidates packet filtering, NAT, and other network processing into a single tool and syntax. Unlike iptables, which requires distinct binaries—such as iptables for IPv4, ip6tables for IPv6, arptables for ARP, and ebtables for Ethernet bridging—nftables utilizes the sole nft utility to manage rules across all supported address families, including ip, ip6, inet, arp, bridge, and netdev. This unification eliminates the fragmentation inherent in iptables, where protocol-specific tools lead to inconsistent syntax and duplicated functionality.[1][3]
The organizational structure of nftables further diverges from iptables through its use of flexible, user-defined tables and chains. In nftables, tables serve as namespaces containing chains, sets, and other objects, with no predefined tables like iptables' filter, nat, mangle, or raw; administrators create tables explicitly for specific address families. Chains in nftables are entirely user-defined, including base chains that attach to netfilter hooks (e.g., input, output) with customizable priorities, contrasting iptables' reliance on built-in chains such as INPUT, FORWARD, and PREROUTING within each table. This design allows for greater modularity, as chains can be organized hierarchically without rigid, protocol-bound constraints.[20][3][32]
nftables employs a declarative rule language that enhances expressiveness and modularity compared to iptables' imperative, chain-oriented commands. Rules in nftables consist of left-to-right evaluated expressions and verdicts, supporting advanced constructs like references to sets (e.g., ip daddr @allowed_hosts accept) for dynamic matching without separate extensions. In contrast, iptables uses verbose, match-action pairs specific to chains and requires tools like ipset for similar bulk operations, resulting in less modular and more repetitive configurations. This declarative approach in nftables facilitates complex logic, such as verdict maps, in a concise manner.[32][3]
To support legacy systems, nftables includes an iptables-nft compatibility layer introduced in Linux kernel 3.13, which translates traditional iptables commands into native nftables rulesets via the nf_tables backend. This layer enables seamless execution of iptables syntax through tools like iptables-nft, preserving backward compatibility while encouraging migration to the unified nftables structure.[1][33]
nftables achieves efficiency gains over iptables primarily through its single-pass evaluation mechanism, which processes packets in a unified manner across chains and tables, avoiding the multiple table traversals required in iptables where packets are routed through separate filter, NAT, and mangle tables sequentially.[34] This design reduces processing overhead by compiling rules into an optimized kernel-space representation, minimizing redundant checks and context switches. Additionally, nftables minimizes kernel-userspace data copies by using a streamlined ABI that batches rule updates and leverages efficient netlink communication, leading to lower latency in rule management compared to iptables' legacy interface.[35]
At the core of nftables' performance are its advanced data structures, including hash tables for sets and maps, which enable average O(1) lookup times for matching packet attributes against large collections of elements.[34] Unlike iptables' linear chain traversal, these structures allow nftables to handle expansive rulesets—such as those exceeding 10,000 rules—with low CPU overhead, maintaining efficient performance under load as nftables scales better than iptables.[36] This scalability is particularly beneficial for scenarios involving frequent IP or port matching, where nftables maintains consistent performance without the exponential degradation seen in iptables' custom chain jumps.
Benchmarks demonstrate nftables' advantages in high-traffic environments, with studies showing slightly lower or comparable latency to iptables for large frame sizes (e.g., 1024 bytes or more) and modest rule counts (under 100 rules), though results vary by configuration—nftables can exhibit higher latency for small frames (64-128 bytes) and very large rulesets (over 1,000 rules) using linear lookups.[37] In throughput tests at 1 Gbps+ speeds, nftables sustains near-linear performance scaling with rule complexity, achieving better efficiency than iptables in scenarios like multi-port matching or chain-heavy setups, where nftables scales more effectively without proportional performance drops due to sequential processing.[36] For indexed structures, the two frameworks perform nearly identically, highlighting nftables' edge in optimized deployments.
As of 2025, integrations like Kubernetes' nftables mode for kube-proxy demonstrate continued performance improvements over iptables in production environments.[38]
nftables further enhances efficiency through integration with eBPF for hardware offloading to NICs, allowing compatible network interface cards to execute rules in hardware, bypassing kernel processing for eligible flows and reducing CPU load in high-throughput environments like data centers.
Despite these strengths, nftables has limitations, including initial setup overhead for complex maps due to the time required for kernel compilation and backend selection, which can delay configuration in dynamic environments.[3] Dynamic sets also incur higher memory usage than static rules in iptables, as hash tables and interval trees consume additional resources for elements with timeouts or frequent updates, though this is tunable via flags like flags interval to balance performance and footprint.[3]
Adoption and Integration
In Linux Distributions
In Red Hat Enterprise Linux (RHEL) 8, released in 2019, nftables became the default backend for the firewalld service, replacing the previous iptables-based implementation to leverage nftables' improved performance and flexibility.[39] This shift applies similarly to downstream distributions like CentOS Stream and Fedora, where nftables is packaged in the base repositories and integrated as the standard netfilter framework.[3] Red Hat provides migration tools and guides, such as the iptables-restore-translate command, to convert legacy iptables rulesets to nftables syntax during upgrades, ensuring compatibility for existing configurations.[40]
In Debian, the nftables package has been available since version 8 (Jessie) in 2015, shortly after its upstream introduction, and is maintained in the main repository for easy installation via apt.[41] Ubuntu, building on Debian, includes nftables since 14.04 (Trusty Tahr) in 2014, with the Uncomplicated Firewall (ufw) frontend adopting nftables as its default backend starting in Ubuntu 21.10 (Impish Indri) and continuing in 22.04 LTS (Jammy Jellyfish) and later releases.[42] Ubuntu also supports firewalld with its nftables backend enabled by default in recent versions, allowing users to choose between ufw or firewalld for nftables management.[43] The nftables.service systemd unit is provided in both distributions for enabling persistent rule loading at boot, typically via systemctl enable nftables.service after installing the package.[44]
Arch Linux includes nftables as an official package in its extra repository, making it readily available for installation and considered a core component of the system's networking stack.[45] The distribution encourages manual configuration using the nft command-line tool, with rules stored in /etc/nftables.conf for simplicity and direct control, rather than relying on higher-level frontends.[28] Integration with systemd ensures persistence through the nftables.service unit, which loads the configuration file on startup when enabled.[46]
openSUSE has adopted nftables as the backend for firewalld since Leap 15.4 (released in 2022), with Tumbleweed using it by default for dynamic firewall management.[47] Gentoo provides nftables as the recommended successor to iptables, available via Portage, and recent kernel configurations (such as in 6.17) disable legacy iptables by default in favor of nftables compatibility.[48]
By 2025, nftables has achieved widespread adoption across major Linux distributions, with most deprecating or phasing out iptables in favor of nftables as the primary firewall framework, driven by its superior syntax and efficiency. In Linux kernel series 6.x and later, new netfilter features are developed primarily for nftables, with iptables supported through compatibility layers like iptables-nft.
Several higher-level front-ends simplify nftables management by providing abstracted interfaces for common firewall configurations. Firewalld, a dynamic firewall management tool, has utilized nftables as its backend since version 0.6.0, enabling zone-based rule application and runtime changes without service restarts.[43] UFW (Uncomplicated Firewall), a user-friendly frontend originally designed for iptables, added support for nftables in recent versions, allowing it to manage nftables rulesets on modern Linux distributions like Ubuntu 22.04 and later.[49]
Graphical interfaces offer visual tools for nftables configuration, often layered over front-ends like firewalld. Firewall-config, the GNOME graphical frontend for firewalld, provides an intuitive interface for defining zones, services, and rules, leveraging nftables under the hood for backend enforcement on desktop environments. For more direct nftables interaction, limited options exist. Shorewall and Shorewall6, configuration tools for iptables-based firewalls, do not yet fully support an nftables mode, though community discussions explore potential migrations.[50]
Programmatic access to nftables is facilitated through libraries and automation integrations. The libnftables C library offers a high-level API for interacting with the nftables Netlink interface, enabling applications to create, modify, and query rules programmatically without invoking the nft command-line tool.[3] Python bindings, provided by the python3-nftables package, wrap libnftables to allow scripting nftables configurations in Python, supporting tasks like dynamic rule generation.[51] Configuration management tools integrate nftables via dedicated modules: the Ansible nftables collection uses python3-nftables to automate firewall deployments across hosts, while the Puppet nftables module generates opinionated nftables configurations for infrastructure-as-code setups.[52]
Monitoring nftables involves tools for traffic accounting and metrics export. Nfacct serves as the userspace utility for managing netfilter accounting objects, allowing the creation and querying of counters for packet and byte statistics within nftables rulesets.[53] For observability, nftables integrates with Prometheus through exporters like nftables-exporter, which scrapes counter data from nftables tables and exposes it in Prometheus format for alerting and visualization in tools like Grafana.