Hi folks, I'm currently working on setting up a packet filter using AF_XDP on my Linux server to manage network traffic in userspace. I tried to work with xdp-tutorial/AF_XDP example, I've attached a simple XDP program that redirects to the traffic by using xsks_map on enp8s0. You can find the XDP code below. To test my setup, I'm trying to block a specific IPv4 address. Although I can see the traffic on userspace, I couldn't block any traffic. You can find the userspace code below. I think there is something I am missing, can you help me what I am doing wrong? Here's a brief overview of my current setup: Network Interfaces: enp1s0 (Egress Interface), ens8s0 (Local Network Interface) Current iptables Rules: -A FORWARD -i enp1s0 -o ens8s0 -m state --state RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i ens8s0 -o enp1s0 -j ACCEPT Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 23461 1790K MASQUERADE 0 -- * enp1s0 0.0.0.0/0 0.0.0.0/0 XDP Code: ----- /* SPDX-License-Identifier: GPL-2.0 */ #include <linux/bpf.h> #include <bpf/bpf_helpers.h> struct { __uint(type, BPF_MAP_TYPE_XSKMAP); __type(key, __u32); __type(value, __u32); __uint(max_entries, 64); } xsks_map SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __type(key, __u32); __type(value, __u32); __uint(max_entries, 64); } xdp_stats_map SEC(".maps"); SEC("xdp") int xdp_sock_prog(struct xdp_md *ctx) { int index = ctx->rx_queue_index; __u32 *pkt_count; pkt_count = bpf_map_lookup_elem(&xdp_stats_map, &index); if (pkt_count) { /* We pass every other packet */ if ((*pkt_count)++ & 1) return XDP_PASS; } /* A set entry here means that the correspnding queue_id * has an active AF_XDP socket bound to it. */ if (bpf_map_lookup_elem(&xsks_map, &index)) return bpf_redirect_map(&xsks_map, index, 0); return XDP_PASS; } char _license[] SEC("license") = "GPL"; ---- Userspace code (rest of the code is identical with xdp-tutorial/AF_XDP [https://github.com/xdp-project/xdp-tutorial/blob/master/advanced03-AF_XDP/af_xdp_user.c]): static bool process_packet(struct xsk_socket_info *xsk, uint64_t addr, uint32_t len) { uint8_t *pkt = xsk_umem__get_data(xsk->umem->buffer, addr); struct ethhdr *eth = (struct ethhdr *) pkt; struct iphdr *ip = (struct iphdr *) (eth + 1); struct in_addr tmp_ip; tmp_ip.s_addr = ip->saddr; char src_ip_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &tmp_ip, src_ip_str, INET_ADDRSTRLEN); tmp_ip.s_addr = ip->daddr; char dest_ip_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &tmp_ip, dest_ip_str, INET_ADDRSTRLEN); printf("saddr: %s, daddr: %s\n", src_ip_str, dest_ip_str); // trying to block an ip if (strcmp(src_ip_str, "x.y.z.t") == 0 || strcmp(dest_ip_str, "x.y.z.t") == 0) { return false; } int ret; uint32_t tx_idx = 0; ret = xsk_ring_prod__reserve(&xsk->tx, 1, &tx_idx); if (ret != 1) { /* No more transmit slots, drop the packet */ return false; } xsk_ring_prod__tx_desc(&xsk->tx, tx_idx)->addr = addr; xsk_ring_prod__tx_desc(&xsk->tx, tx_idx)->len = len; xsk_ring_prod__submit(&xsk->tx, 1); xsk->outstanding_tx++; return true; } ... /* Process received packets */ for (i = 0; i < rcvd; i++) { uint64_t addr = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx)->addr; uint32_t len = xsk_ring_cons__rx_desc(&xsk->rx, idx_rx++)->len; if (!process_packet(xsk, addr, len)) xsk_free_umem_frame(xsk, addr); }