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

Quic Support #32

Merged
merged 64 commits into from
Jun 6, 2024
Merged

Quic Support #32

merged 64 commits into from
Jun 6, 2024

Conversation

bokeefe123
Copy link
Contributor

Quic Retina Support

Adds support for subscribing to Quic V1 and V2 packets into Retina. Allows the ability to subscribe to core aspects of Quic headers such as header type (short/long) and packet type (initial, 0-RTT, ...)

New Features

  • Adds Quic to streams module
  • Includes a sample quic application
  • Includes a sample pcap of quic traffic in traces
  • Includes the corresponding quic.toml for sample quic application in /configs/quic.toml

Testing Process:

  • Tested across various pcaps of real Quic traffic
  • Validated with custom test application to verify parsed quic packets match wireshark on the same pcap
  • Prior to merging, should ensure a successful run on Stanford tap

Assumptions and Design Decisions:

Note: These are also included at the top of the /core/src/protocols/stream/quic/mod.rs file as well. However, further logic/rational provided here:

  • Assumption: that the Quic version is one as listed in the QuicVersion Enum in the /core/src/protocols/stream/quic/parser.rs file
    • Currently only support Quic V1 and V2, however adding new versions should only require adding to version enum as the parser relies on mostly invariant parts of quic packets. QUIC-INVARIANTS
  • Design Decision: To resolve what the connection id for a short header is, we only match with connection ids that have been resolved from long headers.
    • This decision was made because there is no indicator what the length in bytes of a short header's connection id is and thus the only way to resolve it is to search within the range of possible lengths and try to match to existing known connection ids.
  • Assumption: that the destination connection ids of a short header is a maximum of 20 bytes.
    • Quic V1 and V2 both use a maximum 20 bytes for the connection ids however, this is not an invariant feature and the invariant length would be a total of 255 bytes.
    • Adding support for 255 byte length would add unnecessary slowdown when searching short header connection ids because it isn't used in practice yet.
  • Assumption: that the packet will not try to grease the fixed bit.
    • Variants of Quic (QUIC-GREASE) have designed ways to grease the fixed bit, however, we make the assumption this does not occur.
  • Design Decision: The payload bytes count is a lazy counter. This means it does not try to exclude tokens used for tls or other parts that may not be directly considered parts of the payload. This results in a computed payload bytes count different from Wireshark.
    • If this makes the implementation of the payload bytes field not helpful then it can certainly be removed.

@bokeefe123 bokeefe123 marked this pull request as ready for review June 3, 2024 17:38
@thegwan thegwan self-requested a review June 3, 2024 18:41
Copy link
Contributor

@thegwan thegwan left a comment

Choose a reason for hiding this comment

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

Thanks Ben! I've confirmed that functionally there are no panics when running against real traffic on the tap. However, throughput performance is limited. A 0-cycle spin application subscribed to connection records and filtered on quic reaches around 29 Gbps processing throughput with ~3% packet loss, whereas a filter for just udp runs for at least 2 minutes with zero loss. I marked some places where we might be able to improve throughput by reducing the number of copies.

core/src/subscription/quic_connection.rs Outdated Show resolved Hide resolved
core/src/protocols/stream/quic/mod.rs Outdated Show resolved Hide resolved
core/src/protocols/stream/quic/mod.rs Outdated Show resolved Hide resolved
}

/// Returns the source connection ID of the Quic packet or an empty string if it does not exist
pub fn scid(&self) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above

examples/log_quic/README.md Outdated Show resolved Hide resolved
core/src/protocols/stream/quic/parser.rs Outdated Show resolved Hide resolved
@thegwan thegwan requested a review from thearossman June 3, 2024 22:19
@thegwan
Copy link
Contributor

thegwan commented Jun 4, 2024

With these changes, I was able to run log_conn filtered on quic with hardware filtering support at at least 80 Gbps throughput on our network for 2 minutes with no loss.

Copy link
Collaborator

@thearossman thearossman left a comment

Choose a reason for hiding this comment

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

So excited to see this come together and very glad to have the ability to filter on QUIC! This is particularly necessary for some experiments we want to run that will require discarding encrypted traffic.

High-level comments:

  • QUIC is a transport and application protocol, which makes it tricky to fit into the Retina framework which assumes each protocol is one or the other. Put two ideas re: naming things clearly where we can.
  • I think parsing should be "done" for a given "unit of QUIC data" (which you're defining as a QUIC packet) at some point. Put a comment with an idea of how to do this.

Renaming would be nice. I don't think "ParseResult::Done" ask is a check-in blocker if it's tricky to change or would require a lot more testing.

core/src/subscription/quic_transaction.rs Outdated Show resolved Hide resolved
examples/log_quic/src/main.rs Outdated Show resolved Hide resolved
core/src/protocols/stream/quic/mod.rs Outdated Show resolved Hide resolved
core/src/protocols/stream/quic/parser.rs Show resolved Hide resolved
core/src/subscription/quic_stream.rs Show resolved Hide resolved
core/src/subscription/quic_stream.rs Show resolved Hide resolved
core/src/protocols/stream/quic/mod.rs Outdated Show resolved Hide resolved
}
} else {
if let Some(ref mut short_header_value) = quic_clone.short_header {
short_header_value.dcid =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Based on only delivering short headers if connection id is present from long header, should you only deliver if get_connection_id returns None?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question! No, because I only return a ProbeResult::Certain when the header is a long header because those give enough information to be certain. From my understanding, this then results in the connection becoming tracked so that future packets that match this 5 tuple also use the parse pathway, which means they also call the on_match function if successful in initial parsing. Given that it is a part of an existing 5 tuple I'm certain enough that it is a quic header, but there's still a chance that I cannot match the dcid from that packet and so no matter if I get None or Some in the response I'll still want to populate the dcid appropriately.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed Quic -> QuicPacket. Thank you for the insight!

@thegwan
Copy link
Contributor

thegwan commented Jun 4, 2024

Here are the latest in throughput results as of 26210e3:

configs/online.toml was modified to run for 120 seconds with hardware filtering disabled, but otherwise kept the same.

Using a modified spin to subscribe to Connection records filtered on quic:

#[filter("quic")]
fn main() -> Result<()> {
    env_logger::init();
    let args = Args::parse();
    let config = load_config(&args.config);

    let cycles = args.spin;
    let callback = |_: Connection| {
        spin(cycles);
    };
    let mut runtime = Runtime::new(config, filter, callback)?;
    runtime.run();
    Ok(())
}
sudo env LD_LIBRARY_PATH=$LD_LIBRARY_PATH RUST_LOG=error ./target/release/spin -c configs/online.toml --spin 100000

AVERAGE Ingress: 94864318682.520 bps / 12205610.113 pps
AVERAGE Good:    94489256702.299 bps / 12205572.156 pps
AVERAGE Process: 94489256702.299 bps / 12205572.156 pps
DROPPED: 0 pkts (0%)

Main done. Ran for 120.112216759s

Using log_quic:

sudo env LD_LIBRARY_PATH=$LD_LIBRARY_PATH RUST_LOG=error ./target/release/log_quic -c configs/online.toml

AVERAGE Ingress: 93096828887.130 bps / 11949421.481 pps
AVERAGE Good:    92732955316.729 bps / 11949419.159 pps
AVERAGE Process: 92732955316.729 bps / 11949419.159 pps
DROPPED: 0 pkts (0%)

Main done. Ran for 120.110697638s
Done. Logged 39175955 Quic stream to "quic.jsonl"

configs/quic.toml Outdated Show resolved Hide resolved
@bokeefe123
Copy link
Contributor Author

@thegwan and @thearossman I think all requested changes should be included. Please let me know if there's any other action items to get this merged.

@thearossman
Copy link
Collaborator

LGTM! (Assuming it still runs with good performance and outputs sensible parsed results on the live traffic.)

@thegwan
Copy link
Contributor

thegwan commented Jun 5, 2024

LGTM! Please rebase on the main branch, I just submitted a fix for the CI failure.

@bokeefe123 bokeefe123 force-pushed the main branch 2 times, most recently from 0121bed to fda1e23 Compare June 5, 2024 06:55
@bokeefe123
Copy link
Contributor Author

I think I just rebased properly and it should be good to merge. As always, let me know if there are any issues.

@thegwan
Copy link
Contributor

thegwan commented Jun 5, 2024

Can you run cargo clippy with at least Rust 1.75.0 and fix the warnings that show up? These should all be relatively minor lints.

@bokeefe123
Copy link
Contributor Author

I just merged changes fixing my clippy warnings. I am still seeing quite a few clippy issues from files unrelated to my changes, so I'm not sure if that's an issue?

@thegwan thegwan merged commit 33139bd into stanford-esrg:main Jun 6, 2024
2 checks passed
thearossman pushed a commit to thearossman/retina that referenced this pull request Jun 7, 2024
* Add quic support

* Update main.rs

* fix indexing errors

* probe indexing change

* configs

* fix usize error

* further usize fixes

* another index fix

* return configs

* minimal performance improvements

* config changes

* rename file

* lazy load bytes

* lazy string copy

* other string conversion

* small change again

* renove config changes

* rename quic stream

* parseresult done

* revert parse result

* remove configs

* this is gonna break a lot

* config changes

* fix reference errors

* import fixes

* pub header

* public vec_u8

* import hell

* rename

* slight fixes

* everything mutable

* this wont work

* better cloning

* cloning

* fix

* fully clone

* more cloning

* copy trait

* partial move

* remove ref

* fix

* println debugging

* fix

* more prints

* hashset

* from clone

* y not

* cleanliness

* print quic clone

* done

* remove prints

* clear on end

* remove dead code

* remove imports

* remove configs

* reference based conn_ids

* configs

* rename quic to quicpacket

* remove quic.toml

* remove configs

* revert

* remove configs

* clippy fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants