While atomic rule replacement is documented:
Atomic Rule Replacement
You can use the -f
option to atomically update your ruleset:
% nft -f file
it's not explicitly documented for element replacement, but that's really just a case of rule replacement. One can delete and add back the element in a single atomic transaction introduced with -f
: this will replace the older entry with the newer and its updated expiration time, without ever getting the element temporarily missing.
So instead of doing the following, which wouldn't be atomic because between the two invocations of nft
, the element would be temporarily not existing and rules depending on this set would temporarily not match:
# nft delete element ip mytable myset '{ 10.10.10.1 }'
# nft add element ip mytable myset '{ 10.10.10.1 timeout 60s expires 60s }'
this should be done using -f
and an input file (-
standing for stdin counts as valid input file):
# nft -f - <<'EOF'
delete element ip mytable myset { 10.10.10.1 }
add element ip mytable myset { 10.10.10.1 timeout 60s }
EOF
where the element will never cease to existing because it's an atomic change.
As usual with this nft construct, if one wants to do this idempotently, without having to know if the element already exists, and without touching other elements, it should be added, deleted and re-added, because while adding an existing element isn't an error, deleting a missing element will be an error:
# nft -f - <<'EOF'
add element ip mytable myset { 10.10.10.1 }
delete element ip mytable myset { 10.10.10.1 }
add element ip mytable myset { 10.10.10.1 timeout 60s }
EOF
It's still a single atomic transaction.
Additional notes
from packet path
When doing this from packet path there's a distinction between add @myset
which will set the timeout only when creating a new element, but won't update the timeout of an already existing element, allowing it to timeout over its full duration later, and update @myset
which does set the timeout in all cases.
atomic rule update isn't limited to elements but can be used at any level
For example the same can be done at the set level if there's a single element to care for:
# nft -f - <<'EOF'
add set ip mytable myset { type ipv4_addr; flags timeout; }
delete set ip mytable myset
add set ip mytable myset {
type ipv4_addr
flags timeout
elements = { 127.0.0.1 timeout 1m }
}
EOF
Actually above example will likely fail because there's probably a rule referencing the set, so it isn't allowed to delete it even during the transaction (one could instead rewrite likewise the whole table, with add table ip mytable
, delete table ip mytable
, add table ip mytable { ...
). If the set is known to exist before, flushing it before adding back the single element is enough:
# nft -f - <<'EOF'
flush set ip mytable myset
add element ip mytable myset { 127.0.0.1 timeout 1m }
EOF
Of course an actual file can be used instead of - <<'EOF'
...EOF
.