-
Notifications
You must be signed in to change notification settings - Fork 4
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
Add XDP redirect example #5
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: astoycos <[email protected]>
Signed-off-by: astoycos <[email protected]>
Add the ability to update the Dport of the packet, and add some documentation. Signed-off-by: astoycos <[email protected]>
Not at all ready to go in yet, XDP bits are working but userspace is still hardcoded :) |
// Here we only want to iterate through payload | ||
// NOT trailing bits | ||
for (int i = 0; i <= MAX_UDP_LENGTH; i += 2) { | ||
if (i > udp_packet_nibbles) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this test will ever be true because nibbles is 2 * number of bytes. The if statement on line 78 will end the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I'm still getting confused here... maybe it's because i'm using the term nibble incorrectly
So the issue is, data_end
is a PTR which includes the payload AND any trailing bits, while I forced udp_packet_nibbles
to be the number of "digits" in the raw hex payload...
For example in the following packet
13:23:15.756911 06:56:87:ec:fd:1f > 86:ad:33:29:ff:5e, ethertype IPv4 (0x0800), length 60: (tos 0x0, ttl 57, id 20891, offset 0, flags [DF], proto UDP (17), length 33)
10.8.125.12.58980 > 192.168.10.2.sapv1: [bad udp cksum 0xd301 -> 0xaf43!] UDP, length 5
0x0000: 86ad 3329 ff5e 0656 87ec fd1f 0800 4500
0x0010: 0021 519b 4000 3911 9e72 0a08 7d0c c0a8
0x0020: 0a02 e664 2693 000d d301 7465 7374 0a00
0x0030: 0000 0000 d2f2 935d 0000 0000
The UDP header + Data is
e664 2693 000d d301 7465 7374 0a00
0000 0000 d2f2 935d 0000 0000
so
for (int i = 0; i <= MAX_UDP_LENGTH; i += 2) {
if ((void *)(buf + 1) > data_end) {
break;
}
csum_total += *buf;
buf++;
}
would iterate through all of that ^^ (i.e increment buff and read 13 times == 26 bytes of data)
Here packet length is 000d(13 bytes) so I know that I want to exit after incrementing buff 6.5 times ignoring those last 6.5 iterations (13 bytes of data)
The confusing part here is that i
is a nibble index (1 hex digit (4 bytes)) (maybe) here, so that we can represent those 6 16 bit iterations and 1 8 bit iteration
I guess I'm confused trying to calculate 6 from the packet data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A nibble is half a byte, i.e. 4 bits, 0..15 (what I think you are calling a hex digit). It's not useful to think about nibbles or try and do anything in terms of nibbles, except if you are writing your own code to convert numbers to hex strings.
__u16 *buf = (void *)udp;
This declares buf to be a pointer that will point to __u16
width values. buf++
will increment it by 2, to point at the next __u16
width value:
__u16 *buf = 0xf00;
printf("%x\n", buf);
printf("%x\n", buf + 1);
f00
f02
This means that if ((void *)(buf + 1) > data_end)
would trigger too early because buf + 1
is actually +2
and would exit even if there were 2 bytes to be read.
It's safer to do all the arithmetic in bytes since the payload is a byte stream and the udp->len is in bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated this to be much simpler
|
||
static __always_inline __u16 iph_csum(struct iphdr *iph) { | ||
iph->check = 0; | ||
unsigned long long csum = bpf_csum_diff(0, 0, (unsigned int *)iph, sizeof(struct iphdr), 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible to use bpf_csum_diff to just recompute the checksum for the changed fields, i.e. just the src and dest ip pseudo headers in the UDP csum. Need to see if we can find an example of a bpf program that does this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed I had tried that in the past with little luck which is why I did it so manually here, but it would definitely be much easier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I tried this
static __always_inline __u16 udp_csum_diff(struct udphdr *udp) {
udp->check = 0;
unsigned long long csum = bpf_csum_diff(0, 0, (unsigned int *)udp, sizeof(struct udphdr), 0);
return csum_fold_helper(csum);
}
But it doesn't return the right values (I know the Manual Cksum calc is working)
[016] dNs3. 354704.109793: bpf_trace_printk: Manual Cksum: C8A7 Diff Cksum 8B14
36719a2
to
1d0a065
Compare
bpf/xdp_udp.bpf.c
Outdated
// Last byte | ||
if (i + 1 == udp_len) { | ||
csum_total += (*(__u8 *)buf); | ||
// Verifier fails without this print statement, I have no Idea why :/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@donaldh this was baffling
f8dd6bb
to
01af1cf
Compare
01af1cf
to
8bdf053
Compare
No description provided.