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

Moving Option 82 to end of options as per RFC3046 section 2.1.

Adjusting tail instead of headers because of complications with
variable length DHCP options - beware that this doesn't appear to work
with veth interfaces. Use a physical NIC for testing for now.
This commit is contained in:
Yoel Caspersen
2021-10-13 20:11:06 +02:00
parent 51381f01b1
commit 09bc68580f
4 changed files with 421 additions and 139 deletions

View File

@@ -1,7 +1,7 @@
Usage
-----
dhcp_user_xdp takes network interface and dhcp relay server IP
as inputs and stores it in a map. Filters the incoming DHCP requests and inserts
dhcp_user_xdp takes network interface, DHCP server IP and DHCP relay agent IP
as inputs and stores them in a map. Filters the incoming DHCP requests and inserts
option 82 in the DHCP request packets and overwrites the destination IP to that
of DHCP relay server IP.
@@ -10,7 +10,7 @@ cd bpf-examples/dhcp-relay
make
Loading bpf program:
sudo ./dhcp_user_xdp -i <netif> -d <dhcp relay IP>
sudo ./dhcp_user_xdp -i <netif> -d <dhcp server IP> -s <dhcp relay agent IP>
where,
netif: Ingress network interface name
@@ -20,6 +20,12 @@ sudo ./dhcp_user_xdp -i <netif> -u
To run in SKB mode:
add option "-m skb" for both load and uload commands
Verify using tcpdump:
sudo tcpdump -s 0 -i <netif> port 67 and port 68 -vvv
Please beware that testing requires a physical NIC because we tail extend
packets due to complications with variable length DHCP options.
Enable forwarding and allow local address spoofing:
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
sudo echo 1 > /proc/sys/net/ipv4/conf/all/accept_local
Verify using tcpdump:
sudo tcpdump -s 0 -i <netif> port 67 and port 68 -vvv

View File

@@ -12,10 +12,12 @@
#define RAI_REMOTE_ID 2
#define RAI_OPTION_LEN 2
#define DEST_PORT 67 /* UDP destination port for dhcp */
#define MAX_BYTES 280 /* Max bytes supported by xdp load/store apis */
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCP_REQUEST 1
#define DHCP_REPLY 2
/* structure for sub-options in option 82*/
/* Structure for sub-options in option 82 */
struct sub_option {
__u8 option_id;
__u8 len;
@@ -30,6 +32,11 @@ struct dhcp_option_82 {
struct sub_option remote_id;
};
/*structure for dhcp option 255 */
struct dhcp_option_255 {
__u8 t;
};
struct dhcp_packet {
__u8 op; /* 0: Message opcode/type */
__u8 htype; /* 1: Hardware addr type (net/if_types.h) */

View File

@@ -8,49 +8,66 @@
#include "dhcp-relay.h"
/*
* This map is for storing the DHCP relay server
* IP address configured by user. It is received
* as an argument by user program.
*/
* This map is for storing the DHCP relay configuration, including:
*
* Relay server IP address
* Relay agent IP address
* Relay agent MAC address
*
* Configuration parameters are set by CLI arguments in user space program.
*/
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, __u32);
__type(value, __u32);
__uint(max_entries, 1);
} dhcp_server SEC(".maps");
__type(value, __u64);
__uint(max_entries, 3);
} relay_config SEC(".maps");
/* Inserts DHCP option 82 into the received dhcp packet
* at the specified offset.
*/
static __always_inline int write_dhcp_option(void *ctx, int offset,
struct collect_vlans *vlans)
{
*/
static __always_inline int write_dhcp_option_82(void *ctx, int offset,
struct collect_vlans *vlans) {
struct dhcp_option_82 option;
option.t = DHO_DHCP_AGENT_OPTIONS;
option.len = 8;
option.circuit_id.option_id = RAI_CIRCUIT_ID;
option.circuit_id.len = RAI_OPTION_LEN;
option.circuit_id.val = bpf_htons(vlans->id[0]);
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_htons(vlans->id[1]);
option.remote_id.val = bpf_ntohs(vlans->id[1]);
return xdp_store_bytes(ctx, offset, &option, sizeof(option), 0);
return xdp_store_bytes(ctx, offset, &option, sizeof (option), 0);
}
/* Inserts DHCP option 255 into the received dhcp packet
* at the specified offset.
*/
static __always_inline int write_dhcp_option_255(void *ctx, int offset) {
struct dhcp_option_255 option;
option.t = 255;
return xdp_store_bytes(ctx, offset, &option, sizeof (option), 0);
}
/* Calculates the IP checksum */
static __always_inline int calc_ip_csum(struct iphdr *oldip, struct iphdr *ip,
__u32 oldcsum)
{
__u32 size = sizeof(struct iphdr);
__u32 csum = bpf_csum_diff((__be32 *)oldip, size, (__be32 *)ip, size,
~oldcsum);
__u32 oldcsum) {
__u32 size = sizeof (struct iphdr);
__u32 csum = bpf_csum_diff((__be32 *) oldip, size, (__be32 *) ip, size,
~oldcsum);
__u32 sum = (csum >> 16) + (csum & 0xffff);
sum += (sum >> 16);
return sum;
}
#define dhcp_offset \
sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr)
//offsetof(struct dhcp_packet, options)
/* Offset to DHCP Options part of the packet */
#define static_offset \
sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) + \
@@ -59,26 +76,56 @@ static __always_inline int calc_ip_csum(struct iphdr *oldip, struct iphdr *ip,
/* Delta value to be adjusted at xdp head*/
#define delta sizeof(struct dhcp_option_82)
#ifndef DHCP_MAX_OPTIONS
#define DHCP_MAX_OPTIONS 20
#endif
/* buf needs to be a static global var because the verifier won't allow
* unaligned stack accesses
*/
static __u8 buf[static_offset + VLAN_MAX_DEPTH * sizeof(struct vlan_hdr)];
*/
//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)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct collect_vlans vlans = { 0 };
int xdp_dhcp_relay(struct xdp_md *ctx) {
bpf_printk("\n");
/* Tail extend packet */
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;
}
//bpf_printk("static_offset %i (hex %x)", static_offset, static_offset);
//bpf_printk("dhcp_offset %i (hex %x)", dhcp_offset, dhcp_offset);
void *data_end = (void *) (long) ctx->data_end;
void *data = (void *) (long) ctx->data;
struct collect_vlans vlans = {0};
struct ethhdr *eth;
struct iphdr *ip;
struct iphdr oldip;
struct udphdr *udp;
__u32 *dhcp_srv;
struct dhcp_packet *dhcp;
__u32 *dhcp_srv_ip;
__u32 *relay_agent_ip;
__u64 *relay_hwaddr;
int rc = XDP_PASS;
__u16 offset = static_offset;
__u16 option_offset = offset;
__u16 ip_offset = 0;
__u16 vlan_length = 0;
__u8 option_code = 0;
__u8 option_length = 0;
int i = 0;
/* These keep track of the next header type and iterator pointer */
@@ -95,89 +142,254 @@ int xdp_dhcp_relay(struct xdp_md *ctx)
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;
goto out;
}
if (ether_type != bpf_htons(ETH_P_IP))
if (ether_type != bpf_htons(ETH_P_IP)) {
bpf_printk("Ethertype %#x is not ETH_P_IP", bpf_ntohs(ether_type));
goto out;
}
bpf_printk("Ethertype %x", bpf_ntohs(ether_type));
/* Check at least two vlan tags are present */
if (vlans.id[1] == 0)
goto out;
/* Read dhcp relay server IP from map */
dhcp_srv = bpf_map_lookup_elem(&dhcp_server, &key);
if (dhcp_srv == NULL)
if (vlans.id[1] == 0) {
bpf_printk("No VLAN tags set");
goto out;
}
h_proto = parse_iphdr(&nh, data_end, &ip);
/* only handle fixed-size IP header due to static copy */
/* Only handle fixed-size IP header due to static copy */
if (h_proto != IPPROTO_UDP || ip->ihl > 5) {
goto out;
}
/*old ip hdr backup for re-calculating the checksum later*/
/* Old ip hdr backup for re-calculating the checksum later */
oldip = *ip;
ip_offset = ((void *)ip - data) & 0x3fff;
ip_offset = ((void *) ip - data) & 0x3fff;
len = parse_udphdr(&nh, data_end, &udp);
if (len < 0)
goto out;
if (udp->dest != bpf_htons(DEST_PORT))
/* Handle DHCP packets only */
if (udp->dest != bpf_htons(DHCP_SERVER_PORT) && udp->dest != bpf_htons(DHCP_CLIENT_PORT))
goto out;
if (xdp_load_bytes(ctx, 0, buf, static_offset))
/* Read DHCP server IP from config map */
key = 0;
dhcp_srv_ip = bpf_map_lookup_elem(&relay_config, &key);
if (dhcp_srv_ip == NULL)
goto out;
/* Read relay agent IP from config map */
key = 1;
relay_agent_ip = bpf_map_lookup_elem(&relay_config, &key);
if (relay_agent_ip == NULL)
goto out;
/* Read relay agent MAC address from config map */
key = 2;
relay_hwaddr = bpf_map_lookup_elem(&relay_config, &key);
if (relay_hwaddr == NULL)
goto out;
/* Copy headers of packet to buf */
//if (xdp_load_bytes(ctx, 0, buf, static_offset))
// goto out;
/* Increment offset by 4 bytes for each VLAN (to accomodate VLAN headers */
for (i = 0; i < VLAN_MAX_DEPTH; i++) {
if (vlans.id[i]) {
if (xdp_load_bytes(ctx, offset, buf + offset, 4))
goto out;
bpf_printk("Found VLAN tag %i at depth %i", vlans.id[i], i);
/* For each VLAN present, copy 4 bytes of DHCP options to buffer */
//if (xdp_load_bytes(ctx, offset, buf + offset, 4))
// goto out;
offset += 4;
vlan_length += 4;
}
}
/* adjusting the packet head by delta size to insert option82 */
if (bpf_xdp_adjust_head(ctx, 0 - (int)delta) < 0)
return XDP_ABORTED;
/* Find packet boundaries */
data_end = (void *) (long) ctx->data_end;
data = (void *) (long) ctx->data;
data_end = (void *)(long)ctx->data_end;
data = (void *)(long)ctx->data;
/* Parse DHCP packet */
if (data + vlan_length + dhcp_offset + sizeof (dhcp) > data_end) {
goto out;
}
dhcp = data + vlan_length + dhcp_offset;
bpf_printk("Parsing DHCP packet, opcode %i, hops %i", dhcp->op, dhcp->hops);
if (dhcp->op == DHCP_REQUEST && (eth->h_dest[0] == 0xff
&& eth->h_dest[1] == 0xff
&& eth->h_dest[2] == 0xff
&& eth->h_dest[3] == 0xff
&& eth->h_dest[4] == 0xff
&& eth->h_dest[5] == 0xff)) {
/* Request from client received as broadcast */
bpf_printk("Broadcast packet received, opcode %i, hops %i", dhcp->op, dhcp->hops);
// Set destination MAC
memcpy(eth->h_dest, relay_hwaddr, ETH_ALEN);
// Set source MAC
//memcpy(eth->h_source, relay_hwaddr, ETH_ALEN);
// Set GIADDR
if(&dhcp->giaddr.s_addr + sizeof(relay_agent_ip) > data_end) {
rc = XDP_ABORTED;
goto out;
}
dhcp->giaddr.s_addr = *relay_agent_ip;
} else if (dhcp->op == DHCP_REPLY && (eth->h_dest[0] != 0xff
|| eth->h_dest[1] != 0xff
|| eth->h_dest[2] != 0xff
|| eth->h_dest[3] != 0xff
|| eth->h_dest[4] != 0xff
|| eth->h_dest[5] != 0xff)) {
/* Response from server received as unicast */
bpf_printk("Unicast packet received, opcode %i, hops %i", dhcp->op, dhcp->hops);
/* FIXME: Add code for reply packets
* Basically:
* - Set dest and src MAC
* - Add VLAN tags
* - Remove option 82
* - Use XDP_TX (or XDP_REDIRECT) to send the response
* to the end user
*/
}
/* Check hops */
if (dhcp->hops > 16) {
bpf_printk("Max hops exceeded, discarding packet");
rc = XDP_ABORTED;
goto out;
}
/* Increment hops */
dhcp->hops++;
/* Check if we exceed boundaries to make verifier happy */
if (data + offset > data_end)
return XDP_ABORTED;
goto out;
if (xdp_store_bytes(ctx, 0, buf, static_offset, 0))
return XDP_ABORTED;
option_offset = offset;
if (offset > static_offset) {
__u8 *pos = (__u8 *) (data + option_offset);
/* Loop through all DHCP options */
#pragma unroll DHCP_MAX_OPTIONS
for (i = 0; i < DHCP_MAX_OPTIONS; i++) {
/* Verifier check */
if (pos + 1 > data_end)
break;
option_code = *pos;
bpf_printk("Got option code %i at offset %i, hex %x", option_code, option_offset, option_offset);
if (option_code == 255) {
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)) {
bpf_printk("Could not write DHCP option 82 at offset %i", option_offset);
return XDP_ABORTED;
}
/* Set END option */
/* Verifier check */
if (pos + delta > data_end) {
return XDP_ABORTED;
}
pos += delta;
option_offset += delta;
if (write_dhcp_option_255(ctx, option_offset)) {
bpf_printk("Could not write DHCP option 255 at offset %i", option_offset);
return XDP_ABORTED;
}
break;
}
pos++;
option_length = *pos;
option_offset += option_length + 2;
if (pos + 1 > data_end) {
break;
}
pos++;
if (pos + option_length > data_end) {
break;
}
pos += option_length;
}
//return XDP_PASS;
/* Copy stored headers from buf to context */
/*if (xdp_store_bytes(ctx, 0, buf, static_offset, 0)) {
bpf_printk("xdp_store_bytes(ctx, 0, buf, %i) failed", static_offset);
return XDP_ABORTED;
}*/
/* make space for option 82 - copy DHCP options after increasing offset */
/*if (offset > static_offset) {
offset = static_offset;
for (i = 0; i < VLAN_MAX_DEPTH; i++) {
if (vlans.id[i]) {
if (xdp_store_bytes(ctx, offset, buf + offset,
4, 0))
return XDP_ABORTED;
offset += 4;
}
}
}
if (write_dhcp_option(ctx, offset, &vlans))
if (vlans.id[i]) {*/
/* */
/*if (xdp_store_bytes(ctx, offset, buf + offset,
4, 0))
return XDP_ABORTED;
offset += 4;
}
}
}*/
ip = data + ip_offset;
if (ip + 1 > data_end)
return XDP_ABORTED;
/* overwrite the destination IP in IP header */
ip->daddr = *dhcp_srv;
/* Overwrite the destination IP in IP header */
ip->daddr = *dhcp_srv_ip;
//re-calc ip checksum
/* Overwrite source IP */
ip->saddr = *relay_agent_ip;
/* Re-calculate ip checksum */
__u32 sum = calc_ip_csum(&oldip, ip, oldip.check);
ip->check = ~sum;
rc = XDP_PASS;
bpf_printk("Wrote DHCP option at offset %i, returning XDP_PASS", offset);
goto out;
out:
return rc;
}
char _license[] SEC("license") = "GPL";

View File

@@ -13,21 +13,24 @@
#include <linux/if_link.h> /* depend on kernel-headers installed */
#include <arpa/inet.h>
#define SERVER_MAP "dhcp_server"
#include <sys/ioctl.h>
#include <unistd.h>
#define SERVER_MAP "relay_config"
#define XDP_OBJ "dhcp_kern_xdp.o"
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "help", no_argument, NULL, 'h'},
{ "interface", required_argument, NULL,
'i' }, // Name of interface to run on
{ "dhcp-server", required_argument, NULL, 'd' },
{ "mode", required_argument, NULL, 'm' },
{ "unload", no_argument, NULL, 'u' },
{ 0, 0, NULL, 0 }
'i'}, // Name of interface to run on
{ "dhcp-server", required_argument, NULL, 'd'},
{ "relay-agent-address", required_argument, NULL, 's'},
{ "mode", required_argument, NULL, 'm'},
{ "unload", no_argument, NULL, 'u'},
{ 0, 0, NULL, 0}
};
static void print_usage(char *argv[])
{
static void print_usage(char *argv[]) {
int i;
printf("Usage:\n");
printf("%s\n", argv[0]);
@@ -45,8 +48,7 @@ static void print_usage(char *argv[])
printf("\n");
}
static int xdp_link_detach(int ifindex, __u32 xdp_flags)
{
static int xdp_link_detach(int ifindex, __u32 xdp_flags) {
int err;
if ((err = bpf_set_link_xdp_fd(ifindex, -1, xdp_flags)) < 0) {
@@ -57,8 +59,7 @@ static int xdp_link_detach(int ifindex, __u32 xdp_flags)
return 0;
}
int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd)
{
int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd) {
int err;
/* libbpf provide the XDP net_device link-level hook attach helper */
@@ -71,15 +72,15 @@ int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd)
ifindex, -err, strerror(-err));
switch (-err) {
case EBUSY:
case EEXIST:
fprintf(stderr, "Hint: XDP already loaded on device\n");
break;
case EOPNOTSUPP:
fprintf(stderr, "Hint: Native-XDP not supported\n");
break;
default:
break;
case EBUSY:
case EEXIST:
fprintf(stderr, "Hint: XDP already loaded on device\n");
break;
case EOPNOTSUPP:
fprintf(stderr, "Hint: Native-XDP not supported\n");
break;
default:
break;
}
return -1;
}
@@ -90,9 +91,9 @@ int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd)
/* User program takes two or three arguments
* interface name, relay server IP and prog
* unload flag
*/
int main(int argc, char **argv)
{
*/
int main(int argc, char **argv) {
char filename[256] = "dhcp_kern_xdp.o";
int prog_fd, err;
int opt;
@@ -104,64 +105,100 @@ int main(int argc, char **argv)
struct bpf_object *obj = NULL;
int map_fd;
int key = 0;
struct in_addr addr = {};
bool addr_set = false;
struct in_addr dhcp_server_addr = {};
struct in_addr relay_agent_addr = {};
bool dhcp_server_addr_set = false;
bool relay_agent_addr_set = false;
__u16 ifindex = 0;
int fd;
unsigned char *mac;
struct ifreq ifr;
while ((opt = getopt_long(argc, argv, "hui:d:m:", options, NULL)) !=
-1) {
while ((opt = getopt_long(argc, argv, "hui:d:m:s:", options, NULL)) !=
-1) {
switch (opt) {
case 'i':
strncpy(dev, optarg, IF_NAMESIZE);
dev[IF_NAMESIZE - 1] = '\0';
ifindex = if_nametoindex(dev);
if (ifindex <= 0) {
printf("Couldn't find ifname:%s \n", dev);
return -EINVAL;
}
break;
case 'd':
if (inet_aton(optarg, &addr) == 0) {
fprintf(stderr,
"Couldn't validate IP address:%s\n",
optarg);
return -EINVAL;
}
addr_set = true;
break;
case 'm':
if (strcmp(optarg, "skb") == 0) {
xdp_flags = XDP_FLAGS_SKB_MODE;
} else if (strcmp(optarg, "drv") != 0) {
fprintf(stderr, "Invalid mode: %s\n", optarg);
return -EINVAL;
}
case 'i':
strncpy(dev, optarg, IF_NAMESIZE);
dev[IF_NAMESIZE - 1] = '\0';
ifindex = if_nametoindex(dev);
if (ifindex <= 0) {
printf("Couldn't find ifname:%s \n", dev);
return -EINVAL;
}
break;
case 'd': // DHCP server address
if (inet_aton(optarg, &dhcp_server_addr) == 0) {
fprintf(stderr,
"Couldn't validate DHCP server IP address:%s\n",
optarg);
return -EINVAL;
}
dhcp_server_addr_set = true;
break;
case 's': // Relay agent address
if (inet_aton(optarg, &relay_agent_addr) == 0) {
fprintf(stderr,
"Couldn't validate relay agent IP address:%s\n",
optarg);
return -EINVAL;
}
relay_agent_addr_set = true;
break;
case 'm':
if (strcmp(optarg, "skb") == 0) {
xdp_flags = XDP_FLAGS_SKB_MODE;
} else if (strcmp(optarg, "drv") != 0) {
fprintf(stderr, "Invalid mode: %s\n", optarg);
return -EINVAL;
}
break;
case 'u':
do_unload = 1;
break;
case 'h':
print_usage(argv);
exit(0);
default:
fprintf(stderr, "Unknown option %s\n", argv[optind]);
return -EINVAL;
break;
case 'u':
do_unload = 1;
break;
case 'h':
print_usage(argv);
exit(0);
default:
fprintf(stderr, "Unknown option %s\n", argv[optind]);
return -EINVAL;
}
}
if (!ifindex) {
fprintf(stderr, "Missing ifname\n");
fprintf(stderr, "Please specify interface name\n");
return -EINVAL;
}
if (!addr_set) {
fprintf(stderr, "Missing server address\n");
if (!dhcp_server_addr_set) {
fprintf(stderr, "Please specify DHCP server address with -d parameter\n");
return -EINVAL;
}
if (!relay_agent_addr_set) {
fprintf(stderr, "Please specify DHCP relay agent address with -s parameter\n");
return -EINVAL;
}
if (do_unload)
return xdp_link_detach(ifindex, xdp_flags);
// Find MAC address of interface
fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, dev, IF_NAMESIZE);
ioctl(fd, SIOCGIFHWADDR, &ifr);
close(fd);
mac = (unsigned char *) ifr.ifr_hwaddr.sa_data;
__u64 hwaddr = 0;
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]);
/* 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);
if (err) {
@@ -191,7 +228,27 @@ int main(int argc, char **argv)
exit(-1);
}
err = bpf_map_update_elem(map_fd, &key, &addr.s_addr, BPF_ANY);
// Set DHCP server address
key = 0;
err = bpf_map_update_elem(map_fd, &key, &dhcp_server_addr.s_addr, BPF_ANY);
if (err) {
fprintf(stderr, "Could not update map %s in %s\n", SERVER_MAP,
XDP_OBJ);
exit(-1);
}
// Set relay agent IP address
key = 1;
err = bpf_map_update_elem(map_fd, &key, &relay_agent_addr.s_addr, BPF_ANY);
if (err) {
fprintf(stderr, "Could not update map %s in %s\n", SERVER_MAP,
XDP_OBJ);
exit(-1);
}
// Set relay agent MAC address
key = 2;
err = bpf_map_update_elem(map_fd, &key, &hwaddr, BPF_ANY);
if (err) {
fprintf(stderr, "Could not update map %s in %s\n", SERVER_MAP,
XDP_OBJ);