Ist im Grunde das, was wir auch machen, allerdings haben wir mittlerweile die fastd-Prozesse auf den Host verlagert und wir bridgen die fastd-Interfaces in die Gateway-VMs. Das ist deutlich weniger schmerzhaft als früher, als die Gateway-VMs lokal fastd laufen hatten.
root@thunderflare:~# brctl show
[…]
fastd176-br 8000.deafbee00001 no gut176-vpn
one-199-1
fastd177-br 8000.deafbee00002 no gut177-vpn
one-199-2
fastd178-br 8000.deafbee00003 no gut178-vpn
one-199-3
fastd179-br 8000.deafbee00004 no gut179-vpn
one-199-4
[…]
(gutNNN-vpn ist ein VXLAN zwischen unseren Hosts, somit kann auf jedem eine GW-VM gestartet werden. Wie man sieht, laufen hier 4 fastd-Tunnel in eine VM (one-199; wir nutzen OpenNebula als Virrtualisierungsfrontend), die ohne fastd nichts rechenintensives mehr zu leisten hat.)
Weil fastd aber auf mehreren Ebenen »keinen Spaß« macht, schwenken wir ›derzeit‹ auf L2TP als Tunnelprotokoll; tunneldigger läuft dann wieder in der GW-VM (die bei uns traditionell – batman_adv.ko hat sonst phasenweise Stabilitätsprobleme – 1 CPU haben). Die alten GWs haben wir mit Puppet nach dem Muster von Freifunk Nord aufgesetzt, für das neue Setup setzen wir auf die Ansible-›Rollen‹ nach Münsteraner Muster.
Jene setzt die GWs dann so auf, daß dann je Mesh (»Domäne«) u. a. ein tunneldigger läuft, eine entsprechende Bridge besteht, ein batman-Interface, …
root@l2tp-ham01 ~ # ps -Aelf|grep tunneld
4 S root 578 1 0 80 0 - 16378 ep_pol Jun14 ? 00:00:02 /srv/tunneldigger/env_tunneldigger/bin/python -m tunneldigger_broker.main /srv/tunneldigger/broker/l2tp_broker_domain00.cfg
4 S root 607 1 0 80 0 - 16442 ep_pol Jun14 ? 00:04:37 /srv/tunneldigger/env_tunneldigger/bin/python -m tunneldigger_broker.main /srv/tunneldigger/broker/l2tp_broker_domain02.cfg
4 S root 608 1 0 80 0 - 16378 ep_pol Jun14 ? 00:00:00 /srv/tunneldigger/env_tunneldigger/bin/python -m tunneldigger_broker.main /srv/tunneldigger/broker/l2tp_broker_domain03.cfg
4 S root 609 1 0 80 0 - 16742 ep_pol Jun14 ? 00:15:46 /srv/tunneldigger/env_tunneldigger/bin/python -m tunneldigger_broker.main /srv/tunneldigger/broker/l2tp_broker_domain04.cfg
4 S root 614 1 0 80 0 - 16378 ep_pol Jun14 ? 00:00:00 /srv/tunneldigger/env_tunneldigger/bin/python -m tunneldigger_broker.main /srv/tunneldigger/broker/l2tp_broker_domain06.cfg
4 S root 616 1 0 80 0 - 17007 ep_pol Jun14 ? 01:31:21 /srv/tunneldigger/env_tunneldigger/bin/python -m tunneldigger_broker.main /srv/tunneldigger/broker/l2tp_broker_domain01.cfg
4 S root 637 1 0 80 0 - 16475 ep_pol Jun14 ? 00:16:25 /srv/tunneldigger/env_tunneldigger/bin/python -m tunneldigger_broker.main /srv/tunneldigger/broker/l2tp_broker_domain05.cfg
root@l2tp-ham01 ~ # brctl show
bridge name bridge id STP enabled interfaces
br00 8000.02caffee0002 no
br01 8000.02caffee0102 no l2tp379-379
l2tp436-436
l2tp437-437
l2tp443-443
l2tp445-445
l2tp446-446
l2tp447-447
br02 8000.02caffee0202 no
br03 8000.02caffee0302 no
br04 8000.02caffee0402 no l2tp153-153
br05 8000.02caffee0502 no l2tp152-152
br06 8000.02caffee0602 no
root@l2tp-ham01 ~ # batctl -m bat00 if
br00: active
t00-karte: active
t00-l2tp-ams01: active
root@l2tp-ham01 ~ # batctl -m bat06 if
br06: active
t06-karte: active
t06-l2tp-ber01: active
Wieviele Meshes je GW laufen sollen kann man einstellen, so ist der Partner für die zukünftige »Domäne 00« nicht, wie für alle anderen, eine VM auf unserem System in Berlin sondern eine VM in Amsterdam.
Tunnel zum Kartenserver und zu anderen GWs werden auch automatisch angelegt (auf Wunsch auch die Kartenserver-VM gebaut), das macht das recht pflegeleicht 
BTW: Ich würde bevorzugt auf L2TP o. ä. zwischen den Gateways setzen, keinesfalls fastd: fastd verbrät nur unnütz Rechenzeit, das geht heute eleganter und performanter.
Nachtrag: Das Routing zwischen den Meshes läuft über OSPF, auch das wird automagisch eingerichtet.