-
Notifications
You must be signed in to change notification settings - Fork 8
First working prototype - DHCPv4 #11
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
base: main
Are you sure you want to change the base?
Changes from 2 commits
83b9795
8d91b14
17f1da5
813cfa2
f266202
b970472
fd2b750
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,13 @@ | |
#include <xdp/context_helpers.h> | ||
#include "dhcp-relay.h" | ||
|
||
#define bpf_printk(fmt, ...) \ | ||
({ \ | ||
char ____fmt[] = fmt; \ | ||
bpf_trace_printk(____fmt, sizeof(____fmt), \ | ||
##__VA_ARGS__); \ | ||
}) | ||
|
||
/* | ||
* This map is for storing the DHCP relay configuration, including: | ||
* | ||
|
@@ -49,76 +56,104 @@ struct { | |
__uint(max_entries, 16384); | ||
} client_vlans SEC(".maps"); | ||
|
||
void memcpy_var(void *to, void *from, __u64 len) { | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
__u8 *t8 = to, *f8 = from; | ||
int i; | ||
|
||
for (i = 0; i < len && i < MAX_LOOPS; i++) { | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
*t8++ = *f8++; | ||
} | ||
|
||
} | ||
|
||
void memset_var(void *d, __u8 c, __u64 len) { | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
__u8 *d8 = d; | ||
int i; | ||
|
||
for (i = 0; i < len && i < MAX_LOOPS; i++) { | ||
*d8++ = c; | ||
} | ||
|
||
} | ||
|
||
/* Inserts DHCP option 82 into the received DHCP packet | ||
* at the specified offset. | ||
*/ | ||
static __always_inline int write_dhcp_option_82(void *ctx, int offset, | ||
|
||
struct collect_vlans *vlans, char *dev) { | ||
|
||
struct dhcp_option_82 option; | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
|
||
static __u8 buf[RAI_OPTION_LEN]; | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
option.t = DHO_DHCP_AGENT_OPTIONS; | ||
option.len = sizeof (struct sub_option) + sizeof (struct sub_option); | ||
option.circuit_id.option_id = RAI_CIRCUIT_ID; | ||
option.circuit_id.len = sizeof(option.circuit_id.val); | ||
option.circuit_id.len = sizeof (option.circuit_id.val); | ||
option.remote_id.option_id = RAI_REMOTE_ID; | ||
option.remote_id.len = sizeof (option.remote_id.val); | ||
|
||
/* Initialize val arrays */ | ||
memset_var(option.circuit_id.val, 0, sizeof (option.circuit_id.val)); | ||
memset_var(option.remote_id.val, '*', sizeof (option.remote_id.val)); | ||
//memset(option.circuit_id.val, 0, sizeof (option.circuit_id.val)); | ||
//memset(option.remote_id.val, '*', sizeof (option.remote_id.val)); | ||
|
||
/* Reconstruct VLAN device name | ||
* Convert VLAN tags to ASCII from right to left, starting with | ||
* inner VLAN tag. | ||
* Device name is 16 characters long and prepended with dash, e.g.: | ||
* ----ens6f0.83.20 | ||
* We avoid null bytes to ensure compatibility with DHCP servers that | ||
* interpret null as a string terminator. | ||
* Device name is up to 16 characters long - remaining buffer space | ||
* contains null bytes. | ||
*/ | ||
|
||
char buf[IF_NAMESIZE]; | ||
memset(buf, '-', sizeof (buf)); | ||
|
||
memset(buf, 0, sizeof (buf)); | ||
|
||
int c = VLAN_ASCII_MAX; /* We will need 4 bytes at most */ | ||
int i = RAI_OPTION_LEN - 1; | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
int c = VLAN_ASCII_MAX; /* We will need 4 bytes at most */ | ||
int i = IF_NAMESIZE - 1; | ||
__u16 inner_vlan = vlans->id[1]; | ||
__u16 outer_vlan = vlans->id[0]; | ||
|
||
|
||
/* Convert inner VLAN to ASCII */ | ||
#pragma unroll VLAN_ASCII_MAX | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
for (c = VLAN_ASCII_MAX; c > 0; c--) { | ||
buf[i--] = (inner_vlan % 10) + '0'; | ||
inner_vlan /= 10; | ||
if (inner_vlan == 0) { | ||
break; | ||
} | ||
} | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
buf[i--] = '.'; | ||
|
||
|
||
/* Convert outer VLAN to ASCII */ | ||
#pragma unroll VLAN_ASCII_MAX | ||
for (c = VLAN_ASCII_MAX; c > 0; c--) { | ||
buf[i--] = (outer_vlan % 10) + '0'; | ||
outer_vlan /= 10; | ||
if (outer_vlan == 0) { | ||
break; | ||
} | ||
} | ||
|
||
|
||
buf[i--] = '.'; | ||
|
||
for (c = IF_NAMESIZE - 1; c >= 0; c--) { | ||
|
||
if (dev[c] != 0) { | ||
/* Append interface name */ | ||
#pragma unroll RAI_OPTION_LEN | ||
for (c = RAI_OPTION_LEN - 1; c >= 0; c--) { | ||
if (dev[c] != 0) | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
buf[i--] = dev[c]; | ||
} | ||
|
||
if (i < 0) { | ||
break; | ||
} | ||
|
||
} | ||
|
||
if(sizeof(option.circuit_id.val) == sizeof(buf)) { | ||
memcpy(option.circuit_id.val, buf, sizeof(buf)); | ||
if (i < 0) | ||
break; | ||
} | ||
|
||
/* Initialize remote ID */ | ||
memset(option.remote_id.val, 0, sizeof(option.remote_id.val)); | ||
option.remote_id.option_id = RAI_REMOTE_ID; | ||
option.remote_id.len = sizeof(option.remote_id.val); | ||
i++; | ||
|
||
/* Copy resulting interface name to circuit_id */ | ||
if (sizeof (option.circuit_id.val) == sizeof (buf)) { | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
memcpy_var(option.circuit_id.val, buf + i, sizeof (buf) - i); | ||
//memcpy_var(option.circuit_id.val, buf, sizeof (buf)); | ||
} | ||
|
||
return xdp_store_bytes(ctx, offset, &option, sizeof (option), 0); | ||
yoelcaspersen marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
} | ||
|
@@ -166,13 +201,6 @@ static __always_inline int calc_ip_csum(struct iphdr *oldip, struct iphdr *ip, | |
*/ | ||
//static __u8 buf[static_offset + VLAN_MAX_DEPTH * sizeof (struct vlan_hdr)]; | ||
|
||
#define bpf_printk(fmt, ...) \ | ||
({ \ | ||
char ____fmt[] = fmt; \ | ||
bpf_trace_printk(____fmt, sizeof(____fmt), \ | ||
##__VA_ARGS__); \ | ||
}) | ||
|
||
/* XDP program for parsing the DHCP packet and inserting the option 82*/ | ||
SEC(XDP_PROG_SEC) | ||
int xdp_dhcp_relay(struct xdp_md *ctx) { | ||
|
@@ -183,10 +211,10 @@ int xdp_dhcp_relay(struct xdp_md *ctx) { | |
int res = bpf_xdp_adjust_tail(ctx, delta); | ||
if (res != 0) { | ||
bpf_printk("Cannot tail extend packet, delta %i - error code %i", delta, res); | ||
return XDP_ABORTED; | ||
return XDP_PASS; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a packet we figured we should handle, but that failed; so what is XDP_PASS supposed to do with it? Better to drop... |
||
} | ||
|
||
bpf_printk("Tail extended packet by %i bytes", delta); | ||
//bpf_printk("Tail extended packet by %i bytes", delta); | ||
|
||
void *data_end = (void *) (long) ctx->data_end; | ||
void *data = (void *) (long) ctx->data; | ||
|
@@ -217,27 +245,34 @@ int xdp_dhcp_relay(struct xdp_md *ctx) { | |
int key = 0; | ||
int len = 0; | ||
|
||
if (data + 1 > data_end) | ||
return XDP_ABORTED; | ||
if (data + 1 > data_end) { | ||
bpf_printk("Empty packet\n"); | ||
goto out; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unneded braces |
||
|
||
nh.pos = data; | ||
ether_type = parse_ethhdr_vlan(&nh, data_end, ð, &vlans); | ||
/* check for valid ether type */ | ||
if (ether_type < 0) { | ||
bpf_printk("Cannot determine ethertype"); | ||
rc = XDP_ABORTED; | ||
bpf_printk("Cannot determine ethertype\n"); | ||
goto out; | ||
} | ||
|
||
if (ether_type != bpf_htons(ETH_P_IP)) { | ||
bpf_printk("Ethertype %#x is not ETH_P_IP", bpf_ntohs(ether_type)); | ||
//bpf_printk("Ethertype %x is not ETH_P_IP\n", bpf_ntohs(ether_type)); | ||
goto out; | ||
} | ||
|
||
bpf_printk("Ethertype %x", bpf_ntohs(ether_type)); | ||
|
||
bpf_printk("Ethertype %x\n", bpf_ntohs(ether_type)); | ||
/* Check at least two vlan tags are present */ | ||
if (vlans.id[0] == 0) { | ||
bpf_printk("No outer VLAN tag set\n"); | ||
goto out; | ||
} | ||
|
||
if (vlans.id[1] == 0) { | ||
bpf_printk("No VLAN tags set"); | ||
bpf_printk("No inner VLAN tag set\n"); | ||
goto out; | ||
} | ||
|
||
|
@@ -264,6 +299,8 @@ int xdp_dhcp_relay(struct xdp_md *ctx) { | |
|
||
/* Increase UDP length header */ | ||
udp->len += bpf_htons(delta); | ||
|
||
udp->check = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here you're modifying the packet, but any |
||
|
||
/* Read DHCP server IP from config map */ | ||
key = 0; | ||
|
@@ -294,6 +331,7 @@ int xdp_dhcp_relay(struct xdp_md *ctx) { | |
// goto out; | ||
|
||
/* Increment offset by 4 bytes for each VLAN (to accomodate VLAN headers */ | ||
#pragma unroll VLAN_MAX_DEPTH | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not needed |
||
for (i = 0; i < VLAN_MAX_DEPTH; i++) { | ||
if (vlans.id[i]) { | ||
|
||
|
@@ -426,7 +464,7 @@ int xdp_dhcp_relay(struct xdp_md *ctx) { | |
bpf_printk("Could not write DHCP option 82 at offset %i", option_offset); | ||
return XDP_ABORTED; | ||
} | ||
|
||
/* Set END option */ | ||
|
||
/* Verifier check */ | ||
|
Uh oh!
There was an error while loading. Please reload this page.