stm32plus::net, IPv4 Module

The IPv4 module (abbreviated to just IP from hereon) implements the Internet Protocol, version 4. IP is a network layer protocol that is responsible for marshalling data to and from the transport layer protocols such as UDP and TCP and the datalink layer protocols such as Ethernet. To do this it draws on the services provided by the ARP protocol.

The stm32plus::net implementation of IP optionally supports large packet fragmentation and reassembly, though it is advisable to avoid this situation where possible for performance reasons.

stm32plus::net does not support any of the optional IP header options.

Packet fragmentation and reassembly

Your datalink layer has a hard limit on the number of bytes that it can send in one frame. For ethernet it’s 1500. When you subtract the 20 bytes required by the IP header you’re down to 1480 bytes available for user data in one IP packet.

If you need to send more than that then IP has the ability to break the large packet into a sequence of fragments small enough to be transmitted through the datalink layer and then reassemble them on the other side.

stm32plus::net supports this functionality but it comes with a big performance warning. Fragmentation on the transmit side isn’t too bad but reassembly by the receiver costs both memory and CPU due to the need to cope with packet loss and out-of order delivery. Generally you should design your application to avoid fragmentation if you can do that. TCP automatically does that by setting a maximum MTU size but with UDP it’s up to you.

IP implementation

stm32plus::net allows you to choose at compile time whether you want to include support for IP packet fragmentation, reassembly, both or neither. Pick one of these handy IP typedefs that helps you with the template-feature syntax.

Note that these Network layer examples are cut down to just show Ip being configured. In practice you’ll need to include more protocols in the layer, e.g. ARP.

typedef NetworkLayer<MyDatalinkLayer,DefaultIp> MyNetworkLayer;
typedef NetworkLayer<MyDatalinkLayer,IpWithOutboundFragmentation> MyNetworkLayer;
typedef NetworkLayer<MyDatalinkLayer,IpPacketReassemblerFeature> MyNetworkLayer;
typedef NetworkLayer<MyDatalinkLayer,IpWithFragmentationAndReassembly> MyNetworkLayer;

Configuration Parameters

The following parameters are made available in the stack’s configuration object for customisation:

uint8_t ip_initialTtl;  ///< TTL value inserted into new IP packets. The default is 64.

IP packets have a time-to-live counter that is decreased by one each time the packet is forwarded by a router on the network. If the counter reaches zero then the packet is discarded. This is to prevent cycles in the network. ip_initialTtl is the initial value that we put in our IP packets before we send them.

Additional packet fragmentation parameters

In addition to the basic IP parameters, if you are using the fragmentation feature then these parameters will become available to you:

bool ip_checksumOnLargeUdpPackets; ///< true if we manually calculate checksums on large UDP packets. default is true.

Non-fragmented IP packets use the hardware checksum offload capability built in to the STM32 MAC peripheral. Fragmented packets cannot use this facility so we offer the ability to calculate the checksum in software. Set ip_checksumOnLargeUdpPackets to true to perform the calculation, or false to not bother with it. Not calculating the checksum will increase performance at the possible expense of having the packets dropped by routers and/or IP stacks that perform checksum verification.

Additional packet reassembly parameters

Packet reassembly is performed using the memory-optimised algorithm described in RFC 815. The following additional features are available if you have enabled the packet reassembly feature.

// max length of any packet. default is 2048 bytes
uint16_t ip_maxPacketLength;                    

// max incoming packets that can be fragmented and incompletely assembled in memory. The default is 2.
uint16_t ip_maxInProgressFragmentedPackets;     

// similar to ip_maxInProgressFragmentedPackets, but restricts overall memory usage of the fragment reassembler. The default is 4096.
uint32_t ip_maxFragmentedPacketMemoryUsage;     

// seconds after which partially reassembled packets are dropped (default is 15)
uint8_t ip_fragmentExpirySeconds;               

// how often to wake up and check for expired fragments
uint8_t ip_fragmentExpiryIntervalCheckSeconds;	

ip_maxPacketLength limits the maximum size of any reassembled IP packet. The default is a rather low 2048 bytes.

ip_maxInProgressFragmentedPackets sets the maximum number of fragmented packets that can be outstanding, i.e. not fully reassembled, at any one time.

ip_maxFragmentedPacketMemoryUsage sets an overall cap on the memory usage by the whole reassembly feature. Set this to a value high enough that it won’t restrict your application but low enough that you don’t threaten the stability of your overall system.

ip_fragmentExpirySeconds sets the number of seconds that a fragmented packet can remain fragmented before we decide that it’s dead and will discard it and reclaim the memory that was being used for its reassembly.

ip_fragmentExpiryIntervalCheckSeconds sets the interval in seconds when we will wake up and check the fragmented packet list for any that have expired.

Methods exposed

const IpAddress& getIpAddress() const;
constexpr uint32_t getIpTransmitHeaderSize() const;

getIpAddress will return a reference to our IP address.

getIpTransmitHeaderSize returns the size required by the IP headers. This is 20.

Events raised

The IP module raises the following events.

sender IpReceiveEventSender
event IpPacketEvent
identifier NetEventType::IP_PACKET
context IRQ
purpose IP packet received
		/**
		 * Event descriptor for an IP packet arrival
		 */

		struct IpPacketEvent : NetEventDescriptor {

			/**
			 * The IP packet reference
			 */

			IpPacket& ipPacket;


			/**
			 * Constructor
			 * @param frame
			 */

			IpPacketEvent(IpPacket& packet)
				: NetEventDescriptor(NetEventType::IP_PACKET),
					ipPacket(packet) {
			}
		};

This event notifies anyone that cares that an IP packet has been received by the datalink layer and is ready for processing. The transport layer protocols subscribe to this event.