Compare commits

..

1 Commits

Author SHA1 Message Date
Jan Schär 7a668d7c79 Set rule handle during flush
This change makes it possible to delete rules after inserting them,
without needing to query the rules first. Additionally, this allows
positioning a new rule next to an existing rule.

There are two ways to refer to a rule: Either by ID or by handle. The ID
is assigned by userspace, and is only valid within a transaction, so it
can only be used before the flush. The handle is assigned by the kernel
when the transaction is committed, and can thus only be used after the
flush. We thus need to set an ID on each newly created rule, and
retrieve the handle of the rule during the flush.

I implemented a new mechanism for retrieving replies in Flush, and
handling these replies by adding a callback to netlink messages. There
was some existing code to handle "overrun", which I deleted, because it
was nonsensical and just worked by accident. NLMSG_OVERRUN is in fact
not a flag, but a complete message type, so the (re&netlink.Overrun)
masking makes no sense. Even better, NLMSG_OVERRUN is never actually
used by Linux. What this code was actually doing was skipping over the
NFT_MSG_NEWRULE replies, and possibly a NFT_MSG_NEWGEN reply.

I updated tests to generate replies for the NFT_MSG_NEWRULE messages
with a handle added.
2025-03-18 09:46:35 +00:00
2 changed files with 9 additions and 10 deletions

View File

@ -52,7 +52,7 @@ type Conn struct {
type netlinkMessage struct { type netlinkMessage struct {
Header netlink.Header Header netlink.Header
Data []byte Data []byte
rule *Rule handleReply func(reply netlink.Message) error
} }
// ConnOption is an option to change the behavior of the nftables Conn returned by Open. // ConnOption is an option to change the behavior of the nftables Conn returned by Open.
@ -274,8 +274,7 @@ func (cc *Conn) Flush() error {
} else if replyIndex < len(cc.messages) { } else if replyIndex < len(cc.messages) {
msg := messages[replyIndex+1] msg := messages[replyIndex+1]
if msg.Header.Sequence == reply.Header.Sequence && msg.Header.Type == reply.Header.Type { if msg.Header.Sequence == reply.Header.Sequence && msg.Header.Type == reply.Header.Type {
// The only messages which set the echo flag are rule create messages. err := cc.messages[replyIndex].handleReply(reply)
err := cc.messages[replyIndex].rule.handleCreateReply(reply)
if err != nil { if err != nil {
errs = errors.Join(errs, err) errs = errors.Join(errs, err)
} }

View File

@ -174,14 +174,14 @@ func (cc *Conn) newRule(r *Rule, op ruleOperation) *Rule {
} }
var flags netlink.HeaderFlags var flags netlink.HeaderFlags
var ruleRef *Rule var handleReply func(reply netlink.Message) error
switch op { switch op {
case operationAdd: case operationAdd:
flags = netlink.Request | netlink.Acknowledge | netlink.Create | netlink.Echo | netlink.Append flags = netlink.Request | netlink.Acknowledge | netlink.Create | netlink.Echo | netlink.Append
ruleRef = r handleReply = r.handleCreateReply
case operationInsert: case operationInsert:
flags = netlink.Request | netlink.Acknowledge | netlink.Create | netlink.Echo flags = netlink.Request | netlink.Acknowledge | netlink.Create | netlink.Echo
ruleRef = r handleReply = r.handleCreateReply
case operationReplace: case operationReplace:
flags = netlink.Request | netlink.Acknowledge | netlink.Replace flags = netlink.Request | netlink.Acknowledge | netlink.Replace
} }
@ -202,7 +202,7 @@ func (cc *Conn) newRule(r *Rule, op ruleOperation) *Rule {
Flags: flags, Flags: flags,
}, },
Data: append(extraHeader(uint8(r.Table.Family), 0), msgData...), Data: append(extraHeader(uint8(r.Table.Family), 0), msgData...),
rule: ruleRef, handleReply: handleReply,
}) })
return r return r