pmlag

Poor man's link aggregation
git clone git://git.finwo.net/app/pmlag
Log | Files | Refs | README | LICENSE

commit 7ec86efc4ed1c6a8e112e5afca6c5c310a34ef27
parent b939f76bbb2fc40c1996c1296b9e2febb2a98c6e
Author: Robin Bron <robin@finwo.nl>
Date:   Sun, 26 Feb 2023 01:09:53 +0100

Data being transferred through the bond again

Diffstat:
Msrc/main.c | 229-------------------------------------------------------------------------------
Msrc/task/bond.c | 195++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/task/iface.c | 104+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/task/iface.h | 2+-
Msrc/util/config.c | 29+++++++++++++----------------
Msrc/util/config.h | 13++++---------
Asrc/util/linked-list.h | 6++++++
Msrc/util/routing-table.c | 15+++++++++++++++
Msrc/util/routing-table.h | 14++++++++++++++
9 files changed, 351 insertions(+), 256 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -22,8 +22,6 @@ #include "task/bond.h" /* #include "socket.h" */ -#define RCVBUFSIZ 65536 - static const char *const usage[] = { __NAME " [options]", NULL @@ -118,223 +116,7 @@ static const char *const usage[] = { /* pthread_mutex_unlock(&(iface->bond->mtx_rt)); */ /* } */ -/* void * thread_iface(void *arg) { */ -/* struct pmlag_iface *iface = (struct pmlag_iface *)arg; */ - -/* // Open socket for the interface in the bond */ -/* iface->sockfd = sockraw_open(iface->name); */ -/* if (iface->sockfd < 0) { */ -/* pthread_exit(NULL); */ -/* return NULL; */ -/* } */ - -/* // Reserve receive buffer, support 64k packets just in case */ -/* int buflen; */ -/* unsigned char *buffer = (unsigned char *) malloc(RCVBUFSIZ); */ -/* struct sockaddr saddr; */ -/* int saddr_len = sizeof(saddr); */ - -/* // Get the interface's idx on the socket */ -/* iface->ifidx = iface_idx(iface->sockfd, iface->name); */ - -/* /1* printf("Thread started for iface: %s->%s(%d)\n", iface->bond->name, iface->name, iface->sockfd); *1/ */ - -/* // Wait for the bond thread to finish initializing */ -/* pthread_mutex_lock(&(iface->bond->mtx_rt)); */ -/* pthread_mutex_unlock(&(iface->bond->mtx_rt)); */ - -/* // Find bond socket iface_idx */ -/* int send_len; */ -/* uint16_t proto; */ -/* uint16_t bcidx; */ - -/* size_t rt_len; */ - -/* while(1) { */ - -/* // Zero out buffer, to prevent pollution, & receive packet {{{ */ -/* /1* memset(buffer, 0, RCVBUFSIZ); *1/ */ -/* buflen = recvfrom(iface->sockfd, buffer, RCVBUFSIZ, 0, &saddr, (socklen_t *)&saddr_len); */ -/* if (buflen < 0) { */ -/* perror("recvfrom"); */ -/* pthread_exit(NULL); */ -/* return NULL; */ -/* } */ -/* // }}} */ - -/* printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x < %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%d)\n", */ -/* buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5], // DST */ -/* buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11], // SRC */ -/* ((unsigned int)((unsigned char)buffer[12]) << 8) + buffer[13], // PROTO */ -/* buflen */ -/* ); */ - -/* // Update routing table if our custom protocol is seen */ -/* proto = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+0]) << 8) + buffer[(ETH_ALEN*2)+1]; */ -/* if (proto == 0x0666) { */ -/* bcidx = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+2]) << 8) + buffer[(ETH_ALEN*2)+3]; */ -/* iface_add_rt(iface, buffer+ETH_ALEN, bcidx); */ -/* continue; */ -/* } else { */ -/* iface_add_rt(iface, buffer+ETH_ALEN, 0); */ -/* } */ - -/* /1* trim_rt(iface->bond, *1/ */ -/* rt_len = btree_count(iface->bond->rt); */ -/* printf("Current RT length: %ld\n", rt_len); */ - -/* // Redirect packet to bond socket as-is */ -/* send_len = write(iface->bond->sockfd, buffer, buflen); */ -/* if (buflen != send_len) { */ -/* perror("write(bond)"); */ -/* /1* pthread_exit(NULL); *1/ */ -/* /1* return NULL; *1/ */ -/* } */ - -/* } */ - -/* pthread_exit(NULL); */ -/* return NULL; */ -/* } */ - -/* void * thread_bond(void *arg) { */ -/* struct pmlag_bond *bond = (struct pmlag_bond *)arg; */ -/* /1* printf("Thread started for bond: %s\n", bond->name); *1/ */ - -/* // Assign bond interface */ -/* unsigned char *mac = iface_mac(bond->interfaces->name); */ -/* bond->sockfd = tap_alloc(bond->name, mac); */ -/* printf("FREE LINE %d (%p)\n", __LINE__, mac); */ -/* free(mac); */ -/* if (bond->sockfd < 0) { */ -/* perror("Allocating bond interface"); */ -/* pthread_exit(NULL); */ -/* return NULL; */ -/* }; */ - -/* // Lock this bond's routing table */ -/* pthread_mutex_lock(&(bond->mtx_rt)); */ - -/* // Start thread for each interface of this bond */ -/* struct pmlag_iface *iface = bond->interfaces; */ -/* while(iface) { */ -/* if(pthread_create(&(iface->tid), NULL, thread_iface, iface)) { */ -/* perror("Starting iface thread"); */ -/* pthread_exit((void*)1); */ -/* return (void*)1; */ -/* } */ -/* iface = iface->next; */ -/* } */ - -/* // Give iface threads time to run into the lock */ -/* /1* sleep(1); *1/ */ -/* // Free this bond's routing table */ -/* pthread_mutex_unlock(&(bond->mtx_rt)); */ - -/* int buflen, send_len; */ -/* unsigned char *buffer = (unsigned char *) malloc(RCVBUFSIZ); */ -/* struct sockaddr_ll saddr_ll; */ -/* saddr_ll.sll_halen = ETH_ALEN; */ - -/* struct pmlag_rt_entry *rt_entry; */ -/* int iface_list_len; */ -/* int iface_list_sel; */ -/* pmlag_iface_llist *iface_list_entry; */ - -/* sleep(1); */ - -/* while(1) { */ -/* /1* sleep(1); *1/ */ - -/* buflen = read(bond->sockfd, buffer, RCVBUFSIZ); */ -/* if (buflen < 0) { */ -/* perror("read(bond)"); */ -/* pthread_exit(NULL); */ -/* return NULL; */ -/* } */ - -/* /1* printf("\n"); *1/ */ -/* /1* printf("Got packet: %d bytes\n", buflen); *1/ */ - -/* /1* printf("Ethernet header\n"); *1/ */ -/* printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x > %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%d)\n", */ -/* buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11], // SRC */ -/* buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5], // DST */ -/* ((unsigned int)((unsigned char)buffer[12]) << 8) + buffer[13], // PROTO */ -/* buflen */ -/* ); */ - -/* // Insert destination MAC into saddr_ll */ -/* memcpy(saddr_ll.sll_addr, buffer, ETH_ALEN); */ - -/* // Fetch entry from routing table */ -/* pthread_mutex_lock(&(bond->mtx_rt)); */ -/* rt_entry = btree_get(bond->rt, &(struct pmlag_rt_entry){ .mac = buffer }); */ - -/* // Broadcast on ALL interfaces if no rt entry OR broadcast packet */ -/* if ((!rt_entry) || (memcmp(buffer, "\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ALEN) == 0)) { */ -/* pthread_mutex_unlock(&(bond->mtx_rt)); */ -/* iface = bond->interfaces; */ -/* while(iface) { */ -/* saddr_ll.sll_ifindex = iface->ifidx; */ -/* send_len = sendto(iface->sockfd, buffer, buflen, 0, (const struct sockaddr*)&saddr_ll, sizeof(struct sockaddr_ll)); */ -/* if(send_len != buflen) { */ -/* perror("sendto"); */ -/* /1* pthread_exit(NULL); *1/ */ -/* /1* return NULL; *1/ */ -/* } */ -/* iface = iface->next; */ -/* } */ -/* continue; */ -/* } */ - -/* // Fetch length of interface list */ -/* iface_list_len = 0; */ -/* iface_list_entry = rt_entry->interfaces; */ -/* while(iface_list_entry) { */ -/* iface_list_len++; */ -/* iface_list_entry = iface_list_entry->next; */ -/* } */ - -/* // Select interface at random */ -/* iface_list_sel = rand() % iface_list_len; */ -/* iface_list_entry = rt_entry->interfaces; */ -/* while(iface_list_sel--) iface_list_entry = iface_list_entry->next; */ -/* iface = iface_list_entry->data; */ - -/* // Unlock routing table */ -/* pthread_mutex_unlock(&(bond->mtx_rt)); */ - -/* // Prepare saddr_ll for sendto */ -/* saddr_ll.sll_ifindex = iface->ifidx; */ -/* memcpy(saddr_ll.sll_addr, buffer, ETH_ALEN); */ - -/* // Forward packet to iface as-is */ -/* send_len = sendto(iface->sockfd, buffer, buflen, 0, (const struct sockaddr*)&saddr_ll, sizeof(struct sockaddr_ll)); */ -/* if(send_len != buflen) { */ -/* perror("sendto"); */ -/* /1* pthread_exit(NULL); *1/ */ -/* /1* return NULL; *1/ */ -/* } */ -/* } */ - -/* // Wait for iface threads to finish */ -/* iface = bond->interfaces; */ -/* while(iface) { */ -/* pthread_join(iface->tid, NULL); */ -/* iface = iface->next; */ -/* } */ - -/* pthread_exit(NULL); */ -/* return NULL; */ -/* } */ - -/* static int compare_rt_entries(const void *a, const void *b, void *udata) { */ -/* struct pmlag_rt_entry *ta = (struct pmlag_rt_entry*)a; */ -/* struct pmlag_rt_entry *tb = (struct pmlag_rt_entry*)b; */ -/* return memcmp(ta->mac, tb->mac, ETH_ALEN); */ -/* } */ int main(int argc, const char **argv) { char *config_file="/etc/pmlag/pmlag.ini"; @@ -357,8 +139,6 @@ int main(int argc, const char **argv) { ); argc = argparse_parse(&argparse, argc, argv); - printf("config file: %s\n", config_file); - // Load configuration file struct pmlag_configuration *config = config_load(config_file); if (!config) { @@ -369,15 +149,6 @@ int main(int argc, const char **argv) { struct pmlag_bond *bond = config->bonds; while(bond) { - /* // Initialize routing table lock */ - /* if (pthread_mutex_init(&(bond->mtx_rt), NULL) != 0) { */ - /* perror("Initializing mutex for bond"); */ - /* return 1; */ - /* } */ - - /* // Initialize routing table */ - /* bond->rt = btree_new(sizeof(void*), 0, compare_rt_entries, bond); */ - // Start the bond's thread if(pthread_create(&(bond->tid), NULL, task_bond_thread, bond)) { perror("Starting bond thread"); diff --git a/src/task/bond.c b/src/task/bond.c @@ -1,10 +1,203 @@ +#include <linux/if_ether.h> +#include <linux/if_packet.h> +#include <pthread.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> +#include "tidwall/btree.h" +#include "../util/config.h" +#include "../util/routing-table.h" +#include "../util/socket.h" +#include "iface.h" +int task_bond_onpacket(struct pmlag_bond *bond, unsigned char *buffer, size_t buflen) { + struct sockaddr_ll saddr_ll; + saddr_ll.sll_halen = ETH_ALEN; + + // Debug: print eth header + printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x > %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%ld)\n", + buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11], // SRC + buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5], // DST + ((unsigned int)((unsigned char)buffer[12]) << 8) + buffer[13], // PROTO + buflen + ); + + // Send packet to the first available iface + struct pmlag_iface *iface = bond->interfaces->data; + +/* // Select interface at random */ +/* iface_list_sel = rand() % iface_list_len; */ +/* iface_list_entry = rt_entry->interfaces; */ +/* while(iface_list_sel--) iface_list_entry = iface_list_entry->next; */ +/* iface = iface_list_entry->data; */ + +/* // Unlock routing table */ +/* pthread_mutex_unlock(&(bond->mtx_rt)); */ + + // Prepare saddr_ll for sendto + saddr_ll.sll_ifindex = iface->ifidx; + memcpy(saddr_ll.sll_addr, buffer, ETH_ALEN); + + // Forward packet to iface as-is + size_t send_len = sendto(iface->sockfd, buffer, buflen, 0, (const struct sockaddr*)&saddr_ll, sizeof(struct sockaddr_ll)); + if(send_len != buflen) { + perror("sendto"); + return 1; + } + + return 0; +} + +// Responsible for init + calling task_bond_onpacket void * task_bond_thread(void *arg) { + struct pmlag_bond *bond = arg; + + // Initialize routing table lock + if (pthread_mutex_init(&(bond->mtx_rt), NULL) != 0) { + perror("Initializing mutex for bond"); + pthread_exit(NULL); + return NULL; + } + + // Initialize routing table + bond->rt = rt_init(bond); + + // Assign bond interface + unsigned char *mac = iface_mac(bond->interfaces->data->name); + bond->sockfd = tap_alloc(bond->name, mac); + free(mac); + if (bond->sockfd < 0) { + perror("Allocating bond interface"); + pthread_exit(NULL); + return NULL; + }; + + // Lock this bond's routing table + pthread_mutex_lock(&(bond->mtx_rt)); + + // Start thread for each interface of this bond + pmlag_iface_llist *iface_entry = bond->interfaces; + while(iface_entry) { + if(pthread_create(&(iface_entry->data->tid), NULL, task_iface_thread, iface_entry->data)) { + perror("Starting iface thread"); + pthread_exit((void*)1); + return (void*)1; + } + iface_entry = iface_entry->next; + } + + // Free this bond's routing table + pthread_mutex_unlock(&(bond->mtx_rt)); + + // Predefine things we'll re-use + size_t buflen; + unsigned char *buffer = (unsigned char *) malloc(RCVBUFSIZ); + + // TODO: replace by waiting for the iface to finish initializing + sleep(1); + + // This is our life now + while(1) { + + // Wait for a packet to arrive + buflen = read(bond->sockfd, buffer, RCVBUFSIZ); + if (buflen < 0) { + perror("read(bond)"); + pthread_exit(NULL); + return NULL; + } + + // And let the more specific method handle the packet + if(task_bond_onpacket(bond, buffer, buflen)) { + pthread_exit(NULL); + return NULL; + } + + } + + // Wait for iface threads to finish + iface_entry = bond->interfaces; + while(iface_entry) { + pthread_join(iface_entry->data->tid, NULL); + iface_entry = iface_entry->next; + } + + pthread_exit(NULL); + return NULL; +} + +void * thread_bond_old(void *arg) { +/* struct pmlag_rt_entry *rt_entry; */ +/* int iface_list_len; */ +/* int iface_list_sel; */ +/* pmlag_iface_llist *iface_list_entry; */ + +/* sleep(1); */ + +/* while(1) { */ +/* /1* sleep(1); *1/ */ + +/* // Fetch entry from routing table */ +/* pthread_mutex_lock(&(bond->mtx_rt)); */ +/* rt_entry = btree_get(bond->rt, &(struct pmlag_rt_entry){ .mac = buffer }); */ + +/* // Broadcast on ALL interfaces if no rt entry OR broadcast packet */ +/* if ((!rt_entry) || (memcmp(buffer, "\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ALEN) == 0)) { */ +/* pthread_mutex_unlock(&(bond->mtx_rt)); */ +/* iface = bond->interfaces; */ +/* while(iface) { */ +/* saddr_ll.sll_ifindex = iface->ifidx; */ +/* send_len = sendto(iface->sockfd, buffer, buflen, 0, (const struct sockaddr*)&saddr_ll, sizeof(struct sockaddr_ll)); */ +/* if(send_len != buflen) { */ +/* perror("sendto"); */ +/* /1* pthread_exit(NULL); *1/ */ +/* /1* return NULL; *1/ */ +/* } */ +/* iface = iface->next; */ +/* } */ +/* continue; */ +/* } */ + +/* // Fetch length of interface list */ +/* iface_list_len = 0; */ +/* iface_list_entry = rt_entry->interfaces; */ +/* while(iface_list_entry) { */ +/* iface_list_len++; */ +/* iface_list_entry = iface_list_entry->next; */ +/* } */ + +/* // Select interface at random */ +/* iface_list_sel = rand() % iface_list_len; */ +/* iface_list_entry = rt_entry->interfaces; */ +/* while(iface_list_sel--) iface_list_entry = iface_list_entry->next; */ +/* iface = iface_list_entry->data; */ + +/* // Unlock routing table */ +/* pthread_mutex_unlock(&(bond->mtx_rt)); */ + +/* // Prepare saddr_ll for sendto */ +/* saddr_ll.sll_ifindex = iface->ifidx; */ +/* memcpy(saddr_ll.sll_addr, buffer, ETH_ALEN); */ + +/* // Forward packet to iface as-is */ +/* send_len = sendto(iface->sockfd, buffer, buflen, 0, (const struct sockaddr*)&saddr_ll, sizeof(struct sockaddr_ll)); */ +/* if(send_len != buflen) { */ +/* perror("sendto"); */ +/* /1* pthread_exit(NULL); *1/ */ +/* /1* return NULL; *1/ */ +/* } */ +/* } */ - printf("Thread started!\n"); + /* // Wait for iface threads to finish */ + /* iface = bond->interfaces; */ + /* while(iface) { */ + /* pthread_join(iface->tid, NULL); */ + /* iface = iface->next; */ + /* } */ + pthread_exit(NULL); return NULL; } diff --git a/src/task/iface.c b/src/task/iface.c @@ -0,0 +1,104 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <unistd.h> + +#include "../util/config.h" +#include "../util/socket.h" + +void * task_iface_thread(void *arg) { + struct pmlag_iface *iface = arg; + + // Open socket for the interface in the bond + iface->sockfd = sockraw_open(iface->name); + if (iface->sockfd < 0) { + pthread_exit(NULL); + return NULL; + } + + // Get the interface's idx on the socket + iface->ifidx = iface_idx(iface->sockfd, iface->name); + + // Reserve receive buffer, support 64k packets just in case + size_t buflen, send_len; + unsigned char *buffer = (unsigned char *) malloc(RCVBUFSIZ); + struct sockaddr saddr; + int saddr_len = sizeof(saddr); + + // Wait for the bond thread to finish initializing + pthread_mutex_lock(&(iface->bond->mtx_rt)); + pthread_mutex_unlock(&(iface->bond->mtx_rt)); + + printf("Thread started for iface %s\n", iface->name); + + // This is our life now + while(1) { + + // Zero out buffer, to prevent pollution, & receive packet + memset(buffer, 0, RCVBUFSIZ); + buflen = recvfrom(iface->sockfd, buffer, RCVBUFSIZ, 0, &saddr, (socklen_t *)&saddr_len); + if (buflen < 0) { + perror("recvfrom"); + pthread_exit(NULL); + return NULL; + } + + // Debug: print eth header + printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x < %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%ld)\n", + buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5], // DST + buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11], // SRC + ((unsigned int)((unsigned char)buffer[12]) << 8) + buffer[13], // PROTO + buflen + ); + + // Redirect packet to bond socket as-is + send_len = write(iface->bond->sockfd, buffer, buflen); + if (buflen != send_len) { + perror("write(bond)"); + pthread_exit(NULL); + return NULL; + } + + /* sleep(1); */ + } + + return NULL; +} + + + +/* /1* printf("Thread started for iface: %s->%s(%d)\n", iface->bond->name, iface->name, iface->sockfd); *1/ */ + + +/* // Find bond socket iface_idx */ +/* int send_len; */ +/* uint16_t proto; */ +/* uint16_t bcidx; */ + +/* size_t rt_len; */ + +/* while(1) { */ + + + +/* // Update routing table if our custom protocol is seen */ +/* proto = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+0]) << 8) + buffer[(ETH_ALEN*2)+1]; */ +/* if (proto == 0x0666) { */ +/* bcidx = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+2]) << 8) + buffer[(ETH_ALEN*2)+3]; */ +/* iface_add_rt(iface, buffer+ETH_ALEN, bcidx); */ +/* continue; */ +/* } else { */ +/* iface_add_rt(iface, buffer+ETH_ALEN, 0); */ +/* } */ + +/* /1* trim_rt(iface->bond, *1/ */ +/* rt_len = btree_count(iface->bond->rt); */ +/* printf("Current RT length: %ld\n", rt_len); */ + + +/* } */ + +/* pthread_exit(NULL); */ +/* return NULL; */ +/* } */ diff --git a/src/task/iface.h b/src/task/iface.h @@ -1,7 +1,7 @@ #ifndef __PMLAG_TASK_IFACE_H__ #define __PMLAG_TASK_IFACE_H__ - +void * task_iface_thread(void *arg); #endif // __PMLAG_TASK_IFACE_H__ diff --git a/src/util/config.c b/src/util/config.c @@ -31,7 +31,7 @@ static int config_load_handler( } // Get interface being configured - struct pmlag_iface *iface = bond->interfaces; + pmlag_iface_llist *iface_entry = bond->interfaces; if (0) { // Intentionally empty @@ -51,28 +51,25 @@ static int config_load_handler( } else if (!strcmp(name, "interface")) { // Select the right interface - while(iface) { - if (!strcmp(iface->name, value)) { + while(iface_entry) { + if (!strcmp(iface_entry->data->name, value)) { break; } - iface = iface->next; + iface_entry = iface_entry->next; } // Create iface if not found - if (!iface) { - iface = calloc(1, sizeof(struct pmlag_iface)); - iface->next = bond->interfaces; - iface->name = strdup(value); - /* iface->weight = 10; */ - iface->bond = bond; - bond->interfaces = iface; + if (!iface_entry) { + // Create the list entry + iface_entry = calloc(1, sizeof(pmlag_iface_llist)); + iface_entry->next = bond->interfaces; + bond->interfaces = iface_entry; + // Create the iface + iface_entry->data = calloc(1, sizeof(struct pmlag_iface)); + iface_entry->data->name = strdup(value); + iface_entry->data->bond = bond; } - /* } else if (!strcmp(name, "weight")) { */ - /* if (!iface) { */ - /* return 0; */ - /* } */ - /* iface->weight = atoi(value); */ } else { // Unknown key return 0; diff --git a/src/util/config.h b/src/util/config.h @@ -6,6 +6,8 @@ #include "tidwall/btree.h" +#include "linked-list.h" + #ifdef __cplusplus extern "C" { #endif @@ -15,12 +17,11 @@ extern "C" { #define PMLAG_MODE_BROADCAST 2 #define PMLAG_MODE_BALANCED_RR 3 -#define LLIST(x) struct { void *next; x *data; } +#define RCVBUFSIZ 65536 typedef LLIST(struct pmlag_iface) pmlag_iface_llist; struct pmlag_iface { - void *next; // linked-list next reference char *name; // name of the interface this object represents /* int weight; // weight of this interface within the bond */ int sockfd; // file descriptor for the iface raw socket @@ -38,13 +39,7 @@ struct pmlag_bond { pthread_t tid; // thread id where the bond interface listener recides in pthread_mutex_t mtx_rt; // lock for the routing table of the bond struct btree *rt; // pointer to the routing table - struct pmlag_iface *interfaces; // linked-list of interfaces contained in the bond -}; - -struct pmlag_rt_entry { - unsigned char *mac; // mac address of the remote entity - uint16_t bcidx; // broadcast index last seen from the mac - pmlag_iface_llist *interfaces; // list of pointers to interfaces + pmlag_iface_llist *interfaces; // linked-list of interfaces contained in the bond }; struct pmlag_configuration { diff --git a/src/util/linked-list.h b/src/util/linked-list.h @@ -0,0 +1,6 @@ +#ifndef __PMLAG_UTIL_LL_H__ +#define __PMLAG_UTIL_LL_H__ + +#define LLIST(x) struct { void *next; x *data; } + +#endif // __PMLAG_UTIL_LL_H__ diff --git a/src/util/routing-table.c b/src/util/routing-table.c @@ -0,0 +1,15 @@ +#include <linux/if_ether.h> +#include <string.h> + +#include "tidwall/btree.h" +#include "routing-table.h" + +static int compare_rt_entries(const void *a, const void *b, void *udata) { + struct pmlag_rt_entry *ta = (struct pmlag_rt_entry*)a; + struct pmlag_rt_entry *tb = (struct pmlag_rt_entry*)b; + return memcmp(ta->mac, tb->mac, ETH_ALEN); +} + +struct btree * rt_init(void *udata) { + return btree_new(sizeof(void*), 0, compare_rt_entries, udata); +} diff --git a/src/util/routing-table.h b/src/util/routing-table.h @@ -0,0 +1,14 @@ +#ifndef __PMLAG_UTIL_RT_H__ +#define __PMLAG_UTIL_RT_H__ + +#include "config.h" + +struct pmlag_rt_entry { + unsigned char *mac; // mac address of the remote entity + uint16_t bcidx; // broadcast index last seen from the mac + pmlag_iface_llist *interfaces; // list of pointers to interfaces +}; + +struct btree * rt_init(void *udata); + +#endif // __PMLAG_UTIL_RT_H__