3

I need to program a basic network stack in c, but have some questions regarding proper practices. Let's assume that I only need to support UDP at L4 and IP at L3.

When I want to sent a big message that needs to be fragmented. What is the proper order in which to handle this?

1) Initialize the udp header and calculating the checksum over the whole data field (plus udp and pseudo header) Then fragment the data field, build the IP header for each fragment, then send out the fragments.

2) Fragment the data field, then build a udp header with a different checksum tacked on the front of each fragment. Then build an IP header to tack in fron of that for each fragment. Then send our the fragments.

My confusions stems from whether the udp checksum should encompass the entire assembled datagram, or just the individual fragment. I greatly appreciate any help you can provide.

indiv
  • 17,306
  • 6
  • 61
  • 82
user1764386
  • 5,311
  • 9
  • 29
  • 42

2 Answers2

5

The network layers work independently of each other. When the IP layer fragments a packet, the UDP layer has no knowledge of it. By the time an application-layer UDP listener receives the packet, it will have been re-assembled and will have had no idea that the packet was ever fragmented.

With that knowledge, we can say that the UDP checksum must cover the fully assembled packet and does not have to change during fragmentation. In fact, nothing in the UDP header changes.

To error check the fragmented packets, you use the IPv4 checksum header field. The IPv6 header does not have a checksum field since the lower layers are expected to have error-free packet delivery.

When you do fragment an IPv4 packet, you must re-compute the IPv4 header for the fragment. The IPv4 wikipedia entry tells us what must be changed when you fragment a packet:

  • The total length field is the segment size.
  • The more fragments (MF) flag is set for all segments except the last one, which is set to 0.
  • The fragment offset field is set, based on the offset of the segment in the original data payload. This is measured in units of eight-byte blocks.
  • The [IPv4] header checksum field is recomputed.

So in conclusion, you do the following:

  1. Take the application-level data and wrap it in a UDP header.
  2. Give the packet with UDP header to the IP layer.
  3. Divide the data into fragments.
  4. For each fragment, put an IPv4 fragment header on it.
    • Give the fragment to layer 2 and put the layer 2 header on it.
    • Send the fragment.
indiv
  • 17,306
  • 6
  • 61
  • 82
  • Thanks for the detailed response. Is there a typical approach that avoids excessive memcpys? For example, after I take by starting data and create the udp header, does one generally copy those together into new address space? Or instead maintain them separately. If maintained separately then the data field could be segmented up, then both the udp header and data fragment could be memcpy'd to the final Ethernet payload before sending. I appreciate your help - I have the code working fine, I just want to do it the right way. – user1764386 Nov 24 '14 at 18:50
  • Packet copies are a throughput killer. Do whatever you can to avoid them. If you really have a lot of time to implement this, you want to pre-allocate your memory into a pool. No malloc/free. And then when you do your first (and only) copy of user data into your own internal buffer, copy it like halfway into the buffer. So you have plenty of room at the front of the buffer to add headers without moving any data from the upper layers as you move down through the network stack. Track header locations by pointers into the buffer. – indiv Nov 24 '14 at 18:55
0

Number 1 and the overall checksum before packets should match the checksum of what is reconstructed back into its original form

les
  • 564
  • 7
  • 19
  • What then is the rule regarding the udp header length and checksum fields? Should they be set only in the first fragment? – user1764386 Nov 24 '14 at 18:34