pmlag

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

commit b939f76bbb2fc40c1996c1296b9e2febb2a98c6e
parent cd0da59b7dec9892d6c1c9777e22dbc3c2ebdf56
Author: Robin Bron <robin@finwo.nl>
Date:   Sat, 25 Feb 2023 23:56:17 +0100

Added structure, back to bond thread initialization

Diffstat:
Dsrc/config.h | 61-------------------------------------------------------------
Msrc/main.c | 734++++++++++++++++++++++++++++++++++++++++---------------------------------------
Asrc/task/announce.c | 0
Asrc/task/announce.h | 7+++++++
Asrc/task/bond.c | 10++++++++++
Asrc/task/bond.h | 7+++++++
Asrc/task/iface.c | 0
Asrc/task/iface.h | 7+++++++
Rsrc/config.c -> src/util/config.c | 0
Asrc/util/config.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/routing-table.c | 0
Asrc/util/routing-table.h | 0
Rsrc/socket.c -> src/util/socket.c | 0
Rsrc/socket.h -> src/util/socket.h | 0
14 files changed, 460 insertions(+), 426 deletions(-)

diff --git a/src/config.h b/src/config.h @@ -1,61 +0,0 @@ -#ifndef __PMLAG_CONFIG_H__ -#define __PMLAG_CONFIG_H__ - -#include <pthread.h> -#include <stdint.h> - -#include "tidwall/btree.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define PMLAG_MODE_NONE 0 -#define PMLAG_MODE_ACTIVE_BACKUP 1 -#define PMLAG_MODE_BROADCAST 2 -#define PMLAG_MODE_BALANCED_RR 3 - -#define LLIST(x) struct { void *next; x *data; } - -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 - int ifidx; // index of the interface within the socket - pthread_t tid; // thread id where the iface listener recides in - struct pmlag_bond *bond; // reference to the bond this iface belongs to -}; - -struct pmlag_bond { - void *next; // linked-list next reference - char *name; // name of the bond interface - int mode; // which mode to run pmlag in for this bond - int sockfd; // file descriptor for the bond socket interface - uint16_t bcidx; // big-endian broadcast index for quickly detecting dead paths - 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 -}; - -struct pmlag_configuration { - struct pmlag_bond *bonds; -}; - -struct pmlag_configuration * config_load(const char * filename); - - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // __PMLAG_CONFIG_H__ diff --git a/src/main.c b/src/main.c @@ -17,8 +17,10 @@ #include "tidwall/btree.h" #include "cofyc/argparse.h" -#include "config.h" -#include "socket.h" +#include "util/config.h" + +#include "task/bond.h" +/* #include "socket.h" */ #define RCVBUFSIZ 65536 @@ -27,312 +29,312 @@ static const char *const usage[] = { NULL }; -void trim_rt(struct pmlag_bond *bond, size_t limit) { - -} - -void iface_add_rt(struct pmlag_iface *iface, unsigned char *mac, uint16_t bcidx) { - struct pmlag_rt_entry *rt_entry; - int iface_list_len; - struct pmlag_iface *iface_list_entry; - - pthread_mutex_lock(&(iface->bond->mtx_rt)); - printf("\nRCV bc: %s\n", iface->name); - - // Fetch or build rt entry - rt_entry = btree_get(iface->bond->rt, &(struct pmlag_rt_entry){ .mac = mac }); - if (!rt_entry) { - /* printf(" new mac\n"); */ - // Build new entry - rt_entry = malloc(sizeof(struct pmlag_rt_entry)); - bzero(rt_entry, sizeof(struct pmlag_rt_entry)); - /* rt_entry->bcidx = 0; */ - - // Insert the mac address - rt_entry->mac = malloc(ETH_ALEN); - memcpy(rt_entry->mac, mac, ETH_ALEN); - - /* // And an empty list of interfaces */ - /* rt_entry->interfaces = NULL; */ - } else { - /* printf(" known mac\n"); */ - } - - // Bail if we receive a regular packet on an interface with bcidx - if (!bcidx && rt_entry->bcidx) { - /* printf(" bail, regular packet on pmlag remote\n"); */ - pthread_mutex_unlock(&(iface->bond->mtx_rt)); - return; - } - - // Clear list of known interfaces if - pmlag_iface_llist *iface_entry; - if ( - (bcidx && (rt_entry->bcidx != bcidx)) || // We got a NEW broadcast index - (!bcidx && (rt_entry->bcidx == 0)) // Or we're updating a non-pmlag remote - ) { - // Free list 1-by-1 - while(rt_entry->interfaces) { - printf("FREE LINE %d (%p)\n", __LINE__, iface_entry); - printf("FREE LINE %d (%p)\n", __LINE__, rt_entry->interfaces); - iface_entry = rt_entry->interfaces; - printf("FREE LINE %d (%p)\n", __LINE__, iface_entry); - printf("FREE LINE %d (%p)\n", __LINE__, iface_entry->next); - rt_entry->interfaces = iface_entry->next; - printf("FREE LINE %d (%p)\n", __LINE__, iface_entry); - free(iface_entry); - } - rt_entry->bcidx = bcidx; - /* printf(" clear interface list\n"); */ - } else { - // Don't track the interface - /* printf(" keep interface list\n"); */ - } - - // Add given interface to the entry's interface list - iface_entry = malloc(sizeof(pmlag_iface_llist)); - iface_entry->next = rt_entry->interfaces; - iface_entry->data = iface; - rt_entry->interfaces = iface_entry; - - /* iface_list_len = 0; */ - /* iface_list_entry = rt_entry->interfaces[iface_list_len]; */ - /* while(iface_list_entry) { */ - /* iface_list_entry = rt_entry->interfaces[++iface_list_len]; */ - /* } */ - - /* /1* printf(" len before: %d\n", iface_list_len); *1/ */ - /* rt_entry->interfaces = realloc(rt_entry->interfaces, (iface_list_len+2) * sizeof(struct pm_rt_entry *)); */ - /* /1* printf(" reallocated\n"); *1/ */ - /* rt_entry->interfaces[iface_list_len ] = iface; */ - /* rt_entry->interfaces[iface_list_len+1] = NULL; */ - /* /1* printf(" len after: %d\n", iface_list_len+1); *1/ */ - - // Save rt entry in the routing table again - btree_set(iface->bond->rt, rt_entry); - /* printf(" saved to tree\n"); */ - /* printf("\n"); */ - - 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); - - /* printf("Thread started for iface: %s->%s(%d)\n", iface->bond->name, iface->name, iface->sockfd); */ - - // 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 {{{ - /* 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; - } - // }}} - - 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); - } - - /* trim_rt(iface->bond, */ - 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)"); - /* pthread_exit(NULL); */ - /* return NULL; */ - } - - } - - pthread_exit(NULL); - return NULL; -} - -void * thread_bond(void *arg) { - struct pmlag_bond *bond = (struct pmlag_bond *)arg; - /* printf("Thread started for bond: %s\n", bond->name); */ - - // 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 - /* sleep(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) { - /* sleep(1); */ - - buflen = read(bond->sockfd, buffer, RCVBUFSIZ); - if (buflen < 0) { - perror("read(bond)"); - pthread_exit(NULL); - return NULL; - } - - /* printf("\n"); */ - /* printf("Got packet: %d bytes\n", buflen); */ - - /* printf("Ethernet header\n"); */ - 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"); - /* pthread_exit(NULL); */ - /* return NULL; */ - } - 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"); - /* pthread_exit(NULL); */ - /* return NULL; */ - } - } - - // 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); -} +/* void trim_rt(struct pmlag_bond *bond, size_t limit) { */ + +/* } */ + +/* void iface_add_rt(struct pmlag_iface *iface, unsigned char *mac, uint16_t bcidx) { */ +/* struct pmlag_rt_entry *rt_entry; */ +/* int iface_list_len; */ +/* struct pmlag_iface *iface_list_entry; */ + +/* pthread_mutex_lock(&(iface->bond->mtx_rt)); */ +/* printf("\nRCV bc: %s\n", iface->name); */ + +/* // Fetch or build rt entry */ +/* rt_entry = btree_get(iface->bond->rt, &(struct pmlag_rt_entry){ .mac = mac }); */ +/* if (!rt_entry) { */ +/* /1* printf(" new mac\n"); *1/ */ +/* // Build new entry */ +/* rt_entry = calloc(1, sizeof(struct pmlag_rt_entry)); */ +/* /1* bzero(rt_entry, sizeof(struct pmlag_rt_entry)); *1/ */ +/* /1* rt_entry->bcidx = 0; *1/ */ + +/* // Insert the mac address */ +/* rt_entry->mac = malloc(ETH_ALEN); */ +/* memcpy(rt_entry->mac, mac, ETH_ALEN); */ + +/* /1* // And an empty list of interfaces *1/ */ +/* /1* rt_entry->interfaces = NULL; *1/ */ +/* } else { */ +/* /1* printf(" known mac\n"); *1/ */ +/* } */ + +/* // Bail if we receive a regular packet on an interface with bcidx */ +/* if (!bcidx && rt_entry->bcidx) { */ +/* /1* printf(" bail, regular packet on pmlag remote\n"); *1/ */ +/* pthread_mutex_unlock(&(iface->bond->mtx_rt)); */ +/* return; */ +/* } */ + +/* // Clear list of known interfaces if */ +/* pmlag_iface_llist *iface_entry; */ +/* if ( */ +/* (bcidx && (rt_entry->bcidx != bcidx)) || // We got a NEW broadcast index */ +/* (!bcidx && (rt_entry->bcidx == 0)) // Or we're updating a non-pmlag remote */ +/* ) { */ +/* // Free list 1-by-1 */ +/* while(rt_entry->interfaces) { */ +/* printf("FREE LINE %d (%p)\n", __LINE__, iface_entry); */ +/* printf("FREE LINE %d (%p)\n", __LINE__, rt_entry->interfaces); */ +/* iface_entry = rt_entry->interfaces; */ +/* printf("FREE LINE %d (%p)\n", __LINE__, iface_entry); */ +/* printf("FREE LINE %d (%p)\n", __LINE__, iface_entry->next); */ +/* rt_entry->interfaces = iface_entry->next; */ +/* printf("FREE LINE %d (%p)\n", __LINE__, iface_entry); */ +/* free(iface_entry); */ +/* } */ +/* rt_entry->bcidx = bcidx; */ +/* /1* printf(" clear interface list\n"); *1/ */ +/* } else { */ +/* // Don't track the interface */ +/* /1* printf(" keep interface list\n"); *1/ */ +/* } */ + +/* // Add given interface to the entry's interface list */ +/* iface_entry = calloc(1, sizeof(pmlag_iface_llist)); */ +/* iface_entry->next = rt_entry->interfaces; */ +/* iface_entry->data = iface; */ +/* rt_entry->interfaces = iface_entry; */ + +/* /1* iface_list_len = 0; *1/ */ +/* /1* iface_list_entry = rt_entry->interfaces[iface_list_len]; *1/ */ +/* /1* while(iface_list_entry) { *1/ */ +/* /1* iface_list_entry = rt_entry->interfaces[++iface_list_len]; *1/ */ +/* /1* } *1/ */ + +/* /1* /2* printf(" len before: %d\n", iface_list_len); *2/ *1/ */ +/* /1* rt_entry->interfaces = realloc(rt_entry->interfaces, (iface_list_len+2) * sizeof(struct pm_rt_entry *)); *1/ */ +/* /1* /2* printf(" reallocated\n"); *2/ *1/ */ +/* /1* rt_entry->interfaces[iface_list_len ] = iface; *1/ */ +/* /1* rt_entry->interfaces[iface_list_len+1] = NULL; *1/ */ +/* /1* /2* printf(" len after: %d\n", iface_list_len+1); *2/ *1/ */ + +/* // Save rt entry in the routing table again */ +/* btree_set(iface->bond->rt, rt_entry); */ +/* /1* printf(" saved to tree\n"); *1/ */ +/* /1* printf("\n"); *1/ */ + +/* 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"; @@ -355,6 +357,8 @@ 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) { @@ -365,17 +369,17 @@ 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 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); + /* // 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, thread_bond, bond)) { + if(pthread_create(&(bond->tid), NULL, task_bond_thread, bond)) { perror("Starting bond thread"); return 1; } @@ -383,55 +387,55 @@ int main(int argc, const char **argv) { bond = bond->next; } - // Timer, keep broadcasting "I'm here" packets - struct pmlag_iface *iface; - struct sockaddr_ll saddr_ll; - saddr_ll.sll_halen = ETH_ALEN; - unsigned char *mac; - uint16_t ethtype = htons(0x0666); - int buflen = (ETH_ALEN*2) + 2 + 46; - unsigned char *buffer = calloc(1, buflen); - int send_len; - memset(buffer, 0xFF, ETH_ALEN); // DST = broadcast - memcpy(buffer+(ETH_ALEN*2), &ethtype, sizeof(uint16_t)); // EtherType = 0x0666 = custom - while(1) { - bond = config->bonds; - while(bond) { - // Set source address in saddr_ll and packet - mac = iface_mac(bond->name); - memcpy(saddr_ll.sll_addr, mac, ETH_ALEN); - memcpy(buffer+ETH_ALEN, mac, ETH_ALEN); - printf("FREE LINE %d (%p)\n", __LINE__, mac); - free(mac); - // Set the bcidx - memcpy(buffer + (ETH_ALEN*2) + sizeof(uint16_t), &(bond->bcidx), sizeof(uint16_t)); - - /* printf("Ethernet header\n"); */ - /* printf("\nSending: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x > %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%d)\n\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 */ - /* ); */ - - // Output to all interfaces - iface = bond->interfaces; - while(iface) { - if (iface->sockfd) { - 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 < 0) { - perror("SENDTO"); - } - } - iface = iface->next; - } - bond->bcidx = htons((ntohs(bond->bcidx)+1)|1); - bond = bond->next; - } - /* usleep(100000); // 100ms */ - sleep(1); - } + /* // Timer, keep broadcasting "I'm here" packets */ + /* struct pmlag_iface *iface; */ + /* struct sockaddr_ll saddr_ll; */ + /* saddr_ll.sll_halen = ETH_ALEN; */ + /* unsigned char *mac; */ + /* uint16_t ethtype = htons(0x0666); */ + /* int buflen = (ETH_ALEN*2) + 2 + 46; */ + /* unsigned char *buffer = calloc(1, buflen); */ + /* int send_len; */ + /* memset(buffer, 0xFF, ETH_ALEN); // DST = broadcast */ + /* memcpy(buffer+(ETH_ALEN*2), &ethtype, sizeof(uint16_t)); // EtherType = 0x0666 = custom */ + /* while(1) { */ + /* bond = config->bonds; */ + /* while(bond) { */ + /* // Set source address in saddr_ll and packet */ + /* mac = iface_mac(bond->name); */ + /* memcpy(saddr_ll.sll_addr, mac, ETH_ALEN); */ + /* memcpy(buffer+ETH_ALEN, mac, ETH_ALEN); */ + /* printf("FREE LINE %d (%p)\n", __LINE__, mac); */ + /* free(mac); */ + /* // Set the bcidx */ + /* memcpy(buffer + (ETH_ALEN*2) + sizeof(uint16_t), &(bond->bcidx), sizeof(uint16_t)); */ + + /* /1* printf("Ethernet header\n"); *1/ */ + /* /1* printf("\nSending: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x > %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%d)\n\n", *1/ */ + /* /1* buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11], // SRC *1/ */ + /* /1* buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5], // DST *1/ */ + /* /1* ((unsigned int)((unsigned char)buffer[12]) << 8) + buffer[13], // PROTO *1/ */ + /* /1* buflen *1/ */ + /* /1* ); *1/ */ + + /* // Output to all interfaces */ + /* iface = bond->interfaces; */ + /* while(iface) { */ + /* if (iface->sockfd) { */ + /* 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 < 0) { */ + /* perror("SENDTO"); */ + /* } */ + /* } */ + /* iface = iface->next; */ + /* } */ + /* bond->bcidx = htons((ntohs(bond->bcidx)+1)|1); */ + /* bond = bond->next; */ + /* } */ + /* /1* usleep(100000); // 100ms *1/ */ + /* sleep(1); */ + /* } */ // Wait for all bonds to finish diff --git a/src/task/announce.c b/src/task/announce.c diff --git a/src/task/announce.h b/src/task/announce.h @@ -0,0 +1,7 @@ +#ifndef __PMLAG_TASK_ANNOUNCE_H__ +#define __PMLAG_TASK_ANNOUNCE_H__ + + + + +#endif // __PMLAG_TASK_ANNOUNCE_H__ diff --git a/src/task/bond.c b/src/task/bond.c @@ -0,0 +1,10 @@ +#include <stdlib.h> +#include <stdio.h> + + +void * task_bond_thread(void *arg) { + + printf("Thread started!\n"); + + return NULL; +} diff --git a/src/task/bond.h b/src/task/bond.h @@ -0,0 +1,7 @@ +#ifndef __PMLAG_TASK_BOND_H__ +#define __PMLAG_TASK_BOND_H__ + +void * task_bond_thread(void *arg); + +#endif // __PMLAG_TASK_BOND_H__ + diff --git a/src/task/iface.c b/src/task/iface.c diff --git a/src/task/iface.h b/src/task/iface.h @@ -0,0 +1,7 @@ +#ifndef __PMLAG_TASK_IFACE_H__ +#define __PMLAG_TASK_IFACE_H__ + + + +#endif // __PMLAG_TASK_IFACE_H__ + diff --git a/src/config.c b/src/util/config.c diff --git a/src/util/config.h b/src/util/config.h @@ -0,0 +1,60 @@ +#ifndef __PMLAG_CONFIG_H__ +#define __PMLAG_CONFIG_H__ + +#include <pthread.h> +#include <stdint.h> + +#include "tidwall/btree.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PMLAG_MODE_NONE 0 +#define PMLAG_MODE_ACTIVE_BACKUP 1 +#define PMLAG_MODE_BROADCAST 2 +#define PMLAG_MODE_BALANCED_RR 3 + +#define LLIST(x) struct { void *next; x *data; } + +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 + int ifidx; // index of the interface within the socket + pthread_t tid; // thread id where the iface listener recides in + struct pmlag_bond *bond; // reference to the bond this iface belongs to +}; + +struct pmlag_bond { + void *next; // linked-list next reference + char *name; // name of the bond interface + int mode; // which mode to run pmlag in for this bond + int sockfd; // file descriptor for the bond socket interface + uint16_t bcidx; // big-endian broadcast index for quickly detecting dead paths + 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 +}; + +struct pmlag_configuration { + struct pmlag_bond *bonds; +}; + +struct pmlag_configuration * config_load(const char * filename); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __PMLAG_CONFIG_H__ diff --git a/src/util/routing-table.c b/src/util/routing-table.c diff --git a/src/util/routing-table.h b/src/util/routing-table.h diff --git a/src/socket.c b/src/util/socket.c diff --git a/src/socket.h b/src/util/socket.h