Hello Dmitry,

I followed your suggestions, and this is what I came up with:

#include "../include/flow.h"
#include <stdio.h>
#include <string.h>

int flow_filtering(uint16_t port_id, uint32_t ip_addr, uint16_t udp_port) {
struct rte_flow_error error;
struct rte_flow_attr attr = { .ingress = 1, .priority = 0 };
struct rte_flow_item pattern[4];
struct rte_flow_action action[2];
struct rte_flow *flow;

// Définir le motif Ethernet
memset(pattern, 0, sizeof(pattern));
pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;

// Définir le motif IPv4
struct rte_flow_item_ipv4 ipv4_spec = { .hdr.dst_addr = RTE_BE32(ip_addr) };
struct rte_flow_item_ipv4 ipv4_mask = { .hdr.dst_addr = RTE_BE32(0xFFFFFFFF) };
pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
pattern[1].spec = &ipv4_spec;
pattern[1].mask = &ipv4_mask;

// Définir le motif UDP
struct rte_flow_item_udp udp_spec = { .hdr.dst_port = RTE_BE16(udp_port) };
struct rte_flow_item_udp udp_mask = { .hdr.dst_port = RTE_BE16(0xFFFF) };
pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
pattern[2].spec = &udp_spec;
pattern[2].mask = &udp_mask;

// Terminer le motif
pattern[3].type = RTE_FLOW_ITEM_TYPE_END;

// Définir l'action
action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
struct rte_flow_action_queue queue_action = { .index = 0 };
action[0].conf = &queue_action;
action[1].type = RTE_FLOW_ACTION_TYPE_END;

// Créer la règle de flux
flow = rte_flow_create(port_id, &attr, pattern, action, &error);
if (!flow) {
printf("Erreur lors de la création de la règle de flux : %s\n", error.message);
return -1;
}

// rte_flow_isolate(port_id, 1, &error);

printf("Règle de flux créée avec succès pour IP %u.%u.%u.%u et port UDP %u\n",
(ip_addr >> 24) & 0xFF, (ip_addr >> 16) & 0xFF,
(ip_addr >> 8) & 0xFF, ip_addr & 0xFF, udp_port);

return 0;
}

int create_drop_all_rule(uint16_t port_id) {
struct rte_flow_attr attr = { .ingress = 1, .priority = 1};
struct rte_flow_item pattern[2];
struct rte_flow_action actions[2];
struct rte_flow *flow;
struct rte_flow_error error;

pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
pattern[1].type = RTE_FLOW_ITEM_TYPE_END;

actions[0].type = RTE_FLOW_ACTION_TYPE_DROP;
actions[1].type = RTE_FLOW_ACTION_TYPE_END;

if (!rte_flow_validate(port_id, &attr, pattern, actions, &error)){
flow = rte_flow_create(port_id, &attr, pattern, actions, &error);
}

if(flow != 0){
printf("Filed to create drop flow filter \n");
return -1;
}

printf("Default drop rule created successfully.\n");
return 0;
}

#include "../include/port.h"
#include "../include/flow.h"
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>
#include <rte_ether.h>
#include <rte_ip.h>
#include <arpa/inet.h>

#define MAX_PKT_BURST 32

int main(int argc, char **argv) {
struct rte_mempool *mbuf_pool;
int ret;

// Initialiser l'EAL
ret = rte_eal_init(argc, argv);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "Erreur lors de l'initialisation de l'EAL\n");
}

// Créer le pool de mbufs
mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0,
RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (!mbuf_pool) {
rte_exit(EXIT_FAILURE, "Impossible de créer le pool de mbufs\n");
}

if (port_init(PORT_ID, mbuf_pool) != 0) {
rte_exit(EXIT_FAILURE, "Erreur initialisation port\n");
}

// Créer la règle principale
uint32_t ip_addr = RTE_IPV4(10, 81, 16, 111);
uint16_t udp_port = 1234;

if (flow_filtering(PORT_ID, ip_addr, udp_port) != 0) {
rte_exit(EXIT_FAILURE, "Erreur création règle principale\n");
}

// Créer la règle drop-all
if (create_drop_all_rule(PORT_ID) != 0) {
rte_exit(EXIT_FAILURE, "Erreur création règle drop-all\n");
}

printf("Traitement des paquets...\n");
struct rte_mbuf *bufs[MAX_PKT_BURST];

while (1) {
// Récupérer un burst de paquets sur la file RX de la queue 0
const uint16_t nb_rx = rte_eth_rx_burst(PORT_ID, 0, bufs, MAX_PKT_BURST);
if (nb_rx > 0) {
printf("Reçu %u paquet(s)\n", nb_rx);
for (uint16_t i = 0; i < nb_rx; i++) {
// Afficher la taille du paquet
printf("Paquet %u : taille = %u octets\n",
i, rte_pktmbuf_pkt_len(bufs[i]));

// Traiter le paquet pour afficher les adresses source et destination
struct rte_ether_hdr *eth_hdr;
eth_hdr = rte_pktmbuf_mtod(bufs[i], struct rte_ether_hdr *);

// Vérifier que le paquet est de type IPv4
if (rte_be_to_cpu_16(eth_hdr->ether_type) == RTE_ETHER_TYPE_IPV4) {
struct rte_ipv4_hdr *ip_hdr;
ip_hdr = (struct rte_ipv4_hdr *)(eth_hdr + 1);

// Récupérer les adresses source et destination (conversion en format hôte)
uint32_t src_ip = rte_be_to_cpu_32(ip_hdr->src_addr);
uint32_t dst_ip = rte_be_to_cpu_32(ip_hdr->dst_addr);

// Convertir les adresses en chaîne de caractères lisible
char src_str[INET_ADDRSTRLEN];
char dst_str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &src_ip, src_str, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &dst_ip, dst_str, INET_ADDRSTRLEN);

printf("Adresse source : %s\n", src_str);
printf("Adresse destination : %s\n", dst_str);
} else {
printf("Paquet non IPv4, impossible d'extraire les adresses\n");
}

// Libérer le mbuf une fois le traitement terminé
rte_pktmbuf_free(bufs[i]);
}
}
// Petite pause pour éviter une utilisation CPU trop intensive
rte_delay_us_block(100);
}

// Nettoyage
port_cleanup(PORT_ID);
return 0;
}



The issue is that when I implement this, I get an error on the drop filter: "Failed to create rule." Do you have any idea why this might be happening?

Thank you for your time.

Best regards,
Ali


Le mar. 28 janv. 2025 à 19:46, Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> a écrit :
Hi Ali,

2025-01-28 17:54 (UTC+0100), Sid ali cherrati:
> I am attempting to use DPDK's rte_flow API to filter incoming packets at
> the hardware level. My goal is to drop all packets except those with a
> specific IP address and UDP port.
>
> I have implemented the following flow filtering rule in my code:
> [...]
> However, despite this configuration, I continue to receive packets with
> other IP addresses and ports that do not match the specified filter.

Packets that do not match the rule pattern are processed as usual.
If without the rule queue RX_ID could receive any packet,
it will also receive them after the rule is created.
You need another rule with lower priority (BTW, 0 is the highest one)
that matches all packets and drops them or steers to other queues.
If you want your DPDK app to only process packets matching the rule
and to leave all other traffic for the OS to process,
flow isolated mode may be what you're looking for:

https://doc.dpdk.org/guides/prog_guide/ethdev/flow_offload.html#flow-isolated-mode

> Could you provide any insights into why the filtering isn't working as
> expected? Any advice on ensuring the rule is properly applied at the
> hardware level would be greatly appreciated.

The usual way to check that the rule is matched
is to all a counter to the rule and check if it increases.
I suggest using testpmd for playing with flow rules:

https://doc.dpdk.org/guides/testpmd_app_ug/testpmd_funcs.html#flow-rules-management

There was also a useful talk abound HW rules debugging on DPDK Summit:

https://dpdksummit2024.sched.com/event/1iAtU/debug-functional-and-performance-issues-in-rteflow-dariusz-sosnowski-nvidia-corp