Compare commits

..

2 Commits

Author SHA1 Message Date
Jan Schär b4abe93265 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 extended the message struct with a pointer to the Rule which the
message creates. This allows calling the reply handler callback which
sets the handle.

I updated tests to add a handle to generated replies for the
NFT_MSG_NEWRULE messages.
2025-03-24 10:31:04 +01:00
Jan Schär 295e413abc Receive replies in Flush
Commit 0d9bfa4d18 added code to handle "overrun", but the commit is
very misleading. 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.

The actual bug which the commit was attempting to fix is that Flush was
not receiving replies which the kernel sent for messages with the echo
flag. This change reverts that commit and instead adds code in Flush to
receive the replies.

I updated tests which simulate the kernel to generate replies.
2025-03-24 10:25:46 +01:00
2 changed files with 10 additions and 9 deletions

View File

@ -52,7 +52,7 @@ type Conn struct {
type netlinkMessage struct {
Header netlink.Header
Data []byte
handleReply func(reply netlink.Message) error
rule *Rule
}
// ConnOption is an option to change the behavior of the nftables Conn returned by Open.
@ -274,7 +274,8 @@ func (cc *Conn) Flush() error {
} else if replyIndex < len(cc.messages) {
msg := messages[replyIndex+1]
if msg.Header.Sequence == reply.Header.Sequence && msg.Header.Type == reply.Header.Type {
err := cc.messages[replyIndex].handleReply(reply)
// The only messages which set the echo flag are rule create messages.
err := cc.messages[replyIndex].rule.handleCreateReply(reply)
if err != nil {
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 handleReply func(reply netlink.Message) error
var ruleRef *Rule
switch op {
case operationAdd:
flags = netlink.Request | netlink.Acknowledge | netlink.Create | netlink.Echo | netlink.Append
handleReply = r.handleCreateReply
ruleRef = r
case operationInsert:
flags = netlink.Request | netlink.Acknowledge | netlink.Create | netlink.Echo
handleReply = r.handleCreateReply
ruleRef = r
case operationReplace:
flags = netlink.Request | netlink.Acknowledge | netlink.Replace
}
@ -202,7 +202,7 @@ func (cc *Conn) newRule(r *Rule, op ruleOperation) *Rule {
Flags: flags,
},
Data: append(extraHeader(uint8(r.Table.Family), 0), msgData...),
handleReply: handleReply,
rule: ruleRef,
})
return r