1use core::fmt::Debug;
8use core::marker::PhantomData;
9
10use net_types::ip::{IpAddress, Ipv4, Ipv6};
11use netstack3_base::{
12 ChecksumRxOffloading, Counter, GsoInfo, Ipv4IdMode, MAX_GSO_PAYLOAD_LEN, NetworkParsingContext,
13 NetworkSerializationContext, Payload,
14};
15use netstack3_filter::{DynTransportSerializer, FilterIpExt, ForwardedPacket, RawIpBody};
16use packet::{
17 BufferMut, EmptyBuf, FragmentedBytesMut, InnerPacketBuilder, InnerSerializer,
18 NestablePacketBuilder, NestableSerializer as _, Nested, PacketBuilder, PacketConstraints,
19 ParsablePacket as _, ParseBuffer, SerializationContext, SerializeTarget,
20};
21use packet_formats::icmp::{IcmpIpExt, IcmpMessage, IcmpPacketBuilder};
22use packet_formats::ip::{FragmentOffset, IpExt, IpPacket as _, IpProto};
23use packet_formats::ipv4::{
24 HDR_PREFIX_LEN, Ipv4Header, Ipv4Packet, Ipv4PacketBuilder, Ipv4PacketBuilderWithOptions,
25};
26use packet_formats::ipv6::{Ipv6Packet, Ipv6PacketBuilder, Ipv6PacketBuilderWithHbhOptions};
27use packet_formats::tcp::options::TcpOptionsRef;
28use packet_formats::tcp::{TcpParseArgs, TcpSegment, TcpSegmentBuilderWithOptions};
29use packet_formats::udp::UdpPacketBuilder;
30
31use crate::internal::fragmentation::{
32 AsFragmentableIpPacketBuilder, FragmentationError, FragmentationIpExt,
33};
34
35#[derive(Debug, Eq, PartialEq)]
37pub enum GsoError {
38 Parse,
40 NotSegmentable,
42 UnsupportedHeaders,
45 PayloadTooLong,
47}
48
49pub trait GsoIpExt:
52 IpExt<PacketBuilder<NetworkSerializationContext>: AsSegmentableIpPacketBuilder<Self>>
53 + FragmentationIpExt
54{
55 type ForwardedSegmentBuilder: SegmentableIpPacketBuilder<Self>;
57
58 fn try_segmented_packet_builder<'a>(
63 packet: &Self::Packet<&'a [u8]>,
64 ) -> Result<Self::ForwardedSegmentBuilder, GsoError>;
65}
66
67impl GsoIpExt for Ipv4 {
68 type ForwardedSegmentBuilder = Ipv4PacketBuilder;
69
70 fn try_segmented_packet_builder<'a>(
71 packet: &Ipv4Packet<&'a [u8]>,
72 ) -> Result<Ipv4PacketBuilder, GsoError> {
73 if packet.header_len() != HDR_PREFIX_LEN {
77 return Err(GsoError::UnsupportedHeaders);
78 }
79 if packet.fragment_offset() != FragmentOffset::ZERO || packet.mf_flag() {
82 return Err(GsoError::UnsupportedHeaders);
83 }
84 Ok(Ipv4Header::builder(packet))
85 }
86}
87
88impl GsoIpExt for Ipv6 {
89 type ForwardedSegmentBuilder = ForwardedIpv6SegmentBuilder;
90
91 fn try_segmented_packet_builder<'a>(
92 packet: &Ipv6Packet<&'a [u8]>,
93 ) -> Result<ForwardedIpv6SegmentBuilder, GsoError> {
94 if packet.iter_extension_hdrs().next().is_some() {
99 return Err(GsoError::UnsupportedHeaders);
100 }
101 Ok(ForwardedIpv6SegmentBuilder(packet.builder()))
102 }
103}
104
105#[derive(Clone, Debug)]
112pub struct ForwardedIpv6SegmentBuilder(Ipv6PacketBuilder);
113
114impl SegmentableIpPacketBuilder<Ipv6> for ForwardedIpv6SegmentBuilder {
115 type SegmentBuilder = Self;
116
117 fn segment_builder(&self, _index: u16, _gso_info: GsoInfo) -> Self {
118 self.clone()
120 }
121}
122
123impl AsFragmentableIpPacketBuilder<Ipv6> for ForwardedIpv6SegmentBuilder {
124 type Builder<'a>
125 = <Ipv6PacketBuilder as AsFragmentableIpPacketBuilder<Ipv6>>::Builder<'a>
126 where
127 Self: 'a;
128
129 fn try_as_fragmentable(&self) -> Result<Self::Builder<'_>, FragmentationError> {
130 Err(FragmentationError::NotAllowed)
138 }
139}
140
141impl NestablePacketBuilder for ForwardedIpv6SegmentBuilder {
142 fn constraints(&self) -> PacketConstraints {
143 let Self(builder) = self;
144 builder.constraints()
145 }
146}
147
148impl PacketBuilder<NetworkSerializationContext> for ForwardedIpv6SegmentBuilder {
149 fn context_state(&self) -> <NetworkSerializationContext as SerializationContext>::ContextState {
150 let Self(builder) = self;
151 PacketBuilder::<NetworkSerializationContext>::context_state(builder)
152 }
153
154 fn serialize(
155 &self,
156 context: &mut NetworkSerializationContext,
157 target: &mut SerializeTarget<'_>,
158 body: FragmentedBytesMut<'_, '_>,
159 ) {
160 let Self(builder) = self;
161 builder.serialize(context, target, body)
162 }
163}
164
165pub trait MaybeSegmentableIpSerializer<I: GsoIpExt> {
173 const SOURCE: GsoSource;
175
176 type IpBuilder<'a>: SegmentableIpPacketBuilder<I>
178 where
179 Self: 'a;
180
181 type TransportBuilder<'a>: SegmentableTransportBuilder
183 where
184 Self: 'a;
185
186 type Payload<'a>: Payload + InnerPacketBuilder + Copy
188 where
189 Self: 'a;
190
191 fn try_segmenter(
196 &self,
197 gso_info: GsoInfo,
198 ) -> Result<
199 GsoSegmenter<I, Self::IpBuilder<'_>, Self::TransportBuilder<'_>, Self::Payload<'_>>,
200 GsoError,
201 >;
202}
203
204impl<I, B> MaybeSegmentableIpSerializer<I> for ForwardedPacket<I, B>
205where
206 I: GsoIpExt,
207 B: BufferMut,
208{
209 const SOURCE: GsoSource = GsoSource::Forwarded;
210
211 type IpBuilder<'a>
212 = I::ForwardedSegmentBuilder
213 where
214 Self: 'a;
215 type TransportBuilder<'a>
216 = ParsedForwardedTransport<'a, I::Addr>
217 where
218 Self: 'a;
219 type Payload<'a>
220 = &'a [u8]
221 where
222 Self: 'a;
223
224 fn try_segmenter(
225 &self,
226 gso_info: GsoInfo,
227 ) -> Result<GsoSegmenter<I, Self::IpBuilder<'_>, Self::TransportBuilder<'_>, &[u8]>, GsoError>
228 {
229 segmenter_from_packet_bytes(self.buffer().as_ref(), gso_info)
230 }
231}
232
233impl<I, S, B> MaybeSegmentableIpSerializer<I> for Nested<S, B>
234where
235 I: GsoIpExt,
236 S: MaybeSegmentableTransportSerializer,
237 B: AsSegmentableIpPacketBuilder<I>,
238{
239 const SOURCE: GsoSource = GsoSource::Local;
241
242 type IpBuilder<'a>
243 = B::Builder<'a>
244 where
245 Self: 'a;
246 type TransportBuilder<'a>
247 = S::Builder<'a>
248 where
249 Self: 'a;
250 type Payload<'a>
251 = S::Payload<'a>
252 where
253 Self: 'a;
254
255 fn try_segmenter(
256 &self,
257 gso_info: GsoInfo,
258 ) -> Result<GsoSegmenter<I, B::Builder<'_>, S::Builder<'_>, S::Payload<'_>>, GsoError> {
259 let ip_builder = self.outer().try_as_segmentable()?;
260 let (transport_builder, payload) = self.inner().try_as_segmentable()?;
261 GsoSegmenter::new(ip_builder, transport_builder, payload, gso_info)
262 }
263}
264
265pub trait AsSegmentableIpPacketBuilder<I: GsoIpExt> {
268 type Builder<'a>: SegmentableIpPacketBuilder<I>
270 where
271 Self: 'a;
272
273 fn try_as_segmentable(&self) -> Result<Self::Builder<'_>, GsoError>;
276}
277
278impl AsSegmentableIpPacketBuilder<Ipv4> for Ipv4PacketBuilder {
279 type Builder<'a>
280 = &'a Ipv4PacketBuilder
281 where
282 Self: 'a;
283
284 fn try_as_segmentable(&self) -> Result<&Ipv4PacketBuilder, GsoError> {
285 Ok(self)
286 }
287}
288
289impl AsSegmentableIpPacketBuilder<Ipv6> for Ipv6PacketBuilder {
290 type Builder<'a>
291 = &'a Ipv6PacketBuilder
292 where
293 Self: 'a;
294
295 fn try_as_segmentable(&self) -> Result<&Ipv6PacketBuilder, GsoError> {
296 Ok(self)
297 }
298}
299
300impl<O> AsSegmentableIpPacketBuilder<Ipv4> for Ipv4PacketBuilderWithOptions<'_, O> {
301 type Builder<'a>
302 = !
303 where
304 Self: 'a;
305
306 fn try_as_segmentable(&self) -> Result<!, GsoError> {
307 Err(GsoError::UnsupportedHeaders)
309 }
310}
311
312impl<O> AsSegmentableIpPacketBuilder<Ipv6> for Ipv6PacketBuilderWithHbhOptions<'_, O> {
313 type Builder<'a>
314 = !
315 where
316 Self: 'a;
317
318 fn try_as_segmentable(&self) -> Result<!, GsoError> {
319 Err(GsoError::UnsupportedHeaders)
321 }
322}
323
324pub trait SegmentableIpPacketBuilder<I: GsoIpExt> {
328 type SegmentBuilder: PacketBuilder<NetworkSerializationContext>
330 + NestablePacketBuilder
331 + AsFragmentableIpPacketBuilder<I>;
332
333 fn segment_builder(&self, index: u16, gso_info: GsoInfo) -> Self::SegmentBuilder;
336}
337
338impl SegmentableIpPacketBuilder<Ipv4> for Ipv4PacketBuilder {
339 type SegmentBuilder = Self;
340
341 fn segment_builder(&self, index: u16, gso_info: GsoInfo) -> Self {
342 let GsoInfo { ipv4_id_mode, gso_size: _, gso_segs: _ } = gso_info;
343 let mut builder = self.clone();
344 match ipv4_id_mode {
345 Some(Ipv4IdMode::Fixed) => {}
346 Some(Ipv4IdMode::Incrementing) | None => {
347 builder.id(self.read_id().wrapping_add(index));
348 }
349 }
350 builder
351 }
352}
353
354impl SegmentableIpPacketBuilder<Ipv6> for Ipv6PacketBuilder {
355 type SegmentBuilder = Self;
356
357 fn segment_builder(&self, _index: u16, _gso_info: GsoInfo) -> Self {
358 self.clone()
360 }
361}
362
363impl SegmentableIpPacketBuilder<Ipv4> for ! {
364 type SegmentBuilder = Ipv4PacketBuilder;
365
366 fn segment_builder(&self, _index: u16, _gso_info: GsoInfo) -> Ipv4PacketBuilder {
367 match *self {}
368 }
369}
370
371impl SegmentableIpPacketBuilder<Ipv6> for ! {
372 type SegmentBuilder = Ipv6PacketBuilder;
373
374 fn segment_builder(&self, _index: u16, _gso_info: GsoInfo) -> Ipv6PacketBuilder {
375 match *self {}
376 }
377}
378
379impl<I: GsoIpExt, T: SegmentableIpPacketBuilder<I>> SegmentableIpPacketBuilder<I> for &T {
382 type SegmentBuilder = T::SegmentBuilder;
383
384 fn segment_builder(&self, index: u16, gso_info: GsoInfo) -> T::SegmentBuilder {
385 T::segment_builder(*self, index, gso_info)
386 }
387}
388
389pub trait MaybeSegmentableTransportSerializer {
392 type Builder<'a>: SegmentableTransportBuilder
394 where
395 Self: 'a;
396
397 type Payload<'a>: Payload + InnerPacketBuilder + Copy
399 where
400 Self: 'a;
401
402 fn try_as_segmentable(&self) -> Result<(Self::Builder<'_>, Self::Payload<'_>), GsoError>;
405}
406
407impl<A, P, B, O> MaybeSegmentableTransportSerializer
408 for Nested<InnerSerializer<P, B>, TcpSegmentBuilderWithOptions<A, O>>
409where
410 A: IpAddress,
411 P: Payload + InnerPacketBuilder + Copy,
412 O: InnerPacketBuilder + Clone,
413{
414 type Builder<'a>
415 = &'a TcpSegmentBuilderWithOptions<A, O>
416 where
417 Self: 'a;
418 type Payload<'a>
419 = P
420 where
421 Self: 'a;
422
423 fn try_as_segmentable(&self) -> Result<(&TcpSegmentBuilderWithOptions<A, O>, P), GsoError> {
424 Ok((self.outer(), *self.inner().inner()))
425 }
426}
427
428macro_rules! impl_not_segmentable {
431 ([$($generics:tt)*] $ty:ty) => {
432 impl<$($generics)*> MaybeSegmentableTransportSerializer for $ty {
433 type Builder<'x> = ! where Self: 'x;
434 type Payload<'x> = &'x [u8] where Self: 'x;
435
436 fn try_as_segmentable(
437 &self,
438 ) -> Result<(!, &[u8]), GsoError> {
439 Err(GsoError::NotSegmentable)
440 }
441 }
442 };
443}
444
445impl_not_segmentable!([S, A: IpAddress] Nested<S, UdpPacketBuilder<A>>);
447
448impl_not_segmentable!(['a, I: FilterIpExt] DynTransportSerializer<'a, I>);
451impl_not_segmentable!([I: IpExt, B: ParseBuffer] RawIpBody<I, B>);
452impl_not_segmentable!([S, I: IcmpIpExt, M: IcmpMessage<I>] Nested<S, IcmpPacketBuilder<I, M>>);
453impl_not_segmentable!([S] Nested<S, ()>);
454impl_not_segmentable!([P, B] InnerSerializer<P, B>);
455
456pub trait SegmentableTransportBuilder {
463 type SegmentBuilder: PacketBuilder<NetworkSerializationContext> + NestablePacketBuilder;
465
466 fn segment_builder(&self, offset: u16, has_more: bool) -> Self::SegmentBuilder;
471}
472
473impl<A: IpAddress, O: InnerPacketBuilder + Clone> SegmentableTransportBuilder
474 for TcpSegmentBuilderWithOptions<A, O>
475{
476 type SegmentBuilder = Self;
477
478 fn segment_builder(&self, offset: u16, has_more: bool) -> Self {
479 let mut builder = self.clone();
480 let prefix_builder = builder.prefix_builder_mut();
481 let seq_num = prefix_builder.seq_num().wrapping_add(u32::from(offset));
482 prefix_builder.set_seq_num(seq_num);
483 if has_more {
484 prefix_builder.psh(false);
487 prefix_builder.fin(false);
488 }
489 builder
490 }
491}
492
493#[derive(Clone, Debug)]
495pub enum ParsedForwardedTransport<'a, A: IpAddress> {
496 Tcp(TcpSegmentBuilderWithOptions<A, TcpOptionsRef<&'a [u8]>>),
498}
499
500impl<A: IpAddress> SegmentableTransportBuilder for ParsedForwardedTransport<'_, A> {
501 type SegmentBuilder = Self;
502
503 fn segment_builder(&self, offset: u16, has_more: bool) -> Self {
504 match self {
505 Self::Tcp(builder) => Self::Tcp(builder.segment_builder(offset, has_more)),
506 }
507 }
508}
509
510impl<A: IpAddress> NestablePacketBuilder for ParsedForwardedTransport<'_, A> {
511 fn constraints(&self) -> PacketConstraints {
512 match self {
513 Self::Tcp(builder) => builder.constraints(),
514 }
515 }
516}
517
518impl<A: IpAddress> PacketBuilder<NetworkSerializationContext> for ParsedForwardedTransport<'_, A> {
519 fn context_state(&self) -> <NetworkSerializationContext as SerializationContext>::ContextState {
520 match self {
521 Self::Tcp(builder) => {
522 PacketBuilder::<NetworkSerializationContext>::context_state(builder)
523 }
524 }
525 }
526
527 fn serialize(
528 &self,
529 context: &mut NetworkSerializationContext,
530 target: &mut SerializeTarget<'_>,
531 body: FragmentedBytesMut<'_, '_>,
532 ) {
533 match self {
534 Self::Tcp(builder) => builder.serialize(context, target, body),
535 }
536 }
537}
538
539impl<T: SegmentableTransportBuilder> SegmentableTransportBuilder for &T {
540 type SegmentBuilder = T::SegmentBuilder;
541
542 fn segment_builder(&self, offset: u16, has_more: bool) -> T::SegmentBuilder {
543 T::segment_builder(*self, offset, has_more)
544 }
545}
546
547impl SegmentableTransportBuilder for ! {
548 type SegmentBuilder = !;
549
550 fn segment_builder(&self, _offset: u16, _has_more: bool) -> ! {
551 match *self {}
552 }
553}
554
555pub struct GsoSegmenter<I: GsoIpExt, IB, B, P> {
564 ip_builder: IB,
566 transport_builder: B,
568 payload: P,
570 payload_len: u16,
572 consumed: u16,
574 index: u16,
576 gso_info: GsoInfo,
577 _marker: PhantomData<I>,
578}
579
580impl<I, IB, B, P> GsoSegmenter<I, IB, B, P>
581where
582 I: GsoIpExt,
583 IB: SegmentableIpPacketBuilder<I>,
584 B: SegmentableTransportBuilder,
585 P: Payload + InnerPacketBuilder + Copy,
586{
587 fn new(
588 ip_builder: IB,
589 transport_builder: B,
590 payload: P,
591 gso_info: GsoInfo,
592 ) -> Result<Self, GsoError> {
593 if payload.len() > usize::from(MAX_GSO_PAYLOAD_LEN) {
594 return Err(GsoError::PayloadTooLong);
595 }
596 let payload_len =
597 u16::try_from(payload.len()).expect("payload length is at most MAX_GSO_PAYLOAD_LEN");
598 Ok(Self {
599 ip_builder,
600 transport_builder,
601 payload,
602 payload_len,
603 consumed: 0,
604 index: 0,
605 gso_info,
606 _marker: PhantomData,
607 })
608 }
609}
610
611type SegmentSerializer<P, TB, IB> = Nested<Nested<InnerSerializer<P, EmptyBuf>, TB>, IB>;
613
614impl<I, IB, B, P> Iterator for GsoSegmenter<I, IB, B, P>
615where
616 I: GsoIpExt,
617 IB: SegmentableIpPacketBuilder<I>,
618 B: SegmentableTransportBuilder,
619 P: Payload + InnerPacketBuilder + Copy,
620{
621 type Item = (SegmentSerializer<P, B::SegmentBuilder, IB::SegmentBuilder>, bool);
624
625 fn next(&mut self) -> Option<Self::Item> {
626 let Self {
627 ip_builder,
628 transport_builder,
629 payload,
630 payload_len,
631 consumed,
632 index,
633 gso_info,
634 _marker: _,
635 } = self;
636 let GsoInfo { gso_size: max_segment_body, gso_segs: _, ipv4_id_mode: _ } = gso_info;
637
638 let remaining = *payload_len - *consumed;
639 if remaining == 0 {
640 return None;
641 }
642 let take = remaining.min(max_segment_body.get());
643 let has_more = take < remaining;
644 let segment_body = payload.slice(u32::from(*consumed)..u32::from(*consumed + take));
645
646 let transport_builder = transport_builder.segment_builder(*consumed, has_more);
647 let ip_builder = ip_builder.segment_builder(*index, *gso_info);
648
649 *consumed += take;
650 *index = index.checked_add(1).expect("number of segments cannot exceed u16::MAX");
651
652 Some((
653 segment_body.into_serializer().wrap_in(transport_builder).wrap_in(ip_builder),
654 has_more,
655 ))
656 }
657}
658
659fn segmenter_from_packet_bytes<I: GsoIpExt>(
665 packet_bytes: &[u8],
666 gso_info: GsoInfo,
667) -> Result<
668 GsoSegmenter<I, I::ForwardedSegmentBuilder, ParsedForwardedTransport<'_, I::Addr>, &[u8]>,
669 GsoError,
670> {
671 let mut buffer = packet_bytes;
672 let packet = <I as IpExt>::Packet::parse(&mut buffer, ()).map_err(|_| GsoError::Parse)?;
673 if packet.proto() != IpProto::Tcp.into() {
674 return Err(GsoError::NotSegmentable);
675 }
676 let ip_builder = I::try_segmented_packet_builder(&packet)?;
677
678 let (src_ip, dst_ip) = (packet.src_ip(), packet.dst_ip());
679 let ip_body =
682 &packet_bytes[packet.parse_metadata().header_len()..][..packet.parse_metadata().body_len()];
683 let mut tcp_bytes = ip_body;
684 let mut parsing_context = NetworkParsingContext::new(ChecksumRxOffloading::FullyOffloaded);
688 let tcp = TcpSegment::parse(
689 &mut tcp_bytes,
690 TcpParseArgs::with_context(src_ip, dst_ip, &mut parsing_context),
691 )
692 .map_err(|_| GsoError::Parse)?;
693 let payload = &ip_body[tcp.header_len()..];
696 let tcp_builder = ParsedForwardedTransport::Tcp(tcp.into_builder(src_ip, dst_ip));
697
698 GsoSegmenter::new(ip_builder, tcp_builder, payload, gso_info)
699}
700
701#[derive(Clone, Copy, Debug, Eq, PartialEq)]
703pub enum GsoSource {
704 Forwarded,
709 Local,
711}
712
713#[derive(Default, Debug)]
716#[cfg_attr(
717 any(test, feature = "testutils"),
718 derive(PartialEq, netstack3_macros::CounterCollection)
719)]
720pub struct GsoCounters<C = Counter> {
721 pub forwarded: GsoSourceCounters<C>,
723 pub local: GsoSourceCounters<C>,
725}
726
727impl GsoCounters {
728 pub(crate) fn for_source(&self, source: GsoSource) -> &GsoSourceCounters {
729 let Self { forwarded, local } = self;
730 match source {
731 GsoSource::Forwarded => forwarded,
732 GsoSource::Local => local,
733 }
734 }
735}
736
737#[derive(Default, Debug)]
739#[cfg_attr(
740 any(test, feature = "testutils"),
741 derive(PartialEq, netstack3_macros::CounterCollection)
742)]
743pub struct GsoSourceCounters<C = Counter> {
744 pub segmentation_required: C,
746 pub segments: C,
748 pub error_parse: C,
750 pub error_not_segmentable: C,
752 pub error_unsupported_headers: C,
754 pub error_payload_too_long: C,
756}
757
758impl GsoSourceCounters {
759 pub(crate) fn error_counter(&self, error: &GsoError) -> &Counter {
760 match error {
761 GsoError::Parse => &self.error_parse,
762 GsoError::NotSegmentable => &self.error_not_segmentable,
763 GsoError::UnsupportedHeaders => &self.error_unsupported_headers,
764 GsoError::PayloadTooLong => &self.error_payload_too_long,
765 }
766 }
767}
768
769#[cfg(test)]
770mod tests {
771 use super::*;
772
773 use alloc::vec::Vec;
774 use core::num::NonZeroU16;
775
776 use ip_test_macro::ip_test;
777 use net_types::Witness as _;
778 use net_types::ip::IpVersion;
779 use netstack3_base::testutil::{TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt};
780 use packet::{Buf, Serializer};
781 use packet_formats::ip::{IpPacketBuilder as _, IpProto};
782 use packet_formats::ipv4::options::Ipv4Option;
783 use packet_formats::tcp::TcpSegmentBuilder;
784 use packet_formats::tcp::options::{
785 TcpOptions as _, TcpOptionsBuilder, TcpSackBlock, TimestampOption,
786 };
787 use test_case::{test_case, test_matrix};
788
789 const SRC_PORT: NonZeroU16 = NonZeroU16::new(1234).unwrap();
790 const DST_PORT: NonZeroU16 = NonZeroU16::new(80).unwrap();
791 const SEQ_NUM: u32 = 100;
792 const TTL: u8 = 64;
793 const GSO_SIZE: NonZeroU16 = NonZeroU16::new(100).unwrap();
796 const NUM_SEGMENTS: usize = 3;
798 const LAST_SEGMENT_LEN: usize = GSO_SIZE.get() as usize / 2;
801 const PAYLOAD_LEN: usize = (NUM_SEGMENTS - 1) * GSO_SIZE.get() as usize + LAST_SEGMENT_LEN;
804 const TIMESTAMP: TimestampOption = TimestampOption::new(1, 2);
806 static SACK_BLOCKS: [TcpSackBlock; 2] = [TcpSackBlock::new(10, 20), TcpSackBlock::new(30, 40)];
808
809 #[derive(Clone, Copy, Debug)]
811 enum TcpPacketSource {
812 Bytes,
815 Serializer,
818 }
819
820 fn gso_info<I: net_types::ip::Ip>(id_mode: Ipv4IdMode) -> GsoInfo {
821 let ipv4_id_mode = match I::VERSION {
822 IpVersion::V4 => Some(id_mode),
823 IpVersion::V6 => None,
824 };
825 GsoInfo {
826 gso_size: GSO_SIZE,
827 gso_segs: NonZeroU16::new(NUM_SEGMENTS as u16).unwrap(),
828 ipv4_id_mode,
829 }
830 }
831
832 fn test_payload(len: usize) -> Vec<u8> {
833 (0u8..251).cycle().take(len).collect()
836 }
837
838 fn new_tcp_serializer<'a, I: TestIpExt + GsoIpExt>(
841 payload: &'a [u8],
842 fin: bool,
843 psh: bool,
844 ) -> impl MaybeSegmentableIpSerializer<I> + Serializer<NetworkSerializationContext> + 'a {
845 let src_ip = I::TEST_ADDRS.local_ip.get();
846 let dst_ip = I::TEST_ADDRS.remote_ip.get();
847 let mut prefix_builder =
848 TcpSegmentBuilder::new(src_ip, dst_ip, SRC_PORT, DST_PORT, SEQ_NUM, None, u16::MAX);
849 prefix_builder.fin(fin);
850 prefix_builder.psh(psh);
851 let options = TcpOptionsBuilder {
855 timestamp: Some(TIMESTAMP),
856 sack_blocks: Some(&SACK_BLOCKS),
857 ..Default::default()
858 };
859 payload
860 .into_serializer()
861 .wrap_in(
862 TcpSegmentBuilderWithOptions::new(prefix_builder, options).expect("create builder"),
863 )
864 .wrap_in(I::PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Tcp.into()))
865 }
866
867 fn new_tcp_packet<I: TestIpExt + GsoIpExt>(payload: &[u8], fin: bool, psh: bool) -> Vec<u8> {
869 new_tcp_serializer::<I>(payload, fin, psh)
870 .serialize_vec_outer_no_reuse(&mut NetworkSerializationContext::default())
871 .expect("serialize packet")
872 .into_inner()
873 }
874
875 fn create_and_segment_tcp_packet<I: TestIpExt + GsoIpExt>(
878 source: TcpPacketSource,
879 payload: &[u8],
880 fin: bool,
881 psh: bool,
882 gso_info: GsoInfo,
883 ) -> Vec<Buf<Vec<u8>>> {
884 match source {
885 TcpPacketSource::Bytes => {
886 let packet = new_tcp_packet::<I>(payload, fin, psh);
887 collect_segments(
888 segmenter_from_packet_bytes::<I>(&packet, gso_info).expect("create segmenter"),
889 )
890 }
891 TcpPacketSource::Serializer => {
892 let serializer = new_tcp_serializer::<I>(payload, fin, psh);
893 collect_segments(serializer.try_segmenter(gso_info).expect("create segmenter"))
894 }
895 }
896 }
897
898 fn collect_segments<I, IB, B, P>(mut segmenter: GsoSegmenter<I, IB, B, P>) -> Vec<Buf<Vec<u8>>>
900 where
901 I: GsoIpExt,
902 IB: SegmentableIpPacketBuilder<I>,
903 B: SegmentableTransportBuilder,
904 P: Payload + InnerPacketBuilder + Copy,
905 {
906 let mut segments = Vec::new();
907 let mut expect_more = true;
908 while let Some((segment, has_more)) = segmenter.next() {
909 assert!(expect_more);
911 expect_more = has_more;
912 let segment = segment
913 .serialize_vec_outer(&mut NetworkSerializationContext::default())
914 .map_err(|(err, _serializer)| err)
915 .expect("serialize segment")
916 .unwrap_b();
917 segments.push(segment);
918 }
919 assert!(!expect_more);
920 segments
921 }
922
923 fn check_tcp_ip_packet<I: TestIpExt>(
926 buf: &mut Buf<Vec<u8>>,
927 index: u16,
928 id_mode: Ipv4IdMode,
929 fin: bool,
930 psh: bool,
931 ) -> Vec<u8> {
932 let src_ip = I::TEST_ADDRS.local_ip.get();
933 let dst_ip = I::TEST_ADDRS.remote_ip.get();
934 {
935 let packet = buf.parse::<<I as IpExt>::Packet<_>>().expect("parse IP packet");
936 assert_eq!(packet.src_ip(), src_ip);
937 assert_eq!(packet.dst_ip(), dst_ip);
938 assert_eq!(packet.proto(), IpProto::Tcp.into());
939 assert_eq!(packet.ttl(), TTL);
940 I::map_ip_in(
941 &packet,
942 |packet| {
943 let expected_id = match id_mode {
944 Ipv4IdMode::Fixed => 0,
945 Ipv4IdMode::Incrementing => index,
946 };
947 assert_eq!(packet.id(), expected_id);
948 },
949 |_packet| {},
950 );
951 }
952
953 let tcp = buf
954 .parse_with::<_, TcpSegment<_>>(TcpParseArgs::new(src_ip, dst_ip))
955 .expect("parse TCP segment");
956 assert_eq!(tcp.src_port(), SRC_PORT);
957 assert_eq!(tcp.dst_port(), DST_PORT);
958 assert_eq!(tcp.fin(), fin);
959 assert_eq!(tcp.psh(), psh);
960 assert_eq!(tcp.options().timestamp(), Some(&TIMESTAMP));
961 assert_eq!(tcp.options().sack_blocks(), Some(&SACK_BLOCKS[..]));
962 tcp.body().to_vec()
963 }
964
965 #[ip_test(I)]
966 #[test_matrix(
967 [TcpPacketSource::Bytes, TcpPacketSource::Serializer],
968 [Ipv4IdMode::Incrementing, Ipv4IdMode::Fixed],
969 [LAST_SEGMENT_LEN, usize::from(GSO_SIZE.get())],
970 [true, false],
971 [true, false]
972 )]
973 fn segments_tcp_packet<I: TestIpExt + GsoIpExt>(
974 source: TcpPacketSource,
975 id_mode: Ipv4IdMode,
976 last_segment_len: usize,
977 fin: bool,
978 psh: bool,
979 ) {
980 let payload =
981 test_payload((NUM_SEGMENTS - 1) * usize::from(GSO_SIZE.get()) + last_segment_len);
982 let mut segments =
983 create_and_segment_tcp_packet::<I>(source, &payload, fin, psh, gso_info::<I>(id_mode));
984 let num_segments = segments.len();
985 assert_eq!(num_segments, NUM_SEGMENTS);
986
987 let mut collected = Vec::new();
988 for (index, segment) in segments.iter_mut().enumerate() {
989 let last = index == num_segments - 1;
990 let expect_fin = last && fin;
992 let expect_psh = last && psh;
993 let body = check_tcp_ip_packet::<I>(
994 segment,
995 u16::try_from(index).unwrap(),
996 id_mode,
997 expect_fin,
998 expect_psh,
999 );
1000 assert_eq!(
1001 body.len(),
1002 if last { last_segment_len } else { usize::from(GSO_SIZE.get()) }
1003 );
1004 collected.extend_from_slice(&body);
1005 }
1006 assert_eq!(collected, payload);
1007 }
1008
1009 #[ip_test(I)]
1010 fn rejects_non_tcp_serializer<I: TestIpExt + GsoIpExt>() {
1011 let payload = test_payload(PAYLOAD_LEN);
1012 let src_ip = I::TEST_ADDRS.local_ip.get();
1013 let dst_ip = I::TEST_ADDRS.remote_ip.get();
1014 let serializer = Buf::new(payload, ..)
1015 .wrap_in(UdpPacketBuilder::new(src_ip, dst_ip, Some(SRC_PORT), DST_PORT))
1016 .wrap_in(I::PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Udp.into()));
1017 assert_eq!(
1018 serializer.try_segmenter(gso_info::<I>(Ipv4IdMode::Incrementing)).err(),
1019 Some(GsoError::NotSegmentable)
1020 );
1021 }
1022
1023 #[test_case(TcpPacketSource::Bytes; "bytes")]
1024 #[test_case(TcpPacketSource::Serializer; "serializer")]
1025 fn segments_advance_sequence_numbers(source: TcpPacketSource) {
1026 let payload = test_payload(PAYLOAD_LEN);
1027 let fin = false;
1028 let psh = true;
1029 let seq_nums: Vec<u32> = create_and_segment_tcp_packet::<Ipv4>(
1030 source,
1031 &payload,
1032 fin,
1033 psh,
1034 gso_info::<Ipv4>(Ipv4IdMode::Incrementing),
1035 )
1036 .into_iter()
1037 .map(|mut segment| {
1038 let _ = segment.parse::<Ipv4Packet<_>>().expect("parse IPv4 packet");
1039 segment
1040 .parse_with::<_, TcpSegment<_>>(TcpParseArgs::new(
1041 TEST_ADDRS_V4.local_ip.get(),
1042 TEST_ADDRS_V4.remote_ip.get(),
1043 ))
1044 .expect("parse TCP segment")
1045 .seq_num()
1046 })
1047 .collect();
1048 let gso_size = u32::from(GSO_SIZE.get());
1049 let expected: Vec<u32> =
1050 (0..NUM_SEGMENTS).map(|i| SEQ_NUM + u32::try_from(i).unwrap() * gso_size).collect();
1051 assert_eq!(seq_nums, expected);
1052 }
1053
1054 #[ip_test(I)]
1055 fn rejects_non_tcp<I: TestIpExt + GsoIpExt>() {
1056 let src_ip = I::TEST_ADDRS.local_ip.get();
1057 let dst_ip = I::TEST_ADDRS.remote_ip.get();
1058 let packet = Buf::new(test_payload(PAYLOAD_LEN), ..)
1059 .wrap_in(UdpPacketBuilder::new(src_ip, dst_ip, Some(SRC_PORT), DST_PORT))
1060 .wrap_in(I::PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Udp.into()))
1061 .serialize_vec_outer(&mut NetworkSerializationContext::default())
1062 .map_err(|(err, _serializer)| err)
1063 .expect("serialize packet")
1064 .unwrap_b()
1065 .into_inner();
1066 assert_eq!(
1067 segmenter_from_packet_bytes::<I>(&packet, gso_info::<I>(Ipv4IdMode::Incrementing))
1068 .err(),
1069 Some(GsoError::NotSegmentable)
1070 );
1071 }
1072
1073 #[test]
1074 fn rejects_unparseable_packet() {
1075 let packet = [0u8; 8];
1076 assert_eq!(
1077 segmenter_from_packet_bytes::<Ipv6>(
1078 &packet[..],
1079 gso_info::<Ipv6>(Ipv4IdMode::Incrementing)
1080 )
1081 .err(),
1082 Some(GsoError::Parse)
1083 );
1084 }
1085
1086 #[test]
1087 fn rejects_ipv4_packet_with_options() {
1088 let src_ip = TEST_ADDRS_V4.local_ip.get();
1089 let dst_ip = TEST_ADDRS_V4.remote_ip.get();
1090 let packet = Buf::new(test_payload(PAYLOAD_LEN), ..)
1091 .wrap_in(TcpSegmentBuilder::new(
1092 src_ip,
1093 dst_ip,
1094 SRC_PORT,
1095 DST_PORT,
1096 SEQ_NUM,
1097 None,
1098 u16::MAX,
1099 ))
1100 .wrap_in(
1101 Ipv4PacketBuilderWithOptions::new(
1102 Ipv4PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Tcp.into()),
1103 [Ipv4Option::RouterAlert { data: 0 }],
1104 )
1105 .expect("create builder"),
1106 )
1107 .serialize_vec_outer(&mut NetworkSerializationContext::default())
1108 .map_err(|(err, _serializer)| err)
1109 .expect("serialize packet")
1110 .unwrap_b()
1111 .into_inner();
1112 assert_eq!(
1113 segmenter_from_packet_bytes::<Ipv4>(
1114 &packet,
1115 gso_info::<Ipv4>(Ipv4IdMode::Incrementing)
1116 )
1117 .err(),
1118 Some(GsoError::UnsupportedHeaders)
1119 );
1120 }
1121
1122 #[test]
1123 fn rejects_ipv6_packet_with_extension_headers() {
1124 use packet_formats::ipv6::Ipv6PacketBuilderWithHbhOptions;
1125 use packet_formats::ipv6::ext_hdrs::{
1126 ExtensionHeaderOptionAction, HopByHopOption, HopByHopOptionData,
1127 };
1128
1129 let src_ip = TEST_ADDRS_V6.local_ip.get();
1130 let dst_ip = TEST_ADDRS_V6.remote_ip.get();
1131 let packet = Buf::new(test_payload(PAYLOAD_LEN), ..)
1132 .wrap_in(TcpSegmentBuilder::new(
1133 src_ip,
1134 dst_ip,
1135 SRC_PORT,
1136 DST_PORT,
1137 SEQ_NUM,
1138 None,
1139 u16::MAX,
1140 ))
1141 .wrap_in(
1142 Ipv6PacketBuilderWithHbhOptions::new(
1143 Ipv6PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Tcp.into()),
1144 &[HopByHopOption {
1145 action: ExtensionHeaderOptionAction::SkipAndContinue,
1146 mutable: false,
1147 data: HopByHopOptionData::RouterAlert { data: 0 },
1148 }],
1149 )
1150 .expect("create builder"),
1151 )
1152 .serialize_vec_outer(&mut NetworkSerializationContext::default())
1153 .expect("serialize packet")
1154 .unwrap_b()
1155 .into_inner();
1156 assert_eq!(
1157 segmenter_from_packet_bytes::<Ipv6>(
1158 &packet,
1159 gso_info::<Ipv6>(Ipv4IdMode::Incrementing)
1160 )
1161 .err(),
1162 Some(GsoError::UnsupportedHeaders)
1163 );
1164 }
1165}