1
0
mirror of https://github.com/xdp-project/BNG-router.git synced 2024-05-06 15:54:53 +00:00

Increasing IP and UDP length headers to match Ethernet frame tail

adjustment.
Adding map client_vlans which allows matching server responses with 
client requests.
Reformatting Option 82 to include interface name (work in progress,
we need to figure out how to convert VLAN tags to ASCII).
This commit is contained in:
Yoel Caspersen
2021-10-17 10:41:06 +02:00
parent 37f30d5811
commit ac9373c82e
3 changed files with 107 additions and 16 deletions

View File

@ -21,7 +21,7 @@
struct sub_option {
__u8 option_id;
__u8 len;
__u16 val;
char val[IF_NAMESIZE];
};
/*structure for dhcp option 82 */

View File

@ -2,6 +2,7 @@
#include <linux/bpf.h>
#include <linux/in.h>
#include <net/if.h> /* IF_NAMESIZE */
#include <bpf/bpf_helpers.h>
#include <xdp/parsing_helpers.h>
#include <xdp/context_helpers.h>
@ -23,22 +24,48 @@ struct {
__uint(max_entries, 3);
} relay_config SEC(".maps");
/*
* This map is for storing the device name in clear text.
* Device name is used for DHCP option 82.
*/
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, char[IF_NAMESIZE]);
__uint(max_entries, 1);
} device_name SEC(".maps");
/*
* This map is used for storing client requests along with their matching
* VLAN tags. That way, we can handle DHCP server replies.
* Client MAC address is used as key, VLAN headers as value.
*/
struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__type(key, __u64);
__type(value, struct collect_vlans);
__uint(max_entries, 16384);
} client_vlans SEC(".maps");
/* 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) {
struct collect_vlans *vlans, char *dev) {
struct dhcp_option_82 option;
option.t = DHO_DHCP_AGENT_OPTIONS;
option.len = 8;
option.len = sizeof(struct sub_option) + sizeof(struct sub_option);
option.circuit_id.option_id = RAI_CIRCUIT_ID;
option.circuit_id.len = RAI_OPTION_LEN;
option.circuit_id.val = bpf_ntohs(vlans->id[0]);
option.circuit_id.len = IF_NAMESIZE;
memcpy(option.circuit_id.val, dev, IF_NAMESIZE);
//option.circuit_id.val = bpf_ntohs(vlans->id[0]);
option.remote_id.option_id = RAI_REMOTE_ID;
option.remote_id.len = RAI_OPTION_LEN;
option.remote_id.val = bpf_ntohs(vlans->id[1]);
option.remote_id.len = IF_NAMESIZE;
//option.remote_id.val = bpf_ntohs(vlans->id[1]);
return xdp_store_bytes(ctx, offset, &option, sizeof (option), 0);
}
@ -104,9 +131,8 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
bpf_printk("Cannot tail extend packet, delta %i - error code %i", delta, res);
return XDP_ABORTED;
}
//bpf_printk("static_offset %i (hex %x)", static_offset, static_offset);
//bpf_printk("dhcp_offset %i (hex %x)", dhcp_offset, dhcp_offset);
bpf_printk("Tail extended packet by %i bytes", delta);
void *data_end = (void *) (long) ctx->data_end;
void *data = (void *) (long) ctx->data;
@ -126,6 +152,8 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
__u16 vlan_length = 0;
__u8 option_code = 0;
__u8 option_length = 0;
__u64 client_mac = 0;
char *dev;
int i = 0;
/* These keep track of the next header type and iterator pointer */
@ -177,6 +205,12 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
if (udp->dest != bpf_htons(DHCP_SERVER_PORT) && udp->dest != bpf_htons(DHCP_CLIENT_PORT))
goto out;
/* Increase IP length header */
ip->tot_len += bpf_htons(delta);
/* Increase UDP length header */
udp->len += bpf_htons(delta);
/* Read DHCP server IP from config map */
key = 0;
dhcp_srv_ip = bpf_map_lookup_elem(&relay_config, &key);
@ -194,6 +228,12 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
relay_hwaddr = bpf_map_lookup_elem(&relay_config, &key);
if (relay_hwaddr == NULL)
goto out;
/* Read device name from device map */
key = 0;
dev = bpf_map_lookup_elem(&device_name, &key);
if (dev == NULL)
goto out;
/* Copy headers of packet to buf */
//if (xdp_load_bytes(ctx, 0, buf, static_offset))
@ -223,6 +263,12 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
}
dhcp = data + vlan_length + dhcp_offset;
/* Store client MAC */
if (dhcp->chaddr + ETH_ALEN > data_end) {
goto out;
}
memcpy(&client_mac, dhcp->chaddr, ETH_ALEN);
bpf_printk("Parsing DHCP packet, opcode %i, hops %i", dhcp->op, dhcp->hops);
if (dhcp->op == DHCP_REQUEST && (eth->h_dest[0] == 0xff
@ -243,12 +289,18 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
//memcpy(eth->h_source, relay_hwaddr, ETH_ALEN);
// Set GIADDR
if(&dhcp->giaddr.s_addr + sizeof(relay_agent_ip) > data_end) {
if (&dhcp->giaddr.s_addr + sizeof (relay_agent_ip) > data_end) {
rc = XDP_ABORTED;
goto out;
}
dhcp->giaddr.s_addr = *relay_agent_ip;
/* Save client VLAN in state map */
if (bpf_map_update_elem(&client_vlans, &client_mac, &vlans, BPF_ANY)) {
bpf_printk("Could not save DHCP request in state map");
goto out;
}
} else if (dhcp->op == DHCP_REPLY && (eth->h_dest[0] != 0xff
|| eth->h_dest[1] != 0xff
@ -270,6 +322,15 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
* to the end user
*/
struct collect_vlans *new_vlans;
new_vlans = bpf_map_lookup_elem(&client_vlans, &client_mac);
if (new_vlans == NULL) {
bpf_printk("Could not find map entry for MAC %i", client_mac);
goto out;
}
bpf_printk("Found map entry for MAC %i", client_mac);
}
/* Check hops */
@ -307,7 +368,7 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
bpf_printk("Going to write DHCP option at offset %i", option_offset);
/* Insert Option 82 before END option */
if (write_dhcp_option_82(ctx, option_offset, &vlans)) {
if (write_dhcp_option_82(ctx, option_offset, &vlans, dev)) {
bpf_printk("Could not write DHCP option 82 at offset %i", option_offset);
return XDP_ABORTED;
}
@ -325,6 +386,8 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
bpf_printk("Could not write DHCP option 255 at offset %i", option_offset);
return XDP_ABORTED;
}
bpf_printk("Wrote DHCP option 255 at offset %i, returning XDP_PASS", option_offset);
break;
}
@ -384,8 +447,6 @@ int xdp_dhcp_relay(struct xdp_md *ctx) {
ip->check = ~sum;
rc = XDP_PASS;
bpf_printk("Wrote DHCP option at offset %i, returning XDP_PASS", offset);
goto out;
out:

View File

@ -17,6 +17,7 @@
#include <unistd.h>
#define SERVER_MAP "relay_config"
#define DEVICE_MAP "device_name"
#define XDP_OBJ "dhcp_kern_xdp.o"
static const struct option options[] = {
@ -102,8 +103,10 @@ int main(int argc, char **argv) {
char dev[IF_NAMESIZE] = "";
bool do_unload = 0;
struct bpf_map *map = NULL;
struct bpf_map *device_map = NULL;
struct bpf_object *obj = NULL;
int map_fd;
int device_map_fd;
int key = 0;
struct in_addr dhcp_server_addr = {};
struct in_addr relay_agent_addr = {};
@ -197,7 +200,7 @@ int main(int argc, char **argv) {
memcpy(&hwaddr, (unsigned char *) ifr.ifr_hwaddr.sa_data, 6);
//display mac address
printf("Mac : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
printf("Using device %s MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", dev, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
/* Load the BPF-ELF object file and get back first BPF_prog FD */
err = bpf_prog_load(filename, BPF_PROG_TYPE_XDP, &obj, &prog_fd);
@ -255,6 +258,33 @@ int main(int argc, char **argv) {
exit(-1);
}
/* read the map from prog object file and update the real
* server IP to the map
*/
device_map = bpf_object__find_map_by_name(obj, DEVICE_MAP);
err = libbpf_get_error(device_map);
if (err) {
fprintf(stderr, "Could not find map %s in %s: %s\n", DEVICE_MAP,
XDP_OBJ, strerror(err));
device_map = NULL;
exit(-1);
}
device_map_fd = bpf_map__fd(device_map);
if (device_map_fd < 0) {
fprintf(stderr, "Could not get device map fd\n");
exit(-1);
}
// Set device name in map
key = 0;
err = bpf_map_update_elem(device_map_fd, &key, dev, BPF_ANY);
if (err) {
fprintf(stderr, "Could not update map %s in %s\n", DEVICE_MAP,
XDP_OBJ);
exit(-1);
}
err = xdp_link_attach(ifindex, xdp_flags, prog_fd);
if (err)
return err;