pmlag

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

commit 1fa26882ee286c25e28d47482b498519f76d27bd
parent 777ba028b2714818ea3599a3a06a590b79e3d7f9
Author: Yersa Nordman <yersa@finwo.nl>
Date:   Wed, 11 Oct 2023 23:53:46 +0200

Keeping track of routing table now

Diffstat:
Msrc/main.c | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/util/routing-table.c | 129++++++++++++++++++++++++++++++++-----------------------------------------------
Msrc/util/routing-table.h | 20++++++++++----------
3 files changed, 125 insertions(+), 116 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -17,13 +17,17 @@ #define RCVBUFSIZ 131072 +#define TICK 100 +#define PMLAG_RT_FAST 4 + +#define PMLAG_COMMAND_STREE_BROADCAST 0 + unsigned char *rcvbuf = NULL; static const char *const usage[] = { __NAME " [options]", NULL }; - int64_t millis() { struct timeval tv; gettimeofday(&tv, NULL); @@ -31,13 +35,19 @@ int64_t millis() { } void handle_packet_bond(struct pmlag_bond *bond) { - printf("Packet on bond %s\n", bond->name); + int send_len, buflen; + buflen = read(bond->sockfd, rcvbuf, RCVBUFSIZ); + printf("Got %d bytes on %s\n", buflen, bond->name); } + void handle_packet_iface(struct pmlag_iface *iface) { printf("Packet on iface %s\n", iface->name); - int send_len, buflen; + struct pmlag_bond *bond = iface->bond; + struct pmlag_rt_entry *rt_entry; + int send_len, buflen, idx; uint16_t ethtype; uint16_t command; + uint16_t bcid; // Read the packet buflen = recvfrom(iface->sockfd, rcvbuf, RCVBUFSIZ, 0, NULL, 0); @@ -50,13 +60,19 @@ void handle_packet_iface(struct pmlag_iface *iface) { // ethernet says minimum of 60, we just need 18 if (buflen < 18) return; - // TODO: track all packets in routing table + // Always add mac to routing table + rt_upsert( + bond->rt, + iface, + rcvbuf + ETH_ALEN, + bond->bc_id + ); // Get the ethtype memcpy(&ethtype, rcvbuf + (2*ETH_ALEN), sizeof(ethtype)); ethtype = ntohs(ethtype); - printf("Read %d bytes (%d)\n", buflen, ethtype); + printf("Read %d bytes (%d) -- rt = %d\n", buflen, ethtype, bond->rt->length); // Don't touch packets that don't use our described protocol if (ethtype != 0x0666) { @@ -77,26 +93,42 @@ void handle_packet_iface(struct pmlag_iface *iface) { memcpy(&command, rcvbuf + (2*ETH_ALEN) + sizeof(ethtype), sizeof(command)); command = ntohs(command); - printf("TODO: do something with this %.2x:%.2x:%.2x:%.2x:%.2x:%.2x - %.4x - %.4x - %.4x\n", - rcvbuf[ 6], - rcvbuf[ 7], - rcvbuf[ 8], - rcvbuf[ 9], - rcvbuf[10], - rcvbuf[11], - (rcvbuf[12] << 8) + rcvbuf[13], - (rcvbuf[14] << 8) + rcvbuf[15], - iface->bond->bc_id - ); + switch(command) { + case PMLAG_COMMAND_STREE_BROADCAST: - // TODO: - // - received untriggered bc with timer > 0: we're a follower now (timer=3) - // - received untriggered bc with timer <= 0: trigger + timer=rand(0/2) - // - received triggered bc: ignore - // - if triggered but received new bc, untrigger - // - if untriggered but received bc, set bc_timer to 0 or 1 (random) - // TODO: commit routing table upon broadcast id change - // a.k.a. cleanup old entries not seen since bcid - 2? + // Stop if we already triggered this round + if (bond->state & PMLAG_STATE_TRIGGERED) break; + bond->state |= PMLAG_STATE_TRIGGERED; + + // Have the network fight for leader status + if (bond->bc_timer) { + // Demote to follower if we were waiting + bond->bc_timer = 3; + } else { + // Random between now leader and pensive + bond->bc_timer = (rand() % 2) * 2; + } + + // Fetch the broadcast id + memcpy(&bcid, rcvbuf + (2*ETH_ALEN) + sizeof(ethtype) + sizeof(command), sizeof(bcid)); + bcid = ntohs(bcid); + bond->bc_id = bcid; + + // Remove old entries from routing table + for( idx = 0; idx < bond->rt->length ; idx++ ) { + rt_entry = bond->rt->items[idx]; + if ((bcid - rt_entry->bcidx) > PMLAG_RT_FAST) { + mindex_delete(bond->rt, rt_entry); // rt_entry is now unsafe + continue; + } + // More things here? + } + + break; + default: + // Unknown command + return; + } } void handle_packet(void *entity) { @@ -180,8 +212,8 @@ int main(int argc, const char **argv) { // Calculate waiting time & periodic actions tdiff = ttime - millis(); if (tdiff <= 0) { - ttime += 100; - tdiff += 100; + ttime += TICK; + tdiff += TICK; // Handle sockets for( b = 0 ; b < config->bond_count ; b++ ) { @@ -191,7 +223,7 @@ int main(int argc, const char **argv) { if (!bond->sockfd) { bond->sockfd = tap_alloc(bond->name, bond->hwaddr); bond->state = 0; - bond->bc_timer = 3; + bond->bc_timer = 3; // set to 2 in combination with the decrement below if (bond->sockfd < 0) { perror("tap_alloc"); bond->sockfd = 0; @@ -254,8 +286,7 @@ int main(int argc, const char **argv) { if (bond->bc_timer < 0) { bond->bc_timer = 0; - // Increment broadcast id - bond->bc_id = ntohs(bond->bc_id); + // Increment broadcast id & prepare network orientation bond->bc_id++; bond->bc_id = htons(bond->bc_id); @@ -267,6 +298,9 @@ int main(int argc, const char **argv) { memset(anc_buffer + (2*ETH_ALEN) + sizeof(ethtype) , 0x00 , sizeof(uint16_t)); // command (interface detection broadcast) memcpy(anc_buffer + (2*ETH_ALEN) + sizeof(ethtype) + sizeof(uint16_t), &(bond->bc_id), sizeof(bond->bc_id)); // broadcast id + // Revert bc_id to host-orientation + bond->bc_id = ntohs(bond->bc_id); + // Send packet on all interfaces for( i=0; i < bond->iface_count ; i++ ) { iface = bond->iface[i]; diff --git a/src/util/routing-table.c b/src/util/routing-table.c @@ -27,83 +27,58 @@ struct mindex_t * rt_init(void *udata) { return mindex_init(rt_compare, rt_purge, udata); } -/* int rt_upsert( */ -/* struct mindex_t *rt, */ -/* pthread_mutex_t *mtx, */ -/* struct pmlag_iface *iface, */ -/* unsigned char *mac, */ -/* int16_t bcidx */ -/* ) { */ -/* int isnew = 0; */ -/* struct pmlag_rt_entry *rt_entry; */ - -/* // Lock the routing table */ -/* pthread_mutex_lock(mtx); */ - -/* // Attempt to fetch the rt entry */ -/* rt_entry = mindex_get(rt, &((struct pmlag_rt_entry){ .mac = mac })); */ - -/* // None given, build new one */ -/* if (!rt_entry) { */ -/* rt_entry = calloc(1, sizeof(struct pmlag_rt_entry)); */ -/* rt_entry->mac = malloc(ETH_ALEN); */ -/* rt_entry->bcidx = 0; */ -/* rt_entry->interfaces = calloc(iface->bond->iface_cnt, sizeof(struct pmlag_iface *)); */ -/* memcpy(rt_entry->mac, mac, ETH_ALEN); */ -/* isnew = 1; */ -/* } */ - -/* // Bail if */ -/* if ( */ -/* (!bcidx && rt_entry->bcidx) || // We receive a regular packet on bcidx-tracked entry */ -/* (rt_entry->bcidx && ((bcidx - rt_entry->bcidx) < 0)) // Or the received bcidx is lower than known (old packet) */ -/* ) { */ -/* if (isnew) { */ -/* rt_purge(rt_entry, NULL); */ -/* } */ -/* pthread_mutex_unlock(mtx); */ -/* return 0; */ -/* } */ - -/* // Clear list of known interfaces if */ -/* 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 */ -/* ) { */ -/* rt_entry->iface_cnt = 0; */ -/* } */ - -/* // Update the rt_entry's broadcast index */ -/* rt_entry->bcidx = bcidx; */ - -/* // Bail if rt_entry->iface_cnt+1 lg bond->iface_cnt */ -/* if ((rt_entry->iface_cnt + 1) > iface->bond->iface_cnt) { */ -/* if (isnew) { */ -/* rt_purge(rt_entry, NULL); */ -/* } */ -/* pthread_mutex_unlock(mtx); */ -/* return 0; */ -/* } */ - -/* // Add our iface to the entry's interface list */ -/* rt_entry->interfaces[rt_entry->iface_cnt] = iface; */ -/* rt_entry->iface_cnt++; */ - -/* // Ensure the entry is in the rt */ -/* if (isnew) { */ -/* mindex_set(rt, rt_entry); */ -/* } */ - -/* if (mindex_length(rt) > RT_MAX_ENTRIES) { */ -/* rt_entry = mindex_rand(rt); */ -/* if (rt_entry) { */ -/* mindex_delete(rt, rt_entry); */ -/* } */ -/* } */ - -/* pthread_mutex_unlock(mtx); */ -/* return 0; */ -/* } */ +int rt_upsert( + struct mindex_t *rt, + struct pmlag_iface *iface, + unsigned char *mac, + int16_t bcidx +) { + struct pmlag_rt_entry *rt_entry; + int i, isnew = 0; + int iface_found = 0; + + // Attempt to fetch the rt entry + rt_entry = mindex_get(rt, &((struct pmlag_rt_entry){ .mac = mac })); + + // None given, build new one + if (!rt_entry) { + rt_entry = calloc(1, sizeof(struct pmlag_rt_entry)); + rt_entry->mac = malloc(ETH_ALEN); + rt_entry->bcidx = bcidx; + rt_entry->iface = calloc(iface->bond->iface_count, sizeof(struct pmlag_iface *)); + rt_entry->iface_count = 0; + memcpy(rt_entry->mac, mac, ETH_ALEN); + isnew = 1; + } + + // Clear interface list if bcidx is different + if (rt_entry->bcidx != bcidx) { + rt_entry->iface_count = 0; + rt_entry->bcidx = bcidx; + } + + // Register the interface on the rt_entry + for( i = 0 ; i < rt_entry->iface_count ; i++ ) { + if (rt_entry->iface[i] != iface) continue; + iface_found = 1; + break; + } + if (!iface_found) { + rt_entry->iface[rt_entry->iface_count] = iface; + rt_entry->iface_count++; + } + + // The actual upsert part + if (isnew) { + mindex_set(rt, rt_entry); + // Keep rt size in check + if (rt->length > PMLAG_RT_MAX) { + mindex_delete(rt, mindex_rand(rt)); + } + } + + return 0; +} /* struct pmlag_iface * rt_find( */ /* struct mindex_t *rt, */ diff --git a/src/util/routing-table.h b/src/util/routing-table.h @@ -1,30 +1,30 @@ #ifndef __PMLAG_UTIL_RT_H__ #define __PMLAG_UTIL_RT_H__ +#define PMLAG_RT_MAX 4096 + #include "config.h" #include "finwo/mindex.h" struct pmlag_rt_entry { - unsigned char *mac; // mac address of the remote entity - int16_t bcidx; // broadcast index last seen from the mac + unsigned char *mac; // mac address of the remote entity + uint16_t bcidx; // broadcast index last seen from the mac struct pmlag_iface **iface; int iface_count; }; struct mindex_t * rt_init(void *udata); -/* int rt_upsert( */ -/* struct mindex_t *rt, */ -/* pthread_mutex_t *mtx, */ -/* struct pmlag_iface *iface, */ -/* unsigned char *mac, */ -/* int16_t bcidx */ -/* ); */ +int rt_upsert( + struct mindex_t *rt, + struct pmlag_iface *iface, + unsigned char *mac, + int16_t bcidx +); /* struct pmlag_iface * rt_find( */ /* struct mindex_t *rt, */ -/* pthread_mutex_t *mtx, */ /* unsigned char *mac */ /* ); */