pmlag

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

commit 5cd99d6705b6384753add53134b9b5cc1c465285
parent aa97a592dc57c4fb94155ad3384702990427d353
Author: Robin Bron <robin@finwo.nl>
Date:   Thu,  9 Mar 2023 22:22:05 +0100

Start separate thread for announcements

Diffstat:
Msrc/main.c | 55++-----------------------------------------------------
Msrc/task/announce.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/task/announce.h | 3+--
Msrc/task/bond.c | 9+++++++++
Msrc/util/config.h | 4++--
5 files changed, 75 insertions(+), 57 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -64,7 +64,7 @@ int main(int argc, const char **argv) { while(bond) { // Start the bond's thread - if(pthread_create(&(bond->tid), NULL, task_bond_thread, bond)) { + if(pthread_create(&(bond->tid_bond), NULL, task_bond_thread, bond)) { perror("Starting bond thread"); return 1; } @@ -72,61 +72,10 @@ 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(int16_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 bond = config->bonds; while(bond) { - pthread_join(bond->tid, NULL); + pthread_join(bond->tid_bond, NULL); bond = bond->next; } diff --git a/src/task/announce.c b/src/task/announce.c @@ -0,0 +1,61 @@ +#include <linux/if_ether.h> +#include <linux/if_packet.h> +#include <netinet/in.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "../util/config.h" +#include "../util/socket.h" +#include "announce.h" + +void * task_announce_thread(void *arg) { + struct pmlag_bond *bond = arg; + struct sockaddr_ll saddr_ll; + saddr_ll.sll_halen = ETH_ALEN; + pmlag_iface_llist *iface_entry; + + uint16_t ethtype = htons(0x0666); + size_t buflen = (ETH_ALEN*2) + sizeof(ethtype) + 46; + size_t sendlen; + + unsigned char *mac = iface_mac(bond->name); + unsigned char *buffer = calloc(1, buflen); + + // Prepare saddr_ll and buffer + memcpy(saddr_ll.sll_addr, mac, ETH_ALEN); + memset(buffer, 0xFF, ETH_ALEN); // Destination = Broadcast + memcpy(buffer+ETH_ALEN, mac, ETH_ALEN); // Source = bond + memcpy(buffer+(ETH_ALEN*2), &ethtype, sizeof(uint16_t)); // EtherType = 0x0666 = custom + + int16_t bcidx = htons(rand() | 1); + + while(1) { + sleep(1); + iface_entry = bond->interfaces; + + // Increment bcidx + bcidx = ntohs(bcidx); + bcidx = (bcidx+1) | 1; + bcidx = htons(bcidx); + + // Store bcidx on buffer + memcpy(buffer + (ETH_ALEN*2) + sizeof(uint16_t), &bcidx, sizeof(int16_t)); + + // Send the buffer as-is over all ifaces + while(iface_entry) { + if (iface_entry->data->sockfd) { + saddr_ll.sll_ifindex = iface_entry->data->ifidx; + sendlen = sendto(iface_entry->data->sockfd, buffer, buflen, 0, (const struct sockaddr*)&saddr_ll, sizeof(struct sockaddr_ll)); + if (sendlen < 0) { + perror("SENDTO"); + } + } + iface_entry = iface_entry->next; + } + } + + return NULL; +} diff --git a/src/task/announce.h b/src/task/announce.h @@ -1,7 +1,6 @@ #ifndef __PMLAG_TASK_ANNOUNCE_H__ #define __PMLAG_TASK_ANNOUNCE_H__ - - +void * task_announce_thread(void *arg); #endif // __PMLAG_TASK_ANNOUNCE_H__ diff --git a/src/task/bond.c b/src/task/bond.c @@ -11,6 +11,8 @@ #include "../util/config.h" #include "../util/routing-table.h" #include "../util/socket.h" + +#include "announce.h" #include "iface.h" int task_bond_onpacket(struct pmlag_bond *bond, unsigned char *buffer, size_t buflen) { @@ -97,6 +99,13 @@ void * task_bond_thread(void *arg) { iface_entry = iface_entry->next; } + // Start an announcement thread + if(pthread_create(&(bond->tid_announce), NULL, task_announce_thread, bond)) { + perror("Starting announce thread"); + pthread_exit((void*)1); + return (void*)1; + } + // Free this bond's routing table pthread_mutex_unlock(&(bond->mtx_rt)); diff --git a/src/util/config.h b/src/util/config.h @@ -35,8 +35,8 @@ struct pmlag_bond { 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 - int16_t bcidx; // big-endian broadcast index for quickly detecting dead paths - pthread_t tid; // thread id where the bond interface listener recides in + pthread_t tid_bond; // thread id where the bond interface listener recides in + pthread_t tid_announce; // thread id that'll output announces for the bond pthread_mutex_t mtx_rt; // lock for the routing table of the bond struct mindex_t *rt; // pointer to the routing table pmlag_iface_llist *interfaces; // linked-list of interfaces contained in the bond