smoltcp icon indicating copy to clipboard operation
smoltcp copied to clipboard

Support IP fragmentation

Open podhrmic opened this issue 7 years ago • 10 comments

In a similar spirit, I would also like to implement support for IP fragmentation. The logic behind fragmentation is pretty straightforward, but the way to implement it less so.

So far it looks like it would need:

  • a queue for the fragmented IP packets, where they can be stored before reassembling and passing them to the higher layers
  • timers associated with each fragmented packet (similar to #25 ) so they can be dropped after a timeout

I think this means adding a queue to the https://github.com/m-labs/smoltcp/blob/master/src/iface/ethernet.rs

Thoughts?

podhrmic avatar Oct 06 '17 23:10 podhrmic

Basically. What you need is...

  • one storage::Assembler per fragmented packet;
  • one managed::ManagedSlice per fragmented packet;
  • one storage::RingBuffer per interface, storing FragmentedPackets in a FIFO queue;
  • one managed::ManagedMap per interface, mapping Option<u16> (ident) to usizes (positions in the queue).

Broadly, how it would work is:

  • every time a fragmented packet is received, its ident is looked up in the map and the corresponding FragmentedPacket is updated if it's still within the bounds;
  • if it's not within bounds, the entry is removed;
  • positions in the queue in the map and positions in the ring buffer are mapped to each other through an offset that is increased every time the queue has a packet removed from it.

whitequark avatar Oct 07 '17 05:10 whitequark

The main issue here is that managed::ManagedMap doesn't exist. It should be a generalized version of SliceArpCache, using a slice on heap-free platforms and a BTreeMap otherwise.

whitequark avatar Oct 07 '17 05:10 whitequark

#51 also needs a ManagedMap.

whitequark avatar Oct 25 '17 00:10 whitequark

There is now a managed::ManagedMap. Also, scratch what I said about FIFO buffers, that doesn't sound like a very good idea on reflection. I'm not actually sure what sort of data structure can be used to implement reassembly without fixing MTU upfront or suffering internal fragmentation.

whitequark avatar Feb 22 '18 12:02 whitequark

After looking at RFC 815 I have some ideas.

First, the buffer for each fragmented packet will have to be manually allocated (similar to defining buffers for sockets), so the number and size can be user-configured.

Second, we need to check packet ID, as well as source and destination address. Something like this:

struct FragmentedPacket {
	assebler: Assembler,
	rx_buffer: RingBuffer<'a>,
	src_addr: Ipv4Address,
	dst_addr: Ipv4Address,
	id: u16,
	// timeout?
}

The interface then will have a ManagedSlice of FragmentedPacket elements, similar to SocketSet.

The actual data processing would happen in process_ipv4 like this:

...
        let mut ipv4_packet = Ipv4Packet::new_checked(eth_frame.payload())?;
        let checksum_caps = self.device_capabilities.checksum.clone();
        
        // >> here we handle fragmentation
        // verify checksum before making repr (in case we need to fragment)
        if checksum_caps.ipv4.rx() && !ipv4_packet.verify_checksum() { return Err(Error::Checksum) }
        
        // contains more fragments ?
        if ipv4_packet.more_frags() || ipv4_packet.frag_offset() > 0 {
        	// pass to the set of fragmented packets
        	// iter over existing IDs, either add a new fragment 
                // or work with an existing one
        	// potentially we end up with a new ipv4_packet
        }
        
        // Repr doesn't support fragmentation yet, so don't give it fragmented packets
        let ipv4_repr = Ipv4Repr::parse(&ipv4_packet, &checksum_caps)?;
...

Plus an appropriate feature guards.

If the buffer backing fragmented packet is exhausted (too small), the packet is dropped.

Thoughts? Does it look like a sane idea?

podhrmic avatar Mar 10 '18 01:03 podhrmic

Sounds reasonable, though I think FragmentedPacket::rx_buffer shouldn't be a RingBuffer.

whitequark avatar Mar 10 '18 01:03 whitequark

Thanks. It could simply be ManagedSlice<u8> to be closer to the example in RFC 815

podhrmic avatar Mar 10 '18 01:03 podhrmic

IPv4 fragmentation has been implemented in #634. We still need fragmentation for IPv6.

thvdveld avatar Sep 28 '22 12:09 thvdveld

IPv4 fragmentation has been implemented in #634

Does it need an special configuration to enable? I have a setup that smoltcp responses ping and ping -s 1000 but when I use ping -s 2000 so that my kernel fragment the icmp packet, it doesn't response.

HKalbasi avatar Aug 27 '23 14:08 HKalbasi

You need to increase the reassembly buffer size of smoltcp. You can do this using feature flags. The default buffer size is 1500 bytes. https://github.com/smoltcp-rs/smoltcp?tab=readme-ov-file#reassembly_buffer_size

thvdveld avatar Aug 28 '23 09:08 thvdveld