pmlag

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

commit 0ec1e7463d3d03d551dd2362de8265516fefb99f
parent b6a8b216f920638b60eeced4a39d83826164dd78
Author: Yersa Nordman <yersa@finwo.nl>
Date:   Tue, 21 Feb 2023 23:11:00 +0100

First routing table tracking attempt

Diffstat:
Mpmlag.1 | 6++++++
Mpmlag.html | 4++++
Msrc/config.c | 13++++++-------
Msrc/config.h | 11++++++++++-
Msrc/main.c | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
5 files changed, 103 insertions(+), 11 deletions(-)

diff --git a/pmlag.1 b/pmlag.1 @@ -22,3 +22,9 @@ pmlag - Poor man\[cq]s link aggregator .SH SYNOPSIS .PP \f[V]pmlag [options]\f[R] +.SH LICENSE +.PP +This project is a work in progress, the license(s) shown here are not +complete +.PP +TODO: - benhoyt/inih - cofyc/argparse - tidwall/btree diff --git a/pmlag.html b/pmlag.html @@ -166,5 +166,9 @@ <p>pmlag - Poor man’s link aggregator</p> <h1 id="synopsis">SYNOPSIS</h1> <p><code>pmlag [options]</code></p> +<h1 id="license">LICENSE</h1> +<p>This project is a work in progress, the license(s) shown here are not +complete</p> +<p>TODO: - benhoyt/inih - cofyc/argparse - tidwall/btree</p> </body> </html> diff --git a/src/config.c b/src/config.c @@ -63,17 +63,16 @@ static int config_load_handler( iface = calloc(1, sizeof(struct pmlag_iface)); iface->next = bond->interfaces; iface->name = strdup(value); - iface->weight = 10; + /* iface->weight = 10; */ iface->bond = bond; bond->interfaces = iface; } - } else if (!strcmp(name, "weight")) { - if (!iface) { - return 0; - } - - iface->weight = atoi(value); + /* } else if (!strcmp(name, "weight")) { */ + /* if (!iface) { */ + /* return 0; */ + /* } */ + /* iface->weight = atoi(value); */ } else { // Unknown key return 0; diff --git a/src/config.h b/src/config.h @@ -4,6 +4,8 @@ #include <pthread.h> #include <stdint.h> +#include "tidwall/btree.h" + #ifdef __cplusplus extern "C" { #endif @@ -16,7 +18,7 @@ extern "C" { 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 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 @@ -31,9 +33,16 @@ struct pmlag_bond { 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 + struct pmlag_iface **interfaces; // list of pointers to interfaces +}; + struct pmlag_configuration { struct pmlag_bond *bonds; }; diff --git a/src/main.c b/src/main.c @@ -1,3 +1,5 @@ +// vim: fdm=marker : + #include <arpa/inet.h> #include <errno.h> #include <linux/if_ether.h> @@ -13,6 +15,7 @@ #include <stdio.h> #include <unistd.h> +#include "tidwall/btree.h" #include "cofyc/argparse.h" #include "config.h" #include "socket.h" @@ -52,10 +55,14 @@ void * thread_iface(void *arg) { // Find bond socket iface_idx int send_len; uint16_t proto; + uint16_t bcidx; + struct pmlag_rt_entry *rt_entry; + int iface_list_len; + struct pmlag_iface *iface_list_entry; while(1) { - // Zero out buffer, to prevent pollution, & receive packet + // 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) { @@ -63,11 +70,69 @@ void * thread_iface(void *arg) { pthread_exit(NULL); return NULL; } + // }}} // Update routing table if our custom protocol is seen - proto = ((uint16_t)((unsigned char)buffer[12]) << 8) + buffer[13]; + proto = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+0]) << 8) + buffer[(ETH_ALEN*2)+1]; if (proto == 0x0666) { pthread_mutex_lock(&(iface->bond->mtx_rt)); + printf("RCV bc:\n"); + + // Fetch or build routing table entry {{{ + rt_entry = btree_get(iface->bond->rt, &(struct pmlag_rt_entry){ .mac = (buffer+ETH_ALEN) }); + if (!rt_entry) { + printf(" known mac\n"); + // Build new entry + rt_entry = malloc(sizeof(struct pmlag_rt_entry)); + + // Insert the mac address + rt_entry->mac = malloc(ETH_ALEN); + memcpy(rt_entry->mac, buffer+ETH_ALEN, ETH_ALEN); + + // Insert the bcidx + rt_entry->bcidx = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+2]) << 8) + buffer[(ETH_ALEN*2)+3]; + + // And an empty list of interfaces + rt_entry->interfaces = calloc(1, sizeof(struct pm_rt_entry *)); + } else { + printf(" new mac\n"); + } + // }}} + + // New bcidx = empty interface list {{{ + bcidx = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+2]) << 8) + buffer[(ETH_ALEN*2)+3]; + if (rt_entry->bcidx != bcidx) { + printf(" new bcidx\n"); + free(rt_entry->interfaces); + rt_entry->interfaces = calloc(1, sizeof(struct pm_rt_entry *)); + } else { + printf(" new bcidx\n"); + } + // }}} + + // Add self to the list of interfaces {{{ + + // Fetch length of interfaces {{{ + 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]; + } + // }}} + // Realloc list to have the expanded length {{{ + rt_entry->interfaces = realloc(rt_entry->interfaces, (iface_list_len+2) * sizeof(struct pm_rt_entry *)); + // }}} + // Actually add receiving interface to the known interfaces for the mac address {{{ + rt_entry->interfaces[iface_list_len ] = iface; + rt_entry->interfaces[iface_list_len+1] = NULL; + // }}} + + // }}} + + // Save rt entry in the routing table again + btree_set(iface->bond->rt, rt_entry); + printf("\n"); + // TODO: update routing table pthread_mutex_unlock(&(iface->bond->mtx_rt)); continue; // Don't forward the packet @@ -190,6 +255,12 @@ void * thread_bond(void *arg) { 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"; @@ -227,6 +298,8 @@ int main(int argc, const char **argv) { 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, thread_bond, bond)) { @@ -282,7 +355,8 @@ int main(int argc, const char **argv) { bond->bcidx = htons(ntohs(bond->bcidx)+1); bond = bond->next; } - usleep(10000); // 10ms + /* usleep(100000); // 100ms */ + sleep(1); }