Rolf Fokkens wrote:
James Yonan wrote:
Also, it would be great if you could #ifdef this code so that we can turn
it on or off.
Sure, I'll do that. I'll do it based on mac_table.[ch], to save time.
OK? If you want we can integrate mac_table functionality into
lists.[ch], but it may require a lot of your help.
Attached the patch with #ifdefs. I added a #define MACTAB in
config.h.in, though that may not be the proper way to do it.
I tested it with and without the #define MACTAB, both ways it compiles
and runs OK with a TAP interface. I didn't test TUN.
Rolf
diff -ruN openvpn-2.0.2.orig/config.h.in openvpn-2.0.2/config.h.in
--- openvpn-2.0.2.orig/config.h.in 2005-08-25 17:48:07.000000000 +0200
+++ openvpn-2.0.2/config.h.in 2005-10-09 11:29:02.000000000 +0200
@@ -511,3 +511,7 @@
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
#undef volatile
+
+/* Define to integrate new MAC table handling for TAP devices.
+ */
+#define MACTAB
diff -ruN openvpn-2.0.2.orig/mac_table.c openvpn-2.0.2/mac_table.c
--- openvpn-2.0.2.orig/mac_table.c 1970-01-01 01:00:00.000000000 +0100
+++ openvpn-2.0.2/mac_table.c 2005-10-09 12:22:11.000000000 +0200
@@ -0,0 +1,319 @@
+#include "config.h"
+
+#ifdef MACTAB
+
+#include "mac_table.h"
+#include <stdio.h>
+
+#define mix(a,b,c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ b -= c; b -= a; b ^= (a<<8); \
+ c -= a; c -= b; c ^= (b>>13); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<16); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>3); \
+ b -= c; b -= a; b ^= (a<<10); \
+ c -= a; c -= b; c ^= (b>>15); \
+}
+
+static uint32_t mactab_hash_func (const uint8_t *k, uint32_t mask)
+{
+ uint32_t a, b, c;
+
+ /* Set up the internal state */
+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+
+ c = 6;
+ b = (uint32_t)*k++;
+ b += (uint32_t)*k++ + (a << 8);
+ b += 0x9e3779b9;
+
+
+ a = (uint32_t)*k++;
+ a += (uint32_t)*k++ + (a << 8);
+ a += (uint32_t)*k++ + (a << 8);
+ a += (uint32_t)*k++ + (a << 8);
+
+ mix (a, b, c);
+
+ return c & mask;
+}
+
+struct mentry
+{
+ char mac[6];
+ short hval;
+ short active;
+
+ time_t expire;
+
+ struct multi_instance *mi;
+
+ struct mentry *hprev, *hnext; /* Hash Link */
+ struct mentry *cprev, *cnext; /* Cache link */
+};
+
+struct mactab
+{
+ int bucketmask;
+ int nentries;
+ struct mentry **buckets;
+ struct mentry *entries, *free, *head, *tail;
+};
+
+struct mactab *mactab_init (int nentries)
+{
+ struct mactab *mh;
+ struct mentry *me;
+ uint32_t i, j, nbuckets;
+
+ for (i = nentries, j = 1; i != 0; i >>= 1, j++);
+
+ nbuckets = (1 << j);
+
+ mh = malloc (sizeof (struct mactab));
+
+ mh->bucketmask = nbuckets - 1;
+ mh->buckets = (struct mentry **) calloc (nbuckets, sizeof (void *));
+
+ mh->nentries = nentries;
+ mh->entries = (struct mentry *) calloc (nentries, sizeof (struct mentry));
+
+ mh->head = NULL;
+ mh->tail = NULL;
+
+ me = mh->entries;
+ me->cprev = NULL;
+ me->cnext = me + 1;
+ mh->free = me++;
+ nentries -= 2;
+
+ while (nentries--) {
+ me->cprev = me - 1;
+ me->cnext = me + 1;
+ me++;
+ }
+ me->cprev = me - 1;
+ me->cnext = NULL;
+
+ return mh;
+};
+
+void mactab_uninit (struct mactab *mh)
+{
+ if (!mh) return;
+
+ free (mh->entries);
+ free (mh->buckets);
+};
+
+static void mactab_unlink_entry (struct mactab *mh, struct mentry *me)
+{
+ struct mentry *mn, *mp;
+
+ mp = me->cprev;
+ mn = me->cnext;
+
+ if (mp) {
+ mp->cnext = mn;
+ } else {
+ mh->head = mn;
+ }
+ if (mn) {
+ mn->cprev = mp;
+ } else {
+ mh->tail = mp;
+ }
+}
+
+static void mactab_unhash_entry (struct mactab *mh, struct mentry *me)
+{
+ struct mentry *mn, *mp;
+
+ mp = me->hprev;
+ mn = me->hnext;
+
+ if (mp) {
+ mp->hnext = mn;
+ } else {
+ mh->buckets[me->hval] = mn;
+ }
+ if (mn) {
+ mn->hprev = mp;
+ }
+};
+
+static void mactab_free_entry (struct mactab *mh, struct mentry *me)
+{
+ struct mentry *mn;
+
+ mactab_unlink_entry (mh, me);
+ mactab_unhash_entry (mh, me);
+
+ mn = mh->free;
+ mn->cprev = me;
+ me->cnext = mn;
+ me->cprev = NULL;
+ mh->free = me;
+
+ me->active = 0;
+};
+
+static void mactab_link_entry (struct mactab *mh, struct mentry *me)
+{
+ struct mentry *mn;
+
+ mn = mh->head;
+ mh->head = me;
+
+ me->cnext = mn;
+ me->cprev = NULL;
+
+ if (mn) {
+ mn->cprev = me;
+ } else {
+ mh->tail = me;
+ }
+};
+
+static void mactab_hash_entry (struct mactab *mh, struct mentry *me)
+{
+ struct mentry *mn;
+
+ me->hval = mactab_hash_func (me->mac, mh->bucketmask);
+
+ mn = mh->buckets[me->hval];
+ mh->buckets[me->hval] = me;
+
+ me->hnext = mn;
+ me->hprev = NULL;
+
+ if (mn) {
+ mn->hprev = me;
+ }
+};
+
+static void mactab_refresh_entry (struct mactab *mh, struct mentry *me)
+{
+ struct mentry *mn, *mp;
+
+ if (mh->head == me) return;
+
+ mactab_unlink_entry (mh, me);
+ mactab_link_entry (mh, me);
+};
+
+static struct mentry *mactab_find_entry (struct mactab *mh, const uint8_t *mac)
+{
+ int hval;
+ struct mentry *me;
+
+ hval = mactab_hash_func (mac, mh->bucketmask);
+ me = mh->buckets[hval];
+ while (me) {
+ if (memcmp (me->mac, mac, 6) == 0) return me;
+ me = me->hnext;
+ }
+ return NULL;
+};
+
+static struct mentry *mactab_get_entry (struct mactab *mh)
+{
+ struct mentry *me;
+
+ if (mh->free) {
+ me = mh->free;
+ mh->free = me->cnext;
+ return me;
+ }
+ me = mh->tail;
+ mactab_unlink_entry (mh, me);
+ mactab_unhash_entry (mh, me);
+
+ return me;
+};
+
+void mactab_learn_mac
+ ( struct mactab *mh, const uint8_t *mac, time_t expire
+ , struct multi_instance *mi)
+{
+ struct mentry *me;
+
+ me = mactab_find_entry (mh, mac);
+ if (me) {
+ mactab_refresh_entry (mh, me);
+ } else {
+ me = mactab_get_entry (mh);
+ memcpy (me->mac, mac, 6);
+ me->mi = mi;
+ me->active = 1;
+ mactab_hash_entry (mh, me);
+ mactab_link_entry (mh, me);
+ }
+ me->expire = expire;
+};
+
+struct multi_instance *mactab_lookup_mac
+ (struct mactab *mh, const uint8_t *mac, time_t now)
+{
+ struct mentry *me;
+
+ me = mactab_find_entry (mh, mac);
+
+ if (!me) return NULL;
+ if (!me->active) return NULL;
+ if (me->expire < now) return NULL;
+
+ return me->mi;
+};
+
+void mactab_remove_mi (struct mactab *mh, struct multi_instance *mi)
+{
+ struct mentry *me, *ml;
+
+ me = mh->entries;
+ ml = me + mh->nentries;
+
+ while (me < ml)
+ {
+ if (me->mi == mi) me->active = 0;
+ me++;
+ }
+};
+
+int mactab_getnext
+ ( struct mactab *mh, int cur, time_t now
+ , char *mac, int *ttl, struct multi_instance **mi)
+{
+ struct mentry *me;
+
+ while (cur < mh->nentries)
+ {
+ me = mh->entries + cur++;
+ if (me->mi && me->expire > now && me->active)
+ {
+ memcpy (mac, me->mac, 6);
+ *ttl = me->expire - now;
+ *mi = me->mi;
+ return cur;
+ }
+ }
+ return 0;
+};
+
+char *mactab_print (uint8_t *mac)
+{
+ static char buf[19];
+ char *cp = buf;
+ int i;
+
+ for (i = 0; i < 6; i++)
+ {
+ cp += sprintf (cp, ":%02X", (int)*mac++);
+ }
+ return buf + 1;
+};
+
+#endif /* MACTAB */
diff -ruN openvpn-2.0.2.orig/mac_table.h openvpn-2.0.2/mac_table.h
--- openvpn-2.0.2.orig/mac_table.h 1970-01-01 01:00:00.000000000 +0100
+++ openvpn-2.0.2/mac_table.h 2005-10-09 11:31:41.000000000 +0200
@@ -0,0 +1,35 @@
+#ifndef H_MHASH
+#define H_MHASH
+
+#ifdef MACTAB
+
+#include <time.h>
+
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+
+struct multi_instance;
+struct mactab;
+struct mactab_entry;
+
+extern struct mactab *mactab_init (int nentries);
+extern void mactab_uninit (struct mactab *mh);
+
+extern void mactab_learn_mac
+ ( struct mactab *mh, const uint8_t *mac, time_t expire
+ , struct multi_instance *mi);
+
+extern struct multi_instance *mactab_lookup_mac
+ (struct mactab *mh, const uint8_t *mac, time_t now);
+
+extern void mactab_remove_mi (struct mactab *mh, struct multi_instance *mi);
+
+extern int mactab_getnext
+ ( struct mactab *mh, int cur, time_t now
+ , char *mac, int *ttl, struct multi_instance **mi);
+
+extern char *mactab_print (uint8_t *mac);
+
+#endif /* MACTAB */
+
+#endif
diff -ruN openvpn-2.0.2.orig/Makefile.in openvpn-2.0.2/Makefile.in
--- openvpn-2.0.2.orig/Makefile.in 2005-08-25 17:48:10.000000000 +0200
+++ openvpn-2.0.2/Makefile.in 2005-10-06 08:46:16.000000000 +0200
@@ -102,7 +102,7 @@
route.$(OBJEXT) schedule.$(OBJEXT) session_id.$(OBJEXT) \
shaper.$(OBJEXT) sig.$(OBJEXT) socket.$(OBJEXT) \
socks.$(OBJEXT) ssl.$(OBJEXT) status.$(OBJEXT) \
- thread.$(OBJEXT) tun.$(OBJEXT)
+ thread.$(OBJEXT) tun.$(OBJEXT) mac_table.$(OBJEXT)
nodist_openvpn_OBJECTS =
openvpn_OBJECTS = $(am_openvpn_OBJECTS) $(nodist_openvpn_OBJECTS)
openvpn_LDADD = $(LDADD)
@@ -135,7 +135,7 @@
@AMDEP_TRUE@ ./$(DEPDIR)/sig.Po ./$(DEPDIR)/socket.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/socks.Po ./$(DEPDIR)/ssl.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/status.Po ./$(DEPDIR)/thread.Po \
-@AMDEP_TRUE@ ./$(DEPDIR)/tun.Po
+@AMDEP_TRUE@ ./$(DEPDIR)/tun.Po ./$(DEPDIR)/mac_table.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
@@ -308,7 +308,8 @@
status.c status.h \
syshead.h \
thread.c thread.h \
- tun.c tun.h
+ tun.c tun.h \
+ mac_table.c mac_table.h
LDADD = @LIBOBJS@
man_MANS = openvpn.8
@@ -484,6 +485,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac_table.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
diff -ruN openvpn-2.0.2.orig/multi.c openvpn-2.0.2/multi.c
--- openvpn-2.0.2.orig/multi.c 2005-08-04 01:59:32.000000000 +0200
+++ openvpn-2.0.2/multi.c 2005-10-09 12:00:40.000000000 +0200
@@ -55,6 +55,10 @@
}
#endif
+#ifdef MACTAB
+static struct multi_instance mi_tap;
+#endif /* MACTAB */
+
static bool
learn_address_script (const struct multi_context *m,
const struct multi_instance *mi,
@@ -130,6 +134,10 @@
struct hash_iterator hi;
struct hash_element *he;
+#ifdef MACTAB
+ if (!m->vhash) return;
+#endif /* MACTAB */
+
if (start_bucket < 0)
{
start_bucket = 0;
@@ -175,6 +183,11 @@
multi_reap_process_dowork (const struct multi_context *m)
{
struct multi_reap *mr = m->reaper;
+
+#ifdef MACTAB
+ if (!m->vhash) return;
+#endif /* MACTAB */
+
if (mr->bucket_base >= hash_n_buckets (m->vhash))
mr->bucket_base = 0;
multi_reap_range (m, mr->bucket_base, mr->bucket_base + mr->buckets_per_pass);
@@ -231,13 +244,26 @@
mroute_addr_hash_function,
mroute_addr_compare_function);
- /*
- * Virtual address hash table. Used to determine
- * which client to route a packet to.
- */
- m->vhash = hash_init (t->options.virtual_hash_size,
- mroute_addr_hash_function,
- mroute_addr_compare_function);
+#ifdef MACTAB
+ if (dev == DEV_TYPE_TAP)
+ {
+ m->vhash = NULL;
+ m->mtab = mactab_init (1024);
+ }
+ else
+ {
+ m->mtab = NULL;
+#endif /* MACTAB */
+ /*
+ * Virtual address hash table. Used to determine
+ * which client to route a packet to.
+ */
+ m->vhash = hash_init (t->options.virtual_hash_size,
+ mroute_addr_hash_function,
+ mroute_addr_compare_function);
+#ifdef MACTAB
+ }
+#endif /* MACTAB */
/*
* This hash table is a clone of m->hash but with a
@@ -485,6 +511,10 @@
ungenerate_prefix (mi);
+#ifdef MACTAB
+ if (m->mtab) mactab_remove_mi (m->mtab, mi);
+#endif /* MACTAB */
+
/*
* Don't actually delete the instance memory allocation yet,
* because virtual routes may still point to it. Let the
@@ -525,7 +555,12 @@
multi_reap_all (m);
hash_free (m->hash);
+#ifdef MACTAB
+ if (m->vhash) hash_free (m->vhash);
+ if (m->mtab) mactab_uninit (m->mtab);
+#else
hash_free (m->vhash);
+#endif /* MACTAB */
hash_free (m->iter);
m->hash = NULL;
@@ -660,7 +695,44 @@
hash_iterator_free (&hi);
status_printf (so, "ROUTING TABLE");
+
+#ifdef MACTAB
+ if (m->mtab)
+ {
+ struct mactab *mh = m->mtab;
+ struct multi_instance *mi;
+ struct gc_arena gc = gc_new ();
+ int ttl, cur = 0;
+ char mac[6];
+
+ status_printf (so, "Virtual Address,Common Name,Real Address,TTL");
+ while (cur = mactab_getnext (mh, cur, now, mac, &ttl, &mi))
+ {
+ if (mi == &mi_tap)
+ {
+ status_printf (so, "%s,%s,%s,%d",
+ mactab_print (mac),
+ "LOCAL",
+ "LOCAL",
+ ttl);
+ }
+ else
+ {
+ status_printf (so, "%s,%s,%s,%d",
+ mactab_print (mac),
+ tls_common_name (mi->context.c2.tls_multi, false),
+ mroute_addr_print (&mi->real, &gc),
+ ttl);
+ }
+ }
+ gc_free (&gc);
+ }
+
+ if (m->vhash)
+ {
+#endif /* MACTAB */
status_printf (so, "Virtual Address,Common Name,Real Address,Last Ref");
+
hash_iterator_init (m->vhash, &hi, true);
while ((he = hash_iterator_next (&hi)))
{
@@ -685,6 +757,9 @@
gc_free (&gc);
}
hash_iterator_free (&hi);
+#ifdef MACTAB
+ }
+#endif /* MACTAB */
status_printf (so, "GLOBAL STATS");
if (m->mbuf)
@@ -722,7 +797,13 @@
}
hash_iterator_free (&hi);
+#ifdef MACTAB
+/* TODO: */
+ if (m->vhash)
+ {
+#endif /* MACTAB */
status_printf (so, "HEADER,ROUTING_TABLE,Virtual Address,Common Name,Real Address,Last Ref,Last Ref (time_t)");
+
hash_iterator_init (m->vhash, &hi, true);
while ((he = hash_iterator_next (&hi)))
{
@@ -748,6 +829,9 @@
gc_free (&gc);
}
hash_iterator_free (&hi);
+#ifdef MACTAB
+ }
+#endif /* MACTAB */
if (m->mbuf)
status_printf (so, "GLOBAL_STATS,Max bcast/mcast queue length,%d",
@@ -779,11 +863,21 @@
const unsigned int flags)
{
struct hash_element *he;
- const uint32_t hv = hash_value (m->vhash, addr);
- struct hash_bucket *bucket = hash_bucket (m->vhash, hv);
+ uint32_t hv;
+ struct hash_bucket *bucket;
struct multi_route *oldroute = NULL;
struct multi_instance *owner = NULL;
+#ifdef MACTAB
+ if (m->mtab) {
+ mactab_learn_mac (m->mtab, addr->addr, now + MULTI_CACHE_ROUTE_TTL, mi);
+ return mi;
+ }
+#endif /* MACTAB */
+
+ hv = hash_value (m->vhash, addr);
+ bucket = hash_bucket (m->vhash, hv);
+
hash_bucket_lock (bucket);
/* if route currently exists, get the instance which owns it */
@@ -874,6 +968,12 @@
if (mroute_addr_equal (addr, &m->local))
return NULL;
+#ifdef MACTAB
+ if (m->mtab) {
+ return mactab_lookup_mac (m->mtab, addr->addr, now);
+ }
+#endif /* MACTAB */
+
route = (struct multi_route *) hash_lookup (m->vhash, addr);
/* does host route (possible cached) exist? */
@@ -1577,6 +1677,7 @@
unsigned int mroute_flags;
struct multi_instance *mi;
bool ret = true;
+ int dev_type;
ASSERT (!m->pending);
@@ -1611,7 +1712,8 @@
/* decrypt in instance context */
process_incoming_link (c);
- if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TUN)
+ dev_type = TUNNEL_TYPE (m->top.c1.tuntap);
+ if (dev_type == DEV_TYPE_TUN)
{
/* extract packet source and dest addresses */
mroute_flags = mroute_extract_addr_from_packet (&src,
@@ -1655,7 +1757,7 @@
}
}
}
- else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP)
+ else if (dev_type == DEV_TYPE_TAP)
{
/* extract packet source and dest addresses */
mroute_flags = mroute_extract_addr_from_packet (&src,
@@ -1677,10 +1779,18 @@
else /* try client-to-client routing */
{
mi = multi_get_instance_by_virtual_addr (m, &dest, false);
-
- /* if dest addr is a known client, route to it */
+#ifdef MACTAB
+ if (!mi)
+ {
+ /* No known client? Do like a switch: broadcast */
+ if (dev_type == DEV_TYPE_TAP) multi_bcast (m, &c->c2.to_tun, m->pending);
+ }
+ else if (mi != &mi_tap)
+#else
if (mi)
+#endif /* MACTAB */
{
+ /* if dest addr is a known client, route to it */
multi_unicast (m, &c->c2.to_tun, mi);
register_activity (c);
c->c2.to_tun.len = 0;
@@ -1748,6 +1858,10 @@
{
struct context *c;
+#ifdef MACTAB
+ if (dev_type == DEV_TYPE_TAP) multi_learn_addr (m, &mi_tap, &src, 0);
+#endif /* MACTAB */
+
/* broadcast or multicast dest addr? */
if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST))
{
@@ -1756,9 +1870,22 @@
}
else
{
- multi_set_pending (m, multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN));
+#ifdef MACTAB
+ struct multi_instance *mi;
+
+ mi = multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN);
+ multi_set_pending (m, mi);
+ if (!mi)
+ {
+ /* No known instance? Do like a switch: broadcast */
+ if (dev_type == DEV_TYPE_TAP) multi_bcast (m, &m->top.c2.buf, NULL);
+ }
+ else if (mi != &mi_tap)
+#else
+ multi_set_pending (m, multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN));
if (m->pending)
+#endif /* MACTAB */
{
/* get instance context */
c = &m->pending->context;
diff -ruN openvpn-2.0.2.orig/multi.h openvpn-2.0.2/multi.h
--- openvpn-2.0.2.orig/multi.h 2005-08-04 21:30:33.000000000 +0200
+++ openvpn-2.0.2/multi.h 2005-10-09 11:48:14.000000000 +0200
@@ -37,6 +37,7 @@
#include "mudp.h"
#include "mtcp.h"
#include "perf.h"
+#include "mac_table.h"
/*
* Walk (don't run) through the routing table,
@@ -97,6 +98,9 @@
struct hash *hash; /* client instances indexed by real address */
struct hash *vhash; /* client instances indexed by virtual address */
+#ifdef MACTAB
+ struct mactab *mtab; /* client instances indexed by virtual MAC address */
+#endif /* MACTAB */
struct hash *iter; /* like real address hash but optimized for iteration */
struct schedule *schedule;
struct mbuf_set *mbuf;