-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set the rule handle after flush #88
base: main
Are you sure you want to change the base?
Changes from 7 commits
8cb78f7
5a645a1
b00522b
39f8fec
87f28ce
994c20d
3650f83
9dc224d
e906f33
3aaad4c
c578ee3
4edcb60
c8335d6
a400c5d
0d3f3ff
0f16d39
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3980,3 +3980,122 @@ func TestStatelessNAT(t *testing.T) { | |
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestHandleBack(t *testing.T) { | ||
|
||
if os.Getenv("TRAVIS") == "true" { | ||
t.SkipNow() | ||
} | ||
|
||
// Create a new network namespace to test these operations, | ||
// and tear down the namespace at test completion. | ||
c, newNS := openSystemNFTConn(t) | ||
defer cleanupSystemNFTConn(t, newNS) | ||
// Clear all rules at the beginning + end of the test. | ||
c.FlushRuleset() | ||
defer c.FlushRuleset() | ||
|
||
filter := c.AddTable(&nftables.Table{ | ||
Family: nftables.TableFamilyIPv4, | ||
Name: "filter", | ||
}) | ||
|
||
chain1 := c.AddChain(&nftables.Chain{ | ||
Name: "chain1", | ||
Table: filter, | ||
Type: nftables.ChainTypeFilter, | ||
Hooknum: nftables.ChainHookPrerouting, | ||
Priority: nftables.ChainPriorityFilter, | ||
}) | ||
|
||
chain2 := c.AddChain(&nftables.Chain{ | ||
Name: "chain2", | ||
Table: filter, | ||
Type: nftables.ChainTypeFilter, | ||
Hooknum: nftables.ChainHookPrerouting, | ||
Priority: nftables.ChainPriorityFilter, | ||
}) | ||
|
||
var rulesCreated1 []*nftables.Rule | ||
var rulesCreated2 []*nftables.Rule | ||
|
||
alexispires marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rulesCreated1 = append(rulesCreated1, c.AddRule(&nftables.Rule{ | ||
Table: filter, | ||
Chain: chain1, | ||
Exprs: []expr.Any{ | ||
&expr.Verdict{ | ||
// [ immediate reg 0 drop ] | ||
Kind: expr.VerdictDrop, | ||
}, | ||
}, | ||
})) | ||
|
||
rulesCreated1 = append(rulesCreated1, c.AddRule(&nftables.Rule{ | ||
Table: filter, | ||
Chain: chain1, | ||
Exprs: []expr.Any{ | ||
&expr.Verdict{ | ||
// [ immediate reg 0 drop ] | ||
Kind: expr.VerdictDrop, | ||
}, | ||
}, | ||
})) | ||
|
||
rulesCreated2 = append(rulesCreated2, c.AddRule(&nftables.Rule{ | ||
Table: filter, | ||
Chain: chain2, | ||
Exprs: []expr.Any{ | ||
&expr.Verdict{ | ||
// [ immediate reg 0 drop ] | ||
Kind: expr.VerdictDrop, | ||
}, | ||
}, | ||
})) | ||
|
||
for i, r := range rulesCreated1 { | ||
if r.Handle != 0 { | ||
t.Fatalf("unexpected handle value at %d", i) | ||
} | ||
} | ||
|
||
for i, r := range rulesCreated2 { | ||
if r.Handle != 0 { | ||
t.Fatalf("unexpected handle value at %d", i) | ||
} | ||
} | ||
|
||
if err := c.Flush(); err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
rulesGetted1, _ := c.GetRule(filter, chain1) | ||
rulesGetted2, _ := c.GetRule(filter, chain2) | ||
|
||
if len(rulesGetted1) != len(rulesCreated1) { | ||
t.Fatalf("Bad ruleset length got %d want %d", len(rulesGetted1), len(rulesCreated1)) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this test running many workers concurrently? In other words: why is not sufficient to test with 1 worker? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To test the behaviors with concurrency as exprimed here: #88 (comment) |
||
if len(rulesGetted2) != len(rulesCreated2) { | ||
t.Fatalf("Bad ruleset length got %d want %d", len(rulesGetted2), len(rulesCreated2)) | ||
} | ||
|
||
for i, r := range rulesGetted1 { | ||
if r.Handle == 0 { | ||
t.Fatalf("handle value is empty at %d", i) | ||
} | ||
|
||
if r.Handle != rulesCreated1[i].Handle { | ||
t.Fatalf("mismatched handle at %d", i) | ||
} | ||
} | ||
|
||
for i, r := range rulesGetted2 { | ||
if r.Handle == 0 { | ||
t.Fatalf("handle value is empty at %d", i) | ||
} | ||
|
||
if r.Handle != rulesCreated2[i].Handle { | ||
t.Fatalf("mismatched handle at %d", i) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of the separate
entites
book-keeping, why not just iterate over cc.messages and check if the type implements HandleResponse?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HandleResponse is not a method that belong to netlink.Message. It's belong to entity.
For a given entity, it's perform some operations on it by using the netlink response. We have to connect an entity (like a Rule) and a netlink message in case of the slice of responses is unordered. I connect them with the netlink sequence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. I’m still not particularly happy about having to manage
messages
andentities
, which are separate but connected.Instead of the current approach, we could make
messages
take an interface type which has aNetlinkMessage
method. putMessages would then wrap anetlink.Message
in a type which implementsNetlinkMessage
, and can optionally implementHandleResponse
as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stapelberg I'm not sure to understand what do you have in mind but the main limit I have is that the SendMessages method of netlink library take a slice of netlink.Message and not a slice of netlink.Message's pointer. So the only data struct that give me the netlink sequence number is the slice of netlink.Message returned by sendMessages. So the slice of netlink.Message have to be connected in one way or another to something else. In your solution I have to connect the type that wrap netlink.Message with the netlink.Message that contains the seq even if both are the same netlink message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m a little confused now: you’re saying the sequence numbers are only set in the []netlink.Message that’s returned by
(*netlink.Conn).SendMessages
, but in your PR, you’re discarding that result:Is that a bug in your PR, or am I misunderstanding?
(Independently, related to your question: the fact that the netlink package takes a []netlink.Message instead of []*netlink.Message doesn’t limit us in which data structures we want to use. If need be, we can do a copy from one to the other. A netlink.Message’s Header is just a few ints, and copying the Body byte slice won’t need to copy its contents.)