-
Notifications
You must be signed in to change notification settings - Fork 4
Fix Vxlan code + small additions #509
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
Conversation
Marking as dont-merge until I double check that these are the good fixes and @daniel-noland approves. |
2ee184c
to
c3a73b2
Compare
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.
Changes look OK to me
6686ec8
to
659328e
Compare
@@ -319,6 +319,11 @@ impl Headers { | |||
Headers::default() | |||
} | |||
|
|||
/// Add / Replace Ethernet header | |||
pub fn set_eth(&mut self, eth: Eth) { |
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.
technically this method is unsafe in the sense that you can set an ethernet header with an ethertype which doesn't match the lower layers of the frame. Will think about a good way to fix this.
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.
Having thought about it some more, I don't think we can fix this safety issue without requiring the user to go through a strongly typed builder API on every packet manipulation.
The actual fix here should be to make the API contract of the packet / headers types free form and then create a validated type wrapper which does not allow mutations without consuming the structure back into the mutable form.
That will prevent us from sending (or accepting) total nonsense while still giving us the latitude to actually manipulate packets.
That said, wherever possible, we should still forbid creating nonsense packets; moving errors closer to their actual cause point is just good practice anyway.
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 would say it's the caller's responsibility to set the ether-type. I mean, IMO, the net crate should provide the machinery to build packets, but can't be foreseeing all possible combinations and, if it ought to, it should probably be after the fact maybe when deparsing(), or via some validation method to be called explicitly?
/// This method _will not_ update the checksum of the header. | ||
/// # Errors | ||
/// This method returns [`Ipv4LengthError`] if the value is too big | ||
pub fn set_payload_len(&mut self, payload_len: u16) -> Result<(), Ipv4LengthError> { |
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.
again, technically an unsafe method. Invariants pushed to the caller.
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.
Yes, this is probably a distinct case. Here consistency matters a bit more. There's distinct ways we could enforce correctness. Either with validation or by "encapsulation"; i.e. somewhat emulate a stack by wrapping layers. But this requires a significant refactor and APIs? E.g. you could have something like packet.eth_encap( Params )
, with packet being anything above L2 (ARP, IPv4, IPv6). This would get the packet, automatically determine ethertype and use params to set src/dst macs. Similarly you could have something like packet.ip_encap( Params )
(where packet would be assumed to contain L4 stuff maybe) and the params contain the fields that would make sense for the user to set. Protocol, header-length, packet length, and so on could be set automatically. So you could do things like:
udp_packet.ip_encap( l3-params ).eth_encap( l2-params )
@@ -74,6 +74,11 @@ impl<Buf: PacketBufferMut> Packet<Buf> { | |||
&self.payload | |||
} | |||
|
|||
/// Add / Replace Ethernet header | |||
pub fn set_eth(&mut self, eth: Eth) { |
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.
technically unsafe
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.
How do you want to proceed? You want me to annotate all those methods as unsafe?
@@ -133,10 +138,7 @@ impl<Buf: PacketBufferMut> Packet<Buf> { | |||
/// ``` | |||
pub fn vxlan_decap(&mut self) -> Option<Result<Vxlan, ParseError<EthError>>> { | |||
match self.headers.try_vxlan() { | |||
None => { |
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.
why are we removing the log here?
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.
We call vxlan_decap for every packet destined to the gateway, but the gateway may receive packets that are not vxlan (control-plane, icmp, etc..). So the prior log would show for every packet sent to it.
|
||
/// Wraps a packet in an `Option` depending on the metadata: | ||
/// If [`Packet`] is to be dropped, returns `None`. Else, `Some`. | ||
pub fn enforce(self) -> Option<Self> { |
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 not sure I follow the logic for the naming here. Why enforce
?
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.
When we iterate over a burst of packets, we pervasively use filter_map
which requires returning Some(packet)
or None
to indicate if the packet should be returned or not. The routing stages (as currently defined) annotate in the packet metadata what to do next: 1) no annotation, 2) some drop condition (there are plenty) 3) whether the packet can be delivered etc. These annotations happen inside the pipeline functions. The enforce is just some sugar syntax to, based on those, determine if Some(packet) / None is to be returned. So, most stages end up calling packet.enforce(). This allows hiding all that logic to the stages and allowing to change it without needing to change them. That's the explanation. Given this purpose, do you have suggestions for the naming? You're the native speaker here!
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 think we need to consider some API issues here, but my only actual hard concern is the naming of the enforce
method. Given that this is easily refactored later, I'm ok with approving this.
That said, we should talk through my thoughts on a validated packet type at some point
I can easily change the naming for
|
659328e
to
43fd427
Compare
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Either Daniel forgot these in the final PR, or we developed it on the phone 😂 Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
There are several changes in this function. The only one that is surely needed is the overwrite of headers with the cloned-then-modified headers at the end of the method. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Malformed => used when the packet does not seem to be right. MissingEtherType => used when we can't determine ethertype to use Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
The alternative is to log from the caller if needed. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
43fd427
to
caaf7bf
Compare
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Adds a method to compute a hash over invariant packet fields, including ethernet header fields and vlan plus the fields consi- dered already for ecmp hashing. A second method leverages the aforementioned to build an entropy source UDP port suitable for VxLAN encapsulations. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
To encapsulate a packet in VxLAN, a UDP header needs to be built. In the current API, the caller is requested to build and pass the UDP information. All of the information in the UDP header, however, can be automatically be set by the API. This includes: * dst port, which should almost always be the well-known value. * source port, which can be computed from the payload itself. * length * checksums (optional for ipv4) This patch changes the API to not require UDP header and build it automatically, so that callers need not have to set those. This may be useful when needing to encapsulate traffic e.g. for L2 EVIs. Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
Signed-off-by: Fredi Raspall <fredi@githedgehog.com>
No description provided.