Conversation
qmonnet
left a comment
There was a problem hiding this comment.
This is a great addition, but I've got a concern about concurrency. Could it be that we bump the config while the packet is being processed, for example after we've agreed to bypass flow-filter or after we've looked at the NAT context, and that we pick the genid for a new config that no longer allows it when creating the sessions? Should we attach the genid to the packet in the flow-filter instead, and pass it along to be sure that it doesn't change while we process the packet?
I did a first implementation with that idea, but later thought that this was cleaner. (I can re-add the marking of packets with the genid). In the case you mentioned, yes, we'd allowing a packet that should not longer be allowed. But is that a problem? I mean, if the config was applied 1ns later, tons of packets would be allowed. Sure, NFs may not find the right state to process it, but all are (should otherwise) be prepared for that, right? |
I agree, that part is a non-issue.
I'm not sure we're talking of the same thing. My issue is the following: let's consider a change of config from gen X to X+1, and a packet valid for gen X but invalid for gen X+1.
The issue is not at step 5, it's fine that this packet goes through. The issue is at step 4 (then 6): if we retrieve the Looking again at the code I think you're right that we don't need to pass the |
That's the exact example I was thinking about. I have to think of a solution to that. |
Ok. I've had the time now to think about this. Yes, this needs to be addressed, good catch. With that in mind, the problem is that the condition to bypass (flow.genid = current.genid) is insufficient to tell that the flow is okay for the new genid, because by the time the flow was created, we skipped the validation in the case of the race.
... a simple solution involves augmenting the flow with a new field that says that it was actually validated under the current genid. |
I need to think more about it, too, but I think your proposal should work |
Ok!. There's actually a simpler one that involves the same variables, repurposed.
|
3750381 to
f54731e
Compare
qmonnet
left a comment
There was a problem hiding this comment.
There's actually a simpler [solution] [...]
Yes, I think it looks correct. The flows are tagged with the right genid, it means we can only bypass starting from the 3rd packet (1st creates the flow, 2nd gets validated and sets the genid) but it's still better than no bypass or a flawed bypass.
Please make sure to address, or reply to/resolve all comments from the first review.
We need an easy way for NFs that belong to a pipeline to access
some common data (e.g. the generation Id of the current configuration
applied) in an easy way, without needing to propagate or change
APIs each time.
This commit:
- defines a PipelineData struct with an atomic u64 for the generation
id. A struct is defined so that other fields can be added later.
- extends trait NetWorkFunction so that the stages that require so
can have an Arc to the PipelineData when added to the pipeline.
- Modifies the method to add stages to the pipeline so that those
NFs that implement the new method get access to the shared
PipelineData.
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Extend the masquerade, port-forwarding and flow-filter NFs with an Arc<> to pipeline data and implement the trait method set_data(). Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Pass pipeline data to mgmt and update its generation id when a new config is applied. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Augment the flow_info object with a generation id. The value represents the generation id of the configuration under which the flow was created. Subsequent configuration changes will update the value to the current generation id if the flow is still allowed under that configuration. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
When creating a flow for masquerading or port forwarding, label it with the current generation id. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Modify flow filter so that packets are not unnecessarily
re-evaluated if they refer to a flow and the flow was created with
the current configuration.
The logic is:
- if packet refers to a flow and the flow's gen id is the same
as that of the current configuration, we can bypass the flow
filter since the flow should be allowed.
- if packet refers to a flow but its gen id is lower than that
of the current config, the packet needs to be re-evaluated;
that is, we can't bypass the flow-filter.
- if a packet referring to a flow is re-evaluated, then:
- if the packet is allowed by the flow filter, set the flow
gen id to the current (as the flow is allowed with the
current config) for subsequent packets to bypass.
- if the packet is not anymore allowed, drop it and invalidate
the flow(s) it referred to.
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Move the declaration of tracing target "port-frwarding" to the modules' root so that it governs all port-forwarding logs. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
When creating flows, neither masquerade nor port-forwarding labels them, so that the flow gets a default generation id of 0. This way the flow-filter must always validate a flow after it is created thereby avoiding the potential race where a flow is created for generation N while the packet, processed before by the flow filter, gets validated for config N-1. This race stems from the fact that the generation id is stored in an atomic and could change in the interim between the validation and the flow creation. If config N would allow the flow but N+1 wouldn't we could otherwise be in the situation where we would allow a flow that should be denied (until the next reconfiguration) because NAT would create the flow validated by a prior config. Note: with this changes, neither masquerade nor port-forwarding need to access the pipeline data. However, we leave the Arc's for future use since their cost is negligible. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Add convenience methods to set the genid of a flow and its related flow and to invalidate flows in pairs. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Build the two flows for a stateful NAT session in pairs. This allows invalidating them both on a configuration change. Right now invalidation may not shorten their lifetime, but it will soon. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
f54731e to
70828ec
Compare
If the packet survives, the flow is upgraded and subsequent packets bypass, because the flow conforms to the new config.
If the packet is not allowed, that means that the flow should not be allowed and it gets invalidated.
These changes not only expedite packet processing but also simplify the flow-filter implementation.
E.g. with these, the extra checks in PR #1341 should no longer be needed.
This fixes #1312