Skip to content
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

router: serialize directly into packet buffers #4654

Merged
merged 8 commits into from
Nov 29, 2024

Conversation

jiceatscion
Copy link
Contributor

@jiceatscion jiceatscion commented Nov 19, 2024

In every case where the router modified packets it would serialize updated headers to a temporary buffer and then copy that to the packet buffer.

To avoid this extra copy, replaced gopacket.serializeBuffer with a custom implementation that writes to a given buffer. In this case, the packet's raw buffer.

There is one remaining copy for some SCMP messages because we have to move the existing packet to the payload. This too could be avoided but that's for another PR; it would require to leave headroom in received packets.

The performance impact is very small since, on the critical path, it just avoids copying a scion hdr per packet, but it is a simplification. It also pays back the copy added by a previous simplification of the BFD code. As such...

Contributes to #4593

To that end:
* Introduce an implementation of SerializeBuffer that writes directly into
the raw buffer of the packet to be sent.
* Use this in BfdSend, for now.
* Other uses coming in subsequent commits.

We cannot necessarily use this everywhere: The implementation starts filling
buffers in the middle to ensure that there is space for headers. That also
means that the payload is less than 1/2 the buffer size.
To support some use cases, added the feature that the insertion point can be
changed when resetting a serializeProxy. The default is now the end of the
buffer, which is by far the most common case.
@jiceatscion
Copy link
Contributor Author

This change is Reviewable

Copy link
Contributor

@marcfrei marcfrei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 3 of 3 files at r2, all commit messages.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on @FR4NK-W, @jiceatscion, @lukedirtwalker, and @oncilla)


router/serializeProxy.go line 0 at r2 (raw file):
We don't usually have file names in camel case, right?


router/serializeProxy.go line 27 at r2 (raw file):

// panic. It is designed to be a local variable, so New() returns a value. The entire buffer
// underpinning the given slice may be used; that is, from the start up to the remaining capacity.
type serializeProxy struct {

How about serializeBuffer instead of serializeProxy. "Proxy" can have so many meanings, not sure that the name helps here.


router/serializeProxy.go line 28 at r2 (raw file):

// underpinning the given slice may be used; that is, from the start up to the remaining capacity.
type serializeProxy struct {
	initStart int // Initial starting point (where the first prepend or append occurs)

orig or origStart?

Code quote:

	initStart

router/dataplane.go line 2299 at r2 (raw file):

	payloadOffset := len(rawPkt) - len(s.LayerPayload())
	serBuf := newSerializeProxy(rawPkt)
	serBuf.clear(payloadOffset) // Prepends will go just before payload. (Appends will wreck it)

Wouldn't it be cleaner to provide a special factory function for this use case instead of using serializeProxy.clear?

Code quote:

	serBuf := newSerializeProxy(rawPkt)
	serBuf.clear(payloadOffset) // Prepends will go just before payload. (Appends will wreck it)

Copy link
Contributor Author

@jiceatscion jiceatscion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 4 files reviewed, 4 unresolved discussions (waiting on @FR4NK-W, @lukedirtwalker, @marcfrei, and @oncilla)


router/dataplane.go line 2299 at r2 (raw file):

Previously, marcfrei (Marc Frei) wrote…

Wouldn't it be cleaner to provide a special factory function for this use case instead of using serializeProxy.clear?

Yeah, I wasn't sure that I wanted to add a constructor for such a minority use case. Although it might become more frequent...So, reworked along those lines. I've changed initStart to restart speculatively.


router/serializeProxy.go line 27 at r2 (raw file):

Previously, marcfrei (Marc Frei) wrote…

How about serializeBuffer instead of serializeProxy. "Proxy" can have so many meanings, not sure that the name helps here.

I chose the name to distinguish it from the default implementation. The default implementation does supply the buffer, which is its main downside. This one acts as an intermediary between the using code and the actual buffer. So, a buffer-by-proxy. Of cause proxy is overloaded, but serializeBuffer is already taken and misleading. I have searched for a better name but couldn't find anything that wasn't just as overused. Ideas welcome.


router/serializeProxy.go line 28 at r2 (raw file):

Previously, marcfrei (Marc Frei) wrote…

orig or origStart?

uh, initStart is bad, but so is origStart. We reset to that value at the next Clear()... how about clearStart or resetStart or ...how about restart?


router/serializeProxy.go line at r2 (raw file):

Previously, marcfrei (Marc Frei) wrote…

We don't usually have file names in camel case, right?

oops, fixed

Copy link
Contributor

@marcfrei marcfrei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 3 of 4 files at r3, all commit messages.
Reviewable status: 3 of 4 files reviewed, 3 unresolved discussions (waiting on @FR4NK-W, @jiceatscion, @lukedirtwalker, and @oncilla)


router/serialize_proxy.go line 47 at r3 (raw file):

// newSerializeProxyOffset returns a new serializeProxy. The initial prepend/append point is set to
// the given start value. This has the same effect as calling clear(statr).
func newSerializeProxyOffset(buf []byte, start int) serializeProxy {

NIT: either name the function newSerializeProxyStart or rename the parameter from start to offset

Code quote:

Offset

router/#connector.go# line 0 at r3 (raw file):
Shouldn't be part of this commit, right?

Copy link
Contributor Author

@jiceatscion jiceatscion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 3 of 4 files reviewed, 1 unresolved discussion (waiting on @FR4NK-W, @lukedirtwalker, @marcfrei, and @oncilla)


router/#connector.go# line at r3 (raw file):

Previously, marcfrei (Marc Frei) wrote…

Shouldn't be part of this commit, right?

nope. I was wondering where that file had gone (in another branch - expected to be stashed) :-) removed.


router/serialize_proxy.go line 47 at r3 (raw file):

Previously, marcfrei (Marc Frei) wrote…

NIT: either name the function newSerializeProxyStart or rename the parameter from start to offset

done


router/serializeProxy.go line 27 at r2 (raw file):

Previously, jiceatscion wrote…

I chose the name to distinguish it from the default implementation. The default implementation does supply the buffer, which is its main downside. This one acts as an intermediary between the using code and the actual buffer. So, a buffer-by-proxy. Of cause proxy is overloaded, but serializeBuffer is already taken and misleading. I have searched for a better name but couldn't find anything that wasn't just as overused. Ideas welcome.

I guess you have accepted my reasons.

Copy link
Contributor Author

@jiceatscion jiceatscion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dismissed @marcfrei from a discussion.
Reviewable status: 3 of 4 files reviewed, all discussions resolved (waiting on @FR4NK-W, @lukedirtwalker, and @oncilla)


router/#connector.go# line at r3 (raw file):

Previously, jiceatscion wrote…

nope. I was wondering where that file had gone (in another branch - expected to be stashed) :-) removed.

so, done

Copy link
Contributor

@marcfrei marcfrei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 3 of 3 files at r4, all commit messages.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on @FR4NK-W, @lukedirtwalker, and @oncilla)

@jiceatscion jiceatscion merged commit 3c8e30f into scionproto:master Nov 29, 2024
5 checks passed
@jiceatscion jiceatscion deleted the router_multi_io_2 branch November 29, 2024 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants