pmlag

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

routing-table.c (2499B)


      1 #include <linux/if_ether.h>
      2 /* #include <stdio.h> */
      3 /* #include <stdlib.h> */
      4 #include <string.h>
      5 
      6 #include "finwo/mindex.h"
      7 
      8 #include "config.h"
      9 #include "routing-table.h"
     10 
     11 static int rt_compare(const void *a, const void *b, void *udata) {
     12   struct pmlag_rt_entry *ta = (struct pmlag_rt_entry *)a;
     13   struct pmlag_rt_entry *tb = (struct pmlag_rt_entry *)b;
     14   if (a == b) return 0;
     15   return memcmp(ta->mac, tb->mac, ETH_ALEN);
     16 }
     17 
     18 static void rt_purge(void *item, void *udata) {
     19   struct pmlag_rt_entry *rt_entry = (struct pmlag_rt_entry *)item;
     20   if (!rt_entry) return;
     21   if (rt_entry->iface) free(rt_entry->iface);
     22   if (rt_entry->mac) free(rt_entry->mac);
     23   free(rt_entry);
     24 }
     25 
     26 struct mindex_t * rt_init(void *udata) {
     27   return mindex_init(rt_compare, rt_purge, udata);
     28 }
     29 
     30 int rt_upsert(
     31   struct mindex_t    *rt,
     32   struct pmlag_iface *iface,
     33   unsigned char      *mac,
     34   int16_t             bcidx
     35 ) {
     36   struct pmlag_rt_entry *rt_entry;
     37   int i, isnew = 0;
     38   int iface_found = 0;
     39 
     40   // Attempt to fetch the rt entry
     41   rt_entry = mindex_get(rt, &((struct pmlag_rt_entry){ .mac = mac }));
     42 
     43   // None given, build new one
     44   if (!rt_entry) {
     45     rt_entry              = calloc(1, sizeof(struct pmlag_rt_entry));
     46     rt_entry->mac         = malloc(ETH_ALEN);
     47     rt_entry->bcidx       = bcidx;
     48     rt_entry->iface       = calloc(iface->bond->iface_count, sizeof(struct pmlag_iface *));
     49     rt_entry->iface_count = 0;
     50     memcpy(rt_entry->mac, mac, ETH_ALEN);
     51     isnew = 1;
     52   }
     53 
     54   // Clear interface list if bcidx is different
     55   if (rt_entry->bcidx != bcidx) {
     56     rt_entry->iface_count = 0;
     57     rt_entry->bcidx = bcidx;
     58   }
     59 
     60   // Register the interface on the rt_entry
     61   for( i = 0 ; i < rt_entry->iface_count ; i++ ) {
     62     if (rt_entry->iface[i] != iface) continue;
     63     iface_found = 1;
     64     break;
     65   }
     66   if (!iface_found) {
     67     rt_entry->iface[rt_entry->iface_count] = iface;
     68     rt_entry->iface_count++;
     69   }
     70 
     71   // The actual upsert part
     72   if (isnew) {
     73     mindex_set(rt, rt_entry);
     74     // Keep rt size in check
     75     if (rt->length > PMLAG_RT_MAX) {
     76       mindex_delete(rt, mindex_rand(rt));
     77     }
     78   }
     79 
     80   return 0;
     81 }
     82 
     83 struct pmlag_iface * rt_find(
     84   struct mindex_t *rt,
     85   unsigned char *mac
     86 ) {
     87   struct pmlag_rt_entry *rt_entry;
     88 
     89   // Attempt to fetch the rt entry
     90   rt_entry = mindex_get(rt, &((struct pmlag_rt_entry){ .mac = mac }));
     91   if (!rt_entry) return NULL;
     92 
     93   // Unlock the routing table again
     94   struct pmlag_iface *iface = rt_entry->iface[rand() % rt_entry->iface_count];
     95   return iface;
     96 }