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>);
453impl_not_segmentable!([I: IpExt, B: ParseBuffer] RawIpBody<I, B>);
454impl_not_segmentable!([S, I: IcmpIpExt, M: IcmpMessage<I>] Nested<S, IcmpPacketBuilder<I, M>>);
455impl_not_segmentable!([S] Nested<S, ()>);
456impl_not_segmentable!([P, B] InnerSerializer<P, B>);
457
458pub trait SegmentableTransportBuilder {
465 type SegmentBuilder: PacketBuilder<NetworkSerializationContext> + NestablePacketBuilder;
467
468 fn segment_builder(&self, offset: u16, has_more: bool) -> Self::SegmentBuilder;
473}
474
475impl<A: IpAddress, O: InnerPacketBuilder + Clone> SegmentableTransportBuilder
476 for TcpSegmentBuilderWithOptions<A, O>
477{
478 type SegmentBuilder = Self;
479
480 fn segment_builder(&self, offset: u16, has_more: bool) -> Self {
481 let mut builder = self.clone();
482 let prefix_builder = builder.prefix_builder_mut();
483 let seq_num = prefix_builder.seq_num().wrapping_add(u32::from(offset));
484 prefix_builder.set_seq_num(seq_num);
485 if has_more {
486 prefix_builder.psh(false);
489 prefix_builder.fin(false);
490 }
491 builder
492 }
493}
494
495#[derive(Clone, Debug)]
497pub enum ParsedForwardedTransport<'a, A: IpAddress> {
498 Tcp(TcpSegmentBuilderWithOptions<A, TcpOptionsRef<&'a [u8]>>),
500}
501
502impl<A: IpAddress> SegmentableTransportBuilder for ParsedForwardedTransport<'_, A> {
503 type SegmentBuilder = Self;
504
505 fn segment_builder(&self, offset: u16, has_more: bool) -> Self {
506 match self {
507 Self::Tcp(builder) => Self::Tcp(builder.segment_builder(offset, has_more)),
508 }
509 }
510}
511
512impl<A: IpAddress> NestablePacketBuilder for ParsedForwardedTransport<'_, A> {
513 fn constraints(&self) -> PacketConstraints {
514 match self {
515 Self::Tcp(builder) => builder.constraints(),
516 }
517 }
518}
519
520impl<A: IpAddress> PacketBuilder<NetworkSerializationContext> for ParsedForwardedTransport<'_, A> {
521 fn context_state(&self) -> <NetworkSerializationContext as SerializationContext>::ContextState {
522 match self {
523 Self::Tcp(builder) => {
524 PacketBuilder::<NetworkSerializationContext>::context_state(builder)
525 }
526 }
527 }
528
529 fn serialize(
530 &self,
531 context: &mut NetworkSerializationContext,
532 target: &mut SerializeTarget<'_>,
533 body: FragmentedBytesMut<'_, '_>,
534 ) {
535 match self {
536 Self::Tcp(builder) => builder.serialize(context, target, body),
537 }
538 }
539}
540
541impl<T: SegmentableTransportBuilder> SegmentableTransportBuilder for &T {
542 type SegmentBuilder = T::SegmentBuilder;
543
544 fn segment_builder(&self, offset: u16, has_more: bool) -> T::SegmentBuilder {
545 T::segment_builder(*self, offset, has_more)
546 }
547}
548
549impl SegmentableTransportBuilder for ! {
550 type SegmentBuilder = !;
551
552 fn segment_builder(&self, _offset: u16, _has_more: bool) -> ! {
553 match *self {}
554 }
555}
556
557pub struct GsoSegmenter<I: GsoIpExt, IB, B, P> {
566 ip_builder: IB,
568 transport_builder: B,
570 payload: P,
572 payload_len: u16,
574 consumed: u16,
576 index: u16,
578 gso_info: GsoInfo,
579 _marker: PhantomData<I>,
580}
581
582impl<I, IB, B, P> GsoSegmenter<I, IB, B, P>
583where
584 I: GsoIpExt,
585 IB: SegmentableIpPacketBuilder<I>,
586 B: SegmentableTransportBuilder,
587 P: Payload + InnerPacketBuilder + Copy,
588{
589 fn new(
590 ip_builder: IB,
591 transport_builder: B,
592 payload: P,
593 gso_info: GsoInfo,
594 ) -> Result<Self, GsoError> {
595 if payload.len() > usize::from(MAX_GSO_PAYLOAD_LEN) {
596 return Err(GsoError::PayloadTooLong);
597 }
598 let payload_len =
599 u16::try_from(payload.len()).expect("payload length is at most MAX_GSO_PAYLOAD_LEN");
600 Ok(Self {
601 ip_builder,
602 transport_builder,
603 payload,
604 payload_len,
605 consumed: 0,
606 index: 0,
607 gso_info,
608 _marker: PhantomData,
609 })
610 }
611}
612
613type SegmentSerializer<P, TB, IB> = Nested<Nested<InnerSerializer<P, EmptyBuf>, TB>, IB>;
615
616impl<I, IB, B, P> Iterator for GsoSegmenter<I, IB, B, P>
617where
618 I: GsoIpExt,
619 IB: SegmentableIpPacketBuilder<I>,
620 B: SegmentableTransportBuilder,
621 P: Payload + InnerPacketBuilder + Copy,
622{
623 type Item = (SegmentSerializer<P, B::SegmentBuilder, IB::SegmentBuilder>, bool);
626
627 fn next(&mut self) -> Option<Self::Item> {
628 let Self {
629 ip_builder,
630 transport_builder,
631 payload,
632 payload_len,
633 consumed,
634 index,
635 gso_info,
636 _marker: _,
637 } = self;
638 let GsoInfo { gso_size: max_segment_body, gso_segs: _, ipv4_id_mode: _ } = gso_info;
639
640 let remaining = *payload_len - *consumed;
641 if remaining == 0 {
642 return None;
643 }
644 let take = remaining.min(max_segment_body.get());
645 let has_more = take < remaining;
646 let segment_body = payload.slice(u32::from(*consumed)..u32::from(*consumed + take));
647
648 let transport_builder = transport_builder.segment_builder(*consumed, has_more);
649 let ip_builder = ip_builder.segment_builder(*index, *gso_info);
650
651 *consumed += take;
652 *index = index.checked_add(1).expect("number of segments cannot exceed u16::MAX");
653
654 Some((
655 segment_body.into_serializer().wrap_in(transport_builder).wrap_in(ip_builder),
656 has_more,
657 ))
658 }
659}
660
661fn segmenter_from_packet_bytes<I: GsoIpExt>(
667 packet_bytes: &[u8],
668 gso_info: GsoInfo,
669) -> Result<
670 GsoSegmenter<I, I::ForwardedSegmentBuilder, ParsedForwardedTransport<'_, I::Addr>, &[u8]>,
671 GsoError,
672> {
673 let mut buffer = packet_bytes;
674 let packet = <I as IpExt>::Packet::parse(&mut buffer, ()).map_err(|_| GsoError::Parse)?;
675 if packet.proto() != IpProto::Tcp.into() {
676 return Err(GsoError::NotSegmentable);
677 }
678 let ip_builder = I::try_segmented_packet_builder(&packet)?;
679
680 let (src_ip, dst_ip) = (packet.src_ip(), packet.dst_ip());
681 let ip_body =
684 &packet_bytes[packet.parse_metadata().header_len()..][..packet.parse_metadata().body_len()];
685 let mut tcp_bytes = ip_body;
686 let mut parsing_context = NetworkParsingContext::new(ChecksumRxOffloading::FullyOffloaded);
690 let tcp = TcpSegment::parse(
691 &mut tcp_bytes,
692 TcpParseArgs::with_context(src_ip, dst_ip, &mut parsing_context),
693 )
694 .map_err(|_| GsoError::Parse)?;
695 let payload = &ip_body[tcp.header_len()..];
698 let tcp_builder = ParsedForwardedTransport::Tcp(tcp.into_builder(src_ip, dst_ip));
699
700 GsoSegmenter::new(ip_builder, tcp_builder, payload, gso_info)
701}
702
703#[derive(Clone, Copy, Debug, Eq, PartialEq)]
705pub enum GsoSource {
706 Forwarded,
711 Local,
713}
714
715#[derive(Default, Debug)]
718#[cfg_attr(
719 any(test, feature = "testutils"),
720 derive(PartialEq, netstack3_macros::CounterCollection)
721)]
722pub struct GsoCounters<C = Counter> {
723 pub forwarded: GsoSourceCounters<C>,
725 pub local: GsoSourceCounters<C>,
727}
728
729impl GsoCounters {
730 pub(crate) fn for_source(&self, source: GsoSource) -> &GsoSourceCounters {
731 let Self { forwarded, local } = self;
732 match source {
733 GsoSource::Forwarded => forwarded,
734 GsoSource::Local => local,
735 }
736 }
737}
738
739#[derive(Default, Debug)]
741#[cfg_attr(
742 any(test, feature = "testutils"),
743 derive(PartialEq, netstack3_macros::CounterCollection)
744)]
745pub struct GsoSourceCounters<C = Counter> {
746 pub segmentation_required: C,
748 pub segments: C,
750 pub error_parse: C,
752 pub error_not_segmentable: C,
754 pub error_unsupported_headers: C,
756 pub error_payload_too_long: C,
758}
759
760impl GsoSourceCounters {
761 pub(crate) fn error_counter(&self, error: &GsoError) -> &Counter {
762 match error {
763 GsoError::Parse => &self.error_parse,
764 GsoError::NotSegmentable => &self.error_not_segmentable,
765 GsoError::UnsupportedHeaders => &self.error_unsupported_headers,
766 GsoError::PayloadTooLong => &self.error_payload_too_long,
767 }
768 }
769}
770
771#[cfg(test)]
772mod tests {
773 use super::*;
774
775 use alloc::vec::Vec;
776 use core::num::NonZeroU16;
777
778 use ip_test_macro::ip_test;
779 use net_types::Witness as _;
780 use net_types::ip::IpVersion;
781 use netstack3_base::testutil::{TEST_ADDRS_V4, TEST_ADDRS_V6, TestIpExt};
782 use packet::{Buf, Serializer};
783 use packet_formats::ip::{IpPacketBuilder as _, IpProto};
784 use packet_formats::ipv4::options::Ipv4Option;
785 use packet_formats::tcp::TcpSegmentBuilder;
786 use packet_formats::tcp::options::{
787 TcpOptions as _, TcpOptionsBuilder, TcpSackBlock, TimestampOption,
788 };
789 use test_case::{test_case, test_matrix};
790
791 const SRC_PORT: NonZeroU16 = NonZeroU16::new(1234).unwrap();
792 const DST_PORT: NonZeroU16 = NonZeroU16::new(80).unwrap();
793 const SEQ_NUM: u32 = 100;
794 const TTL: u8 = 64;
795 const GSO_SIZE: NonZeroU16 = NonZeroU16::new(100).unwrap();
798 const NUM_SEGMENTS: usize = 3;
800 const LAST_SEGMENT_LEN: usize = GSO_SIZE.get() as usize / 2;
803 const PAYLOAD_LEN: usize = (NUM_SEGMENTS - 1) * GSO_SIZE.get() as usize + LAST_SEGMENT_LEN;
806 const TIMESTAMP: TimestampOption = TimestampOption::new(1, 2);
808 static SACK_BLOCKS: [TcpSackBlock; 2] = [TcpSackBlock::new(10, 20), TcpSackBlock::new(30, 40)];
810
811 #[derive(Clone, Copy, Debug)]
813 enum TcpPacketSource {
814 Bytes,
817 Serializer,
820 }
821
822 fn gso_info<I: net_types::ip::Ip>(id_mode: Ipv4IdMode) -> GsoInfo {
823 let ipv4_id_mode = match I::VERSION {
824 IpVersion::V4 => Some(id_mode),
825 IpVersion::V6 => None,
826 };
827 GsoInfo {
828 gso_size: GSO_SIZE,
829 gso_segs: NonZeroU16::new(NUM_SEGMENTS as u16).unwrap(),
830 ipv4_id_mode,
831 }
832 }
833
834 fn test_payload(len: usize) -> Vec<u8> {
835 (0u8..251).cycle().take(len).collect()
838 }
839
840 fn new_tcp_serializer<'a, I: TestIpExt + GsoIpExt>(
843 payload: &'a [u8],
844 fin: bool,
845 psh: bool,
846 ) -> impl MaybeSegmentableIpSerializer<I> + Serializer<NetworkSerializationContext> + 'a {
847 let src_ip = I::TEST_ADDRS.local_ip.get();
848 let dst_ip = I::TEST_ADDRS.remote_ip.get();
849 let mut prefix_builder =
850 TcpSegmentBuilder::new(src_ip, dst_ip, SRC_PORT, DST_PORT, SEQ_NUM, None, u16::MAX);
851 prefix_builder.fin(fin);
852 prefix_builder.psh(psh);
853 let options = TcpOptionsBuilder {
857 timestamp: Some(TIMESTAMP),
858 sack_blocks: Some(&SACK_BLOCKS),
859 ..Default::default()
860 };
861 payload
862 .into_serializer()
863 .wrap_in(
864 TcpSegmentBuilderWithOptions::new(prefix_builder, options).expect("create builder"),
865 )
866 .wrap_in(I::PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Tcp.into()))
867 }
868
869 fn new_tcp_packet<I: TestIpExt + GsoIpExt>(payload: &[u8], fin: bool, psh: bool) -> Vec<u8> {
871 new_tcp_serializer::<I>(payload, fin, psh)
872 .serialize_vec_outer_no_reuse(&mut NetworkSerializationContext::default())
873 .expect("serialize packet")
874 .into_inner()
875 }
876
877 fn create_and_segment_tcp_packet<I: TestIpExt + GsoIpExt>(
880 source: TcpPacketSource,
881 payload: &[u8],
882 fin: bool,
883 psh: bool,
884 gso_info: GsoInfo,
885 ) -> Vec<Buf<Vec<u8>>> {
886 match source {
887 TcpPacketSource::Bytes => {
888 let packet = new_tcp_packet::<I>(payload, fin, psh);
889 collect_segments(
890 segmenter_from_packet_bytes::<I>(&packet, gso_info).expect("create segmenter"),
891 )
892 }
893 TcpPacketSource::Serializer => {
894 let serializer = new_tcp_serializer::<I>(payload, fin, psh);
895 collect_segments(serializer.try_segmenter(gso_info).expect("create segmenter"))
896 }
897 }
898 }
899
900 fn collect_segments<I, IB, B, P>(mut segmenter: GsoSegmenter<I, IB, B, P>) -> Vec<Buf<Vec<u8>>>
902 where
903 I: GsoIpExt,
904 IB: SegmentableIpPacketBuilder<I>,
905 B: SegmentableTransportBuilder,
906 P: Payload + InnerPacketBuilder + Copy,
907 {
908 let mut segments = Vec::new();
909 let mut expect_more = true;
910 while let Some((segment, has_more)) = segmenter.next() {
911 assert!(expect_more);
913 expect_more = has_more;
914 let segment = segment
915 .serialize_vec_outer(&mut NetworkSerializationContext::default())
916 .map_err(|(err, _serializer)| err)
917 .expect("serialize segment")
918 .unwrap_b();
919 segments.push(segment);
920 }
921 assert!(!expect_more);
922 segments
923 }
924
925 fn check_tcp_ip_packet<I: TestIpExt>(
928 buf: &mut Buf<Vec<u8>>,
929 index: u16,
930 id_mode: Ipv4IdMode,
931 fin: bool,
932 psh: bool,
933 ) -> Vec<u8> {
934 let src_ip = I::TEST_ADDRS.local_ip.get();
935 let dst_ip = I::TEST_ADDRS.remote_ip.get();
936 {
937 let packet = buf.parse::<<I as IpExt>::Packet<_>>().expect("parse IP packet");
938 assert_eq!(packet.src_ip(), src_ip);
939 assert_eq!(packet.dst_ip(), dst_ip);
940 assert_eq!(packet.proto(), IpProto::Tcp.into());
941 assert_eq!(packet.ttl(), TTL);
942 I::map_ip_in(
943 &packet,
944 |packet| {
945 let expected_id = match id_mode {
946 Ipv4IdMode::Fixed => 0,
947 Ipv4IdMode::Incrementing => index,
948 };
949 assert_eq!(packet.id(), expected_id);
950 },
951 |_packet| {},
952 );
953 }
954
955 let tcp = buf
956 .parse_with::<_, TcpSegment<_>>(TcpParseArgs::new(src_ip, dst_ip))
957 .expect("parse TCP segment");
958 assert_eq!(tcp.src_port(), SRC_PORT);
959 assert_eq!(tcp.dst_port(), DST_PORT);
960 assert_eq!(tcp.fin(), fin);
961 assert_eq!(tcp.psh(), psh);
962 assert_eq!(tcp.options().timestamp(), Some(&TIMESTAMP));
963 assert_eq!(tcp.options().sack_blocks(), Some(&SACK_BLOCKS[..]));
964 tcp.body().to_vec()
965 }
966
967 #[ip_test(I)]
968 #[test_matrix(
969 [TcpPacketSource::Bytes, TcpPacketSource::Serializer],
970 [Ipv4IdMode::Incrementing, Ipv4IdMode::Fixed],
971 [LAST_SEGMENT_LEN, usize::from(GSO_SIZE.get())],
972 [true, false],
973 [true, false]
974 )]
975 fn segments_tcp_packet<I: TestIpExt + GsoIpExt>(
976 source: TcpPacketSource,
977 id_mode: Ipv4IdMode,
978 last_segment_len: usize,
979 fin: bool,
980 psh: bool,
981 ) {
982 let payload =
983 test_payload((NUM_SEGMENTS - 1) * usize::from(GSO_SIZE.get()) + last_segment_len);
984 let mut segments =
985 create_and_segment_tcp_packet::<I>(source, &payload, fin, psh, gso_info::<I>(id_mode));
986 let num_segments = segments.len();
987 assert_eq!(num_segments, NUM_SEGMENTS);
988
989 let mut collected = Vec::new();
990 for (index, segment) in segments.iter_mut().enumerate() {
991 let last = index == num_segments - 1;
992 let expect_fin = last && fin;
994 let expect_psh = last && psh;
995 let body = check_tcp_ip_packet::<I>(
996 segment,
997 u16::try_from(index).unwrap(),
998 id_mode,
999 expect_fin,
1000 expect_psh,
1001 );
1002 assert_eq!(
1003 body.len(),
1004 if last { last_segment_len } else { usize::from(GSO_SIZE.get()) }
1005 );
1006 collected.extend_from_slice(&body);
1007 }
1008 assert_eq!(collected, payload);
1009 }
1010
1011 #[ip_test(I)]
1012 fn rejects_non_tcp_serializer<I: TestIpExt + GsoIpExt>() {
1013 let payload = test_payload(PAYLOAD_LEN);
1014 let src_ip = I::TEST_ADDRS.local_ip.get();
1015 let dst_ip = I::TEST_ADDRS.remote_ip.get();
1016 let serializer = Buf::new(payload, ..)
1017 .wrap_in(UdpPacketBuilder::new(src_ip, dst_ip, Some(SRC_PORT), DST_PORT))
1018 .wrap_in(I::PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Udp.into()));
1019 assert_eq!(
1020 serializer.try_segmenter(gso_info::<I>(Ipv4IdMode::Incrementing)).err(),
1021 Some(GsoError::NotSegmentable)
1022 );
1023 }
1024
1025 #[test_case(TcpPacketSource::Bytes; "bytes")]
1026 #[test_case(TcpPacketSource::Serializer; "serializer")]
1027 fn segments_advance_sequence_numbers(source: TcpPacketSource) {
1028 let payload = test_payload(PAYLOAD_LEN);
1029 let fin = false;
1030 let psh = true;
1031 let seq_nums: Vec<u32> = create_and_segment_tcp_packet::<Ipv4>(
1032 source,
1033 &payload,
1034 fin,
1035 psh,
1036 gso_info::<Ipv4>(Ipv4IdMode::Incrementing),
1037 )
1038 .into_iter()
1039 .map(|mut segment| {
1040 let _ = segment.parse::<Ipv4Packet<_>>().expect("parse IPv4 packet");
1041 segment
1042 .parse_with::<_, TcpSegment<_>>(TcpParseArgs::new(
1043 TEST_ADDRS_V4.local_ip.get(),
1044 TEST_ADDRS_V4.remote_ip.get(),
1045 ))
1046 .expect("parse TCP segment")
1047 .seq_num()
1048 })
1049 .collect();
1050 let gso_size = u32::from(GSO_SIZE.get());
1051 let expected: Vec<u32> =
1052 (0..NUM_SEGMENTS).map(|i| SEQ_NUM + u32::try_from(i).unwrap() * gso_size).collect();
1053 assert_eq!(seq_nums, expected);
1054 }
1055
1056 #[ip_test(I)]
1057 fn rejects_non_tcp<I: TestIpExt + GsoIpExt>() {
1058 let src_ip = I::TEST_ADDRS.local_ip.get();
1059 let dst_ip = I::TEST_ADDRS.remote_ip.get();
1060 let packet = Buf::new(test_payload(PAYLOAD_LEN), ..)
1061 .wrap_in(UdpPacketBuilder::new(src_ip, dst_ip, Some(SRC_PORT), DST_PORT))
1062 .wrap_in(I::PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Udp.into()))
1063 .serialize_vec_outer(&mut NetworkSerializationContext::default())
1064 .map_err(|(err, _serializer)| err)
1065 .expect("serialize packet")
1066 .unwrap_b()
1067 .into_inner();
1068 assert_eq!(
1069 segmenter_from_packet_bytes::<I>(&packet, gso_info::<I>(Ipv4IdMode::Incrementing))
1070 .err(),
1071 Some(GsoError::NotSegmentable)
1072 );
1073 }
1074
1075 #[test]
1076 fn rejects_unparseable_packet() {
1077 let packet = [0u8; 8];
1078 assert_eq!(
1079 segmenter_from_packet_bytes::<Ipv6>(
1080 &packet[..],
1081 gso_info::<Ipv6>(Ipv4IdMode::Incrementing)
1082 )
1083 .err(),
1084 Some(GsoError::Parse)
1085 );
1086 }
1087
1088 #[test]
1089 fn rejects_ipv4_packet_with_options() {
1090 let src_ip = TEST_ADDRS_V4.local_ip.get();
1091 let dst_ip = TEST_ADDRS_V4.remote_ip.get();
1092 let packet = Buf::new(test_payload(PAYLOAD_LEN), ..)
1093 .wrap_in(TcpSegmentBuilder::new(
1094 src_ip,
1095 dst_ip,
1096 SRC_PORT,
1097 DST_PORT,
1098 SEQ_NUM,
1099 None,
1100 u16::MAX,
1101 ))
1102 .wrap_in(
1103 Ipv4PacketBuilderWithOptions::new(
1104 Ipv4PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Tcp.into()),
1105 [Ipv4Option::RouterAlert { data: 0 }],
1106 )
1107 .expect("create builder"),
1108 )
1109 .serialize_vec_outer(&mut NetworkSerializationContext::default())
1110 .map_err(|(err, _serializer)| err)
1111 .expect("serialize packet")
1112 .unwrap_b()
1113 .into_inner();
1114 assert_eq!(
1115 segmenter_from_packet_bytes::<Ipv4>(
1116 &packet,
1117 gso_info::<Ipv4>(Ipv4IdMode::Incrementing)
1118 )
1119 .err(),
1120 Some(GsoError::UnsupportedHeaders)
1121 );
1122 }
1123
1124 #[test]
1125 fn rejects_ipv6_packet_with_extension_headers() {
1126 use packet_formats::ipv6::Ipv6PacketBuilderWithHbhOptions;
1127 use packet_formats::ipv6::ext_hdrs::{
1128 ExtensionHeaderOptionAction, HopByHopOption, HopByHopOptionData,
1129 };
1130
1131 let src_ip = TEST_ADDRS_V6.local_ip.get();
1132 let dst_ip = TEST_ADDRS_V6.remote_ip.get();
1133 let packet = Buf::new(test_payload(PAYLOAD_LEN), ..)
1134 .wrap_in(TcpSegmentBuilder::new(
1135 src_ip,
1136 dst_ip,
1137 SRC_PORT,
1138 DST_PORT,
1139 SEQ_NUM,
1140 None,
1141 u16::MAX,
1142 ))
1143 .wrap_in(
1144 Ipv6PacketBuilderWithHbhOptions::new(
1145 Ipv6PacketBuilder::new(src_ip, dst_ip, TTL, IpProto::Tcp.into()),
1146 &[HopByHopOption {
1147 action: ExtensionHeaderOptionAction::SkipAndContinue,
1148 mutable: false,
1149 data: HopByHopOptionData::RouterAlert { data: 0 },
1150 }],
1151 )
1152 .expect("create builder"),
1153 )
1154 .serialize_vec_outer(&mut NetworkSerializationContext::default())
1155 .expect("serialize packet")
1156 .unwrap_b()
1157 .into_inner();
1158 assert_eq!(
1159 segmenter_from_packet_bytes::<Ipv6>(
1160 &packet,
1161 gso_info::<Ipv6>(Ipv4IdMode::Incrementing)
1162 )
1163 .err(),
1164 Some(GsoError::UnsupportedHeaders)
1165 );
1166 }
1167}