commit 4bb71722241bba47b8369dbb8dcb585c87f3b577
parent f458e825654f7e7f4fdeaa1af0c5985c34c3b55c
Author: Robin Bron <robin@finwo.nl>
Date: Mon, 27 Feb 2023 22:22:37 +0100
Track src mac addresses in routing table again
Diffstat:
6 files changed, 102 insertions(+), 109 deletions(-)
diff --git a/src/main.c b/src/main.c
@@ -27,97 +27,6 @@ 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) { */
-/* /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)); */
-/* } */
-
-
-
int main(int argc, const char **argv) {
char *config_file="/etc/pmlag/pmlag.ini";
@@ -179,7 +88,7 @@ int main(int argc, const char **argv) {
/* 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)); */
+ /* 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/ */
diff --git a/src/task/iface.c b/src/task/iface.c
@@ -1,3 +1,4 @@
+#include <linux/if_ether.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -5,10 +6,13 @@
#include <unistd.h>
#include "../util/config.h"
+#include "../util/routing-table.h"
#include "../util/socket.h"
int task_iface_onpacket(struct pmlag_iface *iface, unsigned char *buffer, size_t buflen) {
size_t send_len;
+ uint16_t proto;
+ int16_t bcidx;
// Debug: print eth header
printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x < %.2x:%.2x:%.2x:%.2x:%.2x:%.2x, %.4x (%ld)\n",
@@ -18,6 +22,23 @@ int task_iface_onpacket(struct pmlag_iface *iface, unsigned char *buffer, size_t
buflen
);
+ // Update the routing table as-needed
+ proto = ((uint16_t)((unsigned char)buffer[(ETH_ALEN*2)+0]) << 8) + buffer[(ETH_ALEN*2)+1];
+ bcidx = 0;
+ if (proto == 0x0666) {
+ bcidx = ((int16_t)((unsigned char)buffer[(ETH_ALEN*2)+2]) << 8) + buffer[(ETH_ALEN*2)+3];
+ }
+ rt_upsert(
+ iface->bond->rt,
+ &(iface->bond->mtx_rt),
+ iface,
+ buffer+ETH_ALEN,
+ bcidx
+ );
+ if (proto == 0x0666) {
+ return 0;
+ }
+
// Redirect packet to bond socket as-is
send_len = write(iface->bond->sockfd, buffer, buflen);
if (buflen != send_len) {
@@ -76,18 +97,5 @@ void * task_iface_thread(void *arg) {
}
-/* // 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); */
diff --git a/src/util/config.h b/src/util/config.h
@@ -35,7 +35,7 @@ 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
- uint16_t bcidx; // big-endian broadcast index for quickly detecting dead paths
+ 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_mutex_t mtx_rt; // lock for the routing table of the bond
struct btree *rt; // pointer to the routing table
diff --git a/src/util/routing-table.c b/src/util/routing-table.c
@@ -1,6 +1,8 @@
#include <linux/if_ether.h>
+#include <stdlib.h>
#include <string.h>
+#include "config.h"
#include "tidwall/btree.h"
#include "routing-table.h"
@@ -13,3 +15,69 @@ static int compare_rt_entries(const void *a, const void *b, void *udata) {
struct btree * rt_init(void *udata) {
return btree_new(sizeof(void*), 0, compare_rt_entries, udata);
}
+
+int rt_upsert(
+ struct btree *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 = btree_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);
+ 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
+ ((bcidx - rt_entry->bcidx) < 0) // Or the received bcidx is lower than known (old packet)
+ ) {
+ pthread_mutex_unlock(&(iface->bond->mtx_rt));
+ return 0;
+ }
+
+ // 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) {
+ iface_entry = rt_entry->interfaces;
+ rt_entry->interfaces = iface_entry->next;
+ free(iface_entry);
+ }
+ }
+
+ // Update the rt_entry's broadcast index
+ rt_entry->bcidx = bcidx;
+
+ // Add our iface 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;
+
+ // Save rt entry in the routing table if it's new
+ // A pre-existing one is already stored (btree holds pointers, no need to re-save)
+ if (isnew) {
+ btree_set(iface->bond->rt, rt_entry);
+ }
+
+ pthread_mutex_unlock(mtx);
+ return 0;
+}
diff --git a/src/util/routing-table.h b/src/util/routing-table.h
@@ -5,10 +5,18 @@
struct pmlag_rt_entry {
unsigned char *mac; // mac address of the remote entity
- uint16_t bcidx; // broadcast index last seen from the mac
+ int16_t bcidx; // broadcast index last seen from the mac
pmlag_iface_llist *interfaces; // list of pointers to interfaces
};
struct btree * rt_init(void *udata);
+int rt_upsert(
+ struct btree *rt,
+ pthread_mutex_t *mtx,
+ struct pmlag_iface *iface,
+ unsigned char *mac,
+ int16_t bcidx
+);
+
#endif // __PMLAG_UTIL_RT_H__
diff --git a/test.ini b/test.ini
@@ -3,8 +3,8 @@
; eth0 = backup, eth1 = primary
[bond0]
interface=virbr1
-interface=virbr2
-; interface=wlp170s0
+; interface=virbr2
+; interface=virbr6
; interface=docker0
; ; broadcast everything on all interfaces