pmlag

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

commit 38f6a4ec1c2888f48ff98df7fb52846c8ffef1d7
parent 0a1cd68d615a5c6064b6de949845a37f3bdefaa1
Author: Yersa Nordman <yersa@finwo.nl>
Date:   Mon, 13 Feb 2023 21:41:21 +0100

Open file descriptors before starting bond/iface threads

Diffstat:
Msrc/main.c | 195++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/socket.c | 7++++---
Mtest.ini | 2+-
3 files changed, 124 insertions(+), 80 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -29,66 +29,68 @@ static const char *const usage[] = { 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; - } + /* // 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); + /* // 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); */ 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)); + /* // Wait for the bond thread to finish initializing */ + /* pthread_mutex_lock(&(iface->bond->mtx_rt)); */ + /* pthread_mutex_unlock(&(iface->bond->mtx_rt)); */ - // Bail if the bond's socket could not be opened - if (!iface->bond->sockfd) { - pthread_exit(NULL); - return NULL; - } + /* // Bail if the bond's socket could not be opened */ + /* if (!iface->bond->sockfd) { */ + /* pthread_exit(NULL); */ + /* return NULL; */ + /* } */ - // Find bond socket iface_idx - int send_len; + /* // Find bond socket iface_idx */ + /* int send_len; */ - while(1) { + /* 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; - } + /* // 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; */ + /* } */ - // TODO: track received proto=0x0666 packet to update routing table + /* // TODO: track received proto=0x0666 packet to update routing table */ - /* printf("\n"); */ - /* printf("Got packet: %d bytes\n", buflen); */ - /* printf("\n"); */ + /* printf("\n"); */ + /* printf("Got packet: %d bytes\n", buflen); */ + /* printf("\n"); */ - /* printf("Ethernet header\n"); */ - /* printf("\t|- DST %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5]); */ - /* printf("\t|- SRC %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11]); */ - /* printf("\t|- PROTO %.4X\n", ((int)((char)buffer[12]) << 8) + buffer[13]); */ + /* printf("Ethernet header\n"); */ + /* printf("\t|- DST %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[ 4],buffer[ 5]); */ + /* printf("\t|- SRC %.2X-%.2X-%.2X-%.2X-%.2X-%.2X\n",buffer[6],buffer[7],buffer[8],buffer[9],buffer[10],buffer[11]); */ + /* printf("\t|- PROTO %.4X\n", ((int)((char)buffer[12]) << 8) + buffer[13]); */ + /* printf("\n"); */ - // 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; - } - } + /* // Redirect packet to bond socket as-is */ + /* printf("Bond iface: %d\n\n", iface->bond->sockfd); */ + /* send_len = write(iface->bond->sockfd, buffer, buflen); */ + /* if (buflen != send_len) { */ + /* perror("write(bond)"); */ + /* pthread_exit(NULL); */ + /* return NULL; */ + /* } */ + /* } */ - sleep(3); + /* sleep(3); */ pthread_exit(NULL); return NULL; } @@ -97,37 +99,37 @@ void * thread_bond(void *arg) { struct pmlag_bond *bond = (struct pmlag_bond *)arg; printf("Thread started for bond: %s\n", bond->name); - // Lock this bond's routing table - pthread_mutex_lock(&(bond->mtx_rt)); + /* // 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; - } + /* // Initialize the bond interface */ + /* bond->sockfd = tap_alloc(bond->name); */ - // Take mac address of last iface - bond->sockfd = tap_alloc(bond->name); + /* // 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; */ + /* } */ - // Free this bond's routing table - pthread_mutex_unlock(&(bond->mtx_rt)); + /* // Free this bond's routing table */ + /* pthread_mutex_unlock(&(bond->mtx_rt)); */ - // TODO: blocked listen on bond, send through routing table to other ifaces - // TODO: send broadcasts to all interfaces - // TODO: timer to broadcast announce our presence to ifaces (vrrp-ish) - // hint: include sequence id, so tracking can react quickly (seq dist > 1) + /* // TODO: blocked listen on bond, send through routing table to other ifaces */ + /* // TODO: send broadcasts to all interfaces */ + /* // TODO: timer to broadcast announce our presence to ifaces (vrrp-ish) */ + /* // hint: include sequence id, so tracking can react quickly (seq dist > 1) */ - // Wait for iface threads to finish - iface = bond->interfaces; - while(iface) { - pthread_join(iface->tid, NULL); - iface = iface->next; - } + /* // Wait for iface threads to finish */ + /* iface = bond->interfaces; */ + /* while(iface) { */ + /* pthread_join(iface->tid, NULL); */ + /* iface = iface->next; */ + /* } */ pthread_exit(NULL); return NULL; @@ -160,19 +162,51 @@ int main(int argc, const char **argv) { return 1; } - // For each bond of config->bonds + // Initialize interfaces for all configured bonds struct pmlag_bond *bond = config->bonds; + struct pmlag_iface *iface; while(bond) { - // Initialize it's routing table lock + + bond->sockfd = tap_alloc(bond->name); + if (bond->sockfd < 0) return 3; + + iface = bond->interfaces; + while(iface) { + iface->sockfd = sockraw_open(iface->name); + if (iface->sockfd < 0) return 2; + iface = iface->next; + } + + bond = bond->next; + } + + + // For each bond of config->bonds + 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; } - // And start it's thread + + // Start the bond's thread if(pthread_create(&(bond->tid), NULL, thread_bond, bond)) { perror("Starting bond thread"); return 1; } + + // Start a thread for each interface + iface = bond->interfaces; + while(iface) { + if(pthread_create(&(iface->tid), NULL, thread_iface, iface)) { + perror("Starting iface thread"); + return 1; + } + iface = iface->next; + } + bond = bond->next; } @@ -180,9 +214,18 @@ int main(int argc, const char **argv) { bond = config->bonds; while(bond) { pthread_join(bond->tid, NULL); + iface = bond->interfaces; + while(iface) { + pthread_join(iface->tid, NULL); + iface = iface->next; + } bond = bond->next; } + + + + /* int sockfd = sockraw_open(INTERFACE); */ /* if (sockfd < 0) { */ /* return 1; */ diff --git a/src/socket.c b/src/socket.c @@ -77,12 +77,13 @@ int tap_alloc(char * ifname) { */ ifr.ifr_flags = IFF_TAP | IFF_NO_PI; if( *ifname ) { - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); } if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ - close(fd); - return err; + perror("Open tun"); + close(fd); + return err; } strcpy(ifname, ifr.ifr_name); diff --git a/test.ini b/test.ini @@ -3,7 +3,7 @@ ; eth0 = backup, eth1 = primary [bond0] mode=active-backup -interface=docker0 +interface=enp0s13f0u1c2 weight=10 ; ; broadcast everything on all interfaces