Skip to content

Commit

Permalink
Upstream direction works with QinQ packets only
Browse files Browse the repository at this point in the history
When allowing packets with 1 VLAN tag only, verifier complains about
BPF program being too large.
Compiled with LLVM 13.
  • Loading branch information
Yoel Caspersen committed Oct 25, 2021
1 parent 83b9795 commit fa17a0e
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 16 deletions.
2 changes: 2 additions & 0 deletions dhcp-relay/dhcp-relay.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#define DHCP_REQUEST 1
#define DHCP_REPLY 2

#define MAX_LOOPS 40

/* Structure for sub-options in option 82 */
struct sub_option {
__u8 option_id;
Expand Down
47 changes: 31 additions & 16 deletions dhcp-relay/dhcp_kern_xdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void memcpy_var(void *to, void *from, __u64 len) {
__u8 *t8 = to, *f8 = from;
int i;

for (i = 0; i < len; i++) {
for (i = 0; i < len && i < MAX_LOOPS; i++) {
*t8++ = *f8++;
}

Expand All @@ -70,7 +70,7 @@ void memset_var(void *d, __u8 c, __u64 len) {
__u8 *d8 = d;
int i;

for (i = 0; i < len; i++) {
for (i = 0; i < len && i < MAX_LOOPS; i++) {
*d8++ = c;
}

Expand All @@ -84,6 +84,8 @@ static __always_inline int write_dhcp_option_82(void *ctx, int offset,

struct dhcp_option_82 option;

static __u8 buf[RAI_OPTION_LEN];

option.t = DHO_DHCP_AGENT_OPTIONS;
option.len = sizeof (struct sub_option) + sizeof (struct sub_option);
option.circuit_id.option_id = RAI_CIRCUIT_ID;
Expand All @@ -104,15 +106,16 @@ static __always_inline int write_dhcp_option_82(void *ctx, int offset,
* contains null bytes.
*/

char buf[RAI_OPTION_LEN];
memset(buf, 0, sizeof (buf));

int c = VLAN_ASCII_MAX; /* We will need 4 bytes at most */
int i = RAI_OPTION_LEN - 1;

__u16 inner_vlan = vlans->id[1];
__u16 outer_vlan = vlans->id[0];

/* Convert inner VLAN to ASCII */
#pragma unroll VLAN_ASCII_MAX
for (c = VLAN_ASCII_MAX; c > 0; c--) {
buf[i--] = (inner_vlan % 10) + '0';
inner_vlan /= 10;
Expand All @@ -124,6 +127,7 @@ static __always_inline int write_dhcp_option_82(void *ctx, int offset,
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;
Expand All @@ -132,10 +136,10 @@ static __always_inline int write_dhcp_option_82(void *ctx, int offset,
}
}


buf[i--] = '.';

/* Append interface name */
#pragma unroll RAI_OPTION_LEN
for (c = RAI_OPTION_LEN - 1; c >= 0; c--) {
if (dev[c] != 0)
buf[i--] = dev[c];
Expand All @@ -148,8 +152,9 @@ static __always_inline int write_dhcp_option_82(void *ctx, int offset,
/* Copy resulting interface name to circuit_id */
if (sizeof (option.circuit_id.val) == sizeof (buf)) {
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);
}

Expand Down Expand Up @@ -206,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;
}

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;
Expand Down Expand Up @@ -240,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;
}

nh.pos = data;
ether_type = parse_ethhdr_vlan(&nh, data_end, &eth, &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;
}

Expand All @@ -287,6 +299,8 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {

/* Increase UDP length header */
udp->len += bpf_htons(delta);

udp->check = 0;

/* Read DHCP server IP from config map */
key = 0;
Expand Down Expand Up @@ -317,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
for (i = 0; i < VLAN_MAX_DEPTH; i++) {
if (vlans.id[i]) {

Expand Down Expand Up @@ -449,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 */
Expand Down

0 comments on commit fa17a0e

Please sign in to comment.