Repository navigation
Policy-based path-aware SCION application library - #187
Conversation
70f49ea to
0c8e970
Compare
juagargi
left a comment
There was a problem hiding this comment.
This is a great addition! We should merge it ASAP to let people use it in their applications.
I didn't do a full review, but I took some notes. Could you please check them? (non blockers)
- How to hook a statistics processor?
- Is a subscriber enough?
- Could the processor push data into the statistics?
- Use case for colibri, in the future we would need:
- path type in fingerprints
- refresher must also create renewals
- scmp path down detection must also check for colibri scmp errors (which are not there yet)
- Policy and Selector are very similar:
- Both components filter paths.
- The PingingSelector partially sorts paths (first one is always the less-than, the rest is unsorted)
- If they are merged into one component, composition (of them) would be easier.
Reviewed 1 of 43 files at r2.
Reviewable status: 1 of 48 files reviewed, all discussions resolved / 0 of 1 LGTMs obtained / 0 of 1 approvals obtained
pkg/pan/stats.go, line 23 at r2 (raw file):
) var stats pathStatsDB
Do we have any scenario where we need the info per connection instead of globally?
pkg/pan/stats.go, line 221 at r2 (raw file):
func (s *pathStatsDB) NotifyPathDown(pf PathFingerprint, pi PathInterface) { s.recordPathDown(pf, pi) for _, subscriber := range s.subscribers {
What about running the loop and callbacks in a separate go-routine?
matzf
left a comment
There was a problem hiding this comment.
How to hook a statistics processor?
There is nothing like this yet, and I don't have a clear idea on what the requirements for this would even be. The statistics are really bare bones at this point, and for this reason I've avoided exporting them from the package API for this version.
Use case for colibri, in the future we would need
Ok, makes sense.
Policy and Selector are very similar:
They may be similar on some level of abstraction, but I see them quite distinct; the Policy expresses the user's general preferences and rules. A policy is state-less, "long-lived" and is generically applicable to all destinations (but of course it can contain different rules for different sets of destinations).
The Selector, on the other hand, is stateful, tied to the life-time of a connection and only cares about the specific destination.
The idea is that the Policy filters and sorts paths based on the "static" path information. The Selector then takes into account "dynamic" information (dead paths, latency probes, etc) to select the "dynamically" best choice among the "statically" ranked paths. Perhaps, this makes more sense when I mention that the PingingSelector currently lacks any tuning parameters that weigh the "static" ranking against the "dynamic" information -- how much lower latency does rank i+1 need to have so we favor it over rank i path? I've left this out until now, as it just seems very tricky to parametrize right (and who would ever pick non-default values anyway?), but I should add a TODO for this.
I think I understand what you mean by the composability argument. Originally, this was in fact implemented as you suggest. The following observations made me change this to the current design with separate Policy/Selector concepts:
- The policy result can be cached until the paths are refreshed. If we directly compose Selectors which potentially use "dynamic" information, we'd need additional quirks to avoid re-evaluating the full chain on every packet. Note that some of the ordering operations for the static information are rather expensive.
- Applying a Policy always makes sense, regardless of which Selector is used.
- The default use case, as I imagine it, is to only specify a custom policy and use the DefaultSelector. This gets more awkward if the policy is (part of) the selector.
- Dynamically changing the policy of a connection (which is an important feature) appears to easier if the connection object contains both the policy and the selector separately.
With that, I'd prefer to keep these two concepts separate for this initial version. However, I'm very open if you have a specific suggestion on how this could be improved.
Reviewable status: 1 of 48 files reviewed, 1 unresolved discussion / 0 of 1 LGTMs obtained / 0 of 1 approvals obtained
pkg/pan/stats.go, line 23 at r2 (raw file):
Previously, juagargi (Juan A. Garcia Pardo) wrote…
Do we have any scenario where we need the info per connection instead of globally?
Good point. The advantages of having this per connection would seem to be: general advantages of less global state (e.g. testability, compatibility of different versions of the library, etc) and information leakage / privacy concerns. The privacy concerns would matter e.g. in a web browser setting where we might want to isolate certain windows from each other.
What would make most sense, I think, would be to allow create multiple instances of the whole global state of the library (e.g. the connection to the sciond, the background runners, and this stats DB) and pass this (in some form) to all the API invocations. This would be quite clean, but I believe it would make the API less convenient to use in the default case, and/or more work to implement correctly. As far as I can tell, at least all the relevant globals are hidden from the API, so implementing this at a later point should be doable.
pkg/pan/stats.go, line 221 at r2 (raw file):
Previously, juagargi (Juan A. Garcia Pardo) wrote…
What about running the loop and callbacks in a separate go-routine?
Good point, will do.
aeb8c96 to
105c7e7
Compare
|
pkg/pan/pan.go, line 37 at r3 (raw file):
chooses |
|
pkg/pan/pan.go, line 52 at r3 (raw file):
I think this sentence got broken in an edit. |
|
pkg/pan/pan.go, line 91 at r3 (raw file):
choose |
|
pkg/pan/quic_dial.go, line 60 at r3 (raw file):
DialQUIC |
|
pkg/pan/quic_dial.go, line 62 at r3 (raw file):
There is no |
|
pkg/pan/quic_dial.go, line 27 at r3 (raw file):
Does it help to include this implementation detail here? |
|
pkg/pan/quic_dial.go, line 86 at r3 (raw file):
DialQUICEarly |
|
pkg/pan/quic_dial.go, line 86 at r3 (raw file): Previously, marcfrei (Marc Frei) wrote…
And DialQUIC instead of DialAddr |
|
pkg/pan/quic_dial.go, line 40 at r3 (raw file):
Not sure, does it make sense to associate the |
|
pkg/pan/udp_dial.go, line 36 at r4 (raw file):
Add doc comment? |
|
pkg/pan/udp_dial.go, line 30 at r4 (raw file):
How about WriteToPath |
|
pkg/pan/udp_dial.go, line 33 at r4 (raw file):
ReadFromPath? |
marcfrei
left a comment
There was a problem hiding this comment.
Reviewed 1 of 34 files at r1, 16 of 43 files at r2, 31 of 36 files at r3, 3 of 4 files at r4.
Reviewable status: 51 of 76 files reviewed, 22 unresolved discussions / 0 of 1 LGTMs obtained / 0 of 1 approvals obtained
_examples/helloquic/helloquic.go, line 1 at r4 (raw file):
// Copyright 2021 ETH Zurich
For consistency, add simple README.md and mention the example in the global README in section ## _examples
_examples/helloworld/helloworld.go, line 82 at r4 (raw file):
defer conn.Close() for i := 0; i < 1; i++ {
Maybe introduce a variable (and a command-line option) for the number of messages to send?
netcat/udp.go, line 47 at r4 (raw file):
func (conn *udpListenConn) Write(b []byte) (int, error) { return conn.write(b)
Take the mutex here too, for consistency?
pkg/pan/raw.go, line 57 at r4 (raw file):
raw snet.PacketConn readMutex sync.Mutex readBuffer snet.Bytes
readBuffer is always == nil, right?
pkg/pan/raw.go, line 59 at r4 (raw file):
readBuffer snet.Bytes writeMutex sync.Mutex writeBuffer snet.Bytes
writeBuffer is always == nil, right?
pkg/pan/raw.go, line 165 at r4 (raw file):
underlay: &lastHop, } n := copy(b, udp.Payload)
This copy hurts, doesn't it? Could we introduce an additional type that somehow wraps snet.Bytes/snet.Packet and that could be used to offer more efficient read operations?
pkg/pan/udp_dial.go, line 76 at r4 (raw file):
remote UDPAddr subscriber *pathRefreshSubscriber Selector Selector
Why is Selectorexported?
pkg/quicutil/single.go, line 39 at r4 (raw file):
unidirectional
pkg/quicutil/single.go, line 42 at r4 (raw file):
unidirectional
And replace tabs in comment in this and the next line with spaces.
ssh/client/ssh/selector.go, line 66 at r4 (raw file):
} p := s.paths[s.current] s.current += 1
% len(s.paths)?
benthor
left a comment
There was a problem hiding this comment.
Reviewed 1 of 43 files at r2.
Reviewable status: 52 of 76 files reviewed, 23 unresolved discussions / 0 of 1 LGTMs obtained / 0 of 1 approvals obtained
pkg/pan/selector.go, line 37 at r4 (raw file):
// OnPathDown is invoked when SCMP path down notifications are received. type Selector interface { Path() *Path
Could this be Path(UDPAddr), to matchSetPath(UDPAddr, []*Path)?
|
(Turned my above suggestion into a PR matzf#1) |
marcfrei
left a comment
There was a problem hiding this comment.
Reviewed 3 of 34 files at r1, 17 of 43 files at r2, 4 of 36 files at r3, 1 of 4 files at r4.
Reviewable status: all files reviewed, 35 unresolved discussions / 0 of 1 LGTMs obtained / 0 of 1 approvals obtained
a discussion (no related file):
TODO: search in all files for occurrences of appnet and check whether they are still correct/needed.
pkg/pan/cli.go, line 41 at r4 (raw file):
// // The options should be presented to the user as: // - a flag --interactve
- space instead of tab after '- '
- "interactve" => "interactive"
pkg/pan/def.go, line 38 at r4 (raw file):
pathExpiryRefreshLeadTime = ... pathExpiryPruneLeadTime = ...
I think we could drop Expiry from both names.
pkg/pan/hosts.go, line 34 at r4 (raw file):
) // ResolveUDPAddrAt parses the address and resolves the hostname.
resolveUDPAddrAt
pkg/pan/hosts.go, line 90 at r4 (raw file):
) // ParseSCIONAddr converts an SCION address string to a SCION address.
parseSCIONAddr
pkg/pan/path.go, line 146 at r4 (raw file):
} // forwardingPathInfo contains information extracted from a dataplane forwardng path.
forwarding
pkg/pan/policy.go, line 95 at r4 (raw file):
} // Sequence is a Policy filtering paths matching a textual pattern. The sequence pattern is
"policy"
pkg/pan/policy.go, line 182 at r4 (raw file):
func (p HighestMTU) Filter(paths []*Path) []*Path { sort.SliceStable(paths, func(i, j int) bool { return paths[i].Metadata.MTU < paths[j].Metadata.MTU
Not sure, shouldn't this be > if we want to sort in descending order?
pkg/pan/quic_listen.go, line 38 at r4 (raw file):
ListenQUIC
pkg/pan/quic_single.go, line 1 at r4 (raw file):
// Copyright 2021 ETH Zurich
Is this file needed?
pkg/pan/silence.go, line 44 at r4 (raw file):
log.Default().SetOutput(logSilencerOriginal) logSilencerOriginal = nil }
Maybe assert (panic) that count is not negative at this point.
pkg/pan/stats.go, line 158 at r4 (raw file):
// Returns true if a does not have any recent down notifications and b does, or // (more generally) if all down notifications for a are strictly older // than any down notificating for b.
notification
matzf
left a comment
There was a problem hiding this comment.
Reviewable status: 55 of 80 files reviewed, 35 unresolved discussions / 0 of 1 LGTMs obtained / 0 of 1 approvals obtained
a discussion (no related file):
Previously, marcfrei (Marc Frei) wrote…
TODO: search in all files for occurrences of
appnetand check whether they are still correct/needed.
Thanks, will do. I'm planning to remove appnet with this PR -- just a few more applications to convert:
- bwtester (this one actually requires some thought and work)
- burster / cbrtester
- camerapp ; will be deleted instead (separate PR #208 )
_examples/helloquic/helloquic.go, line 1 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
For consistency, add simple README.md and mention the example in the global README in section
## _examples
Done.
_examples/helloworld/helloworld.go, line 82 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Maybe introduce a variable (and a command-line option) for the number of messages to send?
Good idea, done.
netcat/udp.go, line 47 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Take the mutex here too, for consistency?
No I think this wouldn't work, Read and Write can be (safely) called concurrently. As far as i understand, this is actually used concurrently -- we copy (io.Copy) in both directions, from stdin to the connection and from the connection to stdout.
The mutex protects the requests/responses channels. I've added a comment to clarify this -- this code could definitely be improved a lot though. I'm not convinced this "UDP Listener" abstraction here even makes much sense...
pkg/pan/cli.go, line 41 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
- space instead of tab after '- '
- "interactve" => "interactive"
Done.
pkg/pan/def.go, line 38 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
pathExpiryRefreshLeadTime = ... pathExpiryPruneLeadTime = ...I think we could drop
Expiryfrom both names.
Done.
pkg/pan/hosts.go, line 34 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
resolveUDPAddrAt
Done.
pkg/pan/hosts.go, line 90 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
parseSCIONAddr
Done.
pkg/pan/pan.go, line 37 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
chooses
Done.
pkg/pan/pan.go, line 52 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
The default reply path selector records a fixed number of paths last uses replies on the path last used by a client.I think this sentence got broken in an edit.
Done.
pkg/pan/pan.go, line 91 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
choose
Done.
pkg/pan/path.go, line 146 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
forwarding
Done.
pkg/pan/policy.go, line 95 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
"policy"
Done.
pkg/pan/policy.go, line 182 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Not sure, shouldn't this be
>if we want to sort in descending order?
💯
pkg/pan/quic_dial.go, line 27 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
// This is needed here because we use quic.Dial, not quic.DialAddr but we want // the close-the-socket behaviour of quic.DialAddr.Does it help to include this implementation detail here?
Hmm yeah, you're right. Removed.
pkg/pan/quic_dial.go, line 40 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Not sure, does it make sense to associate the
Policyconcept also with sessions or should clients callSetPolicydirectly on the connection.
Not entirely sure either; I've removed it for now.
pkg/pan/quic_dial.go, line 60 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
DialQUIC
Done.
pkg/pan/quic_dial.go, line 62 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
raddrThere is no
raddr. UDPAddr does not contain a path anymore.
Done.
pkg/pan/quic_dial.go, line 86 at r3 (raw file):
Previously, marcfrei (Marc Frei) wrote…
And DialQUIC instead of DialAddr
Done.
pkg/pan/quic_listen.go, line 38 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
ListenQUIC
Done.
pkg/pan/raw.go, line 57 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
readBufferis always == nil, right?
Ooh, you're right, great catch! Allocations galore!
Fixed.
pkg/pan/raw.go, line 59 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
writeBufferis always == nil, right?
Done.
pkg/pan/raw.go, line 165 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
This copy hurts, doesn't it? Could we introduce an additional type that somehow wraps snet.Bytes/snet.Packet and that could be used to offer more efficient read operations?
It does hurt a bit, yes. As far as I can tell there is really no way around this though. The io.Reader API lets a caller specify a buffer to fill. The result type for this is only number of bytes written to this user buffer, not a slice -- if it was a slice, we could maybe read directly into the user buffer and then cut the headers off.
So we could provide our own, non-standard ReadSlice (or whatever) function which could avoid this copy, but in many cases we want/need to integrate with existing functionality in libraries that expect the io.Reader API and so we wouldn't really gain much.
FWIW, snet does the same thing here. In the grand scheme of things, this particular copy does not seem to stand out much (at this point in the end host stack, the packet was already copied at least 3 times from kernel to user space buffers or vice versa...).
Btw. I've also thought about whether recvmsg's scatter/gather API could be used to help in any way to avoid this copy (i.e. to make the kernel copy the Payload part directly to the result buffer). With the varying size of the SCION headers, i doubt this is at all possible though.
pkg/pan/selector.go, line 37 at r4 (raw file):
Previously, benthor wrote…
Could this be
Path(UDPAddr), to matchSetPath(UDPAddr, []*Path)?
The idea here is that a selector is used as part of a connected socket, so the remote address never changes -- thus, no need to pass it to Path.
Btw, it's a not very clean to provide this remote address as part of SetPaths -- I did that, just to reduce the number of functions on the interface, maybe that's not a great idea. Perhaps it would be better to split this, something like this:
Initialize(remoteAddress UDPAddr, paths []*Path)
UpdatePaths(paths []*Path) pkg/pan/silence.go, line 44 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Maybe assert (panic) that
countis not negative at this point.
Done.
pkg/pan/stats.go, line 158 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
notification
Done.
pkg/pan/udp_dial.go, line 30 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
How about WriteToPath
I'd prefer not to use WriteTo as prefix as this already has an existing meaning -- WriteTois used for unconnected datagram sockets and let's the caller specify the destination address. I think this could be confusing, as WriteToPath would then exist on both connected and unconnected sockets, but with differing signature (with/without destination address).
Maybe WriteWithPath and ReadWithPath? Or WriteByPath and ReadByPath? Seem a bit forced... I don't know. How strong is your dislike for WritePath? 😅
pkg/pan/udp_dial.go, line 76 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Why is
Selectorexported?
Done.
pkg/quicutil/single.go, line 39 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
unidirectional
Done.
pkg/quicutil/single.go, line 42 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
unidirectionalAnd replace tabs in comment in this and the next line with spaces.
Done.
ssh/client/ssh/selector.go, line 66 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
% len(s.paths)?
Uh, yes that'd be better, thanks! 😅
pkg/pan/quic_single.go, line 1 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Is this file needed?
Nope, done.
matzf
left a comment
There was a problem hiding this comment.
Reviewable status: 54 of 80 files reviewed, 35 unresolved discussions / 0 of 1 LGTMs obtained / 0 of 1 approvals obtained
pkg/pan/udp_dial.go, line 36 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
Add doc comment?
Done.
665b9bd to
11b6299
Compare
|
_examples/helloworld/README.md, line 3 at r10 (raw file):
Remove '.' |
marcfrei
left a comment
There was a problem hiding this comment.
Reviewed 1 of 4 files at r5, 1 of 2 files at r6, 6 of 18 files at r7, 64 of 64 files at r10.
Reviewable status:complete! 1 of 1 LGTMs obtained
pkg/pan/silence.go, line 28 at r10 (raw file):
// silenceLog redirects the log.Default writer to a black hole. // It can be reenabled by calling unsilenceLog. // These functions can safely be called from multiple goroutines concurrently;
What about the following example scenario?
- goroutine A executes
unsilenceLog, evaluatescount == 0totrue, and gets preempted - while goroutine A is passivated, goroutine B executes and completes
silenceLog. - goroutine A gets scheduled again and installs
logSilencerOriginal.
pkg/pan/udp_dial.go, line 30 at r4 (raw file):
Previously, matzf (Matthias Frei) wrote…
I'd prefer not to use
WriteToas prefix as this already has an existing meaning --WriteTois used for unconnected datagram sockets and let's the caller specify the destination address. I think this could be confusing, asWriteToPathwould then exist on both connected and unconnected sockets, but with differing signature (with/without destination address).
MaybeWriteWithPathandReadWithPath? OrWriteByPathandReadByPath? Seem a bit forced... I don't know. How strong is your dislike forWritePath? 😅
It's not a strong dislike. Other ideas: WriteViaPath. Or just Writep? Not sure, so maybe WritePath is the best alternative after all.
matzf
left a comment
There was a problem hiding this comment.
Reviewable status:
complete! 1 of 1 LGTMs obtained
pkg/pan/silence.go, line 28 at r10 (raw file):
Previously, marcfrei (Marc Frei) wrote…
What about the following example scenario?
- goroutine A executes
unsilenceLog, evaluatescount == 0totrue, and gets preempted- while goroutine A is passivated, goroutine B executes and completes
silenceLog.- goroutine A gets scheduled again and installs
logSilencerOriginal.
You're right of course, thanks! I'll just change this to a mutex.
pkg/pan/stats.go, line 221 at r2 (raw file):
Previously, matzf (Matthias Frei) wrote…
Good point, will do.
Done.
pkg/pan/udp_dial.go, line 30 at r4 (raw file):
Previously, marcfrei (Marc Frei) wrote…
It's not a strong dislike. Other ideas:
WriteViaPath. Or justWritep? Not sure, so maybeWritePathis the best alternative after all.
Via sounds good, I like it!
Borrowed from Latin viā (“by the way (of)”), ablative singular of via (“way, road”).
Road is close enough to "path", so maybe we can omit the redundancy and just use WriteVia etc :)
type Conn interface {
Write(b []byte) (int, error)
WriteVia(path *Path, b []byte) (int, error)
Read([] byte) (int, error)
ReadVia([] byte) (int, *Path, error)
}
type ReplyConn interface {
WriteTo(b []byte, addr net.Addr) (int, error)
WriteToVia(b []byte, addr net.Addr, path *Path) (int, error)
ReadFrom(b []byte) (int, net.Addr, error)
ReadFromVia(b []byte) (int, net.Addr, *Path, error)
}I admit that WriteToVia and ReadFromVia still seem somewhat forced, but to me it seems good enough.
marcfrei
left a comment
There was a problem hiding this comment.
Reviewable status:
complete! 1 of 1 LGTMs obtained
marcfrei
left a comment
There was a problem hiding this comment.
Reviewed 4 of 4 files at r11.
Reviewable status:complete! 1 of 1 LGTMs obtained
Burster and cbrtester, while useful at the time for debugging specific issues with the routers, are somewhat redundant with the functionality of the bwtester applications. Moving forward, the idea to integrate the useful bits of these two tools into the bwtester instead; see netsec-ethz#210.
|
Pushed a cleaned up history (to be merged with a merge commit).
|
This is a first version of the pan "Path-Aware Networking" library. The pan library represents the path selection process for SCION connections by Policies, which filter and order the paths based on the information included in the path metadata, and Selectors, which dynamically select the final path for each packet sent. This gives a relatively simple interface for applications that directly translates to an application user interface (e.g. command line interface), and connections can automatically failover in case of SCMP errors messages. The pan library can do the work for querying and updating path information in the background. A small number of default Policies and Selectors are built-in. In the future, we might add more of these out of the box, but the idea is that applications can also define custom Policies and Selectors. See the package documentation for more information. Currently uses inet.af/netaddr to represent IP addresses. This will be replaced by the very similar net/netip once this becomes available, expectedly in go-1.18. Other than this, pan attempts to not expose external libraries in its API and provide a self-contained interface. All applications in scion-apps have been converted to pan, but these changes will be committed separately. Known issues in this first version: - the DefaultReplySelector, i.e. the path selector on the listening side, is susceptible to session hijacking by spoofing source address. - the stats DB is intentionally kept private as this requires more thought. For now, applications need to store their own stats separate from pans internal store. - internal state of DefaultReplySelector and stats DB are never cleaned up and can grow without bounds. - far too many globals Add package quicutil: - single stream quic utilities Using a single quic stream is common in our demo applications. Add a utility function for this, extracted from previous internal implementation in shttp. Incompatible to the previous version in shttp. Now either side can start sending (by using two unidirectional streams), plus it can now reliably close. The listener is also more robust; previously, if a remote session was opened without ever opening a stream, this would have blocked the listener Accept indefinitely. - generate self-signed certificate (previously in appquic) Updated example code: - extend helloworld example and port to pan. - add helloquic example, using pan Misc: - integration: use addr= instead of only ia= as "ready signal" - remove appnet/appquic from main README as these packages are slated for removal. - bugfixes backported to appnet: fix SplitHostPort (bad regex capture group index), extend addrFromString to work with addresses without the optional brackets.
Convert pkg/shttp, pkg/shttp3, bat, skip, and web-gateway to use pan. The shttp package now uses the quicutil.SingleStream, making it incompatible with previous versions. The shttp and shttp3 libraries now allow specifying a pan Policy. This Policy can be changed at any time. Add new path policy commandline options to bat.
Add default path policy options to command line for bwtestclient. For the data channel, we want to ensure to use the path used for the control channel and stick to this, i.e. no more fail-over once connection is established. On the client side, we use the Pin policy to, well, pin the path for the data channel. On the server side, we initialize a default reply path selector with the path known from the control channel. With this approach, we stick to the original forwarding path, but the path can still be refreshed if it expires (however unlikely that is, given the short max duration of tests). We could perhaps go a bit further and use dumb selectors that always return the fixed, initial path.
- update pty dependency (old version is broken for go >= 1.15) - redo the path policy and selector configuration, now based on pan. Make more useful selectors available. Drop related helper packages, merge ssh/sssh into ssh/client/ssh (the package organization here is still rather wacky). - Now uses quicutils.SingleStream, making this incompatible with previous versions. - when executing a command, don't set Uid/Gid if the selected user is already the current user. Only appears to work when sshd is run with root otherwise. - misc fixes and cleanup related to logging and error handling - clean up import order Replace the custom
Add path policy options to command line. Use quicutils.SingleStream, making this incompatible with previous versions. Removed the long list of supported protocols in netcat again -- that was a bit of a brain fart. The delicate handling of the quic streams is enough of a protocol to warrant having a dedicated identifier. Updated netcat QUIC integration tests (dont need the -b now, as both peers can now start transmitting first). Only tangentially related, fix concurrent Read/Close in the udpListenConn.
Add path policy options to command line.
The appnet and appquic libraries have been replaced with "pan".
Policy-based, path-aware SCION application library
Working title "pan" (for pan-ready Path-Aware Networking library (?)).
The goal is to have a common, high-level library that makes it easy to write correct, functional applications using SCION.
Overview
The main entry points for applications are:
Both forms of the Dial call allow to specify a Policy and a Selector.
Policy
A path policy defines the allowed paths and/or a preference order of the paths. Policies are generally stateless and, in particular, they don't look for any short term information like measured latency or path "liveness".
Connections allow to change the path policy at any time.
Built in policies:
Selector
A path selector is a stateful controller associated with a connection/socket. It receives the paths filtered by the Policy as an input. For each packet sent, the selector choses the path.
The default selector keeps using the first chosen path unless SCMP path down notifications are encountered, in which case it will always switch to the next alive path.
Custom selectors implement e.g. active path probing, coupling of multiple connections to either use the same path or to use maximally disjoint paths, direct performance feedback from the application, etc.
Dialed vs Listening
pan differentiates between dialed and listening sockets. Dialed sockets (for "clients") define the path policy and a selector. The client side of a connection is in control of the path used.
The listening side (for "servers") only replies on the paths last used by each client, by means of a customizable reply path selector. The listening side does not implement any policy, nor does it do anything to keep the paths fresh.
The default reply path selector records a fixed number of paths last uses replies on the path last used by a client. It normally uses the path last used by the client, but does use other recorded paths to try routing around temporarily broken paths.
PUDP [experiment]Removed from this branch for now: the idea was to look at including explicit path control information in the packets. This control information allows to send packets redundantly over multiple paths (for racing or redundancy), probing, and some path "negotiation". This experiment included this control data in the UDP payload, which is not great for interoperability. I now think that defining an End-to-End extension header option to transport this control information might be more appropriate.
See documentation in the now removed files for more details: https://github.com/netsec-ethz/scion-apps/blob/4329bc6a7bc6abc2264ad9fd0a3f6fab3e8c3c36/pkg/pan/pudp.go
Changes in this PR:
addrFromStringto work with addresses without the optional brackets.This change is