Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

advanced03-AF_XDP - adapting for UDP #74

Closed
sevagh opened this issue Sep 7, 2019 · 2 comments

Comments

@sevagh
Copy link

commented Sep 7, 2019

Hello. I'm having a hard time adapting the advanced03 AF_XDP code to do a similar action to UDP packets - unless I'm really fundamentally misunderstanding the direction of the rx/tx flow.

I have a socat listener on the external ip of my veth-adv03:

sevagh:~ $ socat - UDP6-LISTEN:1234,bind=[fc00:dead:cafe:1::1],fork
hello world 2
hello world 3
hello world 8
hello world 9

I send hello world 1-10 with socat via the internal ip, after running testenv.sh enter:

[root@localhost sevagh]# for x in 1 2 3 4 5 6 7 8 9 10; do echo "hello world ${x}" | socat - UDP6-SENDTO:[fc00:dead:cafe:1::1]:1234; done

Finally, I have XDP code redirecting half the packets to AF_XDP, where I simply want to do a random sleep, and send them, to scramble the packets and have them arrive out of order.

My desired result is:

sevagh:~ $ socat - UDP6-LISTEN:1234,bind=[fc00:dead:cafe:1::1],fork
hello world 2 // XDP_PASS
hello world 3 // XDP_PASS
hello world 8 // XDP_PASS
hello world 9 // XDP_PASS
hello world 4 // AF_XDP + random sleep
hello world 1 // AF_XDP + random sleep
hello world 10 // AF_XDP + random sleep
...

However, in my AF_XDP code, the packet doesn't go anywhere:

static bool process_packet(struct xsk_socket_info *xsk, uint64_t addr,
			   uint32_t len, int udp4_out, int udp6_out)
{
	uint8_t *pkt = xsk_umem__get_data(xsk->umem->buffer, addr);

	int ret;
	uint32_t tx_idx = 0;

	// sleep randomly to scramble
	dawdle();

	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;
}

As a workaround, I can send those AF_XDP rx packets above, on a different, regular AF_INET6 UDP socket, to achieve my desired goal:

static bool process_packet(struct xsk_socket_info *xsk, uint64_t addr,
			   uint32_t len, int udp4_out, int udp6_out)
{
	uint8_t *pkt = xsk_umem__get_data(xsk->umem->buffer, addr);

        ....

        ssize_t sent_bytes;
        struct sockaddr_in6 sin;
        sin.sin6_family = AF_INET6;
        sin.sin6_port = udphdr->dest;
        inet_pton(AF_INET6, "::1", &sin.sin6_addr);
        sent_bytes = sendto(udp6_out, (void *)nh.pos, len, 0,
                                   (struct sockaddr *)&sin, sizeof(sin))

Is using a regular UDP socket the only way to achieve what I need, or should it be possible to do so with AF_XDP?

@chaudron

This comment has been minimized.

Copy link
Contributor

commented Sep 11, 2019

This code will send the packet back over the interface it's received upon, not back to the kernel.
So TX means send it out of the interface, and RX is the receive path on the interface. The example below uses the same ingress and egress interface.

So TX does not mean the same as XDP_PASS, XDP_PASS continue the packet where TX does not. AF_XDP has no built-in feature to re-insert the packet back into the kernel.

@sevagh

This comment has been minimized.

Copy link
Author

commented Sep 11, 2019

Thank you.

@sevagh sevagh closed this Sep 11, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.