Merge branch 'release-0.6.5'
authorFerry Huberts <ferry.huberts@pelagic.nl>
Thu, 28 Feb 2013 16:42:51 +0000 (17:42 +0100)
committerFerry Huberts <ferry.huberts@pelagic.nl>
Thu, 28 Feb 2013 16:42:51 +0000 (17:42 +0100)
* release-0.6.5:
  gateway: work around kernel IPIP module initialisation bug
  pud: better detection of java jdk
  pud: detect the java include directory

Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
52 files changed:
Makefile
Makefile.inc
README-Olsr-Extensions
doc/Makefile
files/olsrd.conf.commotion
files/olsrd.conf.default.full
files/olsrd.conf.default.lq
files/olsrd.conf.default.lq-fisheye
files/olsrd.ufw.profile [new file with mode: 0644]
files/sgw_policy_routing_setup.sh [new file with mode: 0755]
gui/linux-gtk/Makefile
gui/win32/Inst/installer.nsi
gui/win32/Main/Frontend.rc
lib/dyn_gw/src/olsrd_dyn_gw.c
lib/jsoninfo/src/olsrd_jsoninfo.c
lib/mdns/Makefile
lib/mdns/src/NetworkInterfaces.c
lib/mdns/src/container_of.h
lib/mdns/src/mdns.c
lib/p2pd/Makefile
lib/pud/doc/pud.odt
lib/pud/nmealib/Makefile
lib/pud/nmealib/Makefile.inc
lib/pud/src/configuration.c
lib/pud/src/netTools.h
lib/pud/src/pud.c
lib/pud/src/uplinkGateway.c
lib/pud/wireformat-java/Makefile
lib/pud/wireformat/Makefile
lib/quagga/README_QUAGGA
lib/quagga/src/common.h
lib/quagga/src/plugin.c
lib/quagga/src/quagga.c
make/Makefile.win32
src/bsd/dummy.c
src/cfgparser/cfgfile_gen.c
src/cfgparser/olsrd_conf.c
src/cfgparser/oparse.y
src/cfgparser/oscan.lex
src/gateway.c
src/gateway.h
src/gateway_default_handler.c
src/gateway_list.c [new file with mode: 0644]
src/gateway_list.h [new file with mode: 0644]
src/kernel_routes.h
src/kernel_tunnel.h
src/linux/kernel_routes_nl.c
src/linux/kernel_tunnel.c
src/main.c
src/olsr_cfg.h
src/scheduler.c
src/win32/dummy.c

index 3b14b9d..6d5c0e5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,7 +39,7 @@
 # Please also write a new version to:
 # gui/win32/Main/Frontend.rc (line 71, around "CAPTION [...]")
 # gui/win32/Inst/installer.nsi (line 57, around "MessageBox MB_YESNO [...]")
-VERS =         pre-0.6.5.3
+VERS =         pre-0.6.6
 
 TOPDIR = .
 INSTALLOVERWRITE ?=
@@ -59,6 +59,15 @@ CFGDIR =     src/cfgparser
 include $(CFGDIR)/local.mk
 TAG_SRCS =     $(SRCS) $(HDRS) $(wildcard $(CFGDIR)/*.[ch] $(SWITCHDIR)/*.[ch])
 
+SGW_SUPPORT = 0
+ifeq ($(OS),linux)
+  SGW_SUPPORT = 1
+endif
+ifeq ($(OS),android)
+  SGW_SUPPORT = 1
+endif
+
+
 .PHONY: default_target switch
 default_target: $(EXENAME)
 
@@ -122,6 +131,14 @@ install_bin:
                mkdir -p $(SBINDIR)
                install -m 755 $(EXENAME) $(SBINDIR)
                $(STRIP) $(SBINDIR)/$(EXENAME)
+ifeq ($(SGW_SUPPORT),1)
+               $(MAKECMDPREFIX)if [ -e $(SBINDIR)/$(SGW_POLICY_SCRIPT) ]; then \
+                       cp -f files/$(SGW_POLICY_SCRIPT) $(SBINDIR)/$(SGW_POLICY_SCRIPT).new; \
+                       echo "Policy routing script was saved as $(SBINDIR)/$(SGW_POLICY_SCRIPT).new"; \
+               else \
+                       cp -f files/$(SGW_POLICY_SCRIPT) $(SBINDIR)/$(SGW_POLICY_SCRIPT); \
+               fi
+endif
 
 uninstall_bin:
                rm -f $(SBINDIR)/$(EXENAME)
@@ -180,15 +197,15 @@ rpm:
 
 # This is quite ugly but at least it works
 ifeq ($(OS),linux)
-SUBDIRS = arprefresh bmf dot_draw dyn_gw dyn_gw_plain httpinfo jsoninfo mdns mini nameservice p2pd pgraph pud quagga secure sgwdynspeed txtinfo watchdog
+SUBDIRS := arprefresh bmf dot_draw dyn_gw dyn_gw_plain httpinfo jsoninfo mdns mini nameservice p2pd pgraph pud quagga secure sgwdynspeed txtinfo watchdog
 else
 ifeq ($(OS),win32)
 SUBDIRS := dot_draw httpinfo jsoninfo mini pgraph secure txtinfo
 else
 ifeq ($(OS),android)
-SUBDIRS := arprefresh bmf dot_draw dyn_gw_plain httpinfo jsoninfo mini nameservice pgraph pud secure sgwdynspeed txtinfo watchdog
+SUBDIRS := arprefresh bmf dot_draw dyn_gw dyn_gw_plain httpinfo jsoninfo mdns mini nameservice p2pd pgraph pud secure sgwdynspeed txtinfo watchdog
 else
-SUBDIRS := dot_draw dyn_gw dyn_gw_plain httpinfo jsoninfo mini nameservice pgraph secure txtinfo watchdog
+SUBDIRS := dot_draw httpinfo jsoninfo mini nameservice pgraph secure txtinfo watchdog
 endif
 endif
 endif
index 9ef9881..657f92a 100644 (file)
@@ -68,6 +68,7 @@ MANDIR   ?= $(SHAREDIR)/man
 EXENAME  ?= olsrd
 CFGNAME  ?= $(EXENAME).conf
 CFGFILE  ?= $(ETCDIR)/$(CFGNAME)
+SGW_POLICY_SCRIPT ?= sgw_policy_routing_setup.sh
 
 DOCDIR_OLSRD ?= $(DOCDIR)/$(EXENAME)
 
@@ -189,6 +190,18 @@ LIBS +=            $(OS_LIB_PTHREAD)
 # extra options from the outside
 CPPFLAGS +=    $(EXTRA_CPPFLAGS)
 
+
+# 32/64 cross compilation
+ifdef M32
+CFLAGS +=      -m32
+LDFLAGS +=     -m32
+endif
+ifdef M64
+CFLAGS +=      -m64
+LDFLAGS +=     -m64
+endif
+
+
 ###################################
 #
 # options to save space on small systems
index ac244cf..5423e03 100644 (file)
@@ -251,20 +251,41 @@ All other parameters will be ignored if SmartGateway is set to "no"
 
     5.2) Client Side
 
-1- SmartGatewayAllowNAT controls whether you want to allow the selection
+1- SmartGatewayUseCount controls the maximum number of gateways that can be
+   in use at any given time. This setting is used to mitigate the effects of
+   breaking connections (due to the selection of a new gateway) on a dynamic
+   network.
+   The default setting is 1.
+2- SmartGatewayPolicyRoutingScript controles the policy routing script that is
+   executed during startup and shutdown of olsrd. The script is only executed
+   when SmartGatewayUseCount is set to a value larger than 1. The script must
+   setup policy routing rules such that multi-gateway mode works. A sample
+   script is included.
+   The default setting is 'not set'.
+3- SmartGatewayEgressInterfaces determines the egress interfaces that are part
+   of the multi-gateway setup and therefore only relevant when
+   SmartGatewayUseCount is larger than 1 (in which case it must be explicitly
+   set).
+   The default setting is 'not set'.
+4- SmartGatewayMarkOffsetEgress and SmartGatewayMarkOffsetTunnels determine
+   the ranges of policy routing rule markings that are used in a multi-gateway
+   setup. The ranges are not allowed to overlap. Both settings are only
+   relevant when a multi-gateway setup is used.
+   The default settings are 91 and 101 respectively.
+5- SmartGatewayAllowNAT controls whether you want to allow the selection
    of an outgoing ipv4 gateway with NAT (Network Address Translation).
    The default setting is "yes".
-2- SmartGatewayPeriod determines the period (in milliseconds) on which
+6- SmartGatewayPeriod determines the period (in milliseconds) on which
    a new smart gateway selection is performed.
    The default setting is 10000 milliseconds.
-3- SmartGatewayStableCount determines the number of times the link state
+7- SmartGatewayStableCount determines the number of times the link state
    database must be stable before a new smart gateway is selected.
    The default setting is 6.
-4- SmartGatewayThreshold controls whether you want to allow re-selection
+8- SmartGatewayThreshold controls whether you want to allow re-selection
    of a new outgoing gateway if its routing cost is lower or equal to the
    configured percentage of the routing cost of the current gateway.
    The default setting is 0, which disables it.
-5- SmartGatewayWeightExitLinkUp, SmartGatewayWeightExitLinkDown,
+9- SmartGatewayWeightExitLinkUp, SmartGatewayWeightExitLinkDown,
    SmartGatewayWeightEtx and SmartGatewayDividerEtx control the weighing
    of gateway bandwidth and ETX costs.
 
@@ -331,6 +352,9 @@ All other parameters will be ignored if SmartGateway is set to "no"
    local IPv6 address to use the IPv6 gateway without any kind of address
    translation. The maximum prefix length is 64 bits,
    the default is ::/0 (no prefix).
+5- SmartGatewayAlwaysRemoveServerTunnel can be used to signal that the
+   server tunnel must always be removed on shutdown, irrespective of the
+   interface up/down state during startup.
 
 
     5.4) Architecture & Notes
index c6dec19..ced50a0 100644 (file)
@@ -56,10 +56,10 @@ clean:
 doc: $(DOX_FILE)
        @echo "[$@] doc"
        @echo "  Cleaning up $(OS) outputs..."
-       @rm -fr "$(HTML_OUTPUT)" "$(LATEX_OUTPUT)" "$(PDF_OUTPUT)"
-       @mkdir -p "$(HTML_OUTPUT)"
-       @mkdir -p "$(LATEX_OUTPUT)"
-       @mkdir -p "$(PDF_DIR)"
+       @rm -frv "$(HTML_OUTPUT)" "$(LATEX_OUTPUT)" "$(PDF_OUTPUT)"
+       @mkdir -pv "$(HTML_OUTPUT)"
+       @mkdir -pv "$(LATEX_OUTPUT)"
+       @mkdir -pv "$(PDF_DIR)"
        @echo "  Generating doxygen configuration..."
        @sed \
          -e "s/__OLSRD_VER__/$(OLSRD_VER)/" \
@@ -72,11 +72,11 @@ doc: $(DOX_FILE)
          "$(DOX_FILE)" > "$(TMP_DOX_FILE)"
        @echo "  Running doxygen to create HTML..."
        @doxygen "$(TMP_DOX_FILE)"
-       @rm -f "$(TMP_DOX_FILE)"
+       @rm -fv "$(TMP_DOX_FILE)"
        @echo "  Running latex to create a PDF..."
-       @$(MAKE) -s -C $(LATEX_OUTPUT) all > /dev/null 2>&1
-       @mkdir -p "$(PDF_DIR)"
-       @mv "$(LATEX_OUTPUT)/refman.pdf" "$(PDF_OUTPUT)"
-       @rm -fr "$(LATEX_OUTPUT)"
-       @rmdir --ignore-fail-on-non-empty "$(LATEX_DIR)"
+       @$(MAKE) -s -C $(LATEX_OUTPUT) all
+       @mkdir -pv "$(PDF_DIR)"
+       @mv -v "$(LATEX_OUTPUT)/refman.pdf" "$(PDF_OUTPUT)"
+       @rm -frv "$(LATEX_OUTPUT)"
+       @rmdir -v --ignore-fail-on-non-empty "$(LATEX_DIR)"
        @echo "  Done"
index 3709ed5..029e600 100644 (file)
@@ -23,14 +23,9 @@ LoadPlugin "olsrd_dyn_gw.so.0.5"
 {
 }
 
-LoadPlugin "olsrd_httpinfo.so.0.1"
-{
-       PlParam "Net" "0.0.0.0 0.0.0.0"
-       PlParam "port" "1978"
-}
-
 LoadPlugin "olsrd_nameservice.so.0.3"
 {
+    # you should set this to your own node name
        PlParam "name" "commotion-7814921"
        PlParam "sighup-pid-file" "/var/run/dnsmasq.pid"
        PlParam "suffix" ".mesh"
@@ -43,13 +38,21 @@ LoadPlugin "olsrd_p2pd.so.0.1.0"
        PlParam "UdpDestPort" "224.0.0.251 5353"
 }
 
+LoadPlugin "olsrd_jsoninfo.so.0.0"
+{
+#      PlParam "accept" "0.0.0.0"
+}
+
 LoadPlugin "olsrd_txtinfo.so.0.1"
 {
-       PlParam "accept" "0.0.0.0"
+#      PlParam "accept" "0.0.0.0"
 }
 
-Interface "wlan0"
+InterfaceDefaults
 {
+    # if you using this on Mac OS X, then comment this out because Mac OS X
+    # does weird things with 255.255.255.255. By commenting this out, olsrd
+    # will use the broadcast that's assigned to the network interface
        Ip4Broadcast 255.255.255.255
 }
 
index 6b11c7d..bdb6894 100644 (file)
 
 # SmartGateway no
 
+# Signals that the server tunnel must always be removed on shutdown,
+# irrespective of the interface up/down state during startup.
+# (default is "no")
+
+# SmartGatewayAlwaysRemoveServerTunnel no
+
+# Determines the maximum number of gateways that can be in use at any given
+# time. This setting is used to mitigate the effects of breaking connections
+# (due to the selection of a new gateway) on a dynamic network.
+# (default is 1)
+
+# SmartGatewayUseCount 1
+
+# Determines the policy routing script that is executed during startup and
+# shutdown of olsrd. The script is only executed when SmartGatewayUseCount
+# is set to a value larger than 1. The script must setup policy routing
+# rules such that multi-gateway mode works. A sample script is included.
+# (default is not set)
+
+# SmartGatewayPolicyRoutingScript ""
+
+# Determines the egress interfaces that are part of the multi-gateway setup and
+# therefore only relevant when SmartGatewayUseCount is larger than 1 (in which
+# case it must be explicitly set).
+# (default is not set)
+
+# SmartGatewayEgressInterfaces ""
+
+# Determines the offset of the smart gateway egress interfaces mark that are
+# used in the policy routing rules in a multi-gateway setup. Only relevant
+# when a multi-gateway setup is used.
+# (default is 91)
+
+# SmartGatewayMarkOffsetEgress 91
+
+# Determines the offset of the smart gateway tunnel interfaces mark that are
+# used in the policy routing rules in a multi-gateway setup. Only relevant
+# when a multi-gateway setup is used.
+# The ranges [egress offset, egress offset + egress count] and
+# [tunnel offset, tunnel offset + use count] are not allowed to overlap.
+# (default is 101)
+
+# SmartGatewayMarkOffsetTunnels 101
+
 # Allows the selection of a smartgateway with NAT (only for IPv4)
 # (default is "yes")
 
index 4ed0650..cfb24d4 100644 (file)
 
 # SmartGateway no
 
+# Signals that the server tunnel must always be removed on shutdown,
+# irrespective of the interface up/down state during startup.
+# (default is "no")
+
+# SmartGatewayAlwaysRemoveServerTunnel no
+
+# Determines the maximum number of gateways that can be in use at any given
+# time. This setting is used to mitigate the effects of breaking connections
+# (due to the selection of a new gateway) on a dynamic network.
+# (default is 1)
+
+# SmartGatewayUseCount 1
+
+# Determines the policy routing script that is executed during startup and
+# shutdown of olsrd. The script is only executed when SmartGatewayUseCount
+# is set to a value larger than 1. The script must setup policy routing
+# rules such that multi-gateway mode works. A sample script is included.
+# (default is not set)
+
+# SmartGatewayPolicyRoutingScript ""
+
+# Determines the egress interfaces that are part of the multi-gateway setup and
+# therefore only relevant when SmartGatewayUseCount is larger than 1 (in which
+# case it must be explicitly set).
+# (default is not set)
+
+# SmartGatewayEgressInterfaces ""
+
+# Determines the offset of the smart gateway egress interfaces mark that are
+# used in the policy routing rules in a multi-gateway setup. Only relevant
+# when a multi-gateway setup is used.
+# (default is 91)
+
+# SmartGatewayMarkOffsetEgress 91
+
+# Determines the offset of the smart gateway tunnel interfaces mark that are
+# used in the policy routing rules in a multi-gateway setup. Only relevant
+# when a multi-gateway setup is used.
+# The ranges [egress offset, egress offset + egress count] and
+# [tunnel offset, tunnel offset + use count] are not allowed to overlap.
+# (default is 101)
+
+# SmartGatewayMarkOffsetTunnels 101
+
 # Allows the selection of a smartgateway with NAT (only for IPv4)
 # (default is "yes")
 
index 0437239..7e7b8cc 100644 (file)
 
 # SmartGateway no
 
+# Signals that the server tunnel must always be removed on shutdown,
+# irrespective of the interface up/down state during startup.
+# (default is "no")
+
+# SmartGatewayAlwaysRemoveServerTunnel no
+
+# Determines the maximum number of gateways that can be in use at any given
+# time. This setting is used to mitigate the effects of breaking connections
+# (due to the selection of a new gateway) on a dynamic network.
+# (default is 1)
+
+# SmartGatewayUseCount 1
+
+# Determines the policy routing script that is executed during startup and
+# shutdown of olsrd. The script is only executed when SmartGatewayUseCount
+# is set to a value larger than 1. The script must setup policy routing
+# rules such that multi-gateway mode works. A sample script is included.
+# (default is not set)
+
+# SmartGatewayPolicyRoutingScript ""
+
+# Determines the egress interfaces that are part of the multi-gateway setup and
+# therefore only relevant when SmartGatewayUseCount is larger than 1 (in which
+# case it must be explicitly set).
+# (default is not set)
+
+# SmartGatewayEgressInterfaces ""
+
+# Determines the offset of the smart gateway egress interfaces mark that are
+# used in the policy routing rules in a multi-gateway setup. Only relevant
+# when a multi-gateway setup is used.
+# (default is 91)
+
+# SmartGatewayMarkOffsetEgress 91
+
+# Determines the offset of the smart gateway tunnel interfaces mark that are
+# used in the policy routing rules in a multi-gateway setup. Only relevant
+# when a multi-gateway setup is used.
+# The ranges [egress offset, egress offset + egress count] and
+# [tunnel offset, tunnel offset + use count] are not allowed to overlap.
+# (default is 101)
+
+# SmartGatewayMarkOffsetTunnels 101
+
 # Allows the selection of a smartgateway with NAT (only for IPv4)
 # (default is "yes")
 
diff --git a/files/olsrd.ufw.profile b/files/olsrd.ufw.profile
new file mode 100644 (file)
index 0000000..7b68a12
--- /dev/null
@@ -0,0 +1,4 @@
+[olsrd]
+title=olsrd
+description=optimized link-state routing daemon for OLSR mesh networking
+ports=698
diff --git a/files/sgw_policy_routing_setup.sh b/files/sgw_policy_routing_setup.sh
new file mode 100755 (executable)
index 0000000..7648fe1
--- /dev/null
@@ -0,0 +1,177 @@
+#!/bin/bash
+
+set -e
+set -u
+
+###############################################################################
+#
+# SETTINGS
+#
+###############################################################################
+
+declare IPVERSION_4="ipv4"
+declare IPVERSION_6="ipv6"
+
+declare MODE_GENERIC="generic"
+declare MODE_OLSRIF="olsrif"
+declare MODE_SGWSRVTUN="sgwsrvtun"
+declare MODE_EGRESSIF="egressif"
+declare MODE_SGWTUN="sgwtun"
+
+declare ADDMODE_ADD="add"
+declare ADDMODE_DEL="del"
+
+
+###############################################################################
+#
+# HELPER FUNCTIONS
+#
+###############################################################################
+
+function usage() {
+  echo ""
+  echo "The script was called as:"
+  echo "  ${script} ${arguments[@]:-}"
+  echo ""
+  echo "Usage:"
+  echo "  ${script} ipVersion mode addMode [ifname [ifmark]]"
+  echo "    - ipVersion: ${IPVERSION_4} or ${IPVERSION_6}"
+  echo "    - mode     : ${MODE_GENERIC}, ${MODE_OLSRIF}, ${MODE_SGWSRVTUN}, ${MODE_EGRESSIF} or ${MODE_SGWTUN}"
+  echo "    - addMode  : ${ADDMODE_ADD} or ${ADDMODE_DEL}"
+  echo "    - ifname   : an interface name, not relevant for generic mode"
+  echo "    - ifmark   : an interface marking (number), only relevant for ${MODE_EGRESSIF} and ${MODE_SGWTUN} modes"
+}
+
+function error() {
+  local -i firstLine=1
+  while [ ${#} -gt 0 ]; do
+    if [ ${firstLine} -eq 1 ]; then
+      echo "Error: ${1}"
+    else
+      echo "       ${1}"
+    fi
+    firstLine=0
+    shift 1
+  done
+}
+
+
+###############################################################################
+#
+# MODE FUNCTIONS
+#
+###############################################################################
+
+function generic() {
+  "${IPTABLES}" ${IPTABLES_ARGS} -t mangle "${ADDMODE_IPTABLES}" OUTPUT -j CONNMARK --restore-mark
+}
+
+function olsrif() {
+  "${IPTABLES}" ${IPTABLES_ARGS} -t mangle "${ADDMODE_IPTABLES}" PREROUTING -i "${1}" -j CONNMARK --restore-mark
+}
+
+function sgwsrvtun() {
+  "${IPTABLES}" ${IPTABLES_ARGS} -t mangle "${ADDMODE_IPTABLES}" PREROUTING -i "${1}" -j CONNMARK --restore-mark
+}
+
+function egressif() {
+  "${IPTABLES}" ${IPTABLES_ARGS} -t mangle "${ADDMODE_IPTABLES}" POSTROUTING -m conntrack --ctstate NEW -o "${1}" -j CONNMARK --set-mark "${2}"
+  "${IPTABLES}" ${IPTABLES_ARGS} -t mangle "${ADDMODE_IPTABLES}" INPUT       -m conntrack --ctstate NEW -i "${1}" -j CONNMARK --set-mark "${2}"
+  "${IP}" ${IP_ARGS} rule "${ADDMODE_IP}" fwmark "${2}" table "${2}" pref "${2}"
+}
+
+function sgwtun() {
+  "${IPTABLES}" ${IPTABLES_ARGS} -t mangle "${ADDMODE_IPTABLES}" POSTROUTING -m conntrack --ctstate NEW -o "${1}" -j CONNMARK --set-mark "${2}"
+  "${IP}" ${IP_ARGS} rule "${ADDMODE_IP}" fwmark "${2}" table "${2}" pref "${2}"
+}
+
+
+###############################################################################
+#
+# MAIN
+#
+###############################################################################
+
+declare script="${0}"
+declare -a arguments=( ${@} )
+declare -i argc=${#}
+
+# we always need 3 arguments, check it
+if [ ${argc} -lt 3 ]; then
+  error "Need at least 3 arguments"
+  usage
+  exit 1
+fi
+
+# get first 3 arguments
+declare ipVersion=${1}
+declare mode="${2}"
+declare addMode="${3}"
+shift 3
+argc=${#}
+
+# check IP version argument
+if [ ! "${ipVersion}" == "${IPVERSION_4}" ] && \
+   [ ! "${ipVersion}" == "${IPVERSION_6}" ]; then
+  error "Illegal IP version"
+  usage
+  exit 1
+fi
+
+# check mode argument
+if [ ! "${mode}" == "${MODE_GENERIC}" ] && \
+   [ ! "${mode}" == "${MODE_OLSRIF}" ] && \
+   [ ! "${mode}" == "${MODE_SGWSRVTUN}" ] && \
+   [ ! "${mode}" == "${MODE_EGRESSIF}" ] && \
+   [ ! "${mode}" == "${MODE_SGWTUN}" ]; then
+  error "Illegal mode"
+  usage
+  exit 1
+fi
+
+# check addMode argument
+if [ ! "${addMode}" == "${ADDMODE_ADD}" ] && \
+   [ ! "${addMode}" == "${ADDMODE_DEL}" ]; then
+  error "Illegal addMode"
+  usage
+  exit 1
+fi
+
+# check argument count for all modes
+if ([ "${mode}" == "${MODE_GENERIC}" ]   && [ ${argc} -ne 0 ]) || \
+   ([ "${mode}" == "${MODE_OLSRIF}" ]    && [ ${argc} -ne 1 ]) || \
+   ([ "${mode}" == "${MODE_SGWSRVTUN}" ] && [ ${argc} -ne 1 ]) || \
+   ([ "${mode}" == "${MODE_EGRESSIF}"  ] && [ ${argc} -ne 2 ]) || \
+   ([ "${mode}" == "${MODE_SGWTUN}"  ]   && [ ${argc} -ne 2 ]); then
+  error "Not enough arguments or too many arguments"
+  usage
+  exit 1
+fi
+
+# process ipVersion argument
+declare IPTABLES="iptables"
+declare IPTABLES_ARGS=""
+declare IP="ip"
+declare IP_ARGS="-4"
+if [ "${ipVersion}" == "${IPVERSION_6}" ]; then
+  IPTABLES="ip6tables"
+  IPTABLES_ARGS=""
+  IP="ip"
+  IP_ARGS="-6"
+fi
+
+# process addMode argument
+declare ADDMODE_IPTABLES="-D"
+declare ADDMODE_IP="del"
+if [ "${addMode}" == "${ADDMODE_ADD}" ]; then
+  # first call the delete mode to remove any left-over rules
+  set +e
+  "${mode}" "${@}" 2> /dev/null
+  set -e
+
+  ADDMODE_IPTABLES="-I"
+  ADDMODE_IP="add"
+fi
+
+# call the mode
+"${mode}" "${@}"
index 50e060a..28183cd 100644 (file)
@@ -11,6 +11,17 @@ LDFLAGS = -pie
 
 LIBS := $(shell pkg-config --libs gtk+-2.0) -lm
 
+# 32/64 cross compilation
+ifdef M32
+CFLAGS +=      -m32
+LDFLAGS +=     -m32
+endif
+ifdef M64
+CFLAGS +=      -m64
+LDFLAGS +=     -m64
+endif
+
+
 all: default_target
 
 default_target: olsrd-gui
index 0845552..e0561fc 100644 (file)
@@ -54,7 +54,7 @@ UninstPage uninstConfirm
 UninstPage instfiles
 
 Function .onInit
-        MessageBox MB_YESNO "This will install olsr.org pre-0.6.5.3 on your computer. Continue?" IDYES NoAbort
+        MessageBox MB_YESNO "This will install olsr.org pre-0.6.6 on your computer. Continue?" IDYES NoAbort
         Abort
 NoAbort:
 FunctionEnd
index f4b2741..4e47096 100644 (file)
@@ -68,7 +68,7 @@ IDD_FRONTEND_DIALOG DIALOGEX 0, 0, 399, 289
 STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | \r
     WS_SYSMENU\r
 EXSTYLE WS_EX_APPWINDOW\r
-CAPTION "olsr.org Switch pre-0.6.5.3"
+CAPTION "olsr.org Switch pre-0.6.6"\r
 FONT 8, "MS Sans Serif", 0, 0, 0x1\r
 BEGIN\r
     CONTROL         "Tab1",IDC_TAB1,"SysTabControl32",0x0,7,7,383,256\r
index c006af1..027863c 100644 (file)
@@ -60,9 +60,6 @@
 #include <stdlib.h>
 #include <sys/time.h>
 #include <net/route.h>
-#ifdef __linux__
-#include <linux/in_route.h>
-#endif /* __linux__ */
 #include <unistd.h>
 #include <errno.h>
 #include <time.h>
index 68f9be1..f143b2a 100644 (file)
@@ -983,8 +983,30 @@ ipc_print_config(struct autobuf *abuf)
   abuf_json_string(abuf, "lockFile", olsr_cnf->lock_file);
   abuf_json_boolean(abuf, "useNiit", olsr_cnf->use_niit);
 
+#ifdef __linux__
   abuf_json_boolean(abuf, "smartGateway", olsr_cnf->smart_gw_active);
   if (olsr_cnf->smart_gw_active) {
+    abuf_json_boolean(abuf, "smartGatewayAlwaysRemoveServerTunnel", olsr_cnf->smart_gw_always_remove_server_tunnel);
+    abuf_json_int(abuf, "smartGatewayUseCount", olsr_cnf->smart_gw_use_count);
+    abuf_json_string(abuf, "smartGatewayPolicyRoutingScript", olsr_cnf->smart_gw_policyrouting_script);
+    {
+      struct autobuf egressbuf;
+      struct sgw_egress_if * egressif = olsr_cnf->smart_gw_egress_interfaces;
+
+      abuf_init(&egressbuf, (olsr_cnf->smart_gw_egress_interfaces_count * IFNAMSIZ) /* interface names */
+          + (olsr_cnf->smart_gw_egress_interfaces_count - 1) /* commas */);
+      while (egressif) {
+        if (egressbuf.len) {
+          abuf_puts(&egressbuf, ",");
+        }
+        abuf_appendf(&egressbuf, "%s", egressif->name);
+        egressif = egressif->next;
+      }
+      abuf_json_string(abuf, "smartGatewayEgressInterfaces", egressbuf.buf);
+      abuf_free(&egressbuf);
+    }
+    abuf_json_int(abuf, "smartGatewayMarkOffsetEgress", olsr_cnf->smart_gw_mark_offset_egress);
+    abuf_json_int(abuf, "smartGatewayMarkOffsetTunnels", olsr_cnf->smart_gw_mark_offset_tunnels);
     abuf_json_boolean(abuf, "smartGatewayAllowNat", olsr_cnf->smart_gw_allow_nat);
     abuf_json_boolean(abuf, "smartGatewayUplinkNat", olsr_cnf->smart_gw_uplink_nat);
     abuf_json_int(abuf, "smartGatewayPeriod", olsr_cnf->smart_gw_period);
@@ -997,6 +1019,7 @@ ipc_print_config(struct autobuf *abuf)
                      olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->smart_gw_prefix.prefix));
     abuf_json_int(abuf, "smartGatewayPrefixLength", olsr_cnf->smart_gw_prefix.prefix_len);
   }
+#endif /* __linux__ */
 
   abuf_json_string(abuf, "mainIpAddress",
                    olsr_ip_to_string(&mainaddrbuf, &olsr_cnf->main_addr));
index b27f007..391e3c2 100644 (file)
@@ -11,10 +11,23 @@ LIBS +=     $(OS_LIB_PTHREAD)
 # Must be specified along with -lpthread on linux
 CPPFLAGS += $(OS_CFLAG_PTHREAD)
 
-ifneq ($(OS),linux)
+SUPPORTED = 0
+ifeq ($(OS),linux)
+SUPPORTED = 1
+endif
+ifeq ($(OS),android)
+SUPPORTED = 1
+endif
+
+
+ifeq ($(SUPPORTED),0)
+
+.PHONY: all default_target install clean
+
+all: default_target
 
 default_target install clean:
-       @echo "*** mdns Plugin only supported on Linux, sorry!"
+       @echo "*** $(PLUGIN_NAME) plugin not supported on $(OS), sorry!"
 
 else
 
index 44cd522..831a004 100644 (file)
@@ -285,7 +285,7 @@ CreateRouterElectionSocket(const char *ifName)
                        BmfPError("Could not get ipv4 address of %s interface", ifName);
                        goto bail;
                }
-               ipv4_addr = ((struct sockaddr_in *)&req.ifr_addr)->sin_addr;
+               ipv4_addr = ((struct sockaddr_in *)(void *) &req.ifr_addr)->sin_addr;
                mc_settings.imr_interface = ipv4_addr;
                errno = 0;
                if (setsockopt(rxSocket, ipProtoSetting, ipAddMembershipSetting,
@@ -380,7 +380,7 @@ static int CreateHelloSocket(const char *ifName) {
                        BmfPError("Could not get ipv4 address of %s interface", ifName);
                        goto bail;
                }
-               ipv4_addr = ((struct sockaddr_in *)&req.ifr_addr)->sin_addr;
+               ipv4_addr = ((struct sockaddr_in *)(void *) &req.ifr_addr)->sin_addr;
                address.in4.sin_addr = ipv4_addr;
                address.in4.sin_family = ipFamilySetting;
                address.in4.sin_port = ipPort;
index ca3150c..4fcaebd 100644 (file)
@@ -55,7 +55,7 @@
  * @param member name of node inside struct
  * @return pointer to surrounding struct
  */
-#define container_of(ptr, type, member) ((type *)( (char *)(ptr) - offsetof(type,member) ))
+#define container_of(ptr, type, member) ((type *) (((size_t) ptr) - offsetof(type, member) ))
 
 /**
  * Helper function for NULL safe container_of macro
index 2d5e06a..3012f85 100644 (file)
@@ -91,8 +91,8 @@ static uint16_t ip_checksum(char* data, int len)
     else
         len = (len >> 1) + 1;
     while (len > 0) {
-        sum += *((ushort*)data);
-        data += sizeof(ushort);
+        sum += *((unsigned short int*)(void *)data);
+        data += sizeof(unsigned short int);
         len--;
     }
     sum = (sum >> 16) + (sum & 0xffff);
index b6dc775..9c80d26 100644 (file)
@@ -11,10 +11,23 @@ LIBS +=     $(OS_LIB_PTHREAD)
 # Must be specified along with -lpthread on linux
 CPPFLAGS += $(OS_CFLAG_PTHREAD)
 
-ifneq ($(OS),linux)
+SUPPORTED = 0
+ifeq ($(OS),linux)
+SUPPORTED = 1
+endif
+ifeq ($(OS),android)
+SUPPORTED = 1
+endif
+
+
+ifeq ($(SUPPORTED),0)
+
+.PHONY: all default_target install clean
+
+all: default_target
 
 default_target install clean:
-       @echo "*** p2pd Plugin only supported on Linux, sorry!"
+       @echo "*** $(PLUGIN_NAME) plugin not supported on $(OS), sorry!"
 
 else
 
index 9f3d31f..52cd26d 100755 (executable)
Binary files a/lib/pud/doc/pud.odt and b/lib/pud/doc/pud.odt differ
index 0288a6e..2cbe920 100644 (file)
@@ -47,7 +47,7 @@ lib/$(LIBNAME): $(OBJ)
 ifeq ($(VERBOSE),0)
        @echo "[LD] $@"
 endif
-       $(MAKECMDPREFIX)$(CC) -shared -Wl,-soname=$(LIBNAME) -o "$@" $(LIBRARIES) $(OBJ)
+       $(MAKECMDPREFIX)$(CC) $(LDFLAGS) -Wl,-soname=$(LIBNAME) -o "$@" $(LIBRARIES) $(OBJ)
 
 build/%.o: src/%.c Makefile Makefile.inc
 ifeq ($(VERBOSE),0)
index cb16939..28d90cf 100644 (file)
@@ -31,7 +31,7 @@ endif
 
 # we expect the version to be like 'v0.5.3-27-g0c2727a' and then strip the 'v',
 # and the '-27-g0c2727a' parts
-VERSION=1.0.3
+VERSION=1.0.4
 
 # protect against no version number
 ifeq ($(strip $(VERSION)),)
@@ -52,3 +52,16 @@ CFLAGS+= -O2
 else
 CFLAGS+= -O0
 endif
+
+
+LDFLAGS = -shared -Wl,--warn-common -fPIC
+
+# 32/64 cross compilation
+ifdef M32
+CFLAGS +=      -m32
+LDFLAGS +=     -m32
+endif
+ifdef M64
+CFLAGS +=      -m64
+LDFLAGS +=     -m64
+endif
index 08c3e99..e73d80a 100644 (file)
@@ -1421,11 +1421,6 @@ int setUseLoopback(const char *value, void *data __attribute__ ((unused)),
 unsigned int checkConfig(void) {
        int retval = true;
 
-       if (!olsr_cnf->smart_gw_active) {
-               pudError(false, "Smart Gateway must be active");
-               retval = false;
-       }
-
        if (rxNonOlsrInterfaceCount == 0) {
                pudError(false, "No receive non-OLSR interfaces configured");
                retval = false;
index 84a6168..badda94 100644 (file)
@@ -13,7 +13,7 @@
 #include <net/if.h>
 
 
-#ifdef __ANDROID_API__
+#ifdef __ANDROID__
 typedef __in_port_t in_port_t;
 #endif /* __ANDROID_API__ */
 
index 13bac7e..66ea20e 100644 (file)
@@ -228,7 +228,8 @@ static void packetReceivedFromDownlink(int skfd, void *data __attribute__ ((unus
                        /* we now have a position update (olsrMessage) of a certain length
                         * (olsrMessageLength). this needs to be transmitted over OLSR and on the LAN */
 
-                       /* send out over OLSR interfaces */
+                       /* send out over OLSR interfaces (only when the smart gateway system is enabled) */
+                       if (olsr_cnf->smart_gw_active)
                        {
                                int r;
                                struct interface *ifn;
index a00ecd1..ecb2333 100644 (file)
@@ -28,10 +28,6 @@ static inline unsigned long long gw_speed(struct gateway_entry *gw) {
  * A gateway is better when the sum of its uplink and downlink are greater than
  * the previous best gateway. In case of a tie, the lowest IP address wins.
  *
- * This code is copied from lib/txtinfo/src/olsrd_txtinfo.c, function ipc_print_gateway.
- * It adjusted for best gateway selection but otherwise kept the same as much
- * as possible.
- *
  * @param bestGateway
  * a pointer to the variable in which to store the best gateway
  */
@@ -45,17 +41,9 @@ void getBestUplinkGateway(union olsr_ip_addr * bestGateway) {
                bool eval6 = false;
 
                struct tc_entry * tc = olsr_lookup_tc_entry(&gw->originator);
-               if (!tc) {
+               if (!tc || (tc->path_cost == ROUTE_COST_BROKEN) || (!gw->uplink || !gw->downlink)) {
                        /* gateways should not exist without tc entry */
-                       continue;
-               }
-
-               if (tc->path_cost == ROUTE_COST_BROKEN) {
                        /* do not consider nodes with an infinite ETX */
-                       continue;
-               }
-
-               if (!gw->uplink || !gw->downlink) {
                        /* do not consider nodes without bandwidth or with a uni-directional link */
                        continue;
                }
index c76b26f..0254716 100644 (file)
@@ -9,6 +9,18 @@ OLSRD_PLUGIN = false
 TOPDIR = ../../..
 include $(TOPDIR)/Makefile.inc
 
+LDFLAGS = -shared -Wl,--warn-common -fPIC
+
+# 32/64 cross compilation
+ifdef M32
+CFLAGS +=      -m32
+LDFLAGS +=     -m32
+endif
+ifdef M64
+CFLAGS +=      -m64
+LDFLAGS +=     -m64
+endif
+
 ######################
 #
 # Settings
@@ -131,7 +143,7 @@ $(LIBDIR_BUILD)/$(SONAME): $(BUILD_DIR)/$(JAVA_PKG_UNDER)_UplinkMessage.o \
 ifeq ($(VERBOSE),0)
        @echo "[LD] $@"
 endif
-       $(MAKECMDPREFIX)$(CC) -shared -Wl,-soname=$(SONAME) $(LIBRARIES) -o "$@" \
+       $(MAKECMDPREFIX)$(CC) $(LDFLAGS) -Wl,-soname=$(SONAME) $(LIBRARIES) -o "$@" \
       $(BUILD_DIR)/$(JAVA_PKG_UNDER)_UplinkMessage.o \
       $(BUILD_DIR)/$(JAVA_PKG_UNDER)_ClusterLeader.o \
       $(BUILD_DIR)/$(JAVA_PKG_UNDER)_PositionUpdate.o
index c7c7752..0fc25e2 100644 (file)
@@ -6,6 +6,18 @@ OLSRD_PLUGIN = false
 TOPDIR = ../../..
 include $(TOPDIR)/Makefile.inc
 
+LDFLAGS = -shared -Wl,--warn-common -fPIC
+
+# 32/64 cross compilation
+ifdef M32
+CFLAGS +=      -m32
+LDFLAGS +=     -m32
+endif
+ifdef M64
+CFLAGS +=      -m64
+LDFLAGS +=     -m64
+endif
+
 ######################
 #
 # Settings
@@ -48,7 +60,7 @@ $(LIBDIR_BUILD)/$(SONAME): $(OBJECTS_C)
 ifeq ($(VERBOSE),0)
        @echo "[LD] $@"
 endif
-       $(MAKECMDPREFIX)$(CC) -shared -Wl,-soname=$(SONAME) $(LIBRARIES) -o "$@" $(OBJECTS_C)
+       $(MAKECMDPREFIX)$(CC) $(LDFLAGS) -Wl,-soname=$(SONAME) $(LIBRARIES) -o "$@" $(OBJECTS_C)
 
 $(BUILD_DIR)/%.o: $(SRC_DIR_C)/%.c $(INC_DIR_C)/compiler.h
 ifeq ($(VERBOSE),0)
index 32bbfc8..85fa050 100644 (file)
@@ -26,8 +26,8 @@ PlParam "Redistribute" "<protocol>"
        isis, bgp, hsls
        May be used more then once
 
-PlParam "ExportRoutes" "<only/both>"
-       exports olsr-routes to quagga or to both, quagga and kernel
+PlParam "ExportRoutes" "<only/additional>"
+       exports olsr-routes to quagga only, or to quagga and kernel
        no routes are exported to quagga (normal behaviour) if not set.
 
 PlParam "LocalPref" "<true/false>"
index b6a1a76..7696410 100644 (file)
  * ------------------------------------------------------------------------- */
 
 #define OPTION_EXPORT 1
+#define OPTION_ROUTE_ADDITIONAL 2
 
 /* Zebra route types */
 #define ZEBRA_ROUTE_OLSR               11
 #define ZEBRA_ROUTE_MAX                        14
 
+#include "process_routes.h"
+
 struct zebra {
   unsigned char status;
   unsigned char options;
@@ -33,6 +36,10 @@ struct zebra {
   char *sockpath;
   unsigned int port;
   unsigned char version;
+  export_route_function orig_addroute_function;
+  export_route_function orig_addroute6_function;
+  export_route_function orig_delroute_function;
+  export_route_function orig_delroute6_function;
 };
 
 extern struct zebra zebra;
index c7784c9..1c72c76 100644 (file)
@@ -65,7 +65,6 @@ zplugin_redistribute(const char *value, void *data __attribute__ ((unused)), set
 int
 zplugin_exportroutes(const char *value, void *data __attribute__ ((unused)), set_plugin_parameter_addon addon __attribute__ ((unused)))
 {
-
   if (!strcmp(value, "only")) {
     olsr_addroute_function = zebra_addroute;
     olsr_delroute_function = zebra_delroute;
@@ -73,11 +72,15 @@ zplugin_exportroutes(const char *value, void *data __attribute__ ((unused)), set
     olsr_delroute6_function = zebra_delroute;
     zebra.options |= OPTION_EXPORT;
   } else if (!strcmp(value, "additional")) {
+    zebra.orig_addroute_function = olsr_addroute_function;
+    zebra.orig_delroute_function = olsr_delroute_function;
+    zebra.orig_addroute6_function = olsr_addroute6_function;
+    zebra.orig_delroute6_function = olsr_delroute6_function;
     olsr_addroute_function = zebra_addroute;
     olsr_delroute_function = zebra_delroute;
     olsr_addroute6_function = zebra_addroute;
     olsr_delroute6_function = zebra_delroute;
-    zebra.options |= OPTION_EXPORT;
+    zebra.options |= OPTION_EXPORT | OPTION_ROUTE_ADDITIONAL;
   }
 
   return 0;
index 62fdbe9..43d3d1d 100644 (file)
@@ -99,6 +99,8 @@ zebra_addroute(const struct rt_entry *r)
   }
 
   retval = zclient_write(zpacket_route(olsr_cnf->ip_version == AF_INET ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV6_ROUTE_ADD, &route));
+  if(!retval && zebra.options & OPTION_ROUTE_ADDITIONAL)
+    retval = olsr_cnf->ip_version == AF_INET ? zebra.orig_addroute_function(r) : zebra.orig_addroute6_function(r);
 
   free(route.ifindex);
   free(route.nexthop);
@@ -152,6 +154,8 @@ zebra_delroute(const struct rt_entry *r)
   }
 
   retval = zclient_write(zpacket_route(olsr_cnf->ip_version == AF_INET ? ZEBRA_IPV4_ROUTE_DELETE : ZEBRA_IPV6_ROUTE_DELETE, &route));
+  if(!retval && zebra.options & OPTION_ROUTE_ADDITIONAL)
+    retval = olsr_cnf->ip_version == AF_INET ? zebra.orig_delroute_function(r) : zebra.orig_delroute6_function(r);
 
   free(route.ifindex);
   free(route.nexthop);
index d7ad5dd..217446a 100644 (file)
@@ -14,8 +14,8 @@ CPPFLAGS +=   -I$(TOPDIR)/src/win32
 
 PLUGIN_SONAME ?= $(PLUGIN_NAME)
 PLUGIN_FULLNAME ?= $(PLUGIN_NAME).dll
-INSTALL_LIB =  cp $(PLUGIN_FULLNAME) ../..
-UNINSTALL_LIB =        del /F ../../$(PLUGIN_FULLNAME)
+INSTALL_LIB =  mkdir -p $(LIBDIR);cp $(PLUGIN_FULLNAME) $(LIBDIR)/$(PLUGIN_FULLNAME)
+UNINSTALL_LIB =        del /F $(LIBDIR)/$(PLUGIN_FULLNAME)
 
 ifdef OLSRD_PLUGIN
 LDFLAGS +=     -L$(TOPDIR)
index 114d19b..d1aca7e 100644 (file)
@@ -23,7 +23,7 @@ void olsr_os_cleanup_iptunnel(const char * name __attribute__((unused))) {
 }
 
 struct olsr_iptunnel_entry *olsr_os_add_ipip_tunnel(union olsr_ip_addr *target __attribute__ ((unused)),
-    bool transportV4 __attribute__ ((unused))) {
+    bool transportV4 __attribute__ ((unused)), char *name) {
   return NULL;
 }
 
@@ -49,7 +49,8 @@ void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6 __attribute__ (
 }
 void olsr_os_inetgw_tunnel_route(uint32_t if_idx __attribute__ ((unused)),
     bool ipv4 __attribute__ ((unused)),
-    bool set __attribute__ ((unused))) {
+    bool set __attribute__ ((unused)),
+    uint8_t table __attribute__ ((unused))) {
 }
 
 int olsr_os_policy_rule(int family __attribute__ ((unused)),
index 768bf8f..0ccbab4 100644 (file)
@@ -438,6 +438,75 @@ void olsrd_write_cnf_autobuf(struct autobuf *out, struct olsrd_config *cnf) {
       cnf->smart_gw_active ? "yes" : "no");
   abuf_puts(out,
     "\n"
+    "# Signals that the server tunnel must always be removed on shutdown,\n"
+    "# irrespective of the interface up/down state during startup.\n"
+    "# (default is \"no\")\n"
+    "\n");
+  abuf_appendf(out, "%sSmartGatewayAlwaysRemoveServerTunnel %s\n",
+      cnf->smart_gw_always_remove_server_tunnel == DEF_SMART_GW_ALWAYS_REMOVE_SERVER_TUNNEL ? "# " : "",
+      cnf->smart_gw_always_remove_server_tunnel ? "yes" : "no");
+  abuf_puts(out,
+    "\n"
+    "# Determines the maximum number of gateways that can be in use at any given\n"
+    "# time. This setting is used to mitigate the effects of breaking connections\n"
+    "# (due to the selection of a new gateway) on a dynamic network.\n"
+    "# (default is 1)\n"
+    "\n");
+  abuf_appendf(out, "%sSmartGatewayUseCount %d\n",
+      cnf->smart_gw_use_count == DEF_GW_USE_COUNT ? "# " : "",
+      cnf->smart_gw_use_count);
+  abuf_puts(out,
+    "\n"
+    "# Determines the policy routing script that is executed during startup and\n"
+    "# shutdown of olsrd. The script is only executed when SmartGatewayUseCount\n"
+    "# is set to a value larger than 1. The script must setup policy routing\n"
+    "# rules such that multi-gateway mode works. A sample script is included.\n"
+    "# (default is not set)\n"
+    "\n");
+  abuf_appendf(out, "%sSmartGatewayPolicyRoutingScript %s\n",
+      !cnf->smart_gw_policyrouting_script ? "# " : "",
+      !cnf->smart_gw_policyrouting_script ? "" : cnf->smart_gw_policyrouting_script);
+  abuf_puts(out,
+    "\n"
+    "# Determines the egress interfaces that are part of the multi-gateway setup and\n"
+    "# therefore only relevant when SmartGatewayUseCount is larger than 1 (in which\n"
+    "# case it must be explicitly set).\n"
+    "# (default is not set)\n"
+    "\n");
+  abuf_appendf(out, "%sSmartGatewayEgressInterfaces",
+      !cnf->smart_gw_egress_interfaces ? "# " : "");
+  {
+    struct sgw_egress_if * sgwegressif = olsr_cnf->smart_gw_egress_interfaces;
+    while (sgwegressif) {
+      abuf_appendf(out, " \"%s\"", sgwegressif->name);
+      sgwegressif = sgwegressif->next;
+    }
+    abuf_puts(out, "\n");
+  }
+  abuf_puts(out,
+    "\n"
+    "# Determines the offset of the smart gateway egress interfaces mark that are\n"
+    "# used in the policy routing rules in a multi-gateway setup. Only relevant\n"
+    "# when a multi-gateway setup is used.\n"
+    "# (default is 91)\n"
+    "\n");
+  abuf_appendf(out, "%sSmartGatewayMarkOffsetEgress %u\n",
+      cnf->smart_gw_mark_offset_egress == DEF_GW_MARK_OFFSET_EGRESS ? "# " : "",
+      cnf->smart_gw_mark_offset_egress);
+  abuf_puts(out,
+    "\n"
+    "# Determines the offset of the smart gateway tunnel interfaces mark that are\n"
+    "# used in the policy routing rules in a multi-gateway setup. Only relevant\n"
+    "# when a multi-gateway setup is used.\n"
+    "# The ranges [egress offset, egress offset + egress count] and\n"
+    "# [tunnel offset, tunnel offset + use count] are not allowed to overlap.\n"
+    "# (default is 101)\n"
+    "\n");
+  abuf_appendf(out, "%sSmartGatewayMarkOffsetTunnels %u\n",
+      cnf->smart_gw_mark_offset_tunnels == DEF_GW_MARK_OFFSET_TUNNELS ? "# " : "",
+      cnf->smart_gw_mark_offset_tunnels);
+  abuf_puts(out,
+    "\n"
     "# Allows the selection of a smartgateway with NAT (only for IPv4)\n"
     "# (default is \"yes\")\n"
     "\n");
index 7b6605b..b2cc735 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/types.h>
 #include <linux/rtnetlink.h>
 #include <linux/version.h>
+#include <sys/stat.h>
 #endif /* __linux__ */
 
 extern FILE *yyin;
@@ -554,6 +555,105 @@ olsrd_sanity_check_cnf(struct olsrd_config *cnf)
   }
 
 #ifdef __linux__
+  if ((cnf->smart_gw_use_count < MIN_SMARTGW_USE_COUNT_MIN) || (cnf->smart_gw_use_count > MAX_SMARTGW_USE_COUNT_MAX)) {
+    fprintf(stderr, "Error, bad gateway use count %d, outside of range [%d, %d]\n",
+        cnf->smart_gw_use_count, MIN_SMARTGW_USE_COUNT_MIN, MAX_SMARTGW_USE_COUNT_MAX);
+    return -1;
+  }
+
+  if (cnf->smart_gw_use_count > 1) {
+    struct sgw_egress_if * sgwegressif = cnf->smart_gw_egress_interfaces;
+
+    if (!cnf->smart_gw_policyrouting_script) {
+      fprintf(stderr, "Error, no policy routing script configured in multi-gateway mode\n");
+      return -1;
+    }
+
+    {
+      struct stat statbuf;
+
+      int r = stat(cnf->smart_gw_policyrouting_script, &statbuf);
+      if (r) {
+        fprintf(stderr, "Error, policy routing script not found: %s\n", strerror(errno));
+        return -1;
+      }
+
+      if (!S_ISREG(statbuf.st_mode)) {
+        fprintf(stderr, "Error, policy routing script not a regular file\n");
+        return -1;
+      }
+
+      if (statbuf.st_uid) {
+        fprintf(stderr, "Error, policy routing script must be owned by root\n");
+        return -1;
+      }
+
+      if (!(statbuf.st_mode & (S_IRUSR | S_IXUSR))) {
+        fprintf(stderr, "Error, policy routing script is not executable\n");
+        return -1;
+      }
+    }
+
+    /* egress interface(s) must be set */
+    if (!sgwegressif) {
+      fprintf(stderr, "Error, no egress interfaces configured in multi-gateway mode\n");
+      return -1;
+    }
+
+    /* an egress interface must not be an OLSR interface */
+    while (sgwegressif) {
+      struct olsr_if * olsrif = cnf->interfaces;
+      while (olsrif) {
+        if (!strcmp(olsrif->name, sgwegressif->name)) {
+          fprintf(stderr, "Error, egress interface %s already is an OLSR interface\n", sgwegressif->name);
+          return -1;
+        }
+        olsrif = olsrif->next;
+      }
+      cnf->smart_gw_egress_interfaces_count++;
+      sgwegressif = sgwegressif->next;
+    }
+
+    if (cnf->smart_gw_egress_interfaces_count > MAX_SMARTGW_EGRESS_INTERFACE_COUNT_MAX) {
+      fprintf(stderr, "Error, egress interface count %u not in range [1, %u]\n",
+          cnf->smart_gw_egress_interfaces_count, MAX_SMARTGW_EGRESS_INTERFACE_COUNT_MAX);
+      return -1;
+    }
+
+    {
+      uint8_t egressLow = cnf->smart_gw_mark_offset_egress;
+      uint8_t egressHigh = egressLow + cnf->smart_gw_egress_interfaces_count - 1;
+      uint8_t tunnelsLow = cnf->smart_gw_mark_offset_tunnels;
+      uint8_t tunnelsHigh = tunnelsLow + cnf->smart_gw_use_count - 1;
+      bool overlap = false;
+
+      /* check that the egress interface marks range does not overflow */
+      if (egressLow > (UINT8_MAX - cnf->smart_gw_egress_interfaces_count)) {
+        fprintf(stderr, "Error, egress interface mark offset %u together with egress interface count %u overflows range [0, %u]\n",
+            egressLow, cnf->smart_gw_egress_interfaces_count, UINT8_MAX);
+        return -1;
+      }
+
+      /* check that the tunnel interface marks range does not overflow */
+      if (tunnelsLow > (UINT8_MAX - cnf->smart_gw_use_count)) {
+        fprintf(stderr, "Error, tunnel interface mark offset %u together with use count %u overflows range [0, %u]\n",
+            tunnelsLow, cnf->smart_gw_use_count, UINT8_MAX);
+        return -1;
+      }
+
+      /* check that the egress and tunnel marks ranges do not overlap */
+      overlap =            ((tunnelsLow <= egressLow)   && (egressLow   <= tunnelsHigh));
+      overlap = overlap || ((tunnelsLow <= egressHigh)  && (egressHigh  <= tunnelsHigh));
+      overlap = overlap || ((egressLow  <= tunnelsLow)  && (tunnelsLow  <= egressHigh));
+      overlap = overlap || ((egressLow  <= tunnelsHigh) && (tunnelsHigh <= egressHigh));
+      if (overlap) {
+        fprintf(stderr, "Error, egress interface mark range [%u, %u] overlaps with tunnel interface mark range [%u, %u]\n",
+            egressLow, egressHigh, tunnelsLow, tunnelsHigh);
+        return -1;
+      }
+    }
+  }
+
   if (cnf->smart_gw_period < MIN_SMARTGW_PERIOD || cnf->smart_gw_period > MAX_SMARTGW_PERIOD) {
     fprintf(stderr, "Error, bad gateway period: %d msec (should be %d-%d)\n",
         cnf->smart_gw_period, MIN_SMARTGW_PERIOD, MAX_SMARTGW_PERIOD);
@@ -788,6 +888,13 @@ set_default_cnf(struct olsrd_config *cnf)
   cnf->niit6to4_if_index = 0;
 
   cnf->smart_gw_active = DEF_SMART_GW;
+  cnf->smart_gw_always_remove_server_tunnel = DEF_SMART_GW_ALWAYS_REMOVE_SERVER_TUNNEL;
+  cnf->smart_gw_use_count = DEF_GW_USE_COUNT;
+  cnf->smart_gw_policyrouting_script = NULL;
+  cnf->smart_gw_egress_interfaces = NULL;
+  cnf->smart_gw_egress_interfaces_count = 0;
+  cnf->smart_gw_mark_offset_egress = DEF_GW_MARK_OFFSET_EGRESS;
+  cnf->smart_gw_mark_offset_tunnels = DEF_GW_MARK_OFFSET_TUNNELS;
   cnf->smart_gw_allow_nat = DEF_GW_ALLOW_NAT;
   cnf->smart_gw_period = DEF_GW_PERIOD;
   cnf->smart_gw_stablecount = DEF_GW_STABLE_COUNT;
@@ -916,6 +1023,26 @@ olsrd_print_cnf(struct olsrd_config *cnf)
 
   printf("Smart Gateway    : %s\n", cnf->smart_gw_active ? "yes" : "no");
 
+  printf("SmGw. Del Srv Tun: %s\n", cnf->smart_gw_always_remove_server_tunnel ? "yes" : "no");
+
+  printf("SmGw. Use Count  : %u\n", cnf->smart_gw_use_count);
+
+  printf("SmGw. Pol. Script: %s\n", cnf->smart_gw_policyrouting_script);
+
+  printf("SmGw. Egress I/Fs:");
+  {
+    struct sgw_egress_if * sgwegressif = cnf->smart_gw_egress_interfaces;
+    while (sgwegressif) {
+      printf(" %s", sgwegressif->name);
+      sgwegressif = sgwegressif->next;
+    }
+  }
+  printf("\n");
+
+  printf("SmGw. Mark Egress: %u\n", cnf->smart_gw_mark_offset_egress);
+
+  printf("SmGw. Mark Tunnel: %u\n", cnf->smart_gw_mark_offset_tunnels);
+
   printf("SmGw. Allow NAT  : %s\n", cnf->smart_gw_allow_nat ? "yes" : "no");
 
   printf("SmGw. period     : %d\n", cnf->smart_gw_period);
index c123ae4..e29c560 100644 (file)
@@ -56,6 +56,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
+#include <ctype.h>
 
 #define PARSER_DEBUG 1
 
@@ -215,6 +216,12 @@ static int add_ipv6_addr(YYSTYPE ipaddr_arg, YYSTYPE prefixlen_arg)
 %token TOK_LOCK_FILE
 %token TOK_USE_NIIT
 %token TOK_SMART_GW
+%token TOK_SMART_GW_ALWAYS_REMOVE_SERVER_TUNNEL
+%token TOK_SMART_GW_USE_COUNT
+%token TOK_SMART_GW_POLICYROUTING_SCRIPT
+%token TOK_SMART_GW_EGRESS_IFS
+%token TOK_SMART_GW_MARK_OFFSET_EGRESS
+%token TOK_SMART_GW_MARK_OFFSET_TUNNELS
 %token TOK_SMART_GW_ALLOW_NAT
 %token TOK_SMART_GW_PERIOD
 %token TOK_SMART_GW_STABLECOUNT
@@ -302,6 +309,11 @@ stmt:       idebug
           | alock_file
           | suse_niit
           | bsmart_gw
+          | bsmart_gw_always_remove_server_tunnel
+          | ismart_gw_use_count
+          | ssmart_gw_policyrouting_script
+          | ismart_gw_mark_offset_egress
+          | ismart_gw_mark_offset_tunnels
           | bsmart_gw_allow_nat
           | ismart_gw_period
           | asmart_gw_stablecount
@@ -317,6 +329,7 @@ stmt:       idebug
           | bsrc_ip_routes
           | amain_ip
           | bset_ipforward
+          | ssgw_egress_ifs
 ;
 
 block:      TOK_HNA4 hna4body
@@ -1304,6 +1317,115 @@ bsmart_gw: TOK_SMART_GW TOK_BOOLEAN
 }
 ;
 
+bsmart_gw_always_remove_server_tunnel: TOK_SMART_GW_ALWAYS_REMOVE_SERVER_TUNNEL TOK_BOOLEAN
+{
+       PARSER_DEBUG_PRINTF("Smart gateway always remove server tunnel: %s\n", $2->boolean ? "enabled" : "disabled");
+       olsr_cnf->smart_gw_always_remove_server_tunnel = $2->boolean;
+       free($2);
+}
+;
+
+ismart_gw_use_count: TOK_SMART_GW_USE_COUNT TOK_INTEGER
+{
+  PARSER_DEBUG_PRINTF("Smart gateway use count: %d\n", $2->integer);
+  olsr_cnf->smart_gw_use_count = $2->integer;
+  free($2);
+}
+;
+
+ssmart_gw_policyrouting_script: TOK_SMART_GW_POLICYROUTING_SCRIPT TOK_STRING
+{
+  PARSER_DEBUG_PRINTF("Smart gateway policy routing script: %s\n", $2->string);
+  olsr_cnf->smart_gw_policyrouting_script = $2->string;
+  free($2);
+}
+;
+
+ssgw_egress_ifs:   TOK_SMART_GW_EGRESS_IFS sgw_egress_ifs
+;
+
+sgw_egress_ifs:   | sgw_egress_ifs sgw_egress_if
+;
+
+sgw_egress_if: TOK_STRING
+{
+  struct sgw_egress_if *in, *last;
+  char * str = $1->string;
+  char *end;
+
+  /* Trim leading space */
+  while(isspace(*str)) {
+    str++;
+  }
+
+  /* Trim trailing space */
+  end = str + strlen(str) - 1;
+  while((end > str) && isspace(*end)) {
+    end--;
+  }
+
+  /* Write new null terminator */
+  *(end + 1) = '\0';
+
+  if(*str == 0) {
+    PARSER_DEBUG_PRINTF("Smart gateway egress interface: <empty> (skipped)\n");
+  } else {
+    PARSER_DEBUG_PRINTF("Smart gateway egress interface: %s\n", str);
+
+    in = olsr_cnf->smart_gw_egress_interfaces;
+    last = NULL;
+    while (in != NULL) {
+      if (strcmp(in->name, str) == 0) {
+        free ($1->string);
+        break;
+      }
+      last = in;
+      in = in->next;
+    }
+
+    if (in != NULL) {
+      /* remove old interface from list to add it later at the beginning */
+      if (last) {
+        last->next = in->next;
+      }
+      else {
+        olsr_cnf->smart_gw_egress_interfaces = in->next;
+      }
+    }
+    else {
+      in = malloc(sizeof(*in));
+      if (in == NULL) {
+        fprintf(stderr, "Out of memory(ADD IF)\n");
+        YYABORT;
+      }
+      memset(in, 0, sizeof(*in));
+
+      in->name = str;
+    }
+    /* Queue */
+    in->next = olsr_cnf->smart_gw_egress_interfaces;
+    olsr_cnf->smart_gw_egress_interfaces = in;
+    free($1);
+  }
+}
+;
+
+ismart_gw_mark_offset_egress: TOK_SMART_GW_MARK_OFFSET_EGRESS TOK_INTEGER
+{
+  PARSER_DEBUG_PRINTF("Smart gateway mark offset egress interfaces: %d\n", $2->integer);
+  olsr_cnf->smart_gw_mark_offset_egress = $2->integer;
+  free($2);
+}
+;
+
+ismart_gw_mark_offset_tunnels: TOK_SMART_GW_MARK_OFFSET_TUNNELS TOK_INTEGER
+{
+  PARSER_DEBUG_PRINTF("Smart gateway mark offset tunnel interfaces: %d\n", $2->integer);
+  olsr_cnf->smart_gw_mark_offset_tunnels = $2->integer;
+  free($2);
+}
+;
+
 bsmart_gw_allow_nat: TOK_SMART_GW_ALLOW_NAT TOK_BOOLEAN
 {
        PARSER_DEBUG_PRINTF("Smart gateway allow client nat: %s\n", $2->boolean ? "yes" : "no");
index 194c53a..fc07b1e 100644 (file)
@@ -466,6 +466,36 @@ IPV6ADDR {IPV6PAT1}|{IPV6PAT2}|{IPV6PAT3}|{IPV6PAT4}|{IPV6PAT5}|{IPV6PAT6}|{IPV6
     return TOK_SMART_GW;
 }
 
+"SmartGatewayAlwaysRemoveServerTunnel" {
+    yylval = NULL;
+    return TOK_SMART_GW_ALWAYS_REMOVE_SERVER_TUNNEL;
+}
+
+"SmartGatewayUseCount" {
+    yylval = NULL;
+    return TOK_SMART_GW_USE_COUNT;
+}
+
+"SmartGatewayPolicyRoutingScript" {
+    yylval = NULL;
+    return TOK_SMART_GW_POLICYROUTING_SCRIPT;
+}
+
+"SmartGatewayEgressInterfaces" {
+    yylval = NULL;
+    return TOK_SMART_GW_EGRESS_IFS;
+}
+
+"SmartGatewayMarkOffsetEgress" {
+    yylval = NULL;
+    return TOK_SMART_GW_MARK_OFFSET_EGRESS;
+}
+
+"SmartGatewayMarkOffsetTunnels" {
+    yylval = NULL;
+    return TOK_SMART_GW_MARK_OFFSET_TUNNELS;
+}
+
 "SmartGatewayAllowNAT" {
     yylval = NULL;
     return TOK_SMART_GW_ALLOW_NAT;
index 15587a6..1699c4c 100644 (file)
 #include "duplicate_set.h"
 #include "log.h"
 #include "gateway_default_handler.h"
+#include "gateway_list.h"
 #include "gateway.h"
 
 #include <assert.h>
 #include <net/if.h>
 
+/*
+ * Defines for the multi-gateway script
+ */
+
+#define SCRIPT_MODE_GENERIC   "generic"
+#define SCRIPT_MODE_OLSRIF    "olsrif"
+#define SCRIPT_MODE_SGWSRVTUN "sgwsrvtun"
+#define SCRIPT_MODE_EGRESSIF  "egressif"
+#define SCRIPT_MODE_SGWTUN    "sgwtun"
+
+/** structure that holds an interface name, mark and a pointer to the gateway that uses it */
+struct interfaceName {
+  char name[IFNAMSIZ]; /**< interface name */
+  uint8_t mark; /**< marking */
+  struct gateway_entry *gw; /**< gateway that uses this interface name */
+};
+
 /** the gateway tree */
 struct avl_tree gateway_tree;
 
 /** gateway cookie */
 static struct olsr_cookie_info *gateway_entry_mem_cookie = NULL;
 
+/** gateway container cookie */
+static struct olsr_cookie_info *gw_container_entry_mem_cookie = NULL;
+
 /** the gateway netmask for the HNA */
 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
 
 /** the gateway handler/plugin */
 static struct olsr_gw_handler *gw_handler;
 
-/** the current IPv4 gateway */
-static struct gateway_entry *current_ipv4_gw;
+/** the IPv4 gateway list */
+static struct gw_list gw_list_ipv4;
 
-/** the tunnel of the current IPv4  gateway */
-static struct olsr_iptunnel_entry *v4gw_tunnel;
+/** the IPv6 gateway list */
+static struct gw_list gw_list_ipv6;
+
+/** the current IPv4 gateway */
+static struct gw_container_entry *current_ipv4_gw;
 
 /** the current IPv6 gateway */
-static struct gateway_entry *current_ipv6_gw;
+static struct gw_container_entry *current_ipv6_gw;
+
+/** interface names for smart gateway egress interfaces */
+struct interfaceName * sgwEgressInterfaceNames;
 
-/** the tunnel of the current IPv6  gateway */
-static struct olsr_iptunnel_entry *v6gw_tunnel;
+/** interface names for smart gateway tunnel interfaces, IPv4 */
+struct interfaceName * sgwTunnel4InterfaceNames;
+
+/** interface names for smart gateway tunnel interfaces, IPv6 */
+struct interfaceName * sgwTunnel6InterfaceNames;
 
 /*
  * Forward Declarations
@@ -59,9 +89,31 @@ static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t pr
  * Helper Functions
  */
 
-#define TUNNEL_NAME (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6)
+/**
+ * @return the gateway 'server' tunnel name to use
+ */
+static inline const char * server_tunnel_name(void) {
+  return (olsr_cnf->ip_version == AF_INET ? TUNNEL_ENDPOINT_IF : TUNNEL_ENDPOINT_IF6);
+}
+
+/**
+ * Convert the netmask of the HNA (in the form of an IP address) to a HNA
+ * pointer.
+ *
+ * @param mask the netmask of the HNA (in the form of an IP address)
+ * @param prefixlen the prefix length
+ * @return a pointer to the HNA
+ */
+static inline uint8_t * hna_mask_to_hna_pointer(union olsr_ip_addr *mask, int prefixlen) {
+  return (((uint8_t *)mask) + ((prefixlen+7)/8));
+}
 
-#define OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen) (((uint8_t *)mask) + ((prefixlen+7)/8))
+/**
+ * @return true if multi-gateway mode is enabled
+ */
+static inline bool multi_gateway_mode(void) {
+  return (olsr_cnf->smart_gw_use_count > 1);
+}
 
 /**
  * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent)
@@ -114,6 +166,258 @@ static uint8_t serialize_gw_speed(uint32_t speed) {
   return ((speed - 1) << 3) | exp;
 }
 
+/**
+ * Find an interfaceName struct corresponding to a certain gateway
+ * (when gw != NULL) or to an empty interfaceName struct (when gw == NULL).
+ *
+ * @param gw the gateway to find (when not NULL), or the empty struct to find (when NULL)
+ * @return a pointer to the struct, or NULL when not found
+ */
+static struct interfaceName * find_interfaceName(struct gateway_entry *gw) {
+  struct interfaceName * sgwTunnelInterfaceNames;
+  uint8_t i = 0;
+
+  if (!multi_gateway_mode()) {
+    return NULL;
+  }
+
+  assert(sgwTunnel4InterfaceNames);
+  assert(sgwTunnel6InterfaceNames);
+
+  sgwTunnelInterfaceNames = (olsr_cnf->ip_version == AF_INET) ? sgwTunnel4InterfaceNames : sgwTunnel6InterfaceNames;
+  while (i < olsr_cnf->smart_gw_use_count) {
+    struct interfaceName * ifn = &sgwTunnelInterfaceNames[i];
+    if (ifn->gw == gw) {
+      return ifn;
+    }
+    i++;
+  }
+
+  return NULL;
+}
+
+/**
+ * Get an unused olsr ipip tunnel name for a certain gateway and store it in name.
+ *
+ * @param gw pointer to the gateway
+ * @param name pointer to output buffer (length IFNAMSIZ)
+ * @param interfaceName a pointer to the location where to store a pointer to the interfaceName struct
+ */
+static void get_unused_iptunnel_name(struct gateway_entry *gw, char * name, struct interfaceName ** interfaceName) {
+  static uint32_t counter = 0;
+
+  assert(gw);
+  assert(name);
+  assert(interfaceName);
+
+  memset(name, 0, IFNAMSIZ);
+
+  if (multi_gateway_mode()) {
+    struct interfaceName * ifn = find_interfaceName(NULL);
+
+    if (ifn) {
+      strncpy(&name[0], &ifn->name[0], sizeof(ifn->name));
+      *interfaceName = ifn;
+      ifn->gw = gw;
+      return;
+    }
+
+    /* do not return, fall-through to classic naming as fallback */
+  }
+
+  snprintf(name, IFNAMSIZ, "tnl_%08x", (olsr_cnf->ip_version == AF_INET) ? gw->originator.v4.s_addr : ++counter);
+  *interfaceName = NULL;
+}
+
+/**
+ * Set an olsr ipip tunnel name that is used by a certain gateway as unused
+ *
+ * @param gw pointer to the gateway
+ */
+static void set_unused_iptunnel_name(struct gateway_entry *gw) {
+  struct interfaceName * ifn;
+
+  if (!multi_gateway_mode()) {
+    return;
+  }
+
+  assert(gw);
+
+  ifn = find_interfaceName(gw);
+  if (ifn) {
+    ifn->gw = NULL;
+    return;
+  }
+}
+
+/**
+ * Run the multi-gateway script/
+ *
+ * @param mode the mode (see SCRIPT_MODE_* defines)
+ * @param add true to add policy routing, false to remove it
+ * @param ifname the interface name (optional)
+ * @param ifmark the interface mark (optional
+ * @return true when successful
+ */
+static bool multiGwRunScript(const char * mode, bool add, const char * ifname, uint8_t * ifmark) {
+  struct autobuf buf;
+  int r;
+
+  abuf_init(&buf, 1024);
+
+  abuf_appendf(&buf, "\"%s\"", olsr_cnf->smart_gw_policyrouting_script);
+
+  abuf_appendf(&buf, " \"%s\"", (olsr_cnf->ip_version == AF_INET) ? "ipv4" : "ipv6");
+
+  assert(!strcmp(mode, SCRIPT_MODE_GENERIC) || !strcmp(mode, SCRIPT_MODE_OLSRIF) ||
+      !strcmp(mode, SCRIPT_MODE_SGWSRVTUN) || !strcmp(mode, SCRIPT_MODE_EGRESSIF) ||
+      !strcmp(mode, SCRIPT_MODE_SGWTUN));
+  abuf_appendf(&buf, " \"%s\"", mode);
+
+  abuf_appendf(&buf, " \"%s\"", add ? "add" : "del");
+
+  if (ifname) {
+    assert(!strcmp(mode, SCRIPT_MODE_OLSRIF) || !strcmp(mode, SCRIPT_MODE_SGWSRVTUN) ||
+        !strcmp(mode, SCRIPT_MODE_EGRESSIF) || !strcmp(mode, SCRIPT_MODE_SGWTUN));
+    abuf_appendf(&buf, " \"%s\"", ifname);
+  } else {
+    assert(!strcmp(mode, SCRIPT_MODE_GENERIC));
+  }
+  if (ifmark) {
+    assert(!strcmp(mode, SCRIPT_MODE_EGRESSIF) || !strcmp(mode, SCRIPT_MODE_SGWTUN));
+    assert(ifname);
+    abuf_appendf(&buf, " \"%u\"", *ifmark);
+  } else {
+    assert(!strcmp(mode, SCRIPT_MODE_GENERIC) || !strcmp(mode, SCRIPT_MODE_OLSRIF) ||
+      !strcmp(mode, SCRIPT_MODE_SGWSRVTUN));
+  }
+
+  r = system(buf.buf);
+
+  abuf_free(&buf);
+
+  return (r == 0);
+}
+
+/**
+ * Setup generic multi-gateway iptables and ip rules
+ *
+ * - generic (on olsrd start/stop)
+ * iptablesExecutable -t mangle -A OUTPUT -j CONNMARK --restore-mark
+ *
+ * @param add true to add policy routing, false to remove it
+ * @return true when successful
+ */
+static bool multiGwRulesGeneric(bool add) {
+  return multiGwRunScript(SCRIPT_MODE_GENERIC, add, NULL, NULL);
+}
+
+/**
+ * Setup multi-gateway iptables and ip rules for all OLSR interfaces.
+ *
+ * - olsr interfaces (on olsrd start/stop)
+ * iptablesExecutable -t mangle -A PREROUTING -i ${olsrInterface} -j CONNMARK --restore-mark
+ *
+ * @param add true to add policy routing, false to remove it
+ * @return true when successful
+ */
+static bool multiGwRulesOlsrInterfaces(bool add) {
+  bool ok = true;
+  struct interface * ifn;
+
+  for (ifn = ifnet; ifn; ifn = ifn->int_next) {
+    if (!multiGwRunScript(SCRIPT_MODE_OLSRIF, add, ifn->int_name, NULL)) {
+      ok = false;
+      if (add) {
+        return ok;
+      }
+    }
+  }
+
+  return ok;
+}
+
+/**
+ * Setup multi-gateway iptables and ip rules for the smart gateway server tunnel.
+ *
+ * - sgw server tunnel interface (on olsrd start/stop)
+ * iptablesExecutable -t mangle -A PREROUTING  -i tunl0 -j CONNMARK --restore-mark
+ *
+ * @param add true to add policy routing, false to remove it
+ * @return true when successful
+ */
+static bool multiGwRulesSgwServerTunnel(bool add) {
+  return multiGwRunScript(SCRIPT_MODE_SGWSRVTUN, add, server_tunnel_name(), NULL);
+}
+
+/**
+ * Setup multi-gateway iptables and ip rules for all egress interfaces.
+ *
+ * - egress interfaces (on interface start/stop)
+ * iptablesExecutable -t mangle -A POSTROUTING -m conntrack --ctstate NEW -o ${egressInterface} -j CONNMARK --set-mark ${egressInterfaceMark}
+ * iptablesExecutable -t mangle -A INPUT       -m conntrack --ctstate NEW -i ${egressInterface} -j CONNMARK --set-mark ${egressInterfaceMark}
+ * ip rule add fwmark ${egressInterfaceMark} table ${egressInterfaceMark} pref ${egressInterfaceMark}
+ *
+ * like table:
+ * ppp0 91
+ * eth0 92
+ *
+ * @param add true to add policy routing, false to remove it
+ * @return true when successful
+ */
+static bool multiGwRulesEgressInterfaces(bool add) {
+  bool ok = true;
+  unsigned int i = 0;
+
+  for (i = 0; i < olsr_cnf->smart_gw_egress_interfaces_count; i++) {
+    struct interfaceName * ifn = &sgwEgressInterfaceNames[i];
+    if (!multiGwRunScript(SCRIPT_MODE_EGRESSIF, add, ifn->name, &ifn->mark)) {
+      ok = false;
+      if (add) {
+        return ok;
+      }
+    }
+  }
+
+  return ok;
+}
+
+/**
+ * Setup multi-gateway iptables and ip rules for the smart gateway client tunnels.
+ *
+ * - sgw tunnels (on sgw tunnel start/stop)
+ * iptablesExecutable -t mangle -A POSTROUTING -m conntrack --ctstate NEW -o ${sgwTunnelInterface} -j CONNMARK --set-mark ${sgwTunnelInterfaceMark}
+ * ip rule add fwmark ${sgwTunnelInterfaceMark} table ${sgwTunnelInterfaceMark} pref ${sgwTunnelInterfaceMark}
+ *
+ * like table:
+ * tnl_101 101
+ * tnl_102 102
+ * tnl_103 103
+ * tnl_104 104
+ * tnl_105 105
+ * tnl_106 106
+ * tnl_107 107
+ * tnl_108 108
+ */
+static bool multiGwRulesSgwTunnels(bool add) {
+  bool ok = true;
+  unsigned int i = 0;
+
+  while (i < olsr_cnf->smart_gw_use_count) {
+    struct interfaceName * ifn = (olsr_cnf->ip_version == AF_INET) ? &sgwTunnel4InterfaceNames[i] : &sgwTunnel6InterfaceNames[i];
+    if (!multiGwRunScript(SCRIPT_MODE_SGWTUN, add, ifn->name, &ifn->mark)) {
+      ok = false;
+      if (add) {
+        return ok;
+      }
+    }
+
+    i++;
+  }
+
+  return ok;
+}
+
 /*
  * Callback Functions
  */
@@ -162,13 +466,56 @@ int olsr_init_gateways(void) {
   gateway_entry_mem_cookie = olsr_alloc_cookie("gateway_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
   olsr_cookie_set_memory_size(gateway_entry_mem_cookie, sizeof(struct gateway_entry));
 
+  gw_container_entry_mem_cookie = olsr_alloc_cookie("gw_container_entry_mem_cookie", OLSR_COOKIE_TYPE_MEMORY);
+  olsr_cookie_set_memory_size(gw_container_entry_mem_cookie, sizeof(struct gw_container_entry));
+
   avl_init(&gateway_tree, avl_comp_default);
 
-  current_ipv4_gw = NULL;
-  v4gw_tunnel = NULL;
+  olsr_gw_list_init(&gw_list_ipv4, olsr_cnf->smart_gw_use_count);
+  olsr_gw_list_init(&gw_list_ipv6, olsr_cnf->smart_gw_use_count);
 
+  if (!multi_gateway_mode()) {
+    sgwEgressInterfaceNames = NULL;
+    sgwTunnel4InterfaceNames = NULL;
+    sgwTunnel6InterfaceNames = NULL;
+  } else {
+    uint8_t i;
+    struct sgw_egress_if * egressif;
+
+    /* setup the egress interface name/mark pairs */
+    sgwEgressInterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_egress_interfaces_count, "sgwEgressInterfaceNames");
+    i = 0;
+    egressif = olsr_cnf->smart_gw_egress_interfaces;
+    while (egressif) {
+      struct interfaceName * ifn = &sgwEgressInterfaceNames[i];
+      ifn->gw = NULL;
+      ifn->mark = i + olsr_cnf->smart_gw_mark_offset_egress;
+      egressif->mark = ifn->mark;
+      snprintf(&ifn->name[0], sizeof(ifn->name), egressif->name, egressif->mark);
+
+      egressif = egressif->next;
+      i++;
+    }
+    assert(i == olsr_cnf->smart_gw_egress_interfaces_count);
+
+    /* setup the SGW tunnel name/mark pairs */
+    sgwTunnel4InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel4InterfaceNames");
+    sgwTunnel6InterfaceNames = olsr_malloc(sizeof(struct interfaceName) * olsr_cnf->smart_gw_use_count, "sgwTunnel6InterfaceNames");
+    for (i = 0; i < olsr_cnf->smart_gw_use_count; i++) {
+      struct interfaceName * ifn = &sgwTunnel4InterfaceNames[i];
+      ifn->gw = NULL;
+      ifn->mark = i + olsr_cnf->smart_gw_mark_offset_tunnels;
+      snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_4%03u", ifn->mark);
+
+      ifn = &sgwTunnel6InterfaceNames[i];
+      ifn->gw = NULL;
+      ifn->mark = i + olsr_cnf->smart_gw_mark_offset_tunnels;
+      snprintf(&ifn->name[0], sizeof(ifn->name), "tnl_6%03u", ifn->mark);
+    }
+  }
+
+  current_ipv4_gw = NULL;
   current_ipv6_gw = NULL;
-  v6gw_tunnel = NULL;
 
   gw_handler = NULL;
 
@@ -178,6 +525,7 @@ int olsr_init_gateways(void) {
   gw_handler = &gw_def_handler;
   gw_handler->init();
 
+
   /*
    * There appears to be a kernel bug in some kernels (at least in the 3.0
    * Debian Squeeze kernel, but not in the Fedora 17 kernels) around
@@ -185,7 +533,7 @@ int olsr_init_gateways(void) {
    * a few times before giving up
    */
   while (retries-- > 0) {
-    if (!olsr_os_init_iptunnel(TUNNEL_NAME)) {
+    if (!olsr_os_init_iptunnel(server_tunnel_name())) {
       retries = 5;
       break;
     }
@@ -202,36 +550,103 @@ int olsr_init_gateways(void) {
 }
 
 /**
+ * Startup gateway system
+ */
+int olsr_startup_gateways(void) {
+  bool ok = true;
+
+  if (!multi_gateway_mode()) {
+    return 0;
+  }
+
+  ok = ok && multiGwRulesGeneric(true);
+  ok = ok && multiGwRulesSgwServerTunnel(true);
+  ok = ok && multiGwRulesOlsrInterfaces(true);
+  ok = ok && multiGwRulesEgressInterfaces(true);
+  ok = ok && multiGwRulesSgwTunnels(true);
+  if (!ok) {
+    olsr_printf(0, "Could not setup multi-gateway iptables and ip rules\n");
+    olsr_shutdown_gateways();
+    return 1;
+  }
+
+  return 0;
+}
+
+/**
+ * Shutdown gateway tunnel system
+ */
+void olsr_shutdown_gateways(void) {
+  if (!multi_gateway_mode()) {
+    return;
+  }
+
+  (void)multiGwRulesSgwTunnels(false);
+  (void)multiGwRulesEgressInterfaces(false);
+  (void)multiGwRulesOlsrInterfaces(false);
+  (void)multiGwRulesSgwServerTunnel(false);
+  (void)multiGwRulesGeneric(false);
+}
+
+/**
  * Cleanup gateway tunnel system
  */
 void olsr_cleanup_gateways(void) {
-  struct avl_node * avlnode = NULL;
+  struct gateway_entry * tree_gw;
+  struct gw_container_entry * gw;
 
   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
 
-  olsr_os_cleanup_iptunnel(TUNNEL_NAME);
-
   /* remove all gateways in the gateway tree that are not the active gateway */
-  while ((avlnode = avl_walk_first(&gateway_tree))) {
-    struct gateway_entry* tree_gw = node2gateway(avlnode);
+  OLSR_FOR_ALL_GATEWAY_ENTRIES(tree_gw) {
     if ((tree_gw != olsr_get_inet_gateway(false)) && (tree_gw != olsr_get_inet_gateway(true))) {
       olsr_delete_gateway_tree_entry(tree_gw, FORCE_DELETE_GW_ENTRY, true);
     }
-  }
+  } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
 
-  /* remove the active IPv4 gateway */
-  olsr_delete_gateway_tree_entry(olsr_get_inet_gateway(false), FORCE_DELETE_GW_ENTRY, true);
+  /* remove all active IPv4 gateways (should be at most 1 now) */
+  OLSR_FOR_ALL_GWS(&gw_list_ipv4.head, gw) {
+    if (gw && gw->gw) {
+      olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
+    }
+  }
+  OLSR_FOR_ALL_GWS_END(gw);
 
-  /* remove the active IPv6 gateway */
-  olsr_delete_gateway_tree_entry(olsr_get_inet_gateway(true), FORCE_DELETE_GW_ENTRY, true);
+  /* remove all active IPv6 gateways (should be at most 1 now) */
+  OLSR_FOR_ALL_GWS(&gw_list_ipv6.head, gw) {
+    if (gw && gw->gw) {
+      olsr_delete_gateway_entry(&gw->gw->originator, FORCE_DELETE_GW_ENTRY, true);
+    }
+  }
+  OLSR_FOR_ALL_GWS_END(gw);
 
   /* there should be no more gateways */
   assert(!avl_walk_first(&gateway_tree));
+  assert(!current_ipv4_gw);
+  assert(!current_ipv6_gw);
+
+  olsr_os_cleanup_iptunnel(server_tunnel_name());
 
   assert(gw_handler);
   gw_handler->cleanup();
   gw_handler = NULL;
 
+  if (sgwEgressInterfaceNames) {
+    free(sgwEgressInterfaceNames);
+    sgwEgressInterfaceNames = NULL;
+  }
+  if (sgwTunnel4InterfaceNames) {
+    free(sgwTunnel4InterfaceNames);
+    sgwTunnel4InterfaceNames = NULL;
+  }
+  if (sgwTunnel6InterfaceNames) {
+    free(sgwTunnel6InterfaceNames);
+    sgwTunnel6InterfaceNames = NULL;
+  }
+
+  olsr_gw_list_cleanup(&gw_list_ipv6);
+  olsr_gw_list_cleanup(&gw_list_ipv4);
+  olsr_free_cookie(gw_container_entry_mem_cookie);
   olsr_free_cookie(gateway_entry_mem_cookie);
 }
 
@@ -283,8 +698,9 @@ void olsr_print_gateway_entries(void) {
  * @param prefixlen of the HNA
  */
 void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
-  uint8_t *ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen);
+  uint8_t *ptr = hna_mask_to_hna_pointer(mask, prefixlen);
 
+  /* copy the current settings for uplink/downlink into the mask */
   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen / 8);
   if (olsr_cnf->has_ipv4_gateway) {
     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
@@ -310,17 +726,17 @@ void olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
  */
 void refresh_smartgw_netmask(void) {
   uint8_t *ip;
+
+  /* clear the mask */
   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
 
   if (olsr_cnf->smart_gw_active) {
     ip = (uint8_t *) &smart_gateway_netmask;
 
-    if (olsr_cnf->smart_gw_uplink > 0 && olsr_cnf->smart_gw_downlink > 0) {
-      /* the link is bi-directional with a non-zero bandwidth */
-      ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
-      ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
-      ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
-    }
+    ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
+    ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
+    ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
+
     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
@@ -347,7 +763,7 @@ bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *ma
     return false;
   }
 
-  ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefix->prefix_len);
+  ptr = hna_mask_to_hna_pointer(mask, prefix->prefix_len);
   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
 }
 
@@ -360,6 +776,7 @@ bool olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *ma
  * @param seqno the sequence number of the HNA
  */
 void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
+  struct gw_container_entry * new_gw_in_list;
   uint8_t *ptr;
   struct gateway_entry *gw = node2gateway(avl_find(&gateway_tree, originator));
 
@@ -377,7 +794,7 @@ void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_add
   /* keep new HNA seqno */
   gw->seqno = seqno;
 
-  ptr = OLSR_IP_ADDR_2_HNA_PTR(mask, prefixlen);
+  ptr = hna_mask_to_hna_pointer(mask, prefixlen);
   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
@@ -411,6 +828,21 @@ void olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_add
     gw->cleanup_timer = NULL;
   }
 
+  /* update the costs of the gateway when it is an active gateway */
+  new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
+  if (new_gw_in_list) {
+    assert(gw_handler);
+    new_gw_in_list = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, gw_handler->getcosts(new_gw_in_list->gw));
+    assert(new_gw_in_list);
+  }
+
+  new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
+  if (new_gw_in_list) {
+    assert(gw_handler);
+    new_gw_in_list = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list, gw_handler->getcosts(new_gw_in_list->gw));
+    assert(new_gw_in_list);
+  }
+
   /* call update handler */
   assert(gw_handler);
   gw_handler->update(gw);
@@ -452,7 +884,7 @@ static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t pr
   }
 
   if (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6) {
-    /* found a gw and it wasn't deleted yet */
+    /* the gw  is not scheduled for deletion */
 
     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
       change = gw->ipv4;
@@ -468,6 +900,8 @@ static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t pr
     }
 
     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
+      struct gw_container_entry * gw_in_list;
+
       /* prevent this gateway from being chosen as the new gateway */
       gw->ipv4 = false;
       gw->ipv4nat = false;
@@ -478,23 +912,48 @@ static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t pr
       gw_handler->delete(gw);
 
       /* cleanup gateway if necessary */
-      if (current_ipv4_gw == gw) {
-        if (v4gw_tunnel) {
-          olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, false);
-          olsr_os_del_ipip_tunnel(v4gw_tunnel);
-          v4gw_tunnel = NULL;
+      gw_in_list = olsr_gw_list_find(&gw_list_ipv4, gw);
+      if (gw_in_list) {
+        if (current_ipv4_gw && current_ipv4_gw->gw == gw) {
+          olsr_os_inetgw_tunnel_route(current_ipv4_gw->tunnel->if_index, true, false, olsr_cnf->rt_table_tunnel);
+          current_ipv4_gw = NULL;
         }
 
-        current_ipv4_gw = NULL;
+        if (gw_in_list->tunnel) {
+          struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
+          if (ifn) {
+            olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, true, false, ifn->mark);
+          }
+          olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
+          set_unused_iptunnel_name(gw_in_list->gw);
+          gw_in_list->tunnel = NULL;
+        }
+
+        gw_in_list->gw = NULL;
+        gw_in_list = olsr_gw_list_remove(&gw_list_ipv4, gw_in_list);
+        olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
       }
-      if (current_ipv6_gw == gw) {
-        if (v6gw_tunnel) {
-          olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, false);
-          olsr_os_del_ipip_tunnel(v6gw_tunnel);
-          v6gw_tunnel = NULL;
+
+      gw_in_list = olsr_gw_list_find(&gw_list_ipv6, gw);
+      if (gw_in_list) {
+        if (current_ipv6_gw && current_ipv6_gw->gw == gw) {
+          olsr_os_inetgw_tunnel_route(current_ipv6_gw->tunnel->if_index, false, false, olsr_cnf->rt_table_tunnel);
+          current_ipv6_gw = NULL;
+        }
+
+        if (gw_in_list->tunnel) {
+          struct interfaceName * ifn = find_interfaceName(gw_in_list->gw);
+          if (ifn) {
+            olsr_os_inetgw_tunnel_route(gw_in_list->tunnel->if_index, false, false, ifn->mark);
+          }
+          olsr_os_del_ipip_tunnel(gw_in_list->tunnel);
+          set_unused_iptunnel_name(gw_in_list->gw);
+          gw_in_list->tunnel = NULL;
         }
 
-        current_ipv6_gw = NULL;
+        gw_in_list->gw = NULL;
+        gw_in_list = olsr_gw_list_remove(&gw_list_ipv6, gw_in_list);
+        olsr_cookie_free(gw_container_entry_mem_cookie, gw_in_list);
       }
 
       if (!immediate) {
@@ -503,6 +962,13 @@ static void olsr_delete_gateway_tree_entry(struct gateway_entry * gw, uint8_t pr
       } else {
         cleanup_gateway_handler(gw);
       }
+
+      /* when the current gateway was deleted, then immediately choose a new gateway */
+      if (!current_ipv4_gw || !current_ipv6_gw) {
+        assert(gw_handler);
+        gw_handler->choose(!current_ipv4_gw, !current_ipv6_gw);
+      }
+
     } else if (change) {
       assert(gw_handler);
       gw_handler->update(gw);
@@ -518,12 +984,12 @@ void olsr_trigger_gatewayloss_check(void) {
   bool ipv4 = false;
   bool ipv6 = false;
 
-  if (current_ipv4_gw) {
-    struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->originator);
+  if (current_ipv4_gw && current_ipv4_gw->gw) {
+    struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv4_gw->gw->originator);
     ipv4 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
   }
-  if (current_ipv6_gw) {
-    struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->originator);
+  if (current_ipv6_gw && current_ipv6_gw->gw) {
+    struct tc_entry *tc = olsr_lookup_tc_entry(&current_ipv6_gw->gw->originator);
     ipv6 = (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN);
   }
 
@@ -541,11 +1007,12 @@ void olsr_trigger_gatewayloss_check(void) {
  * Sets a new internet gateway.
  *
  * @param originator ip address of the node with the new gateway
+ * @param path_cost the path cost
  * @param ipv4 set ipv4 gateway
  * @param ipv6 set ipv6 gateway
  * @return true if an error happened, false otherwise
  */
-bool olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6) {
+bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, bool ipv4, bool ipv6) {
   struct gateway_entry *new_gw;
 
   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
@@ -561,37 +1028,118 @@ bool olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6)
   }
 
   /* handle IPv4 */
-  if (ipv4 && new_gw->ipv4 && (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) && current_ipv4_gw != new_gw) {
-    struct olsr_iptunnel_entry *new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true);
-    if (new_v4gw_tunnel) {
-      olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true);
-      if (v4gw_tunnel) {
-        olsr_os_del_ipip_tunnel(v4gw_tunnel);
-        v4gw_tunnel = NULL;
-      }
-      current_ipv4_gw = new_gw;
-      v4gw_tunnel = new_v4gw_tunnel;
+  if (ipv4 &&
+      new_gw->ipv4 &&
+      (!new_gw->ipv4nat || olsr_cnf->smart_gw_allow_nat) &&
+      (!current_ipv4_gw || current_ipv4_gw->gw != new_gw || current_ipv4_gw->path_cost != path_cost)) {
+    /* new gw is different than the current gw, or costs have changed */
+
+    struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv4, new_gw);
+    if (new_gw_in_list) {
+      /* new gw is already in the gw list */
+      assert(new_gw_in_list->tunnel);
+      olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
+      current_ipv4_gw = olsr_gw_list_update(&gw_list_ipv4, new_gw_in_list, path_cost);
     } else {
-      /* adding the tunnel failed, we try again in the next cycle */
-      ipv4 = false;
+      /* new gw is not yet in the gw list */
+      char name[IFNAMSIZ];
+      struct olsr_iptunnel_entry *new_v4gw_tunnel;
+      struct interfaceName * interfaceName;
+
+      if (olsr_gw_list_full(&gw_list_ipv4)) {
+        /* the list is full: remove the worst active gateway */
+        struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv4);
+        assert(worst);
+
+        if (worst->tunnel) {
+          struct interfaceName * ifn = find_interfaceName(worst->gw);
+          if (ifn) {
+            olsr_os_inetgw_tunnel_route(worst->tunnel->if_index, true, false, ifn->mark);
+          }
+          olsr_os_del_ipip_tunnel(worst->tunnel);
+          set_unused_iptunnel_name(worst->gw);
+          worst->tunnel = NULL;
+        }
+        worst->gw = NULL;
+        olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(&gw_list_ipv4, worst));
+      }
+
+      get_unused_iptunnel_name(new_gw, name, &interfaceName);
+      new_v4gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, true, name);
+      if (new_v4gw_tunnel) {
+        if (interfaceName) {
+          olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, interfaceName->mark);
+        }
+        olsr_os_inetgw_tunnel_route(new_v4gw_tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
+
+        new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
+        new_gw_in_list->gw = new_gw;
+        new_gw_in_list->tunnel = new_v4gw_tunnel;
+        new_gw_in_list->path_cost = path_cost;
+        current_ipv4_gw = olsr_gw_list_add(&gw_list_ipv4, new_gw_in_list);
+      } else {
+        /* adding the tunnel failed, we try again in the next cycle */
+        set_unused_iptunnel_name(new_gw);
+        ipv4 = false;
+      }
     }
   }
 
   /* handle IPv6 */
-  if (ipv6 && new_gw->ipv6 && current_ipv6_gw != new_gw) {
-    struct olsr_iptunnel_entry *new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false);
-               if (new_v6gw_tunnel) {
-                       olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true);
-                       if (v6gw_tunnel) {
-                               olsr_os_del_ipip_tunnel(v6gw_tunnel);
-                               v6gw_tunnel = NULL;
-                       }
-                       current_ipv6_gw = new_gw;
-                       v6gw_tunnel = new_v6gw_tunnel;
-               } else {
-                       /* adding the tunnel failed, we try again in the next cycle */
-                       ipv6 = false;
-               }
+  if (ipv6 &&
+      new_gw->ipv6 &&
+      (!current_ipv6_gw || current_ipv6_gw->gw != new_gw || current_ipv6_gw->path_cost != path_cost)) {
+    /* new gw is different than the current gw, or costs have changed */
+
+       struct gw_container_entry * new_gw_in_list = olsr_gw_list_find(&gw_list_ipv6, new_gw);
+    if (new_gw_in_list) {
+      /* new gw is already in the gw list */
+      assert(new_gw_in_list->tunnel);
+      olsr_os_inetgw_tunnel_route(new_gw_in_list->tunnel->if_index, true, true, olsr_cnf->rt_table_tunnel);
+      current_ipv6_gw = olsr_gw_list_update(&gw_list_ipv6, new_gw_in_list, path_cost);
+    } else {
+      /* new gw is not yet in the gw list */
+      char name[IFNAMSIZ];
+      struct olsr_iptunnel_entry *new_v6gw_tunnel;
+      struct interfaceName * interfaceName;
+
+      if (olsr_gw_list_full(&gw_list_ipv6)) {
+        /* the list is full: remove the worst active gateway */
+        struct gw_container_entry* worst = olsr_gw_list_get_worst_entry(&gw_list_ipv6);
+        assert(worst);
+
+        if (worst->tunnel) {
+          struct interfaceName * ifn = find_interfaceName(worst->gw);
+          if (ifn) {
+            olsr_os_inetgw_tunnel_route(worst->tunnel->if_index, false, false, ifn->mark);
+          }
+          olsr_os_del_ipip_tunnel(worst->tunnel);
+          set_unused_iptunnel_name(worst->gw);
+          worst->tunnel = NULL;
+        }
+        worst->gw = NULL;
+        olsr_cookie_free(gw_container_entry_mem_cookie, olsr_gw_list_remove(&gw_list_ipv6, worst));
+      }
+
+      get_unused_iptunnel_name(new_gw, name, &interfaceName);
+      new_v6gw_tunnel = olsr_os_add_ipip_tunnel(&new_gw->originator, false, name);
+      if (new_v6gw_tunnel) {
+        if (interfaceName) {
+          olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, interfaceName->mark);
+        }
+        olsr_os_inetgw_tunnel_route(new_v6gw_tunnel->if_index, false, true, olsr_cnf->rt_table_tunnel);
+
+        new_gw_in_list = olsr_cookie_malloc(gw_container_entry_mem_cookie);
+        new_gw_in_list->gw = new_gw;
+        new_gw_in_list->tunnel = new_v6gw_tunnel;
+        new_gw_in_list->path_cost = path_cost;
+        current_ipv6_gw = olsr_gw_list_add(&gw_list_ipv6, new_gw_in_list);
+      } else {
+        /* adding the tunnel failed, we try again in the next cycle */
+        set_unused_iptunnel_name(new_gw);
+        ipv6 = false;
+      }
+    }
   }
 
   return !ipv4 && !ipv6;
@@ -605,10 +1153,10 @@ bool olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6)
  */
 struct gateway_entry *olsr_get_inet_gateway(bool ipv6) {
        if (ipv6) {
-               return current_ipv6_gw;
+               return current_ipv6_gw ? current_ipv6_gw->gw : NULL;
        }
 
-       return current_ipv4_gw;
+       return current_ipv4_gw ? current_ipv4_gw->gw : NULL;
 }
 
 #endif /* __linux__ */
index 385a48e..7481218 100644 (file)
@@ -103,6 +103,14 @@ struct olsr_gw_handler {
     void (*startup)(void);
 
     /**
+     * Called when the costs of a gateway must be determined.
+     *
+     * @param gw the gateway
+     * @return the costs
+     */
+    uint64_t (*getcosts)(struct gateway_entry *gw);
+
+    /**
      * Called when a new gateway must be chosen.
      *
      * @param ipv4 true when an IPv4 gateway must be chosen
@@ -130,6 +138,8 @@ struct olsr_gw_handler {
  */
 
 int olsr_init_gateways(void);
+int olsr_startup_gateways(void);
+void olsr_shutdown_gateways(void);
 void olsr_cleanup_gateways(void);
 void olsr_trigger_inetgw_startup(void);
 #ifndef NODEBUG
@@ -163,7 +173,7 @@ void olsr_trigger_gatewayloss_check(void);
  * Gateway Plugin Functions
  */
 
-bool olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6);
+bool olsr_set_inet_gateway(union olsr_ip_addr *originator, uint64_t path_cost, bool ipv4, bool ipv6);
 struct gateway_entry *olsr_get_inet_gateway(bool ipv6);
 
 #endif /* GATEWAY_H_ */
index ec331fc..3957b3a 100644 (file)
 
 static uint32_t gw_def_nodecount;
 static uint32_t gw_def_stablecount;
-static bool gw_def_finished_ipv4;
-static bool gw_def_finished_ipv6;
+static bool gw_def_choose_new_ipv4_gw;
+static bool gw_def_choose_new_ipv6_gw;
 static struct timer_entry *gw_def_timer;
 
 /* forward declarations */
 static void gw_default_init(void);
 static void gw_default_cleanup(void);
 static void gw_default_startup_handler(void);
+static uint64_t gw_default_getcosts(struct gateway_entry *gw);
 static void gw_default_choosegw_handler(bool ipv4, bool ipv6);
 static void gw_default_update_handler(struct gateway_entry *);
 static void gw_default_delete_handler(struct gateway_entry *);
@@ -33,6 +34,7 @@ struct olsr_gw_handler gw_def_handler = {
     &gw_default_init,
     &gw_default_cleanup,
     &gw_default_startup_handler,
+    &gw_default_getcosts,
     &gw_default_choosegw_handler,
     &gw_default_update_handler,
     &gw_default_delete_handler
@@ -49,15 +51,11 @@ struct olsr_gw_handler gw_def_handler = {
  * @return the threshold path cost
  */
 static inline uint64_t gw_default_calc_threshold(uint64_t path_cost) {
-  uint64_t path_cost_times_threshold;
-
   if (olsr_cnf->smart_gw_thresh == 0) {
-    path_cost_times_threshold = path_cost;
-  } else {
-    path_cost_times_threshold = (path_cost * (uint64_t) olsr_cnf->smart_gw_thresh + (uint64_t) 50) / (uint64_t) 100;
+    return path_cost;
   }
 
-  return path_cost_times_threshold;
+  return ((path_cost * (uint64_t) olsr_cnf->smart_gw_thresh) + (uint64_t) 50) / (uint64_t) 100;
 }
 
 /**
@@ -103,9 +101,9 @@ static inline uint64_t gw_default_weigh_costs(uint64_t path_cost, uint32_t exitU
    * Wetx   = the ETX path cost weight                          (configured)
    * Detx   = the ETX path cost divider                         (configured)
    *
-   *                      WexitU   WexitD   Wetx
-   * path_cost_weighed =  ------ + ------ + ---- * path_cost
-   *                      exitUm   exitDm   Detx
+   *                     WexitU   WexitD   Wetx
+   * path_cost_weight =  ------ + ------ + ---- * path_cost
+   *                     exitUm   exitDm   Detx
    *
    * Since the gateway exit link bandwidths are in Kbps, the following formula
    * is used to convert them to the desired Mbps:
@@ -114,30 +112,30 @@ static inline uint64_t gw_default_weigh_costs(uint64_t path_cost, uint32_t exitU
    * bwM = ----       bwK = bandwidth in Kbps
    *       1000       bwM = bandwidth in Mbps
    *
-   * exitUm = the gateway exit link uplink   bandwidth, in Kbps
-   * exitDm = the gateway exit link downlink bandwidth, in Kbps
+   * exitUk = the gateway exit link uplink   bandwidth, in Kbps
+   * exitDk = the gateway exit link downlink bandwidth, in Kbps
    *
-   *                      1000 * WexitU   1000 * WexitD   Wetx
-   * path_cost_weighed =  ------------- + ------------- + ---- * path_cost
-   *                          exitUk          exitDk      Detx
+   *                     1000 * WexitU   1000 * WexitD   Wetx
+   * path_cost_weight =  ------------- + ------------- + ---- * path_cost
+   *                         exitUk          exitDk      Detx
    *
    *
    * Analysis of the required bit width of the result:
    *
-   * exitUk    = 29 bits = [1,   320,000,000]
-   * exitDk    = 29 bits = [1,   320,000,000]
-   * WexitU    =  8 bits = [1,           255]
-   * WexitD    =  8 bits = [1,           255]
-   * Wetx      =  8 bits = [1,           255]
-   * Detx      =  8 bits = [1,           255]
-   * path_cost = 32 bits = [1, 4,294,967,295]
+   * exitUk    = [1,   320,000,000] = 29 bits
+   * exitDk    = [1,   320,000,000] = 29 bits
+   * WexitU    = [1,           255] =  8 bits
+   * WexitD    = [1,           255] =  8 bits
+   * Wetx      = [1,           255] =  8 bits
+   * Detx      = [1,           255] =  8 bits
+   * path_cost = [1, 4,294,967,295] = 32 bits
    *
-   *                          1000 * 255   1000 * 255   255
-   * path_cost_weighed(max) = ---------- + ---------- + --- * 4,294,967,295
-   *                               1             1       1
+   *                         1000 * 255   1000 * 255   255
+   * path_cost_weight(max) = ---------- + ---------- + --- * 4,294,967,295
+   *                              1             1       1
    *
-   * path_cost_weighed(max) = 0x3E418    + 0x3E418    + 0xFEFFFFFF01
-   * path_cost_weighed(max) = 0xFF0007C731
+   * path_cost_weight(max) = 0x3E418    + 0x3E418    + 0xFEFFFFFF01
+   * path_cost_weight(max) = 0xFF0007C731
    *
    * Because we can multiply 0xFF0007C731 by 2^24 without overflowing a
    * 64 bits number, we do this to increase accuracy.
@@ -157,90 +155,78 @@ static inline uint64_t gw_default_weigh_costs(uint64_t path_cost, uint32_t exitU
 static void gw_default_choose_gateway(void) {
   uint64_t cost_ipv4_threshold = UINT64_MAX;
   uint64_t cost_ipv6_threshold = UINT64_MAX;
-  bool eval_cost_ipv4_threshold = false;
-  bool eval_cost_ipv6_threshold = false;
-  struct gateway_entry *inet_ipv4 = NULL;
-  struct gateway_entry *inet_ipv6 = NULL;
-  uint64_t cost_ipv4 = UINT64_MAX;
-  uint64_t cost_ipv6 = UINT64_MAX;
+  bool cost_ipv4_threshold_valid = false;
+  bool cost_ipv6_threshold_valid = false;
+  struct gateway_entry *chosen_gw_ipv4 = NULL;
+  struct gateway_entry *chosen_gw_ipv6 = NULL;
+  uint64_t chosen_gw_ipv4_costs = UINT64_MAX;
+  uint64_t chosen_gw_ipv6_costs = UINT64_MAX;
   struct gateway_entry *gw;
-  struct tc_entry *tc;
-  bool dual;
+  bool dual = false;
 
   if (olsr_cnf->smart_gw_thresh) {
     /* determine the path cost thresholds */
 
-    gw = olsr_get_inet_gateway(false);
-    if (gw) {
-      tc = olsr_lookup_tc_entry(&gw->originator);
-      if (tc) {
-        uint64_t cost = gw_default_weigh_costs(tc->path_cost, gw->uplink, gw->downlink);
-        cost_ipv4_threshold = gw_default_calc_threshold(cost);
-        eval_cost_ipv4_threshold = true;
-      }
+    uint64_t cost = gw_default_getcosts(olsr_get_inet_gateway(false));
+    if (cost != UINT64_MAX) {
+      cost_ipv4_threshold = gw_default_calc_threshold(cost);
+      cost_ipv4_threshold_valid = true;
     }
-    gw = olsr_get_inet_gateway(true);
-    if (gw) {
-      tc = olsr_lookup_tc_entry(&gw->originator);
-      if (tc) {
-        uint64_t cost = gw_default_weigh_costs(tc->path_cost, gw->uplink, gw->downlink);
-        cost_ipv6_threshold = gw_default_calc_threshold(cost);
-        eval_cost_ipv6_threshold = true;
-      }
+
+    cost = gw_default_getcosts(olsr_get_inet_gateway(true));
+    if (cost != UINT64_MAX) {
+      cost_ipv6_threshold = gw_default_calc_threshold(cost);
+      cost_ipv6_threshold_valid = true;
     }
   }
 
   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
-    uint64_t path_cost;
-    tc = olsr_lookup_tc_entry(&gw->originator);
-
-    if (!tc) {
-      /* gateways should not exist without tc entry */
-      continue;
-    }
+    uint64_t gw_cost = gw_default_getcosts(gw);
 
-    if (tc->path_cost == ROUTE_COST_BROKEN) {
-      /* do not consider nodes with an infinite ETX */
+    if (gw_cost == UINT64_MAX) {
+      /* never select a node with infinite costs */
       continue;
     }
 
-    if (!gw->uplink || !gw->downlink) {
-      /* do not consider nodes without bandwidth or with a uni-directional link */
-      continue;
+    if (gw_def_choose_new_ipv4_gw) {
+      bool gw_eligible_v4 = gw->ipv4
+          /* && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit) *//* contained in gw_def_choose_new_ipv4_gw */
+          && (olsr_cnf->smart_gw_allow_nat || !gw->ipv4nat);
+      if (gw_eligible_v4 && gw_cost < chosen_gw_ipv4_costs
+          && (!cost_ipv4_threshold_valid || (gw_cost < cost_ipv4_threshold))) {
+        chosen_gw_ipv4 = gw;
+        chosen_gw_ipv4_costs = gw_cost;
+      }
     }
 
-    /* determine the path cost */
-    path_cost = gw_default_weigh_costs(tc->path_cost, gw->uplink, gw->downlink);
-
-    if (!gw_def_finished_ipv4 && gw->ipv4 && gw->ipv4nat == olsr_cnf->smart_gw_allow_nat && path_cost < cost_ipv4
-        && (!eval_cost_ipv4_threshold || (path_cost < cost_ipv4_threshold))) {
-      inet_ipv4 = gw;
-      cost_ipv4 = path_cost;
-    }
-    if (!gw_def_finished_ipv6 && gw->ipv6 && path_cost < cost_ipv6
-        && (!eval_cost_ipv6_threshold || (path_cost < cost_ipv6_threshold))) {
-      inet_ipv6 = gw;
-      cost_ipv6 = path_cost;
+    if (gw_def_choose_new_ipv6_gw) {
+      bool gw_eligible_v6 = gw->ipv6
+          /* && olsr_cnf->ip_version == AF_INET6 *//* contained in gw_def_choose_new_ipv6_gw */;
+      if (gw_eligible_v6 && gw_cost < chosen_gw_ipv6_costs
+          && (!cost_ipv6_threshold_valid || (gw_cost < cost_ipv6_threshold))) {
+        chosen_gw_ipv6 = gw;
+        chosen_gw_ipv6_costs = gw_cost;
+      }
     }
   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
 
-  /* determine if we found an IPv4 and IPv6 gateway */
-  gw_def_finished_ipv4 |= (inet_ipv4 != NULL);
-  gw_def_finished_ipv6 |= (inet_ipv6 != NULL);
+  /* determine if we should keep looking for IPv4 and/or IPv6 gateways */
+  gw_def_choose_new_ipv4_gw = gw_def_choose_new_ipv4_gw && (chosen_gw_ipv4 == NULL);
+  gw_def_choose_new_ipv6_gw = gw_def_choose_new_ipv6_gw && (chosen_gw_ipv6 == NULL);
 
   /* determine if we are dealing with a dual stack gateway */
-  dual = (inet_ipv4 == inet_ipv6) && (inet_ipv4 != NULL);
+  dual = chosen_gw_ipv4 && (chosen_gw_ipv4 == chosen_gw_ipv6);
 
-  if (inet_ipv4) {
+  if (chosen_gw_ipv4) {
     /* we are dealing with an IPv4 or dual stack gateway */
-    olsr_set_inet_gateway(&inet_ipv4->originator, true, dual);
+    olsr_set_inet_gateway(&chosen_gw_ipv4->originator, chosen_gw_ipv4_costs, true, dual);
   }
-  if (inet_ipv6 && !dual) {
+  if (chosen_gw_ipv6 && !dual) {
     /* we are dealing with an IPv6-only gateway */
-    olsr_set_inet_gateway(&inet_ipv6->originator, false, true);
+    olsr_set_inet_gateway(&chosen_gw_ipv6->originator, chosen_gw_ipv6_costs, false, true);
   }
 
-  if ((olsr_cnf->smart_gw_thresh == 0) && gw_def_finished_ipv4 && gw_def_finished_ipv6) {
+  if ((olsr_cnf->smart_gw_thresh == 0) && !gw_def_choose_new_ipv4_gw && !gw_def_choose_new_ipv6_gw) {
     /* stop looking for a better gateway */
     olsr_stop_timer(gw_def_timer);
     gw_def_timer = NULL;
@@ -285,14 +271,14 @@ static void gw_default_timer(void *unused __attribute__ ((unused))) {
 static void gw_default_lookup_gateway(bool ipv4, bool ipv6) {
   if (ipv4) {
     /* get a new IPv4 gateway if we use OLSRv4 or NIIT */
-    gw_def_finished_ipv4 = !(olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
+    gw_def_choose_new_ipv4_gw = (olsr_cnf->ip_version == AF_INET) || olsr_cnf->use_niit;
   }
   if (ipv6) {
     /* get a new IPv6 gateway if we use OLSRv6 */
-    gw_def_finished_ipv6 = !(olsr_cnf->ip_version == AF_INET6);
+    gw_def_choose_new_ipv6_gw = olsr_cnf->ip_version == AF_INET6;
   }
 
-  if (!(gw_def_finished_ipv4 && gw_def_finished_ipv6)) {
+  if (gw_def_choose_new_ipv4_gw || gw_def_choose_new_ipv6_gw) {
     gw_default_choose_gateway();
   }
 }
@@ -312,8 +298,8 @@ static void gw_default_init(void) {
   /* initialize values */
   gw_def_nodecount = 0;
   gw_def_stablecount = 0;
-  gw_def_finished_ipv4 = false;
-  gw_def_finished_ipv6 = false;
+  gw_def_choose_new_ipv4_gw = true;
+  gw_def_choose_new_ipv6_gw = true;
   gw_def_timer = NULL;
 }
 
@@ -332,20 +318,46 @@ static void gw_default_startup_handler(void) {
   gw_def_stablecount = 0;
 
   /* get a new IPv4 gateway if we use OLSRv4 or NIIT */
-  gw_def_finished_ipv4 = !(olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
+  gw_def_choose_new_ipv4_gw = (olsr_cnf->ip_version == AF_INET) || olsr_cnf->use_niit;
 
   /* get a new IPv6 gateway if we use OLSRv6 */
-  gw_def_finished_ipv6 = !(olsr_cnf->ip_version == AF_INET6);
+  gw_def_choose_new_ipv6_gw = olsr_cnf->ip_version == AF_INET6;
 
   /* keep in mind we might be a gateway ourself */
-  gw_def_finished_ipv4 |= olsr_cnf->has_ipv4_gateway;
-  gw_def_finished_ipv6 |= olsr_cnf->has_ipv6_gateway;
+  gw_def_choose_new_ipv4_gw = gw_def_choose_new_ipv4_gw && !olsr_cnf->has_ipv4_gateway;
+  gw_def_choose_new_ipv6_gw = gw_def_choose_new_ipv6_gw && !olsr_cnf->has_ipv6_gateway;
 
   /* (re)start gateway lazy selection timer */
   olsr_set_timer(&gw_def_timer, olsr_cnf->smart_gw_period, 0, true, &gw_default_timer, NULL, 0);
 }
 
 /**
+ * Called when the costs of a gateway must be determined.
+ *
+ * @param gw the gateway
+ * @return the costs, or UINT64_MAX in case the gateway is null or has inifinite costs
+ */
+static uint64_t gw_default_getcosts(struct gateway_entry *gw) {
+  struct tc_entry* tc;
+
+  if (!gw) {
+    return UINT64_MAX;
+  }
+
+  tc = olsr_lookup_tc_entry(&gw->originator);
+
+  if (!tc || (tc->path_cost == ROUTE_COST_BROKEN) || (!gw->uplink || !gw->downlink)) {
+    /* gateways should not exist without tc entry */
+    /* do not consider nodes with an infinite ETX */
+    /* do not consider nodes without bandwidth or with a uni-directional link */
+    return UINT64_MAX;
+  }
+
+  /* determine the path cost */
+  return gw_default_weigh_costs(tc->path_cost, gw->uplink, gw->downlink);
+}
+
+/**
  * Choose a new gateway
  *
  * @param ipv4 lookup new v4 gateway
@@ -354,7 +366,7 @@ static void gw_default_startup_handler(void) {
 static void gw_default_choosegw_handler(bool ipv4, bool ipv6) {
   gw_default_lookup_gateway(ipv4, ipv6);
 
-  if (!(gw_def_finished_ipv4 && gw_def_finished_ipv6)) {
+  if (gw_def_choose_new_ipv4_gw || gw_def_choose_new_ipv6_gw) {
     gw_default_startup_handler();
   }
 }
diff --git a/src/gateway_list.c b/src/gateway_list.c
new file mode 100644 (file)
index 0000000..c84a789
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
+ * IPv4 performance optimization (c) 2006, sven-ola(gmx.de)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifdef __linux__
+
+#include "gateway_list.h"
+
+#include "gateway.h"
+#include "common/list.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+/*
+ * Exported functions
+ */
+
+/**
+ * Initialization
+ *
+ * @param list a pointer to the list
+ * @param count the maximum number of entries to be kept in the list. Must be
+ * larger than zero
+ */
+void olsr_gw_list_init(struct gw_list * list, uint8_t count) {
+       assert(list);
+       assert(count > 0);
+
+       list_head_init(&list->head);
+       list->count_max = count;
+       list->count = 0;
+}
+
+/**
+ * Cleanup
+ *
+ * @param list a pointer to the list
+ */
+void olsr_gw_list_cleanup(struct gw_list * list __attribute__((unused))) {
+       /* nothing to do */
+}
+
+/**
+ * Find an entry on the list
+ *
+ * @param list a pointer to the list
+ * @param entry a pointer to the entry to find
+ * @return a pointer to the entry, or NULL when not found
+ */
+struct gw_container_entry * olsr_gw_list_find(struct gw_list * list, struct gateway_entry * entry) {
+       struct gw_container_entry * gw;
+
+       assert(list);
+       assert(entry);
+
+       OLSR_FOR_ALL_GWS(&list->head, gw) {
+               if (gw && gw->gw && (gw->gw == entry)) {
+                       return gw;
+               }
+       }
+       OLSR_FOR_ALL_GWS_END(gw);
+
+       return NULL;
+}
+
+/**
+ * Add an entry to the list.
+ *
+ * The list is ordered on costs with the lowest costs (best) first and the
+ * highest costs (worst) last. In case of equal costs, the entry is added
+ * _before_ the one(s) that is(are) already in the list.
+ *
+ * @param list a pointer to the list
+ * @param entry a pointer to the entry
+ * @return a pointer to the added entry
+ */
+struct gw_container_entry * olsr_gw_list_add(struct gw_list * list, struct gw_container_entry * entry) {
+       struct gw_container_entry * gw;
+
+       assert(list);
+       assert(entry);
+       assert(!olsr_gw_list_full(list));
+
+       list_node_init(&entry->list_node);
+
+       OLSR_FOR_ALL_GWS(&list->head, gw) {
+               if (gw && (entry->path_cost <= gw->path_cost)) {
+                       /* add before the iterated list entry: the gateway to insert has lower
+                        * costs or has equal costs but is newer (since we insert it) */
+                       list_add_before(&gw->list_node, &entry->list_node);
+                       list->count++;
+                       return entry;
+               }
+       }
+       OLSR_FOR_ALL_GWS_END(gw);
+
+       /* add at the end */
+       list_add_after(list->head.prev, &entry->list_node);
+       list->count++;
+       return entry;
+}
+
+/**
+ * Update an entry on the list.
+ *
+ * @param list a pointer to the list
+ * @param entry a pointer to the entry
+ * @param path_cost the costs of the entry
+ * @return a pointer to the updated entry
+ */
+struct gw_container_entry * olsr_gw_list_update(struct gw_list * list, struct gw_container_entry * entry,
+               uint64_t path_cost) {
+       assert(list);
+       assert(entry);
+       assert(!olsr_gw_list_empty(list));
+
+       if (entry->path_cost == path_cost) {
+               return entry;
+       }
+
+       /* don't touch gw */
+       /* don't touch tunnel */
+       entry->path_cost = path_cost;
+       /* don't touch list_node */
+
+       list_remove(&entry->list_node);
+       list->count--;
+       return olsr_gw_list_add(list, entry);
+}
+
+/**
+ * Remove a gateway from the list (but do not free it's memory)
+ *
+ * @param list a pointer to the list
+ * @param entry a pointer to the gateway
+ * @return a pointer to the removed entry
+ */
+struct gw_container_entry * olsr_gw_list_remove(struct gw_list * list, struct gw_container_entry * entry) {
+       assert(list);
+       assert(entry);
+       assert(!olsr_gw_list_empty(list));
+
+       list_remove(&entry->list_node);
+       list->count--;
+       return entry;
+}
+
+#endif /* __linux__ */
diff --git a/src/gateway_list.h b/src/gateway_list.h
new file mode 100644 (file)
index 0000000..e947b16
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * The olsr.org Optimized Link-State Routing daemon(olsrd)
+ * Copyright (c) 2004, Thomas Lopatic (thomas@lopatic.de)
+ * IPv4 performance optimization (c) 2006, sven-ola(gmx.de)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of olsr.org, olsrd nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Visit http://www.olsr.org for more information.
+ *
+ * If you find this software useful feel free to make a donation
+ * to the project. For more information see the website or contact
+ * the copyright holders.
+ *
+ */
+
+#ifndef _GW_LIST_H
+#define _GW_LIST_H
+
+#ifdef __linux__
+
+#include "gateway.h"
+#include "common/list.h"
+#include "kernel_tunnel.h"
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+/** Holds the list head and list administration */
+struct gw_list {
+               struct list_node head; /**< The (ordered) list of entries */
+               uint8_t count_max; /**< The maximum number of entries in the list */
+               uint8_t count; /**< The number of entries in the list */
+};
+
+/** A container for a gateway and its tunnel */
+struct gw_container_entry {
+               struct gateway_entry * gw; /**< the gateway entry */
+               struct olsr_iptunnel_entry * tunnel; /**< the gateway tunnel */
+               uint64_t path_cost; /**< the gateway path costs */
+               struct list_node list_node; /**< the list node */
+};
+
+/** Cast from list_node to gw_container_entry */
+LISTNODE2STRUCT(olsr_gw_list_node2entry, struct gw_container_entry, list_node);
+
+/** Deletion safe macro for gateway list traversal (do not delete the previous or next node, current node is ok) */
+#define OLSR_FOR_ALL_GWS(head, gw) {\
+  struct list_node * _list_node; \
+  struct list_node * _next_list_node; \
+  for (_list_node = (head)->next; _list_node != (head); _list_node = _next_list_node) { \
+    _next_list_node = _list_node->next; \
+    gw = olsr_gw_list_node2entry(_list_node);
+#define OLSR_FOR_ALL_GWS_END(gw) }}
+
+/**
+ * @param list a pointer to the list
+ * @return true when multiple gateways mode is enabled
+ */
+static inline bool olsr_gw_list_isModeMulti(struct gw_list * list) {
+       assert(list);
+       return (list->count_max > 1);
+}
+
+void olsr_gw_list_init(struct gw_list * list, uint8_t count);
+void olsr_gw_list_cleanup(struct gw_list * list);
+
+/**
+ * @param list a pointer to the list
+ * @return true if the list is empty
+ */
+static inline bool olsr_gw_list_empty(struct gw_list * list) {
+       assert(list);
+       return (list->count == 0);
+}
+
+/**
+ * @param list a pointer to the list
+ * @return true if the list is full
+ */
+static inline bool olsr_gw_list_full(struct gw_list * list) {
+       assert(list);
+       return (list->count >= list->count_max);
+}
+
+/**
+ * Get the best entry that is on the list
+ *
+ * @param list a pointer to the list
+ * @return a pointer to the best entry, or NULL when the list is empty
+ */
+static inline struct gw_container_entry * olsr_gw_list_get_best_entry(struct gw_list * list) {
+       assert(list);
+
+       if (olsr_gw_list_empty(list)) {
+               return NULL;
+       }
+
+       /* get the best (first) entry of the list */
+       return olsr_gw_list_node2entry(list->head.next);
+}
+
+/**
+ * Get the worst entry that is on the list
+ *
+ * @param list a pointer to the list
+ * @return a pointer to the worst entry
+ */
+static inline struct gw_container_entry * olsr_gw_list_get_worst_entry(struct gw_list * list) {
+       assert(list);
+
+       if (olsr_gw_list_empty(list)) {
+               return NULL;
+       }
+
+       /* get the worst (last) entry of the list */
+       return olsr_gw_list_node2entry(list->head.prev);
+}
+
+struct gw_container_entry * olsr_gw_list_find(struct gw_list * list, struct gateway_entry * entry);
+struct gw_container_entry * olsr_gw_list_add(struct gw_list * list, struct gw_container_entry * entry);
+struct gw_container_entry * olsr_gw_list_update(struct gw_list * list, struct gw_container_entry * entry,
+               uint64_t gw_path_cost);
+struct gw_container_entry * olsr_gw_list_remove(struct gw_list * list, struct gw_container_entry * entry);
+
+#endif /* __linux__ */
+#endif /* _GW_LIST_H */
index bb4caae..10e7eca 100644 (file)
@@ -59,7 +59,7 @@ int rtnetlink_register_socket(int);
 
 void olsr_os_niit_4to6_route(const struct olsr_ip_prefix *dst_v4, bool set);
 void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6, bool set);
-void olsr_os_inetgw_tunnel_route(uint32_t if_idx, bool ipv4, bool set);
+void olsr_os_inetgw_tunnel_route(uint32_t if_idx, bool ipv4, bool set, uint8_t table);
 
 int olsr_os_policy_rule(int family, int rttable, uint32_t priority, const char *if_name, bool set);
 int olsr_os_localhost_if(union olsr_ip_addr *ip, bool create);
index f644f9c..1936db2 100644 (file)
@@ -41,7 +41,7 @@ struct olsr_iptunnel_entry {
 int olsr_os_init_iptunnel(const char * name);
 void olsr_os_cleanup_iptunnel(const char * name);
 
-struct olsr_iptunnel_entry *olsr_os_add_ipip_tunnel(union olsr_ip_addr *target, bool transportV4);
+struct olsr_iptunnel_entry *olsr_os_add_ipip_tunnel(union olsr_ip_addr *target, bool transportV4, char *name);
 void olsr_os_del_ipip_tunnel(struct olsr_iptunnel_entry *);
 
 #endif /* KERNEL_TUNNEL_H_ */
index aac38a9..4bf2210 100644 (file)
@@ -466,14 +466,14 @@ void olsr_os_niit_4to6_route(const struct olsr_ip_prefix *dst_v4, bool set) {
   }
 }
 
-void olsr_os_inetgw_tunnel_route(uint32_t if_idx, bool ipv4, bool set) {
+void olsr_os_inetgw_tunnel_route(uint32_t if_idx, bool ipv4, bool set, uint8_t table) {
   const struct olsr_ip_prefix *dst;
 
   assert(olsr_cnf->ip_version == AF_INET6 || ipv4);
 
   dst = ipv4 ? &ipv4_internet_route : &ipv6_internet_route;
 
-  if (olsr_new_netlink_route(ipv4 ? AF_INET : AF_INET6, olsr_cnf->rt_table_tunnel,
+  if (olsr_new_netlink_route(ipv4 ? AF_INET : AF_INET6, table,
       if_idx, RT_METRIC_DEFAULT, olsr_cnf->rt_proto, NULL, NULL, dst, set, false)) {
     olsr_syslog(OLSR_LOG_ERR, ". error while %s inetgw tunnel route to %s for if %d",
         set ? "setting" : "removing", olsr_ip_prefix_to_string(dst), if_idx);
index a0e32b8..983e00d 100644 (file)
@@ -108,7 +108,7 @@ void olsr_os_cleanup_iptunnel(const char * dev) {
 
     olsr_os_del_ipip_tunnel(t);
   }
-  if (!store_iptunnel_state) {
+  if (olsr_cnf->smart_gw_always_remove_server_tunnel || !store_iptunnel_state) {
     olsr_if_set_state(dev, false);
   }
 
@@ -186,38 +186,22 @@ static int os_ip_tunnel(const char *name, void *target) {
 }
 
 /**
- * Dummy for generating an interface name for an olsr ipip tunnel
- * @param target IP destination of the tunnel
- * @param name pointer to output buffer (length IFNAMSIZ)
- */
-static void generate_iptunnel_name(union olsr_ip_addr *target, char *name) {
-  static char PREFIX[] = "tnl_";
-  static uint32_t counter = 0;
-
-  snprintf(name, IFNAMSIZ, "%s%08x", PREFIX,
-      olsr_cnf->ip_version == AF_INET ? target->v4.s_addr : ++counter);
-}
-
-/**
  * demands an ipip tunnel to a certain target. If no tunnel exists it will be created
  * @param target ip address of the target
  * @param transportV4 true if IPv4 traffic is used, false for IPv6 traffic
+ * @param name pointer to name string buffer (length IFNAMSIZ)
  * @return NULL if an error happened, pointer to olsr_iptunnel_entry otherwise
  */
-struct olsr_iptunnel_entry *olsr_os_add_ipip_tunnel(union olsr_ip_addr *target, bool transportV4 __attribute__ ((unused))) {
+struct olsr_iptunnel_entry *olsr_os_add_ipip_tunnel(union olsr_ip_addr *target, bool transportV4 __attribute__ ((unused)), char *name) {
   struct olsr_iptunnel_entry *t;
 
   assert(olsr_cnf->ip_version == AF_INET6 || transportV4);
 
   t = (struct olsr_iptunnel_entry *)avl_find(&tunnel_tree, target);
   if (t == NULL) {
-    char name[IFNAMSIZ];
     int if_idx;
     struct ipaddr_str buf;
 
-    memset(name, 0, sizeof(name));
-    generate_iptunnel_name(target, name);
-
     if_idx = os_ip_tunnel(name, (olsr_cnf->ip_version == AF_INET) ? (void *) &target->v4.s_addr : (void *) &target->v6);
     if (if_idx == 0) {
       // cannot create tunnel
index 141c6cd..e741457 100644 (file)
@@ -234,11 +234,11 @@ static void writePidFile(void) {
     /* write the PID */
     {
       pid_t pid = getpid();
-      int chars = snprintf(buf, sizeof(buf), "%d", pid);
+      int chars = snprintf(buf, sizeof(buf), "%d", (int)pid);
       ssize_t chars_written = write(fd, buf, chars);
       if (chars_written != chars) {
         close(fd);
-        snprintf(buf, sizeof(buf), "Could not write the PID %d to the PID file %s", pid, olsr_cnf->pidfile);
+        snprintf(buf, sizeof(buf), "Could not write the PID %d to the PID file %s", (int)pid, olsr_cnf->pidfile);
         perror(buf);
         if (remove(olsr_cnf->pidfile) < 0) {
           snprintf(buf, sizeof(buf), "Could not remove the PID file %s", olsr_cnf->pidfile);
@@ -591,6 +591,15 @@ int main(int argc, char *argv[]) {
     }
   }
 
+#ifdef __linux__
+  /* startup gateway system */
+  if (olsr_cnf->smart_gw_active) {
+    if (olsr_startup_gateways()) {
+      olsr_exit("Cannot startup gateway tunnels", 1);
+    }
+  }
+#endif /* __linux__ */
+
   olsr_do_startup_sleep();
 
   /* Print heartbeat to stdout */
@@ -828,6 +837,7 @@ static void olsr_shutdown(int signo __attribute__ ((unused)))
 #ifdef __linux__
   /* trigger gateway selection */
   if (olsr_cnf->smart_gw_active) {
+    olsr_shutdown_gateways();
     olsr_cleanup_gateways();
   }
 
index ec83118..24bd69c 100644 (file)
 #define DEF_MIN_TC_VTIME     0.0
 #define DEF_USE_NIIT         true
 #define DEF_SMART_GW         false
+#define DEF_SMART_GW_ALWAYS_REMOVE_SERVER_TUNNEL  false
+#define DEF_GW_USE_COUNT     1
+#define DEF_GW_MARK_OFFSET_EGRESS   91
+#define DEF_GW_MARK_OFFSET_TUNNELS 101
 #define DEF_GW_PERIOD        10*1000
 #define DEF_GW_STABLE_COUNT  6
 #define DEF_GW_ALLOW_NAT     true
 #define MAX_LQ_AGING         1.0
 #define MIN_LQ_AGING         0.01
 
+#define MIN_SMARTGW_USE_COUNT_MIN  1
+#define MAX_SMARTGW_USE_COUNT_MAX  64
+
+#define MAX_SMARTGW_EGRESS_INTERFACE_COUNT_MAX 32
+
 #define MIN_SMARTGW_PERIOD   1*1000
 #define MAX_SMARTGW_PERIOD   320000*1000
 
@@ -231,6 +240,12 @@ struct plugin_entry {
   struct plugin_entry *next;
 };
 
+struct sgw_egress_if {
+  char *name;
+  uint8_t mark;
+  struct sgw_egress_if *next;
+};
+
 /*
  * The config struct
  */
@@ -276,7 +291,13 @@ struct olsrd_config {
   char *lock_file;
   bool use_niit;
 
-  bool smart_gw_active, smart_gw_allow_nat, smart_gw_uplink_nat;
+  bool smart_gw_active, smart_gw_always_remove_server_tunnel, smart_gw_allow_nat, smart_gw_uplink_nat;
+  uint8_t smart_gw_use_count;
+  char *smart_gw_policyrouting_script;
+  struct sgw_egress_if * smart_gw_egress_interfaces;
+  uint8_t smart_gw_egress_interfaces_count;
+  uint8_t smart_gw_mark_offset_egress;
+  uint8_t smart_gw_mark_offset_tunnels;
   uint32_t smart_gw_period;
   uint8_t smart_gw_stablecount;
   uint8_t smart_gw_thresh;
index 6b89732..b581231 100644 (file)
@@ -463,7 +463,7 @@ handle_fds(uint32_t next_interval)
 void __attribute__ ((noreturn))
 olsr_scheduler(void)
 {
-  OLSR_PRINTF(1, "Scheduler started - polling every %f ms\n", (double)olsr_cnf->pollrate);
+  OLSR_PRINTF(1, "Scheduler started - polling every %d ms\n", (int)(olsr_cnf->pollrate*1000));
 
   /* Main scheduler loop */
   while (true) {
index 63d7890..29e2675 100644 (file)
@@ -20,7 +20,7 @@ void olsr_os_cleanup_iptunnel(const char * name __attribute__((unused))) {
 }
 
 struct olsr_iptunnel_entry *olsr_os_add_ipip_tunnel(union olsr_ip_addr *target __attribute__ ((unused)),
-    bool transportV4 __attribute__ ((unused))) {
+    bool transportV4 __attribute__ ((unused)), char *name __attribute__ ((unused))) {
   return NULL;
 }
 
@@ -45,7 +45,8 @@ void olsr_os_niit_6to4_route(const struct olsr_ip_prefix *dst_v6 __attribute__ (
 }
 void olsr_os_inetgw_tunnel_route(uint32_t if_idx __attribute__ ((unused)),
     bool ipv4 __attribute__ ((unused)),
-    bool set __attribute__ ((unused))) {
+    bool set __attribute__ ((unused)),
+    uint8_t table __attribute__ ((unused))) {
 }
 
 int olsr_os_policy_rule(int family __attribute__ ((unused)),