embOS/IP comes with many features already built-in. One of these features is a UDP flood protection that can help you to save execution time on incoming data that would be discarded anyhow. Whether you are really subject to an attack or you are simply part of a really crowded network, this optimization can free up CPU time for other tasks.
Sometimes following the ideas of RFCs (Request For Comments) too closely is not the ideal way.
The latest example of this is the actual WiFi WPA2 problem called KRACK (Key Reinstallation Attack), which is caused by discarding a key after it has been used, as suggested by the RFC, but not thinking to the end what happens if this key is actually required again.
In the world of TCP/IP (or in this example UDP/IP) it is a good manner to respond to a received UDP packet that was not expected with an ICMP error response, telling the other side we were not expecting data.
While the ICMP response is a potential, but unlikely to be used security point, the CPU load that this might cause is real. A UDP packet flood might consume all of the CPU time and render your device unable to execute other jobs. This situation is not exclusive to a UDP flood but might apply if you have a high traffic load in your network.
To cover this situation, embOS/IP comes with UDP flood protection.
Task priorities alone might not be enough
A regular target today consists of a widely popular Cortex-M CPU running at approximately 200MHz, featuring a fair but limited amount of RAM and runs a multi-tasking application. embOS/IP is designed to use one task for management and handling incoming packets. Other tasks in the system exist along with embOS/IP and might also use higher priorities than the IP_Task (used for management and processing received packets) to make sure they fulfill their real time requirements.
While the correct utilization of task priorities helps to prioritize the workload of the target, it is not always possible. In case your target needs a higher priority on Ethernet specific tasks, you need to make sure that the IP_Task is able to execute by granting it an even higher priority. But what if the IP_Task gets executed a lot, just to find out that this packet was not for us?
Receiving many UDP packets does not need to be the result of some kind of UDP flood attack on your network. The same symptoms can occur on every other network that has many clients and therefore a high traffic load.
In a situation like this, the target might become constantly busy with two executions, even without additional jobs to execute:
- Processing the receive interrupt that tells the IP stack that a new packet has been received.
- Processing the received packet content itself.
In the picture above we have measured the system impact of a UDP flood (starting on the marker) on a Cortex-M4 Target running at 168MHz. ISR #100 is the Ethernet receive interrupt while ISR #99 is the Ethernet send interrupt, caused by responding with an ICMP error message for each UDP message that has not been expected.
As you can see from the zoomed in details in SystemView, the CPU is constantly held busy in this flooding situation. While the CPU time consumed for processing receive and send interrupts can be moved into another context (from interrupt into a task context using the embOS/IP RxTask), it can not be optimized away. In addition to the interrupt processing that transfers the data, the IP_Task needs to process the received data and in case of an ICMP response, needs to prepare the answer to send.
If there would be a way to decide if we need to really wake up the IP_Task from a receive interrupt, you could save CPU time in situations where you can clearly say that this packet is not of interest to you.
embOS/IP has you covered in exactly this situation.
To signal or not to signal
Unlike more complex and state driven protocols like TCP, it is fairly simple to decide if a received UDP packet is of interest to us and needs a deeper inspection by signaling the IP_Task. This decision can be made near the driver level, before passing the packet down the entire IP stack. This decision is based on the following criteria:
- Is the destination address of the packet NOT a broadcast AND it is not ours ? -> Discard.
- Is the destination port NOT opened on our side ? -> Discard.
You might wonder what happens with broadcasts that are sent to a UDP port that has been opened on the target. While in many cases broadcasts are not wanted, they are not filtered by our low level check as there are protocols out there that actually communicate using UDP broadcasts. The most popular example for this is the DHCP protocol that is typically used to request an IP address and configuration in your network.
Saving CPU time
Unlike software firewalls that provide an even deeper packet analyzing mechanism, our simple check is sufficient to filter out many unwanted traffic in an early stage of receiving data. The check is designed to be simple enough to not spend too much CPU time for the check itself. This is achieved by the check being aware of open UDP connections in embOS/IP.
The pictures above (same as before) show the CPU consume in a high traffic situation without the early UDP check. For the test, the target was unicast UDP flooded on a closed port, not only causing the IP_Task to be signaled but also causing an optional ICMP response to be sent back each time.
In the pictures the receive interrupt is ISR #100 and the send interrupt is ISR # 99.
The pictures below show the same situation with the check implemented (since embOS/IP v3.20). As you can see, not only does the IP_Task not get signaled and executed but the optional ICMP response is not sent as well.
Unlike before, the application is able to return to idle instead of rushing from one interrupt to another and to the IP_Task whenever there is no interrupt being processed.
Spend time on what is important to YOU
As you can see from the comparison before, this improvement is able to free a lot of CPU time that you can use for other things in your application.