DPDK rte_flow traffic drop filter v2#13891
Conversation
Added pattern based drop-filter. Supported patterns are listed in "util-dpdk-rte-flow-pattern.c" in "enum index next_item[]" and their corresponding attributes in "enum index item_<pattern>[]". The syntax of the pattern used in suricata.yaml is taken from test-pmd application. Other attributes, such as actions, are omitted, and only pattern is accepted, e.g., a valid entry in suricata.yaml is: "pattern eth / ipv4 src is 192.168.11.12 / end". The user needs to validate the pattern used for a specific driver first, otherwise, Suricata shuts down if the pattern is unsupported. Source for supported patterns with different drivers: https://doc.dpdk.org/guides/nics/overview.html More patterns can be added in the future if needed. This new entry needs to be specified in the `enum index`. This pattern then needs to be present in `enum index next_item[]` and its corresponding attributes in `enum index item_<pattern>[]`. Also, new entry needs to be provided to `struct token token_list[]` with appropriate attributes. The feature was tested on NIC drivers mlx5, ice, i40e, and ixgbe. mlx5 accepts multiple rules with different patterns and various corresponding specifications of pattern items. The driver does not have any additional restrictions on the pattern. ice does not support broad patterns; some pattern item has to have specification, e.g., pattern "eth / ipv4 / end" raises an error but "eth / ipv4 src is x / end" or "eth / ipv4 / tcp src is x" works fine. i40e does not support different item sets on the same pattern item type, e.g., if the first rule has the pattern `eth / ipv4 src is x / end`, then if any other rule contains an ipv4 pattern type, it needs to have exclusively attribute src. ixgbe does not support this feature. Ticket: 7629
Added counter for packets filtered by the drop filter. These statistics are only available on mlx5 and ice drivers. Additionally, ice driver supports gathering statistic only when any of the rules does not contain range of any kind (mask on IP address, last on ports etc.). These statistics are available in eve.json under "dpdk.rte_flow_filtered". Ticket: 7629
lukashino
left a comment
There was a problem hiding this comment.
First pass is in. Well done, the code looks much better now!
| ----------------------------- | ||
|
|
||
| Drop filter can improve the performance of Suricata by filtering | ||
| used-predefined flows directly in the Network interface card. The user can |
There was a problem hiding this comment.
/used-predefined flows/user-predefined traffic patterns/
| ----------------------------- | ||
|
|
||
| Drop filter can improve the performance of Suricata by filtering | ||
| used-predefined flows directly in the Network interface card. The user can |
There was a problem hiding this comment.
also, since NIC is mentioned previously, you could either use acronym (NIC) or lowercase the "Network".
|
|
||
| Drop filter can improve the performance of Suricata by filtering | ||
| used-predefined flows directly in the Network interface card. The user can | ||
| specify unwanted flows before the start of Suricata. These flows are not going to be |
There was a problem hiding this comment.
Generally, I would avoid mentioning "flows" and focus more on the traffic patterns (or a more suitable term).
Potentially "traffic filter expression/rule"
| iconf->pkt_mempools = NULL; | ||
| } | ||
|
|
||
| ldev_instance->dpdk_vars = iconf->pkt_mempools; |
There was a problem hiding this comment.
This should have been moved out of this commit.
| * \param items parsed items used when creating rte_flow rules | ||
| * \return 0 on success, -1 on error | ||
| */ | ||
| int ParsePattern( |
There was a problem hiding this comment.
If we move forward with this approach, this is definitely a must-have candidate for unit tests.
There was a problem hiding this comment.
items_data_buffer could be a static variable to save function arguments in ParsePattern
| { | ||
| if (strcmp(driver_name, "net_ice") == 0) { | ||
| if (iceDeviceRteFlowPatternError(items) == true) { | ||
| char msg[] = "Driver specific errmsg: ice driver does not support broad patterns"; |
There was a problem hiding this comment.
I would suggest changing this to %s: ice driver ... where %s would be the PCIe address of the current interface.
There was a problem hiding this comment.
Generally, the whole error messaging in this part seems overly complicated. I think you could just issue an error (even if multiple) here directly, or what was the intention?
There was a problem hiding this comment.
The goal was to combine both reasons for error into one error message, which is why I am not logging the error in the DriverSpecificErrorMessage() but returning the error string and logging in RteFlowRulesCreate(). I can change it to two distinct error messages.
There was a problem hiding this comment.
Ok, I see, you can leave it as is now. Thanks.
|
Continues in #13903 |
Followup of #12848
Changes:
v2:
Ticket: #7629
Motivation
This feature brings a new approach to filter unwanted network traffic in hardware in Suricata's DPDK runmode, even before it reaches Suricata. The main benefit is the ability to offload the processing of unwanted traffic from the software, thus reducing the load on both the PCIe bus and the CPU and increasing Suricata throughput. This is achieved via DPDK's rte_flow API, which provides flow rules that define the behaviour of matched flows in the hardware.
The rules and their relationships work similarly to Suricata rules, as the individual pattern parts inside one rule are connected with an AND operation, and the whole rules are connected with an OR operation. For example, if a rule in dpdk-testpmd syntax looks like
flow create 0 ingress pattern eth / ipv4 src is 192.11.11.12 / tcp src is 10 / end actions drop / end, then matching pattern parts (eth,ipv4,andtcp) are combined with an AND operation. If there is another rule with a different pattern, then the first rule and the second rule would be connected with an OR operation, meaning that the incoming traffic will either match the first rule, match the second rule or it will be passed to Suricata.Explored options
Rule syntax
dpdk-testpmd-like syntax
dpdk-testpmd syntax offers a wide range of different patterns and adjustments, which are well documented in the DPDK documentation. This means that the drop-filter is limited only by the capabilities of the used NIC. Another advantage is that Suricata operators can easily test and adjust the rules they want to apply in the dpdk-testpmd application, with the possibility of copying the tested patterns into suricata.yaml.
The whole rule, as could be applied in dpdk-testpmd application, would, for example, look like
flow create 0 ingress pattern eth / ipv4 src is 199.11.23.5 / tcp src is 42 / end actions drop end / end. However, only the pattern part is important when defining rte_flow rules for Suricata, so onlypattern eth / ipv4 src is 199.11.23.5 / tcp src is 42 / endwould be present in suricata.yaml.This example shows how the rules are defined in suricata.yaml:
If supported by the NIC, this syntax also offers the ability to adjust the matched range (of IP addresses, ports, …) with two keywords,
maskandlast. For example, rules including these keywords could look as follows:BPF syntax
One of the reasons why I did not choose the BPF syntax is that both BPF and rte_flow offer multiple distinct features that the other does not. For example, BPF syntax provides the capability to use an OR operand inside the pattern (
tcp dst port 80 or 8000), which would require two distinct rte_flow rules. Another difference is the lack of negation operand and exact-byte reading in rte_flow rules.A disadvantage of BPF in this case is the lack of an existing parser to convert BPF syntax into rte_flow rules. In contrast, the dpdk-testpmd syntax already has a usable parser implementation that transforms the dpdk-testpmd string rules into rte_flow rules. With some modifications, it is suitable for our use case.
Simple filter
Another considered option to define what traffic should be filtered is to declare a simple list of IP addresses and ports, which will then be parsed into rte_flow rules. However, this way we lose a substantial part of the available matching power, as we can match only specific flows and we can not utilize the various supported protocols, such as matching on VLAN or other encapsulation protocols.
This method is not implemented, but could serve as an alternative/support mode for the dpdk-testpmd rule-based filter. It could be present in an exclusive mode, meaning only one of the options will be available at a time, or it could work as an additional way to declare what traffic to discard.
A concept of how such a filter could be defined in suricata.yaml:
Allow-filter
The allow-filter was expected to work as the exact opposite of the drop-filter, with Suricata receiving only traffic defined by rte_flow rules. This filter would behave similarly to a BPF program that passes only specified traffic and drops everything else.
This filter could be implemented via DPDK's isolated mode, which restricts the NIC to accept only traffic defined via some rte_flow rule. Unfortunately, this filter would currently work only on Mellanox NICs (among the ones we tested), as isolated mode is not supported on Intel NICs.
If this hypothetical allow-filter were implemented, it could serve as an alternative/exclusive mode to the drop-filter, as its implicit behavior is to drop all unwanted traffic.
NIC limitations and more detailed description
Limitations of supported NICs, as well as a more expanded description of the feature, can be found in the file
/doc/userguide/capture-hardware/dpdk.rst.