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

First working prototype - DHCPv4 #11

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

yoelcaspersen
Copy link
Contributor

@yoelcaspersen yoelcaspersen commented Oct 24, 2021

This version works with kernel 5.15 and LLVM 13.

Improvements:

  • Interface name is added to Option 82 Circuit ID
  • On server replies, Option 82 is wiped completely
  • Char array parameters replaced with structs

Functions that previously used char arrays as function parameters now
use structs instead - otherwise the verifier cannot perform proper
boundary checks.

To-do:

  • IPv6 support
  • Multiple interface support

Built-in memcpy and memset functions cause verifier to complain about
misaligned stack access. To get around that (and be able to copy a
dynamic number of bytes via memcpy), two custom functions are added.
This version of the relay uses interface name + VLAN identifiers in
option 82 circuit ID (left-aligned, length IF_NAMESIZE with trailing
null bytes).

Signed-off-by: Yoel Caspersen <[email protected]>
When allowing packets with 1 VLAN tag only, verifier complains about
BPF program being too large.
Compiled with LLVM 13.

Signed-off-by: Yoel Caspersen <[email protected]>
dhcp-relay/Makefile Show resolved Hide resolved
dhcp-relay/dhcp-relay.h Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
Yoel Caspersen added 2 commits November 5, 2021 14:37
In this version of the relay, we assume that client requests are
received on a double tagged VLAN interface and server replies are
received on a single tagged VLAN interface.

Test scripts are added:

- test.sh (configures BNG and sets L3 config)
- cleanup_test.sh (removes BNG configuration)
- trace.sh (opens trace pipe for debugging)

The code for adding interface name is disabled because it makes the
verifier complain about the BPF program being too large.

To-do:
- Fix verifier issue to include interface name in option 82
- For server replies, erase option 82 instead of (partial) overwrite

Signed-off-by: Yoel Caspersen <[email protected]>
This version works with kernel 5.15 and LLVM 13.

Improvements:

- Interface name is added to Option 82 Circuit ID
- On server replies, Option 82 is wiped completely
- Char array parameters replaced with structs

Functions that previously used char arrays as function parameters now
use structs instead - otherwise the verifier cannot perform proper
boundary checks.

To-do:
- IPv6 support
- Multiple interface support

Signed-off-by: Yoel Caspersen <[email protected]>
@yoelcaspersen yoelcaspersen changed the title Adding custom memcpy and memset functions to pass verifier checks First working prototype - DHCPv4 Nov 9, 2021
Copy link
Member

@tohojo tohojo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job getting something to work! Unfortunately the code has turned a wee bit spaghetti in the process; I guess most of the comments below could be summed up as changes that fix that :)

@@ -38,6 +43,11 @@ struct dhcp_option_255 {
__u8 t;
};

struct dev_name {
char name[IF_NAMESIZE];
__u8 len;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len is unneeded, see below

dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
dhcp-relay/dhcp_kern_xdp.c Outdated Show resolved Hide resolved
}

if (i > 0) {
opt->val[--i] = '.';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is called u16_to_ascii, so what is this doing here? Better leave this to the caller.

}

if (i > RAI_OPTION_LEN)
return -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is not needed...

}
/* Adjust IP offset for VLAN header when VLAN header has been added */
if (head_adjusted) {
ip = data + ip_offset + sizeof (struct vlan_hdr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why carry this head_adjusted all the way down here instead of just modifying ip_offset directly when doing the adjustment?

return XDP_ABORTED;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary braces

@@ -499,7 +685,6 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
/* Re-calculate ip checksum */
__u32 sum = calc_ip_csum(&oldip, ip, oldip.check);
ip->check = ~sum;
rc = XDP_PASS;

goto out;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant goto

@@ -499,7 +685,6 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
/* Re-calculate ip checksum */
__u32 sum = calc_ip_csum(&oldip, ip, oldip.check);
ip->check = ~sum;
rc = XDP_PASS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above; this is actually the right place to change the return code back into something that sends out the packet, as this is where the packet is once again valid...

OUTER_VLAN=83
INNER_VLAN=20
UPLINK_VLAN=84
IF="ens6f0"
Copy link
Member

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 test this using network namespaces; having a test that is runnable without needing special hardware makes it way easier to test. Such a test should really be added so it can be run as part of a CI job.

This makes several changes to improve the readability of write_dhcp_option_82():

The main change is in reworking the string helpers to be smaller and more
modular, and using a separate buffer for stringifying the VLAN tags before
copying them to the DHCP option field. Get rid of str_len() and the len
member of struct dev_name. To aid in this, the whole containing function is
made global (i.e., a separate BPF subprog) instead of the helpers.

In addition, the local variables are renamed to be more descriptive, and
the option struct is initialised using struct initialisation syntax.

Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
The case statements of the option parsing 'switch' had grown an extra level
of indentation. Get rid of that.

Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
Add a -v option to turn on verbose logging in libbpf; this makes it
possible to see which relocations libbpf is making, which is useful to see
which functions get turned into separate sub functions.

Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
@tohojo
Copy link
Member

tohojo commented Nov 12, 2021

Took the liberty of fixing some of the issues I pointed out myself, and pushed them to your branch :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants