summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore35
-rw-r--r--AUTHORS1
-rw-r--r--COPYING27
-rw-r--r--Makefile.am22
-rw-r--r--NEWS1
-rw-r--r--README1
-rw-r--r--configure.ac36
-rw-r--r--debian/README6
-rwxr-xr-xdebian/autogen.sh37
-rw-r--r--debian/changelog5
-rw-r--r--debian/changelog.bar5
-rw-r--r--debian/compat1
-rw-r--r--debian/control24
-rw-r--r--debian/copyright34
-rw-r--r--debian/docs2
-rw-r--r--debian/linda1
-rw-r--r--debian/lintian2
-rwxr-xr-xdebian/rules101
-rw-r--r--debian/vyatta-wanloadbalance.postinst.in6
-rw-r--r--debian/vyatta-wanloadbalance.postrm.in6
-rw-r--r--etc/bash_completion.d/20vyatta-cfg892
-rwxr-xr-xetc/init.d/vyatta-ofr214
l---------src/.#hosttool.cpp1
-rw-r--r--src/.gitignore9
-rw-r--r--src/hosttool.cpp395
-rw-r--r--src/hosttool.h86
-rw-r--r--src/lbdata.cc212
-rw-r--r--src/lbdata.hh146
-rw-r--r--src/lbdatafactory.cc334
-rw-r--r--src/lbdatafactory.hh94
-rw-r--r--src/lbdecision.cc318
-rw-r--r--src/lbdecision.hh70
-rw-r--r--src/lboutput.cc58
-rw-r--r--src/lboutput.hh45
-rw-r--r--src/lbpathtest.cc336
-rw-r--r--src/lbpathtest.hh73
-rw-r--r--src/lbrule.hh5
-rw-r--r--src/loadbalance.cc110
-rw-r--r--src/loadbalance.conf50
-rw-r--r--src/loadbalance.hh75
-rw-r--r--src/main.cc138
-rw-r--r--src/rl_str_proc.cc82
-rw-r--r--src/rl_str_proc.hh24
43 files changed, 4120 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..358c973
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+*~
+.*.swp
+*.[oa]
+*.l[oa]
+*.so
+*.libs
+*.deps
+.dirstamp
+libtool
+/aclocal.m4
+/autom4te.cache
+/build-stamp
+/ChangeLog
+/config
+/config.log
+/config.guess
+/config.status
+/config.sub
+/configure
+/debian/files
+/debian/vyatta-cfg
+/debian/vyatta-cfg.postinst
+/debian/vyatta-cfg.postrm
+/INSTALL
+/Makefile.in
+/Makefile
+/src/my_commit
+/src/my_set
+/src/my_delete
+/src/cli_def.c
+/src/cli_parse.c
+/src/cli_parse.h
+/src/cli_val.c
+/tools/rl_passwd
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..ee635b2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+eng@vyatta.com
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..c678d16
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,27 @@
+/*
+ * Package: vyatta-wanloadbalance
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) "2007" Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: eng@vyatta.com
+ * Date: 2007
+ * Description: Vyatta wan load balancing project
+ *
+ * **** End License ****
+ *
+ */
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..6f42120
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,22 @@
+initddir = /etc/init.d
+
+AM_CPPFLAGS = -I src -Wall -DDEBUG
+
+initd_SCRIPTS = etc/init.d/vyatta-ofr
+
+CLEANFILES = src/main.o src/lbdata.o src/lbdatafactory.o src/loadbalance.o src/rl_str_proc.o src/lbpathtest.o src/lboutput.o
+
+
+sbin_PROGRAMS = src/wan_lb
+src_wan_lb_SOURCES = src/main.cc
+src_wan_lb_SOURCES += src/lbdata.cc
+src_wan_lb_SOURCES += src/lbdatafactory.cc
+src_wan_lb_SOURCES += src/loadbalance.cc
+src_wan_lb_SOURCES += src/rl_str_proc.cc
+src_wan_lb_SOURCES += src/lbpathtest.cc
+src_wan_lb_SOURCES += src/lbdecision.cc
+src_wan_lb_SOURCES += src/lboutput.cc
+
+
+cpiop = find . ! -regex '\(.*~\|.*\.bak\|.*\.swp\|.*\#.*\#\)' -print0 | \
+ cpio -0pd
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..78fdaa6
--- /dev/null
+++ b/NEWS
@@ -0,0 +1 @@
+see http://www.vyatta.com/news/
diff --git a/README b/README
new file mode 100644
index 0000000..1512679
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+This package has the Vyatta wan load balancing project.
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..38b00d0
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,36 @@
+# Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.59)
+
+m4_define([VERSION_ID], [m4_esyscmd([
+ if test -f .version ; then
+ head -n 1 .version | tr -d \\n
+ else
+ echo -n 2.4
+ fi])])
+AC_INIT([vyatta-wanloadbalance], VERSION_ID, [vyatta-support@vyatta.com])
+
+test -n "$VYATTA_VERSION" || VYATTA_VERSION=$PACKAGE_VERSION
+
+AC_CONFIG_AUX_DIR([config])
+AM_INIT_AUTOMAKE([gnu no-dist-gzip dist-bzip2 subdir-objects])
+AC_PREFIX_DEFAULT([/opt/vyatta])
+
+AC_PROG_CC
+AM_PROG_AS
+AM_PROG_CC_C_O
+AC_PROG_LIBTOOL
+
+AC_ARG_ENABLE([nostrip],
+ AC_HELP_STRING([--enable-nostrip],
+ [include -nostrip option during packaging]),
+ [NOSTRIP=-nostrip], [NOSTRIP=])
+
+AC_CONFIG_FILES(
+ [Makefile]
+ [debian/vyatta-wanloadbalance.postinst]
+ [debian/vyatta-wanloadbalance.postrm])
+
+AC_SUBST(NOSTRIP)
+
+AC_OUTPUT
+
diff --git a/debian/README b/debian/README
new file mode 100644
index 0000000..9acb769
--- /dev/null
+++ b/debian/README
@@ -0,0 +1,6 @@
+The Debian Package vyatta-wanloadbalance
+----------------------------
+
+This package contains the wan load balance project developed by vyatta. This package includes the process, plus cli operational and commands.
+
+ -- Michael Larson <mike@vyatta.com> 12/14/07
diff --git a/debian/autogen.sh b/debian/autogen.sh
new file mode 100755
index 0000000..ff125d1
--- /dev/null
+++ b/debian/autogen.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+
+if [ -d .git ] ; then
+# generate GNU/Debian format ChangeLog from git log
+
+ rm -f ChangeLog
+
+ if which git2cl >/dev/null ; then
+ git-log --pretty --numstat --summary | git2cl >> ChangeLog
+ else
+ git-log --pretty=short >> ChangeLog
+ fi
+
+# append repository reference
+
+ url=` git repo-config --get remote.origin.url`
+ test "x$url" = "x" && url=`pwd`
+
+ branch=`git-branch --no-color | sed '/^\* /!d; s/^\* //'`
+ test "x$branch" = "x" && branch=master
+
+ sha=`git log --pretty=oneline --no-color -n 1 | cut -c-8`
+ test "x$sha" = "x" && sha=00000000
+
+ echo "$url#$branch-$sha" >> ChangeLog
+
+fi
+
+rm -rf config
+rm -f aclocal.m4 config.guess config.statusconfig.sub configure INSTALL
+
+autoreconf --force --install
+
+rm -f config.sub config.guess
+ln -s /usr/share/misc/config.sub .
+ln -s /usr/share/misc/config.guess .
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..0b71448
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+vyatta-wanloadbalance (0.1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- Michael Larson <mike@vyatta.com> Fri, 14 Dec 2007 17:31:53 -0700
diff --git a/debian/changelog.bar b/debian/changelog.bar
new file mode 100644
index 0000000..01b2125
--- /dev/null
+++ b/debian/changelog.bar
@@ -0,0 +1,5 @@
+vyatta-cfg (0.1) unstable; urgency=low
+
+ * Initial Release.
+
+ -- An-Cheng Huang <ancheng@vyatta.com> Mon, 24 Sep 2007 17:31:53 -0700
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..2835656
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,24 @@
+Source: vyatta-wanloadbalance
+Section: contrib/net
+Priority: extra
+Maintainer: Michael Larson <mike@vyatta.com>
+Build-Depends: debhelper (>= 5), autotools-dev
+Standards-Version: 3.7.2
+
+Package: vyatta-wanloadbalance
+Architecture: any
+Depends: bash (>= 3.1),
+ sed (>= 4.1.5),
+ perl (>= 5.8.8),
+ procps (>= 1:3.2.7-3),
+ quagga,
+ coreutils (>= 5.97-5.3),
+ vyatta-config-migrate
+Suggests: util-linux (>= 2.13-5),
+ net-tools,
+ ethtool,
+ ncurses-bin (>= 5.5-5),
+ ntpdate
+Description: Vyatta configuration system
+ This package has the Vyatta wan load balance project. It includes support for
+ the vyatta cli for configuration.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..4de3df5
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,34 @@
+This package was debianized by Michael Larson <mike@vyatta.com> on
+Mon, 24 Sep 2007 17:31:53 -0700.
+
+It's original content from the GIT repository <http://vyatta.com/git/vyatta-cfg>
+
+Upstream Author:
+
+ <eng@vyatta.com>
+
+Copyright:
+
+ Copyright (C) 2007 Vyatta, Inc.
+ All Rights Reserved.
+
+License:
+
+ The contents of this package are subject to the Vyatta Public License
+ Version 1.0 ("License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.vyatta.com/vpl
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ This code was originally developed by Vyatta, Inc.
+ Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL'.
+
+The Debian packaging is (C) 2007, Michael Larson <mike@vyatta.com> and
+is licensed under the GPL, see above.
diff --git a/debian/docs b/debian/docs
new file mode 100644
index 0000000..50bd824
--- /dev/null
+++ b/debian/docs
@@ -0,0 +1,2 @@
+NEWS
+README
diff --git a/debian/linda b/debian/linda
new file mode 100644
index 0000000..0381d9d
--- /dev/null
+++ b/debian/linda
@@ -0,0 +1 @@
+Tag: file-in-opt
diff --git a/debian/lintian b/debian/lintian
new file mode 100644
index 0000000..feed37a
--- /dev/null
+++ b/debian/lintian
@@ -0,0 +1,2 @@
+vyatta-wanloadbalance: file-in-unusual-dir
+vyatta-wanloadbalance: dir-or-file-in-opt
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..244a67b
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,101 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+PACKAGE=vyatta-cfg
+PKGDIR=$(CURDIR)/debian/$(PACKAGE)
+
+CFLAGS = -Wall -g
+
+configure = ./configure
+configure += --host=$(DEB_HOST_GNU_TYPE)
+configure += --build=$(DEB_BUILD_GNU_TYPE)
+configure += --prefix=/opt/vyatta
+configure += --mandir=\$${prefix}/share/man
+configure += --infodir=\$${prefix}/share/info
+configure += CFLAGS="$(CFLAGS)"
+configure += LDFLAGS="-Wl,-z,defs"
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+
+configure: configure.ac Makefile.am
+ chmod +x debian/autogen.sh
+ debian/autogen.sh
+
+config.status: configure
+ dh_testdir
+ rm -f config.cache
+ $(configure)
+
+build: build-stamp
+
+build-stamp: config.status
+ dh_testdir
+ $(MAKE)
+ touch $@
+
+clean: clean-patched
+
+# Clean everything up, including everything auto-generated
+# at build time that needs not to be kept around in the Debian diff
+clean-patched:
+ dh_testdir
+ dh_testroot
+ if test -f Makefile ; then $(MAKE) clean distclean ; fi
+ rm -f build-stamp
+ rm -f config.status config.sub config.guess config.log
+ rm -f aclocal.m4 configure Makefile.in Makefile INSTALL
+ rm -rf config
+ dh_clean
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ $(MAKE) DESTDIR=$(PKGDIR) install
+
+ install -D --mode=0644 debian/lintian $(PKGDIR)/usr/share/lintian/overrides/$(PACKAGE)
+ install -D --mode=0644 debian/linda $(PKGDIR)/usr/share/linda/overrides/$(PACKAGE)
+
+# Build architecture-independent files here.
+binary-indep: build install
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs ChangeLog
+ dh_installdocs
+ dh_install
+ dh_installdebconf
+ dh_link
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+# Build architecture-dependent files here.
+binary-arch: build install
+# This is an architecture independent package
+# so; we have nothing to do by default.
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/debian/vyatta-wanloadbalance.postinst.in b/debian/vyatta-wanloadbalance.postinst.in
new file mode 100644
index 0000000..21218c2
--- /dev/null
+++ b/debian/vyatta-wanloadbalance.postinst.in
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+prefix=@prefix@
+sysconfdir=@sysconfdir@
+
+#nothing
diff --git a/debian/vyatta-wanloadbalance.postrm.in b/debian/vyatta-wanloadbalance.postrm.in
new file mode 100644
index 0000000..262b9fe
--- /dev/null
+++ b/debian/vyatta-wanloadbalance.postrm.in
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+if [ "$1" = "purge" ]; then
+ update-rc.d vyatta-ofr remove >/dev/null || exit $?
+fi
+
diff --git a/etc/bash_completion.d/20vyatta-cfg b/etc/bash_completion.d/20vyatta-cfg
new file mode 100644
index 0000000..f116554
--- /dev/null
+++ b/etc/bash_completion.d/20vyatta-cfg
@@ -0,0 +1,892 @@
+# **** License ****
+# Version: VPL 1.0
+#
+# The contents of this file are subject to the Vyatta Public License
+# Version 1.0 ("License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.vyatta.com/vpl
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2006, 2007 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: An-Cheng Huang
+# Date: 2007
+# Description: bash completion for Vyatta configuration commands
+#
+# **** End License ****
+
+# only do this if we are going into configure mode
+if [ "$_OFR_CONFIGURE" != "ok" ]; then
+ return 0
+fi
+
+umask 0002
+
+if [ -r /etc/default/vyatta ]; then
+ source /etc/default/vyatta
+fi
+
+declare is_set=0
+declare last_idx=0
+declare -a comp_words=()
+
+# commands to unalias
+declare -a unalias_cmds=( clear configure date debug edit exit load \
+ no run set show save terminal undebug )
+for cmd in "${unalias_cmds[@]}"; do
+ unalias $cmd >& /dev/null
+done
+
+show ()
+{
+ local show_all=''
+ local -a args=()
+ for arg in "$@"; do
+ if [ "$arg" == "-all" ]; then
+ show_all='-all'
+ else
+ args[${#args[@]}]="$arg"
+ fi
+ done
+ eval "${vyatta_sbindir}/vyatta-output-config.pl ${show_all}\
+ \${VYATTA_EDIT_LEVEL//\// } ${args[@]}"
+}
+
+save ()
+{
+ eval "sudo sg quaggavty \
+ \"umask 0002 ; ${vyatta_sbindir}/vyatta-save-config.pl $@\""
+}
+
+declare vyatta_cfg_prompt_level=''
+set_config_ps1 ()
+{
+ local level=$1
+ if [ -z "$level" ]; then
+ export PS1="[edit]\n\u@\h# "
+ vyatta_cfg_prompt_level=''
+ else
+ export PS1="[edit $level]\n\u@\h# "
+ vyatta_cfg_prompt_level="$level"
+ fi
+}
+
+load ()
+{
+ # don't load if there are uncommitted changes.
+ if [ -f "$VYATTA_TEMP_CONFIG_DIR/$VYATTA_MOD_NAME" ]; then
+ echo "Cannot load: configuration modified."
+ echo "Commit or discard the changes before loading a config file."
+ return 1
+ fi
+ # return to top level.
+ export VYATTA_EDIT_LEVEL="/"
+ export VYATTA_TEMPLATE_LEVEL="/"
+ set_config_ps1 ''
+ eval "${vyatta_sbindir}/vyatta-load-config.pl $@"
+}
+
+edit ()
+{
+ local num_comp=${#@}
+ local _mpath=${VYATTA_TEMP_CONFIG_DIR}/${VYATTA_EDIT_LEVEL}
+ local _tpath=${VYATTA_CONFIG_TEMPLATE}/${VYATTA_TEMPLATE_LEVEL}
+ local idx
+ for (( idx=1; idx <= num_comp; idx++ )); do
+ local comp
+ eval "comp=\$$idx"
+ vyatta_escape comp comp
+ push_path _mpath $comp
+ push_path _tpath $comp
+ if [ ! -d $_mpath ]; then
+ # "edit" only allows existing node
+ break
+ fi
+
+ # check if it's not tag value
+ if [ -d $_tpath ]; then
+ continue
+ fi
+
+ # check if it's tag value
+ pop_path _tpath
+ push_path _tpath $VYATTA_TAG_NAME
+ if [ -d $_tpath ]; then
+ continue
+ fi
+ pop_path _tpath
+ pop_path _mpath
+ break
+ done
+ # "edit" only valid for
+ # * "node.tag" level
+ # * "node.def" level without "type:"
+ if (( idx != ( num_comp + 1) )); then
+ echo "Invalid node \"$*\" for the 'edit' command"
+ return 1
+ fi
+ if [ "${_tpath:((-9))}" != "/node.tag" ]; then
+ # we are not at "node.tag" level. look for "type:".
+ if [ ! -r "$_tpath/node.def" ]; then
+ vyatta_cfg_type=""
+ else
+ vyatta_parse_tmpl "$_tpath/node.def"
+ fi
+ if [ -n "$vyatta_cfg_type" ]; then
+ # "type:" present
+ echo "The 'edit' command cannot be issued at the \"$*\" level"
+ return 1
+ fi
+ fi
+ export VYATTA_EDIT_LEVEL="${_mpath#$VYATTA_TEMP_CONFIG_DIR}/"
+ export VYATTA_TEMPLATE_LEVEL="${_tpath#$VYATTA_CONFIG_TEMPLATE}/"
+
+ declare -a path_arr
+ path_str2arr VYATTA_EDIT_LEVEL path_arr
+ local path_str="${path_arr[*]}"
+ set_config_ps1 "$path_str"
+}
+
+really_exit()
+{
+ sudo umount $VYATTA_TEMP_CONFIG_DIR
+ sudo rm -rf $VYATTA_TEMP_CONFIG_DIR $VYATTA_CHANGES_ONLY_DIR \
+ $VYATTA_CONFIG_TMP
+ unset _OFR_CONFIGURE
+ builtin exit 0
+}
+
+exit ()
+{
+ local discard
+ if [ $# == 0 ]; then
+ discard=0
+ elif [ $# == 1 ] && [ "$1" == "discard" ]; then
+ discard=1
+ else
+ echo "Invalid argument \"$*\" for 'exit'"
+ return 1
+ fi
+
+ if [ "$VYATTA_EDIT_LEVEL" == "/" ]; then
+ # we are at the root level. check if we can really exit.
+ if [ -f "$VYATTA_TEMP_CONFIG_DIR/$VYATTA_MOD_NAME" ]; then
+ if (( ! discard )); then
+ echo "Cannot exit: configuration modified."
+ echo "Use 'exit discard' to discard the changes and exit."
+ return 1
+ fi
+ fi
+ really_exit
+ fi
+
+ # "exit" to the root level.
+ export VYATTA_EDIT_LEVEL="/"
+ export VYATTA_TEMPLATE_LEVEL="/"
+ set_config_ps1 ''
+}
+
+# run op mode commands
+run ()
+{
+ _vyatta_op_run $@
+}
+
+# do op mode completion
+vyatta_run_complete ()
+{
+ local restore_shopts=$( shopt -p extglob nullglob | tr \\n \; )
+ shopt -s extglob nullglob
+
+ COMP_WORDS=( "${COMP_WORDS[@]:1}" )
+ (( COMP_CWORD -= 1 ))
+ _vyatta_op_expand
+
+ eval $restore_shopts
+}
+
+declare v_cfg_completion_debug=0
+decho ()
+{
+ if (( v_cfg_completion_debug )); then
+ echo -n "$*"
+ fi
+}
+
+push_path_arr ()
+{
+ # $1: \@path_arr
+ # $2: component
+ eval "$1=( \"\${$1[@]}\" '$2' )"
+}
+
+pop_path_arr ()
+{
+ # $1: \@path_arr
+ eval "$1=( \"\${$1[@]:0:((\${#$1[@]}-1))}\" )"
+}
+
+path_arr2str ()
+{
+ # $1: \@path_arr
+ # $2: \$path_str
+ eval "$2=\"\${$1[*]}\""
+ eval "$2=/\${$2// //}"
+}
+
+path_str2arr ()
+{
+ # $1: \$path_str
+ # $2: \@path_arr
+ local tmp
+ eval "tmp=\${$1:1}"
+ eval "$2=( \${tmp//\// } )"
+}
+
+push_path ()
+{
+ # $1: \$path_str
+ # $2: component
+ declare -a path_arr
+ eval "path_str2arr $1 path_arr"
+ eval "push_path_arr path_arr '$2'"
+ eval "path_arr2str path_arr $1"
+}
+
+pop_path ()
+{
+ # $1: \$path_str
+ declare -a path_arr
+ eval "path_str2arr $1 path_arr"
+ pop_path_arr path_arr
+ eval "path_arr2str path_arr $1"
+}
+
+get_filtered_dir_listing ()
+{
+ # $1: path
+ # $2: \@listing
+ if [ ! -d $1 ]; then
+ eval "$2=()"
+ return
+ fi
+ local pattern='^node\.def$|^node\.tag$|^node\.val$|^\.modified$'
+ patterh=$pattern'|^\.commit\.lck$|^\.wh\.'
+ local cmd="ls $1 |egrep -v '$pattern'"
+ declare -a listing=( $(eval $cmd) )
+ for enode in "${listing[@]}"; do
+ local unode
+ vyatta_unescape enode unode
+ eval "$2[\${#$2[@]}]=$unode"
+ done
+}
+
+filter_existing_nodes ()
+{
+ # $1: mpath
+ # $2: \@orig
+ # $3: \@filtered
+ declare -a orig
+ eval "orig=( \"\${$2[@]}\" )"
+ for node in "${orig[@]}"; do
+ if [ -d "$1/$node" ]; then
+ eval "$3[\${#$3[@]}]=$node"
+ fi
+ done
+}
+
+get_prefix_filtered_list ()
+{
+ # $1: prefix
+ # $2: \@list
+ # $3: \@filtered
+ declare -a olist
+ local pfx=$1
+ pfx=${pfx#\"}
+ eval "olist=( \"\${$2[@]}\" )"
+ local idx=0
+ for elem in "${olist[@]}"; do
+ local sub=${elem#$pfx}
+ if [ "$elem" == "$sub" ] && [ -n "$pfx" ]; then
+ continue
+ fi
+ eval "$3[$idx]=\"$elem\""
+ (( idx++ ))
+ done
+}
+
+vyatta_parse_tmpl_comp_fields ()
+{
+ # $1: tmpl
+ # $2: field name
+ sed -n '
+ /^#'"$2"':/,$ {
+ s/^#'"$2"'://
+ h
+ :b
+ $ { x; p; q }
+ n
+ /^#[-_a-z]\+:/ { x; p; q }
+ s/^#//
+ H
+ bb
+ }
+ ' $1
+}
+
+declare vyatta_cfg_help=""
+declare vyatta_cfg_type=""
+declare vyatta_cfg_tag=0
+declare vyatta_cfg_multi=0
+declare -a vyatta_cfg_allowed=()
+declare vyatta_cfg_comp_help=""
+vyatta_parse_tmpl ()
+{
+ # $1: tmpl
+ vyatta_cfg_help=""
+ vyatta_cfg_type=""
+ vyatta_cfg_tag=0
+ vyatta_cfg_multi=0
+ vyatta_cfg_allowed=()
+ vyatta_cfg_comp_help=''
+ if [ ! -r $1 ]; then
+ return
+ fi
+ eval `sed -n '
+ /^help:[ ]\+/,/^[a-z]\+:/ {
+ s/^help:[ ]\+/vyatta_cfg_help=/p
+ /^ /p
+ }
+ /^syntax:[ ]\+\$(@)[ ]\+in[ ]\+/ {
+ s/^syntax:[ ]\+\$(@)[ ]\+in[ ]\+/vyatta_cfg_allowed=( /
+ s/^\([^;]\+\);.*$/\1 )/
+ s/[ ]*,[ ]*/ /gp
+ }
+ s/^tag:/vyatta_cfg_tag=1/p
+ s/^multi:/vyatta_cfg_multi=1/p
+ s/^type:[ ]\+\([^ ;]\+\)\(;.*\)\?/vyatta_cfg_type=\1/p
+ ' $1`
+
+ local acmd=$(vyatta_parse_tmpl_comp_fields $1 "allowed")
+ vyatta_cfg_comp_help=$(vyatta_parse_tmpl_comp_fields $1 "comp_help")
+
+ if (( ${#vyatta_cfg_allowed[@]} == 0 )); then
+ local ares=$(eval "$acmd")
+ eval "vyatta_cfg_allowed=( $ares )"
+ fi
+ if [ -z "$vyatta_cfg_help" ]; then
+ vyatta_cfg_help='<No help text available>'
+ fi
+}
+
+# this fills in $vyatta_help_text
+generate_help_text ()
+{
+ # $1: \@items
+ # $2: \@help_strs
+ declare -a items
+ declare -a helps
+ eval "items=( \"\${$1[@]}\" )"
+ eval "helps=( \"\${$2[@]}\" )"
+ if [ -n "$vyatta_cfg_comp_help" ]; then
+ vyatta_help_text="\\n${vyatta_cfg_comp_help}"
+ return 0
+ fi
+ vyatta_help_text="\\nPossible completions:"
+ for (( idx = 0; idx < ${#items[@]}; idx++ )); do
+ vyatta_help_text="${vyatta_help_text}\\n\\x20\\x20"
+ if [ ${#items[$idx]} -lt 6 ]; then
+ vyatta_help_text="${vyatta_help_text}${items[$idx]}\\t\\t"
+ elif [ ${#items[$idx]} -lt 14 ]; then
+ vyatta_help_text="${vyatta_help_text}${items[$idx]}\\t"
+ else
+ vyatta_help_text="${vyatta_help_text}${items[$idx]}\\n\\x20\\x20\\t\\t"
+ fi
+ vyatta_help_text="${vyatta_help_text}${helps[$idx]}"
+ done
+}
+
+# this fills in $vyatta_help_text
+get_tmpl_subdir_help ()
+{
+ # $1: path
+ # $2: \@subdirs
+ declare -a subdirs
+ eval "subdirs=( \"\${$2[@]}\" )"
+ if [ ${#subdirs[@]} == 0 ]; then
+ vyatta_help_text=""
+ return
+ fi
+ declare -a hitems=()
+ declare -a hstrs=()
+ for subdir in "${subdirs[@]}"; do
+ if [ ! -r $1/$subdir/node.def ]; then
+ vyatta_cfg_help="<No help text available>"
+ else
+ vyatta_parse_tmpl "$1/$subdir/node.def"
+ # comp_help overrides the current help, so we reset it here since
+ # it is from the subdir.
+ vyatta_cfg_comp_help=''
+ fi
+ hitems[${#hitems[@]}]=$subdir
+ hstrs[${#hstrs[@]}]=$vyatta_cfg_help
+ done
+ generate_help_text hitems hstrs
+}
+
+# return 0 if yes. 1 if no.
+item_in_list ()
+{
+ # $1: item
+ # $2: \@list
+ declare -a olist
+ local item
+ eval "olist=( \"\${$2[@]}\" )"
+ for item in "${olist[@]}"; do
+ if [ "$1" == "$item" ]; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+append_allowed_values ()
+{
+ # $1: tmpl_path
+ # $2: \@values
+ if [ ! -r "$1/node.def" ]; then
+ return
+ fi
+ vyatta_parse_tmpl "$1/node.def"
+ local item
+ for item in "${vyatta_cfg_allowed[@]}"; do
+ if ! item_in_list "$item" $2; then
+ eval "$2[\${#$2[@]}]=\"$item\""
+ fi
+ done
+}
+
+# return 0 if yes. 1 if no.
+is_setting_new_leaf ()
+{
+ # $1: tmpl_path
+ if [ $is_set == 0 ]; then
+ return 1
+ fi
+ vyatta_parse_tmpl "$1/node.def"
+ if [ -z "$vyatta_cfg_type" ]; then
+ return 1
+ fi
+ return 0
+}
+
+# this fills in $vyatta_help_text
+get_node_value_help ()
+{
+ # $1: path
+ # $2: \@values
+ declare -a vals
+ eval "vals=( \"\${$2[@]}\" )"
+ if [ $is_set == 0 -a ${#vals[@]} == 0 ]; then
+ vyatta_help_text=""
+ return
+ fi
+ if [ ! -r "$1/node.def" ]; then
+ vyatta_cfg_help="<No help text available>"
+ vyatta_cfg_type=""
+ else
+ vyatta_parse_tmpl "$1/node.def"
+ fi
+ if [ $is_set == 1 -a ! -z "$vyatta_cfg_type" ]; then
+ # add a <type> value
+ local val="<$vyatta_cfg_type>"
+ vals=( $val "${vals[@]}" )
+ fi
+ if [ ${#vals[@]} == 0 ]; then
+ vyatta_help_text=""
+ return
+ fi
+ declare -a hitems=()
+ declare -a hstrs=()
+ for val in "${vals[@]}"; do
+ hitems[${#hitems[@]}]=$val
+ hstrs[${#hstrs[@]}]=$vyatta_cfg_help
+ done
+ generate_help_text hitems hstrs
+}
+
+get_value_list ()
+{
+ # $1: path
+ # $2: \@listing
+ local vfile=$1/node.val
+ if [ ! -r $vfile ]; then
+ eval "$2=()"
+ return
+ fi
+ declare -a listing=()
+ local cmd=$(sed 's/^\(.*\)$/listing[\${#listing[@]}]='\''\1'\''/' $vfile)
+ eval "$cmd"
+ eval "$2=( \"\${listing[@]}\" )"
+}
+
+vyatta_escape ()
+{
+ # $1: \$original
+ # $2: \$escaped
+ eval "$2=\${$1//\%/%25}"
+ eval "$2=\${$2//\*/%2A}"
+ eval "$2=\${$2//\//%2F}"
+}
+
+vyatta_unescape ()
+{
+ # $1: \$escaped
+ # $2: \$original
+ eval "$2=\${$1//\%2F/\/}"
+ eval "$2=\${$2//\%2A/*}"
+ eval "$2=\${$2//\%25/%}"
+}
+
+declare -a vyatta_completions
+declare vyatta_help_text="\\nNo help text available"
+declare vyatta_do_help=0
+vyatta_do_complete ()
+{
+ # when this function is called, it is expected that:
+ # * "vyatta_help_text" is filled with the help text.
+ # * "vyatta_completions" is an array of "filtered" possible completions
+ # (i.e., only those starting with the current last component).
+ local do_help=$vyatta_do_help
+
+ # we may not want to do the following
+<<'ENDCOMMENT'
+ if [ ${#vyatta_completions[@]} == 1 ]; then
+ # no ambiguous completions. do completion instead of help.
+ do_help=0
+ fi
+
+ # now check if we can auto-complete at least 1 more character.
+ if (( do_help )); then
+ local schar=""
+ for comp in "${vyatta_completions[@]}"; do
+ local sub=$comp
+ if [ ! -z "${COMP_WORDS[COMP_CWORD]}" ]; then
+ sub=${comp#${comp_words[$last_idx]}}
+ if [ "$comp" == "$sub" ]; then
+ # should not happen since vyatta_completions should be filtered.
+ continue
+ fi
+ fi
+ if [ -z "$schar" ]; then
+ schar=${sub:0:1}
+ else
+ if [ "$schar" != "${sub:0:1}" ]; then
+ schar=""
+ break
+ fi
+ fi
+ done
+ if [ ! -z "$schar" ]; then
+ do_help=0
+ fi
+ fi
+ENDCOMMENT
+
+ if (( do_help )); then
+ printf "$vyatta_help_text"
+ COMPREPLY=( "" " " )
+ else
+ local -a f_comps=()
+ get_prefix_filtered_list "${COMP_WORDS[COMP_CWORD]}" \
+ vyatta_completions f_comps
+ local estr="COMPREPLY=( "
+ for w in "${f_comps[@]}"; do
+ estr="$estr\"$w\" "
+ done
+ estr="${estr})"
+ eval "$estr"
+ fi
+ vyatta_help_text="\\nNo help text available"
+}
+
+vyatta_config_complete ()
+{
+ local restore_shopts=$( shopt -p extglob nullglob | tr \\n \; )
+ shopt -s extglob nullglob
+
+ if [ "$COMP_LINE" == "$VYATTA_COMP_LINE" ]; then
+ VYATTA_COMP_LINE=''
+ vyatta_do_help=1
+ else
+ VYATTA_COMP_LINE=$COMP_LINE
+ vyatta_do_help=0
+ fi
+
+ local command=${COMP_WORDS[0]}
+ # completion for "set" is different from other commands
+ is_set=0
+ if [ "$command" == "set" ]; then
+ is_set=1
+ fi
+ local end_space=0
+ local num_comp=$COMP_CWORD
+ if [ -z "${COMP_WORDS[$COMP_CWORD]}" ]; then
+ end_space=1
+ (( num_comp -= 1 ))
+ fi
+ (( last_idx = num_comp - 1 ))
+ comp_words=( ${COMP_WORDS[@]:1:$num_comp} )
+
+ # handle "exit"
+ if [ "$command" == "exit" ]; then
+ if (( num_comp > 1 || ( end_space && num_comp > 0 ) )); then
+ COMPREPLY=()
+ return
+ fi
+ declare -a hitems=( "discard" )
+ declare -a hstrs=( "Discard any changes" )
+ generate_help_text hitems hstrs
+ vyatta_completions=( "discard" )
+ vyatta_do_complete
+ return
+ fi
+
+ local _mpath=${VYATTA_TEMP_CONFIG_DIR}/${VYATTA_EDIT_LEVEL}
+ local _tpath=${VYATTA_CONFIG_TEMPLATE}/${VYATTA_TEMPLATE_LEVEL}
+ local last_tag=0
+ local idx=0
+ for (( idx=0; idx < num_comp; idx++ )); do
+ last_tag=0
+ local comp=${comp_words[$idx]}
+ vyatta_escape comp comp
+ push_path _mpath $comp
+ push_path _tpath $comp
+ if [ -d $_tpath ]; then
+ if (( ! is_set )); then
+ # we are not in "set" => only allow existing node
+ if [ ! -d $_mpath ]; then
+ break
+ fi
+ fi
+ continue
+ fi
+ pop_path _tpath
+ push_path _tpath $VYATTA_TAG_NAME
+ if [ -d $_tpath ]; then
+ if (( ! is_set && end_space )); then
+ # we are not in "set" && last component is complete.
+ # => only allow existing tag value.
+ if [ ! -d $_mpath ]; then
+ break
+ fi
+ fi
+ if (( idx != last_idx )); then
+ # TODO validate value
+ # break if not valid
+ # XXX is this validation necessary? (set will validate anyway)
+ true
+ fi
+ last_tag=1
+ continue
+ fi
+ pop_path _tpath
+ pop_path _mpath
+ break
+ done
+ # at the end of the loop, 3 possibilities:
+ # 1. (idx < last_idx): some component before the last is invalid
+ # => invalid command
+ # 2. (idx == last_idx): last component matches neither template nor node.tag
+ # => if end_space, then invalid command
+ # otherwise, may be an incomplete (non-tag) component, or incomplete
+ # "leaf value"
+ # => try matching dirs in _tpath or value(s) in _mpath/node.val
+ # 3. (idx == num_comp): the whole command matches templates/tags
+ if (( idx < last_idx || ( idx == last_idx && end_space ) )); then
+ # TODO error message?
+ COMPREPLY=()
+ return
+ fi
+
+ declare -a matches
+ if (( idx == last_idx )); then
+ # generate possibile matches (dirs in _tpath, and "help" from
+ # node.def in each dir, or values in _mpath/node.val)
+ declare -a fmatches
+ if [ -f $_mpath/node.val ]; then
+ decho {1a}
+ get_value_list $_mpath matches
+ get_prefix_filtered_list ${comp_words[$last_idx]} matches fmatches
+ append_allowed_values $_tpath fmatches
+ get_node_value_help $_tpath fmatches
+ else
+ decho {1b}
+ # see if the last component is a new leaf node
+ fmatches=()
+ if is_setting_new_leaf $_tpath; then
+ append_allowed_values $_tpath fmatches
+ get_node_value_help $_tpath fmatches
+ else
+ # last component is a non-value node. look for child nodes.
+ if (( ! is_set )); then
+ # not "set". only complete existing nodes.
+ declare -a amatches=()
+ get_filtered_dir_listing $_tpath amatches
+ filter_existing_nodes $_mpath amatches matches
+ else
+ get_filtered_dir_listing $_tpath matches
+ fi
+ get_prefix_filtered_list ${comp_words[$last_idx]} matches fmatches
+ get_tmpl_subdir_help $_tpath fmatches
+ fi
+ fi
+ vyatta_completions=( "${fmatches[@]}" )
+ vyatta_do_complete
+ return
+ fi
+
+ if (( last_tag && end_space )); then
+ # if not "set", check _mpath (last component is the tag) is valid
+ # generate possible matches (dirs in _tpath, and "help" from node.def
+ # in each dir)
+ decho {2}
+ if [ $is_set == 1 -o -d $_mpath ]; then
+ if (( ! is_set )); then
+ # not "set". only complete existing nodes.
+ declare -a fmatches=()
+ get_filtered_dir_listing $_tpath fmatches
+ filter_existing_nodes $_mpath fmatches matches
+ else
+ get_filtered_dir_listing $_tpath matches
+ fi
+ get_tmpl_subdir_help $_tpath matches
+ vyatta_completions=( "${matches[@]}" )
+ vyatta_do_complete
+ return
+ fi
+ return
+ fi
+
+ if (( last_tag && !end_space )); then
+ # generate possible matches (dirs in _mpath, and "help" from node.def
+ # in dirs in _tpath)
+ decho {3}
+ pop_path _mpath
+ pop_path _tpath
+ get_filtered_dir_listing $_mpath matches
+ declare -a fmatches
+ get_prefix_filtered_list ${comp_words[$last_idx]} matches fmatches
+ append_allowed_values $_tpath fmatches
+ get_node_value_help $_tpath fmatches
+ vyatta_completions=( "${fmatches[@]}" )
+ vyatta_do_complete
+ return
+ fi
+
+ if (( !last_tag && end_space )); then
+ # generate possible matches
+ # 1. dirs in _tpath, and "help" from node.def in each dir
+ # 2. value(s) in _mpath/node.val (only if _tpath/node.def is "multi:")
+ # 3. dirs in _mpath (only if _tpath/node.def is "tag:")
+ if [ -d $_tpath/node.tag ]; then
+ # last component is a "tag name". look for tag values.
+ decho {4a}
+ get_filtered_dir_listing $_mpath matches
+ append_allowed_values $_tpath matches
+ get_node_value_help $_tpath matches
+ elif [ -f $_mpath/node.val ]; then
+ # last component is a leaf node. look for values.
+ decho {4b}
+ get_value_list $_mpath matches
+ append_allowed_values $_tpath matches
+ get_node_value_help $_tpath matches
+ else
+ decho {4c}
+ # see if the last component is a new leaf node
+ matches=()
+ if is_setting_new_leaf $_tpath; then
+ append_allowed_values $_tpath matches
+ get_node_value_help $_tpath matches
+ else
+ # last component is a non-value node. look for child nodes.
+ if (( ! is_set )); then
+ # not "set". only complete existing nodes.
+ declare -a fmatches=()
+ get_filtered_dir_listing $_tpath fmatches
+ filter_existing_nodes $_mpath fmatches matches
+ else
+ get_filtered_dir_listing $_tpath matches
+ fi
+ get_tmpl_subdir_help $_tpath matches
+ fi
+ fi
+ vyatta_completions=( "${matches[@]}" )
+ vyatta_do_complete
+ return
+ fi
+
+ if (( !last_tag && !end_space )); then
+ # generate possible matches (dirs in _tpath, and "help" from node.def
+ # in each dir)
+ decho {5}
+ pop_path _tpath
+ get_filtered_dir_listing $_tpath matches
+ declare -a fmatches
+ get_prefix_filtered_list ${comp_words[$last_idx]} matches fmatches
+ get_tmpl_subdir_help $_tpath fmatches
+ vyatta_completions=( "${fmatches[@]}" )
+ vyatta_do_complete
+ return
+ fi
+
+ eval $restore_shopts
+}
+
+DEF_GROUP=quaggavty
+make_vyatta_config_dir ()
+{
+ sudo mkdir -m 0775 -p $1
+ sudo chgrp ${DEF_GROUP} $1
+}
+
+make_vyatta_config_dir $VYATTA_ACTIVE_CONFIGURATION_DIR
+make_vyatta_config_dir $VYATTA_CHANGES_ONLY_DIR
+make_vyatta_config_dir $VYATTA_CONFIG_TMP
+if [ ! -d $VYATTA_TEMP_CONFIG_DIR ]; then
+ make_vyatta_config_dir $VYATTA_TEMP_CONFIG_DIR
+ sudo mount -t unionfs -o dirs=${VYATTA_CHANGES_ONLY_DIR}=rw:/opt/vyatta/config/active=ro unionfs ${VYATTA_TEMP_CONFIG_DIR}
+fi
+
+# disallow 'Ctrl-D' exit, since we need special actions on 'exit'
+set -o ignoreeof 1
+
+set_config_ps1 ''
+alias commit=/opt/vyatta/sbin/my_commit
+alias set=/opt/vyatta/sbin/my_set
+alias delete=/opt/vyatta/sbin/my_delete
+
+export VYATTA_COMP_LINE=""
+
+# readline bindings
+bind 'set show-all-if-ambiguous on'
+if ! bind -p |grep -q '\\C-x\\C-t'; then
+ bind '"\C-x\C-t": kill-region'
+fi
+if ! bind -p |grep -q '\\C-x\\C-o'; then
+ bind '"\C-x\C-o": copy-region-as-kill'
+fi
+
+complete -F vyatta_config_complete set
+complete -F vyatta_config_complete delete
+complete -F vyatta_config_complete show
+complete -F vyatta_config_complete edit
+complete -F vyatta_config_complete exit
+complete -F vyatta_run_complete run
+
diff --git a/etc/init.d/vyatta-ofr b/etc/init.d/vyatta-ofr
new file mode 100755
index 0000000..96770f6
--- /dev/null
+++ b/etc/init.d/vyatta-ofr
@@ -0,0 +1,214 @@
+#!/bin/bash
+### BEGIN INIT INFO
+# Provides: ofr
+# Required-Start: $syslog $time $local_fs
+# Required-Stop: $syslog $time $local_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: S 0 1 6
+# Short-Description: Vyatta Router
+# Description: Debian init script for the Vyatta Router
+### END INIT INFO
+# **** License ****
+# Version: VPL 1.0
+#
+# The contents of this file are subject to the Vyatta Public License
+# Version 1.0 ("License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.vyatta.com/vpl
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# This code was originally developed by Vyatta, Inc.
+# Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+# All Rights Reserved.
+#
+# Author: Tom Grennan <tgrennan@vyatta.com>
+# **** End License ****
+
+. /lib/lsb/init-functions
+
+: ${vyatta_env:=/etc/default/vyatta}
+source $vyatta_env
+
+declare progname=${0##*/}
+declare action=$1; shift
+
+declare -x BOOTFILE=$vyatta_sysconfdir/config/config.boot
+
+declare -a subinit
+declare -a all_subinits=(
+ rl-system
+ firewall
+ dhcpd
+ dhcrelay
+ lighttpd )
+
+if [ $# -gt 0 ] ; then
+ for s in $@ ; do
+ [ -x ${vyatta_sbindir}/${s}.init ] && subinit[${#subinit}]=$s
+ done
+else
+ for s in ${all_subinits[@]} ; do
+ [ -x ${vyatta_sbindir}/${s}.init ] && subinit[${#subinit}]=$s
+ done
+# NOTE: rtrmgr (i.e. xorp) is mutually exclusive of quagga
+ if [ -x /etc/init.d/quagga ] ; then
+ # quagga should already be started.
+ GROUP=quaggavty
+ elif [ -x ${vyatta_sbindir}/rtrmgr.init ] ; then
+ subinit[${#subinit}]=rtrmgr
+ GROUP=xorp
+ fi
+fi
+
+
+have_rl_system () {
+ test -x $vyatta_sbindir/rl-system.init
+}
+
+use_floppy () {
+ _fd_=/media/floppy
+
+ if have_rl_system ; then
+## only do this if we have the rl-system package
+## if we donot discover an fd device, try loading the floppy module
+ grep -q fd /proc/devices || modprobe -q floppy 2>/dev/null
+ if grep -q fd /proc/devices ; then
+ if awk -- '$1 ~ /\/dev\/fd/ { exit 1 }' /proc/mounts
+ then
+ mkdir -p $_fd_
+ mount -t ext2 /dev/fd0 $_fd_ -o sync 2>/dev/null
+ test $? -eq 32 && mount -t vfat /dev/fd0 $_fd_ 2>/dev/null
+ fi
+ fi
+ fi
+ test -d ${_fd_}/config
+}
+
+setup_configdir() {
+ [ -f $BOOTFILE ] && return 0
+ mkdir -m 0775 -p ${vyatta_sysconfdir}/config
+ chgrp ${GROUP} ${vyatta_sysconfdir}/config
+ if [ -d ~root/vyatta/config ] ; then
+ mount -o bind ~root/vyatta/config $vyatta_sysconfdir/config
+ elif use_floppy ; then
+ mount -o bind /media/floppy/config $vyatta_sysconfdir/config
+ else
+ mkdir -m 0775 -p ~root/vyatta/config
+ chgrp ${GROUP} ~root/vyatta ~root/vyatta/config
+ mount -o bind ~root/vyatta/config $vyatta_sysconfdir/config
+ fi
+}
+
+setup_rclocal () {
+ [ -f /etc/rc.local ] || touch /etc/rc.local
+ if [ -f ~root/vyatta/rc.local ]; then
+ mount -o bind ~root/vyatta/rc.local /etc/rc.local
+ elif [ -f /media/floppy/rc.local ]; then
+ mount -o bind /media/floppy/rc.local /etc/rc.local
+ fi
+}
+
+restore_rclocal () {
+ umount /etc/rc.local >& /dev/null
+}
+
+# if necessary, provide initial config
+init_bootfile () {
+ if [ ! -f $BOOTFILE ] ; then
+ if [ -f $vyatta_sysconfdir/config.boot.default ]; then
+ cp $vyatta_sysconfdir/config.boot.default $BOOTFILE
+ else
+ $vyatta_sbindir/vyatta_current_conf_ver.pl > $BOOTFILE
+ fi
+ fi
+ chgrp ${GROUP} $BOOTFILE
+ chmod 660 $BOOTFILE
+ ## remove the unnecessary and potentially conflicting
+ ## config-directory statement (i.e. /mnt/floppy vs. /media/floppy
+ sed -i '/^rtrmgr {$/,/^}$/d' $BOOTFILE
+}
+
+# if necessary, migrate initial config
+migrate_bootfile ()
+{
+ if [ -x $vyatta_sbindir/vyatta_config_migrate.pl ]; then
+ log_progress_msg migrate
+ $vyatta_sbindir/vyatta_config_migrate.pl $BOOTFILE
+ fi
+}
+
+# load the initial config
+load_bootfile ()
+{
+ if [ -x $vyatta_sbindir/vyatta-config-loader.pl ]; then
+ log_progress_msg configure
+ sg ${GROUP} -c "$vyatta_sbindir/vyatta-config-loader.pl $BOOTFILE"
+ fi
+}
+
+# this handles the "config dir" (/opt/vyatta/config), which is different
+# from the directory for config files (/opt/vyatta/etc/config).
+mount_cfg_dir ()
+{
+ if [ ! -d ${vyatta_configdir} ] ; then
+ mkdir -m 0775 -p ${vyatta_configdir}
+ chgrp ${GROUP} ${vyatta_configdir}
+ fi
+ mount -o nosuid,nodev -t tmpfs none ${vyatta_configdir}
+}
+
+unmount_cfg_dir ()
+{
+ umount ${vyatta_configdir}
+}
+
+start ()
+{
+ log_daemon_msg "Starting Vyatta Router"
+ setup_configdir
+ setup_rclocal
+ mount_cfg_dir
+ init_bootfile
+ migrate_bootfile
+ for s in ${subinit[@]} ; do
+ log_progress_msg $s
+ ${vyatta_sbindir}/${s}.init start || (log_end_msg $? && return)
+ done
+ load_bootfile
+ echo -n $BOOTFILE > ${vyatta_sysconfdir}/bootfile_path
+ log_end_msg $?
+}
+
+stop()
+{
+ local -i status=0
+ log_daemon_msg "Stopping Vyatta Router"
+ for ((i=${#sub_inits[@]} - 1; i >= 0; i--)) ; do
+ s=${subinit[$i]}
+ log_progress_msg $s
+ ${vyatta_sbindir}/${s}.init stop
+ let status\|=$?
+ done
+ unmount_cfg_dir
+ restore_rclocal
+ log_end_msg $status
+}
+
+case "$action" in
+ start) start ;;
+ stop) stop ;;
+ restart|force-reload) stop && start ;;
+ *) log_failure_msg "usage: $progname [ start|stop|restart ] [ subinit ... ]" ;
+ false ;;
+esac
+
+exit $?
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 4
+# End:
diff --git a/src/.#hosttool.cpp b/src/.#hosttool.cpp
new file mode 120000
index 0000000..ea4c1f7
--- /dev/null
+++ b/src/.#hosttool.cpp
@@ -0,0 +1 @@
+slioch@eng-140.vyatta.com.8654:1196098102 \ No newline at end of file
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..a2b4c94
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,9 @@
+cli_parse.tab.c
+cli_parse.tab.h
+cli_def.lex.c
+cli_def.tab.c
+cli_def.tab.h
+cli_val.lex.c
+delete
+my_*
+show
diff --git a/src/hosttool.cpp b/src/hosttool.cpp
new file mode 100644
index 0000000..4849d03
--- /dev/null
+++ b/src/hosttool.cpp
@@ -0,0 +1,395 @@
+/**
+
+ * Module: Hosts
+
+ * Description: Host IP and last response time for all responding hosts
+
+ * on this LAN segment. This tool uses a broadcast icmp test packet.
+
+ *
+
+ * Note that hosts can also be identified via ARP progressing through
+
+ * all possible addresses on lan segment.
+
+ *
+
+ * Author: Michael Larson
+
+ * email: mike(at)lrlart.com
+
+ * Date: August 2004
+
+ **/
+
+
+
+#include <ostream.h>
+
+#include <sys/time.h>
+
+#include <sys/types.h>
+
+#include <unistd.h>
+
+#include <sys/socket.h>
+
+#include <netinet/udp.h>
+
+#include <netinet/in.h>
+
+#include <netinet/ip.h>
+
+#include <netinet/ip_icmp.h>
+
+#include <errno.h>
+
+#include <memory>
+
+#include <time.h>
+
+#include <sys/timeb.h>
+
+#include <pthread.h>
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include <iostream.h>
+
+#include <string>
+
+#include <algorithm>
+
+
+
+#include "Hosts.hpp"
+
+#include "HostsResult.hpp"
+
+#include "HostsTool.hpp"
+
+
+
+//constant initialization
+
+const int HostsToolKonstants::packet_data_len_ = 40;
+
+const int HostsToolKonstants::recv_timeout_ = 5;
+
+const int HostsToolKonstants::ip_offset_ = 12;
+
+
+
+/**
+
+ * HostsTool::HostsTool()
+
+ * Constructor. Builds socket for use in tests.
+
+ *
+
+ **/
+
+HostsTool::HostsTool(Task<Test> *complete_task, unsigned long local_ip, unsigned long bc_addr) :
+
+ ToolBase(complete_task),
+
+ local_ip_(local_ip),
+
+ send_sock_(0),
+
+ recv_sock_(0),
+
+ bc_addr_(bc_addr),
+
+ packet_id_(0),
+
+ test_in_progress_(false)
+
+{
+
+ sockaddr_in addr;
+
+
+
+ struct protoent *ppe = getprotobyname("icmp");
+
+ send_sock_ = socket(PF_INET, SOCK_RAW, ppe->p_proto);
+
+ if (send_sock_ < 0)
+
+ {
+
+ cerr << "HostsTool::HostsTool(): no send sock: " << send_sock_ << endl;
+
+ send_sock_ = 0;
+
+ return;
+
+ }
+
+
+
+ //set options for broadcasting.
+
+ int val = 1;
+
+ setsockopt(send_sock_, SOL_SOCKET, SO_BROADCAST, &val, 4);
+
+ setsockopt(send_sock_, SOL_SOCKET, SO_REUSEADDR, &val, 4);
+
+
+
+ memset( &addr, 0, sizeof( struct sockaddr_in ));
+
+ addr.sin_family = AF_INET;
+
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ addr.sin_port = 0;
+
+
+
+ recv_sock_ = socket(PF_INET, SOCK_RAW, ppe->p_proto);
+
+ if (recv_sock_ < 0)
+
+ {
+
+ cerr << "HostsTool::HostsTool(): no recv sock: " << recv_sock_ << endl;
+
+ recv_sock_ = 0;
+
+ return;
+
+ }
+
+}
+
+
+
+/**
+
+ * HostsTool::~HostsTools()
+
+ * Destructor, cleans up sockets
+
+ *
+
+ **/
+
+HostsTool::~HostsTool()
+
+{
+
+ if (send_sock_ != 0)
+
+ close(send_sock_);
+
+
+
+ if (recv_sock_ != 0)
+
+ close(recv_sock_);
+
+}
+
+
+
+
+
+/**
+
+ * HostsTool::compute()
+
+ * initiates tests received in its message queue.
+
+ *
+
+ **/
+
+void
+
+HostsTool::compute()
+
+{
+
+ while (true)
+
+ {
+
+ auto_ptr<Test> test(get()); //don't bother keeping this Test object..
+
+ cout << "HostsTool::compute(): received test event..." << endl;
+
+ if (test.get() != NULL)
+
+ {
+
+ GUARD(&mutex_); //protect against concurrent access to test_in_progress_ flag
+
+ /*
+
+ Note that on heavily cycled tests some tests may be dropped. This can be fixed
+
+ by monitoring input queue on completion of sending and processing all incoming
+
+ messages into a set. This isn't expected to be a problem with the current impl.
+
+ */
+
+ if (test_in_progress_ == true)
+
+ continue;
+
+ if (test->get_target() == 0)
+
+ {
+
+ send(bc_addr_, packet_id_++);
+
+ }
+
+ else
+
+ {
+
+ send(test->get_target(), packet_id_++);
+
+ }
+
+ }
+
+ }
+
+}
+
+
+
+/**
+
+ * HostsTool::finish()
+
+ * processes completed tests and pushes results to manager
+
+ *
+
+ **/
+
+void
+
+HostsTool::finish()
+
+{
+
+ while (true)
+
+ {
+
+ HostsResult *host_result = receive();
+
+ // cout << "HostsTool::finish(): received result: " << host_result << endl;
+
+ if (host_result != NULL)
+
+ {
+
+ GUARD(&mutex_);
+
+ test_in_progress_ = false;
+
+ if (host_result->empty() == false)
+
+ {
+
+ Test *test = new Test(kHosts);
+
+ test->set_result(host_result);
+
+ // cout << "HostsTool::finish(), dispatching result" << endl;
+
+ results(test);
+
+ }
+
+ }
+
+ }
+
+}
+
+
+
+/**
+
+ * HostsTool::send()
+
+ * pushes the icmp packet out on the wire.
+
+ *
+
+ **/
+
+void
+
+HostsTool::send(unsigned long target_addr, unsigned short packet_id)
+
+{
+
+ int err;
+
+ ->type) << endl;
+
+}
+
+}
+
+ else
+
+ {
+
+ cerr << "HostsTool::receive(): error from recvfrom" << endl;
+
+ }
+
+}
+
+//then push result upwards
+
+return host_result;
+
+}
+
+
+
+/**
+
+ * HostsTool::in_checksum()
+
+ * computes checksum that accompanies sending icmp packet
+
+ *
+
+ **/
+
+unsigned short
+
+HostsTool::in_checksum(const unsigned short *buffer, int length) const
+
+{
+
+ unsigned long sum;
+
+ for (sum=0; length>0; length--)
+
+ sum += *buffer++;
+
+ sum = (sum >> 16) + (sum & 0xffff);
+
+ sum += (sum >> 16);
+
+ return ~sum;
+
+}
diff --git a/src/hosttool.h b/src/hosttool.h
new file mode 100644
index 0000000..06d03a0
--- /dev/null
+++ b/src/hosttool.h
@@ -0,0 +1,86 @@
+/**
+ * Module: HostsTool
+ * Description: Collects lists of hosts on the network responding to broadcast icmp.
+ * This list of hosts are then dispatched for processing of results
+ *
+ * Author: Michael Larson
+ * email: mike(at)lrlart.com
+ * Date: August 2004
+ **/
+#ifndef HOSTSTOOL_HPP_
+#define HOSTSTOOL_HPP_
+
+//forward decls
+class HostsResult;
+
+//header includes
+#include <vector>
+#include "Task.hpp"
+#include "Test.hpp"
+#include "ToolBase.hpp"
+
+/*********************************************
+ ** HostsToolKonstants **
+ *********************************************/
+class HostsToolKonstants
+{
+ public:
+ static const int packet_data_len_;
+ static const int recv_timeout_;
+ static const int ip_offset_;
+};
+
+/*********************************************
+ ** HostsTool **
+ *********************************************/
+class HostsTool : public ToolBase
+{
+ public:
+ /*
+ * Constructor and Destructor
+ */
+ HostsTool(Task<Test> *pCompleteTask, unsigned long local_ip, unsigned long bc_addr_);
+ ~HostsTool();
+
+ /*
+ * compute test result
+ */
+ void
+ compute();
+
+ /*
+ * finished tests
+ */
+ void
+ finish();
+
+ /*
+ * send a new test
+ */
+ void
+ send(unsigned long target_addr, unsigned short packet_id);
+
+ /*
+ * receive results
+ */
+ HostsResult*
+ receive();
+
+ private:
+ /*
+ * checksum for icmp packets
+ */
+ unsigned short
+ in_checksum(const unsigned short *addr, int len) const;
+
+ private:
+ unsigned long local_ip_;
+ int send_sock_;
+ int recv_sock_;
+ unsigned long bc_addr_;
+ int packet_id_;
+ bool test_in_progress_;
+ PERF_MUTEX mutex_;
+};
+
+#endif //HOSTSTOOL_HPP_
diff --git a/src/lbdata.cc b/src/lbdata.cc
new file mode 100644
index 0000000..14a04c0
--- /dev/null
+++ b/src/lbdata.cc
@@ -0,0 +1,212 @@
+/*
+ * Module: lbdata.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <sys/time.h>
+#include <time.h>
+#include <iostream>
+
+#include "lbdata.hh"
+
+int LBHealthHistory::_buffer_size = 10;
+
+/**
+ *
+ *
+ **/
+void
+LBHealth::put(int rtt)
+{
+ int activity_ct = _hresults.push(rtt);
+
+ if (rtt == -1) {
+ if (activity_ct >= _failure_ct) {
+ if (_is_active == true) {
+ _state_changed = true;
+ }
+ _is_active = false;
+ }
+ }
+ else {
+ if (activity_ct >= _success_ct) {
+ if (_is_active == false) {
+ _state_changed = true;
+ }
+ _is_active = true;
+ }
+ }
+}
+
+/**
+ *
+ *
+ **/
+LBHealthHistory::LBHealthHistory(int buffer_size) :
+ _last_success(0),
+ _last_failure(0),
+ _index(0)
+{
+ _resp_data.resize(10);
+
+ for (int i = 0; i < _buffer_size; ++i) {
+ _resp_data[i] = 0;
+ }
+}
+
+
+
+/**
+ *
+ *
+ **/
+int
+LBHealthHistory::push(int rtt)
+{
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+
+ if (rtt == -1) {
+ _last_failure = tv.tv_sec;
+ }
+ else {
+ _last_success = tv.tv_sec;
+ }
+
+ _resp_data[_index % _buffer_size] = rtt;
+ ++_index;
+
+ //compute count of sequence of same responses
+ int ct = 0;
+ int start_index = (_index - 1) % _buffer_size;
+ for (int i = 0; i < _buffer_size; ++i) {
+ int index = start_index - i;
+ if (index < 0) {
+ //handle wrap around of index here
+ index = _buffer_size - index;
+ }
+
+ if (_resp_data[index] == -1 && rtt == -1) {
+ ++ct;
+ }
+ else if (_resp_data[index] != -1 && rtt != -1) {
+ ++ct;
+ }
+ else {
+ return ct;
+ }
+ }
+ return ct;
+}
+
+/**
+ *
+ *
+ **/
+bool
+LBData::is_active(const string &iface)
+{
+ InterfaceHealthIter iter = _iface_health_coll.find(iface);
+ if (iter != _iface_health_coll.end()) {
+ return iter->second._is_active;
+ }
+ return false;
+}
+
+/**
+ *
+ *
+ **/
+void
+LBData::dump()
+{
+
+ cout << "health" << endl;
+ LBData::InterfaceHealthIter h_iter = _iface_health_coll.begin();
+ while (h_iter != _iface_health_coll.end()) {
+ cout << " " << h_iter->first << endl;
+ cout << " " << h_iter->second._success_ct << endl;
+ cout << " " << h_iter->second._failure_ct << endl;
+ cout << " " << h_iter->second._ping_target << endl;
+ cout << " " << h_iter->second._ping_resp_time << endl;
+ ++h_iter;
+ }
+
+ cout << endl << "wan" << endl;
+ LBData::LBRuleIter r_iter = _lb_rule_coll.begin();
+ while (r_iter != _lb_rule_coll.end()) {
+ cout << " rule: " << r_iter->first << endl;
+ cout << " " << r_iter->second._proto << endl;
+ cout << " " << r_iter->second._s_addr << endl;
+ cout << " " << r_iter->second._s_net << endl;
+ cout << " " << r_iter->second._s_port_num << endl;
+ cout << " " << r_iter->second._s_port_name << endl;
+
+ cout << " " << r_iter->second._d_addr << endl;
+ cout << " " << r_iter->second._d_net << endl;
+ cout << " " << r_iter->second._d_port_num << endl;
+ cout << " " << r_iter->second._d_port_name << endl;
+
+ LBRule::InterfaceDistIter ri_iter = r_iter->second._iface_dist_coll.begin();
+ while (ri_iter != r_iter->second._iface_dist_coll.end()) {
+ cout << " interface: " << ri_iter->first << endl;
+ cout << " weight: " << ri_iter->second << endl;
+ ++ri_iter;
+ }
+ ++r_iter;
+ }
+ cout << "end dump" << endl;
+}
+
+/**
+ *
+ *
+ **/
+bool
+LBData::state_changed()
+{
+ LBData::InterfaceHealthIter h_iter = _iface_health_coll.begin();
+ while (h_iter != _iface_health_coll.end()) {
+ if (h_iter->second.state_changed()) {
+ return true;
+ }
+ ++h_iter;
+ }
+ return false;
+}
+
+/**
+ *
+ *
+ **/
+void
+LBData::reset_state_changed()
+{
+ LBData::InterfaceHealthIter h_iter = _iface_health_coll.begin();
+ while (h_iter != _iface_health_coll.end()) {
+ h_iter->second._state_changed = false;
+ ++h_iter;
+ }
+}
diff --git a/src/lbdata.hh b/src/lbdata.hh
new file mode 100644
index 0000000..6d5c5af
--- /dev/null
+++ b/src/lbdata.hh
@@ -0,0 +1,146 @@
+/*
+ * Module: lbdata.hh
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#ifndef __LBDATA_HH__
+#define __LBDATA_HH__
+
+#include <map>
+#include <set>
+#include <vector>
+#include <string>
+
+using namespace std;
+
+class LBRule {
+ public:
+ typedef map<string, int> InterfaceDistColl;
+ typedef map<string, int>::iterator InterfaceDistIter;
+
+ typedef enum {ALL,ICMP,UDP,TCP} Protocol;
+
+ LBRule() :
+ _proto("all")
+ {}
+
+ public:
+ string _proto;
+ string _s_addr;
+ string _s_net;
+ string _s_port_num;
+ string _s_port_name;
+
+ string _d_addr;
+ string _d_net;
+ string _d_port_num;
+ string _d_port_name;
+
+ InterfaceDistColl _iface_dist_coll;
+};
+
+
+class LBHealthHistory {
+public:
+ LBHealthHistory(int buffer_size);
+
+ //push in the ping response for this...
+ int push(int rtt);
+
+
+public:
+ //results of health testing
+ unsigned long _last_success;
+ unsigned long _last_failure;
+
+ static int _buffer_size;
+ vector<int> _resp_data;
+ int _index;
+};
+
+class LBHealth {
+ public:
+ LBHealth() :
+ _success_ct(0),
+ _failure_ct(0),
+ _ping_resp_time(0),
+ _hresults(10),
+ _is_active(true),
+ _state_changed(true),
+ _last_success(0),
+ _last_failure(0)
+ {}
+
+ void put(int rtt);
+
+ bool
+ state_changed() {return _state_changed;}
+
+ int _success_ct;
+ int _failure_ct;
+ string _ping_target;
+ int _ping_resp_time;
+ LBHealthHistory _hresults;
+ bool _is_active;
+ bool _state_changed;
+ unsigned long _last_success;
+ unsigned long _last_failure;
+};
+
+
+class LBData {
+ public:
+ typedef map<int,LBRule> LBRuleColl;
+ typedef map<int,LBRule>::iterator LBRuleIter;
+ typedef map<int,LBRule>::const_iterator LBRuleConstIter;
+ typedef map<string,LBHealth> InterfaceHealthColl;
+ typedef map<string,LBHealth>::iterator InterfaceHealthIter;
+ typedef map<string,LBHealth>::const_iterator InterfaceHealthConstIter;
+
+ LBData() {}
+
+ bool
+ error() {return false;}
+
+ bool
+ is_active(const string &iface);
+
+ bool
+ state_changed();
+
+ void
+ reset_state_changed();
+
+ void
+ dump();
+
+ public:
+ string _filename;
+
+ LBRuleColl _lb_rule_coll;
+ InterfaceHealthColl _iface_health_coll;
+};
+
+#endif //__LBDATA_HH__
diff --git a/src/lbdatafactory.cc b/src/lbdatafactory.cc
new file mode 100644
index 0000000..0220416
--- /dev/null
+++ b/src/lbdatafactory.cc
@@ -0,0 +1,334 @@
+/*
+ * Module: lbdatafactory.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <syslog.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string>
+#include <algorithm>
+#include <vector>
+#include <iostream>
+#include "rl_str_proc.hh"
+#include "lbdata.hh"
+#include "lbdatafactory.hh"
+
+using namespace std;
+
+
+LBDataFactory::LBDataFactory()
+{
+}
+
+LBDataFactory::~LBDataFactory()
+{
+
+}
+
+bool
+LBDataFactory::load(const string &conf_file)
+{
+ //open file
+ FILE *fp = fopen(conf_file.c_str(), "r");
+ if (fp == NULL) {
+ cerr << "Error opening configuration file: " << conf_file << endl;
+ syslog(LOG_ERR, "wan_lb: configuration file not found: %s", conf_file.c_str());
+ return false;
+ }
+
+ //read line by line and populate vect
+ char str[1025];
+ int depth(0);
+ vector<string> path(10);
+ while (fgets(str, 1024, fp) != 0) {
+ string line(str);
+
+ int pos = line.find("#");
+ line = line.substr(0,pos);
+
+ string key,value;
+
+ StrProc tokens(line, " ");
+ for (int i = 0; i < tokens.size(); ++i) {
+ string symbol = tokens.get(i);
+
+ if (symbol != "{" && symbol != "}") {
+ if (key.empty()) {
+ key = symbol;
+ }
+ else if (value.empty()) {
+ value = symbol;
+ }
+ path[depth] = key;
+ }
+ else if (symbol == "{") {
+ ++depth;
+ }
+ else if (symbol == "}") {
+ --depth;
+ }
+ }
+ if (tokens.size() != 0) {
+ process(path,depth,key,value);
+ }
+ if (depth > 9 || depth < 0) {
+ cerr << "configuration error: malformed configuration file: brackets" << endl;
+ syslog(LOG_ERR, "wan_lb: malformed configuration file: brackets");
+ return false;
+ }
+ }
+
+ fclose(fp);
+ if (depth != 0) {
+ cerr << "configuration error: mismatched brackets in configuration file" << endl;
+ syslog(LOG_ERR, "wan_lb: configuration error due to mismatched brackets");
+ return false;
+ }
+
+#ifdef DEBUG
+ _lb_data.dump();
+#endif
+ return true;
+}
+
+
+void
+LBDataFactory::process(const vector<string> &path, int depth, const string &key, const string &value)
+{
+ string l_key, l_value;
+ std::transform(key.begin(), key.end(), std::back_inserter(l_key),
+ static_cast < int(*)(int) > (std::tolower));
+ std::transform(value.begin(), value.end(), std::back_inserter(l_value),
+ static_cast < int(*)(int) > (std::tolower));
+ if (path[0] == "health") {
+ if (l_key == "interface") {
+ process_health(l_key,l_value);
+ }
+ else {
+ process_health_interface(l_key,l_value);
+ }
+ }
+ else if (path[0] == "rule") {
+ if (depth > 0 && path[1] == "source") {
+ process_rule_source(l_key,l_value);
+ }
+ else if (depth > 0 && path[1] == "destination") {
+ process_rule_destination(l_key,l_value);
+ }
+ else if (depth > 1 && path[1] == "interface") {
+ process_rule_interface(l_key,l_value);
+ }
+ else if (depth > 0 && path[1] == "protocol") {
+ process_rule_protocol(l_key,l_value);
+ }
+ else {
+ process_rule(l_key,l_value);
+ }
+ }
+}
+
+
+void
+LBDataFactory::process_health(const string &key, const string &value)
+{
+ if (value.empty() == false) {
+ LBData::InterfaceHealthIter iter = _lb_data._iface_health_coll.find(key);
+ if (iter == _lb_data._iface_health_coll.end()) {
+ _lb_data._iface_health_coll.insert(pair<string,LBHealth>(value,LBHealth()));
+ }
+ _health_iter = _lb_data._iface_health_coll.find(value);
+ }
+}
+
+
+void
+LBDataFactory::process_health_interface(const string &key, const string &value)
+{
+ if (key == "target") {
+ _health_iter->second._ping_target = value;
+ }
+ else if (key == "success-ct") {
+ int num = strtoul(value.c_str(), NULL, 10);
+ if (num > 0) {
+ _health_iter->second._success_ct = num;
+ }
+ else {
+ cerr << "illegal success-ct specified: " << value << endl;
+ syslog(LOG_ERR, "wan_lb: illegal success-ct specified in configuration file: %s", value.c_str());
+ }
+ }
+ else if (key == "failure-ct") {
+ int num = strtoul(value.c_str(), NULL, 10);
+ if (num > 0) {
+ _health_iter->second._failure_ct = num;
+ }
+ else {
+ cerr << "illegal failure-ct specified: " << value << endl;
+ syslog(LOG_ERR, "wan_lb: illegal failure-ct specified in configuration file: %s", value.c_str());
+ }
+ }
+ else if (key == "ping-resp") {
+ int num = strtoul(value.c_str(), NULL, 10);
+ if (num > 0) {
+ _health_iter->second._ping_resp_time = num;
+ }
+ else {
+ cerr << "illegal ping-resp specified: " << value << endl;
+ syslog(LOG_ERR, "wan_lb: illegal ping-resp specified in configuration file: %s", value.c_str());
+ }
+ }
+ else if (key == "health") {
+ //nothing
+ }
+ else {
+ cout << "LBDataFactory::process_health(): " << "don't understand this symbol: " << key << endl;
+ //nothing
+ }
+
+}
+
+void
+LBDataFactory::process_rule(const string &key, const string &value)
+{
+ if (key.empty()) {
+ return;
+ }
+#ifdef DEBUG
+ cout << "LBDataFactor::process_rule(): " << key << ", " << value << endl;
+#endif
+ int num = strtoul(value.c_str(), NULL, 10);
+ if (num > 0) {
+ _lb_data._lb_rule_coll.insert(pair<int,LBRule>(num,LBRule()));
+ }
+ else {
+ cerr << "Rule number: illegal value" << endl;
+ syslog(LOG_ERR, "wan_lb: illegal rule number: %s", value.c_str());
+ return;
+ }
+ _rule_iter = _lb_data._lb_rule_coll.find(num);
+}
+
+void
+LBDataFactory::process_rule_protocol(const string &key, const string &value)
+{
+ if (key == "protocol") {
+ if (strcasecmp(value.c_str(),"ALL") == 0) {
+ _rule_iter->second._proto = "all";
+ }
+ else if (strcasecmp(value.c_str(),"ICMP") == 0) {
+ _rule_iter->second._proto = "icmp";
+ }
+ else if (strcasecmp(value.c_str(), "UDP") == 0) {
+ _rule_iter->second._proto = "udp";
+ }
+ else if (strcasecmp(value.c_str(),"TCP") == 0) {
+ _rule_iter->second._proto = "tcp";
+ }
+ else {
+ cerr << "protocol not recognized: " << key << ", " << value << endl;
+ syslog(LOG_ERR, "wan_lb: illegal protocol specified: %s", value.c_str());
+ }
+ }
+}
+
+void
+LBDataFactory::process_rule_source(const string &key, const string &value)
+{
+ if (key == "address") {
+ if (inet_addr(value.c_str()) == (unsigned)-1) {
+ cerr << "malformed ip address: " << key << ", " << value << endl;
+ syslog(LOG_ERR, "wan_lb, malformed ip address in configuration: %s,%s", key.c_str(),value.c_str());
+ return;
+ }
+ _rule_iter->second._s_addr = value;
+ }
+ else if (key == "network") {
+ _rule_iter->second._s_net = value;
+ }
+ else if (key == "port-name") {
+ _rule_iter->second._s_port_num = value;
+ }
+ else if (key == "port-number") {
+ _rule_iter->second._s_port_name = value;
+ }
+}
+
+void
+LBDataFactory::process_rule_destination(const string &key, const string &value)
+{
+ if (key == "address") {
+ if (inet_addr(value.c_str()) == (unsigned)-1) {
+ cerr << "malformed ip address: " << key << ", " << value << endl;
+ syslog(LOG_ERR, "wan_lb, malformed ip address in configuration: %s,%s", key.c_str(),value.c_str());
+ return;
+ }
+ _rule_iter->second._d_addr = value;
+ }
+ else if (key == "network") {
+ _rule_iter->second._d_net = value;
+ }
+ else if (key == "port-name") {
+ _rule_iter->second._d_port_num = value;
+ }
+ else if (key == "port-number") {
+ _rule_iter->second._d_port_name = value;
+ }
+}
+
+void
+LBDataFactory::process_rule_interface(const string &key, const string &value)
+{
+#ifdef DEBUG
+ cout << "LBDataFactory::process_rule_interface(): " << key << ", " << value << endl;
+#endif
+ if (key == "interface") {
+ _rule_iter->second._iface_dist_coll.insert(pair<string,int>(value,0));
+ _rule_iface_iter = _rule_iter->second._iface_dist_coll.find(value);
+ }
+ else if (key == "weight") {
+ int num = strtoul(value.c_str(), NULL, 10);
+ if (num > 0) {
+ _rule_iface_iter->second = num;
+ }
+ else {
+ cerr << "illegal interface weight specified: " << value << endl;
+ syslog(LOG_ERR, "wan_lb: illegal interface weight specified in configuration file: %s", value.c_str());
+ }
+ }
+ else {
+ cerr << "LBDataFactory::process_rule(): " << "don't understand this symbol: " << key << endl;
+ }
+}
+
+
+
+LBData
+LBDataFactory::get()
+{
+ return _lb_data;
+}
+
diff --git a/src/lbdatafactory.hh b/src/lbdatafactory.hh
new file mode 100644
index 0000000..29fe609
--- /dev/null
+++ b/src/lbdatafactory.hh
@@ -0,0 +1,94 @@
+/*
+ * Module: lbdatafactory.hh
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#ifndef __LBCONFLOADER_HH__
+#define __LBCONFLOADER_HH__
+
+#include <string>
+#include <vector>
+
+#include "lbdata.hh"
+
+using namespace std;
+
+class LBDataFactory {
+public:
+ typedef vector<string> ConfColl;
+ typedef vector<string>::iterator ConfIter;
+
+public:
+ LBDataFactory();
+ ~LBDataFactory();
+
+ bool
+ load(const string &conf_file);
+
+ LBData
+ get();
+
+private:
+ //parsing goes on here
+ void
+ tokenize(const string& str,
+ vector<string>& tokens,
+ const string& delimiters = " ");
+
+ void
+ process(const vector<string> &path, int depth, const string &key, const string &value);
+
+ void
+ process_health(const string &key, const string &value);
+
+ void
+ process_health_interface(const string &key, const string &value);
+
+ void
+ process_rule(const string &key, const string &value);
+
+ void
+ process_rule_protocol(const string &key, const string &value);
+
+ void
+ process_rule_source(const string &key, const string &value);
+
+ void
+ process_rule_destination(const string &key, const string &value);
+
+ void
+ process_rule_interface(const string &key, const string &value);
+
+private:
+ LBHealth _lb_health;
+ LBRule _lb_rule;
+ LBData _lb_data;
+
+ LBData::LBRuleIter _rule_iter;
+ LBData::InterfaceHealthIter _health_iter;
+ LBRule::InterfaceDistIter _rule_iface_iter;
+};
+
+#endif //__LBCONFLOADER_HH__
diff --git a/src/lbdecision.cc b/src/lbdecision.cc
new file mode 100644
index 0000000..79e86cb
--- /dev/null
+++ b/src/lbdecision.cc
@@ -0,0 +1,318 @@
+/*
+ * Module: lbdecision.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <syslog.h>
+#include <iostream>
+#include "lbdata.hh"
+#include "lbdecision.hh"
+
+using namespace std;
+
+/*
+iptables -t mangle -N ISP1
+iptables -t mangle -A ISP1 -j CONNMARK --set-mark 1
+iptables -t mangle -A ISP1 -j MARK --set-mark 1
+iptables -t mangle -A ISP1 -j ACCEPT
+
+iptables -t mangle -N ISP2
+iptables -t mangle -A ISP2 -j CONNMARK --set-mark 2
+iptables -t mangle -A ISP2 -j MARK --set-mark 2
+iptables -t mangle -A ISP2 -j ACCEPT
+
+
+#THIS APPEARS TO ROUGHLY WORK BELOW, AND CAN BE SET UP WITH SPECIFIC FILTERS.
+iptables -t mangle -A PREROUTING -i eth0 -m statistic --mode nth --every 2 --packet 0 -j ISP1
+iptables -t mangle -A PREROUTING -i eth0 -j ISP2
+
+#iptables -t mangle -A PREROUTING -i eth0 -m state --state NEW -m statistic --mode random --probability .01 -j MARK --set-mark 1
+#iptables -t mangle -A PREROUTING -i eth0 -j MARK --set-mark 2
+
+iptables -t raw -N NAT_CONNTRACK
+iptables -t raw -A NAT_CONNTRACK -j ACCEPT
+iptables -t raw -I PREROUTING 1 -j NAT_CONNTRACK
+iptables -t raw -I OUTPUT 1 -j NAT_CONNTRACK
+ip ro add table 10 default via 192.168.1.2 dev eth1
+ip ru add fwmark 1 table 10
+ip ro fl ca
+ip ro add table 20 default via 192.168.2.2 dev eth2
+ip ru add fwmark 2 table 20
+ip ro fl ca
+
+*/
+
+
+/**
+ *
+ *
+ **/
+LBDecision::LBDecision()
+{
+
+}
+
+/**
+ *
+ *
+ **/
+LBDecision::~LBDecision()
+{
+ shutdown();
+}
+
+/**
+ *
+ *
+ **/
+void
+LBDecision::init(LBData &lbdata)
+{
+ //here is where we set up iptables and policy routing for the interfaces
+ /*
+ iptables -t mangle -N ISP1
+ iptables -t mangle -A ISP1 -j CONNMARK --set-mark 1
+ iptables -t mangle -A ISP1 -j MARK --set-mark 1
+ iptables -t mangle -A ISP1 -j ACCEPT
+ */
+
+ char buf[20];
+ int ct = 1;
+
+ /*
+ do we need:
+iptables -t raw -N NAT_CONNTRACK
+iptables -t raw -A NAT_CONNTRACK -j ACCEPT
+iptables -t raw -I PREROUTING 1 -j NAT_CONNTRACK
+iptables -t raw -I OUTPUT 1 -j NAT_CONNTRACK
+
+if so then this stuff goes here!
+ */
+
+
+ //note: doesn't appear to clean up rule table, may need to individually erase each rule
+ // execute(string("ip rule flush"));
+
+ LBData::InterfaceHealthIter iter = lbdata._iface_health_coll.begin();
+ while (iter != lbdata._iface_health_coll.end()) {
+ string iface = iter->first;
+ sprintf(buf,"%d",ct);
+ execute(string("iptables -t mangle -N ISP_") + buf);
+ execute(string("iptables -t mangle -F ISP_") + buf);
+ execute(string("iptables -t mangle -A ISP_") + buf + " -j CONNMARK --set-mark " + buf);
+ execute(string("iptables -t mangle -A ISP_") + buf + " -j MARK --set-mark " + buf);
+
+ //NOTE, WILL NEED A WAY TO CLEAN UP THIS RULE ON RESTART...
+ execute(string("iptables -t mangle -A ISP_") + buf + " -j ACCEPT");
+
+ execute(string("ip route replace table ") + buf + " default dev " + iface);
+ execute(string("ip rule add fwmark ") + buf + " table " + buf);
+
+ _iface_mark_coll.insert(pair<string,int>(iface,ct));
+ ++ct;
+ ++iter;
+ }
+ execute("ip route flush cache");
+}
+
+
+/**
+ * only responsible for
+
+iptables -t mangle -A PREROUTING -i eth0 -m state --state NEW -m statistic --mode random --probability .01 -j MARK --set-mark 1
+iptables -t mangle -A PREROUTING -i eth0 -j MARK --set-mark 2
+
+ *
+ *
+ *
+ **/
+void
+LBDecision::run(LBData &lb_data)
+{
+#ifdef DEBUG
+ cout << "LBDecision::run(), starting decision" << endl;
+#endif
+
+ //first determine if we need to alter the rule set
+ if (!lb_data.state_changed()) {
+ return;
+ }
+
+#ifdef DEBUG
+ cout << "LBDecision::run(), state changed, applying new rule set" << endl;
+#endif
+
+ //then if we do, flush all
+ execute("iptables -t mangle -F PREROUTING");
+
+ //and compute the new set and apply
+ LBData::LBRuleIter iter = lb_data._lb_rule_coll.begin();
+ while (iter != lb_data._lb_rule_coll.end()) {
+ map<int,float> weights = get_new_weights(lb_data,iter->second);
+ map<int,float>::iterator w_iter = weights.begin();
+ map<int,float>::iterator w_end = weights.end();
+ if (w_iter == w_end) {
+ ++iter;
+ continue;
+ }
+ else {
+ --w_end;
+ }
+
+ //NEED TO HANDLE APPLICATION SPECIFIC DETAILS
+ string app_cmd = get_application_cmd(iter->second);
+
+ char fbuf[20],dbuf[20];
+ while (w_iter != w_end) {
+ sprintf(fbuf,"%f",w_iter->second);
+ sprintf(dbuf,"%d",w_iter->first);
+ execute(string("iptables -t mangle -A PREROUTING ") + app_cmd + " -m state --state NEW -m statistic --mode random --probability " + fbuf + " -j ISP_" + dbuf);
+ ++w_iter;
+ }
+ //last one is special case, the catch all rule
+ ++w_iter;
+ sprintf(dbuf,"%d",w_iter->first);
+ execute(string("iptables -t mangle -A PREROUTING ") + app_cmd + " -j ISP_" + dbuf);
+ ++iter;
+ }
+}
+
+/**
+ *
+ *
+ **/
+void
+LBDecision::shutdown()
+{
+ char buf[20];
+
+ //then if we do, flush all
+ execute("iptables -t mangle -F PREROUTING");
+
+ //remove the policy entries
+ InterfaceMarkIter iter = _iface_mark_coll.begin();
+ while (iter != _iface_mark_coll.end()) {
+ sprintf(buf,"%d",iter->second);
+ execute(string("ip rule del fwmark ") + buf);
+ ++iter;
+ }
+}
+
+/**
+ *
+ *
+ **/
+void
+LBDecision::execute(string cmd)
+{
+#ifdef DEBUG
+ cout << "LBDecision::execute(): applying command to system: " << cmd << endl;
+#endif
+
+ FILE *f = popen(cmd.c_str(), "w");
+ if (f) {
+ if (pclose(f) != 0) {
+ cerr << "LBDecision::execute(): error executing command: " << cmd << endl;
+ syslog(LOG_ERR, "Error executing system command: %s", cmd.c_str());
+ }
+ }
+ else {
+ cerr << "LBDecision::execute(): error executing command: " << cmd << endl;
+ syslog(LOG_ERR, "Error executing system command: %s", cmd.c_str());
+ }
+}
+
+map<int,float>
+LBDecision::get_new_weights(LBData &data, LBRule &rule)
+{
+ map<int,float> weights;
+ int group = 0;
+ int ct = 1;
+ LBRule::InterfaceDistIter iter = rule._iface_dist_coll.begin();
+ while (iter != rule._iface_dist_coll.end()) {
+#ifdef DEBUG
+ cout << "LBDecision::get_new_weights(): " << iter->first << " is active: " << (data.is_active(iter->first) ? "true" : "false") << endl;
+#endif
+ if (data.is_active(iter->first)) {
+ weights.insert(pair<int,float>(ct,iter->second));
+ group += iter->second;
+ }
+ ++ct;
+ ++iter;
+ }
+
+ //now weight the overall distribution
+ map<int,float>::iterator w_iter = weights.begin();
+ while (w_iter != weights.end()) {
+ float w = float(w_iter->second) / float(group);
+ group -= w_iter->second; //I THINK THIS NEEDS TO BE ADJUSTED TO THE OVERALL REMAINING VALUES. which is this...
+ w_iter->second = w;
+ ++w_iter;
+ }
+
+ return weights;
+}
+
+/**
+ *
+ *
+ **/
+string
+LBDecision::get_application_cmd(LBRule &rule)
+{
+ string filter;
+
+ if (rule._proto.empty() == false) {
+ filter += "--proto " + rule._proto + " ";
+ }
+
+ if (rule._proto == "icmp") {
+ filter += "--icmp-type any ";
+ }
+ else if (rule._proto == "udp" || rule._proto == "tcp") {
+ if (rule._s_addr.empty() == false) {
+ filter += "--source " + rule._s_addr + " ";
+ }
+ else if (rule._s_net.empty() == false) {
+ filter += "--source " + rule._s_net + " ";
+ }
+
+ if (rule._d_addr.empty() == false) {
+ filter += "--destination " + rule._d_addr + " ";
+ }
+ else if (rule._d_net.empty() == false) {
+ filter += "--destination " + rule._d_net + " ";
+ }
+
+ if (rule._s_port_name.empty() == false) {
+ filter += "--source-port " + rule._s_port_name + " ";
+ }
+ else if (rule._s_port_num.empty() == false) {
+ filter += "--source-port " + rule._s_port_num + " ";
+ }
+ }
+
+ return filter;
+}
diff --git a/src/lbdecision.hh b/src/lbdecision.hh
new file mode 100644
index 0000000..299544a
--- /dev/null
+++ b/src/lbdecision.hh
@@ -0,0 +1,70 @@
+/*
+ * Module: lbdecision.hh
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#ifndef __LBDECISION_HH__
+#define __LBDECISION_HH__
+
+#include <map>
+#include <string>
+#include "lbdata.hh"
+
+using namespace std;
+
+class LBDecision
+{
+public:
+ typedef map<string,int> InterfaceMarkColl;
+ typedef map<string,int>::iterator InterfaceMarkIter;
+
+public:
+ LBDecision();
+ ~LBDecision();
+
+ void
+ init(LBData &lbdata);
+
+ void
+ run(LBData &lbdata);
+
+ void
+ shutdown();
+
+private:
+ void
+ execute(string cmd);
+
+ map<int,float>
+ get_new_weights(LBData &data, LBRule &rule);
+
+ string
+ get_application_cmd(LBRule &rule);
+
+private:
+ InterfaceMarkColl _iface_mark_coll;
+};
+
+#endif //__LBDECISION_HH__
diff --git a/src/lboutput.cc b/src/lboutput.cc
new file mode 100644
index 0000000..e0ed18b
--- /dev/null
+++ b/src/lboutput.cc
@@ -0,0 +1,58 @@
+/*
+ * Module: lboutput.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <sys/time.h>
+#include <time.h>
+
+#include <iostream>
+
+#include "lbdata.hh"
+#include "lboutput.hh"
+
+void
+LBOutput::write(const LBData &lbdata)
+{
+ timeval tv;
+ gettimeofday(&tv,NULL);
+
+ //dump out the health data
+ LBData::InterfaceHealthConstIter iter = lbdata._iface_health_coll.begin();
+ while (iter != lbdata._iface_health_coll.end()) {
+ cout << iter->first << " "; //interface
+ cout << string(iter->second._is_active ? "true" : "false") << " "; //status
+ cout << tv.tv_sec - iter->second._last_success << " "; //last success
+ cout << tv.tv_sec - iter->second._last_failure << " "; //last failure
+ ++iter;
+ }
+
+ //dump out the application data
+ LBData::LBRuleConstIter r_iter = lbdata._lb_rule_coll.begin();
+ while (r_iter != lbdata._lb_rule_coll.end()) {
+ cout << "squirt out results here." << endl;
+ ++r_iter;
+ }
+}
diff --git a/src/lboutput.hh b/src/lboutput.hh
new file mode 100644
index 0000000..b68c9f2
--- /dev/null
+++ b/src/lboutput.hh
@@ -0,0 +1,45 @@
+/*
+ * Module: lboutput.hh
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#ifndef __LBOUTPUT_HH__
+#define __LBOUTPUT_HH__
+
+#include "lbdata.hh"
+
+using namespace std;
+
+class LBOutput
+{
+public:
+ LBOutput() {}
+ ~LBOutput() {}
+
+ void
+ write(const LBData &lbdata);
+
+};
+#endif //__LBOUTPUT_HH__
diff --git a/src/lbpathtest.cc b/src/lbpathtest.cc
new file mode 100644
index 0000000..7e052c7
--- /dev/null
+++ b/src/lbpathtest.cc
@@ -0,0 +1,336 @@
+/*
+ * Module: lbpathtest.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <syslog.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/sysinfo.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/udp.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <errno.h>
+#include <memory>
+#include <time.h>
+#include <sys/timeb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <string>
+#include <algorithm>
+
+#include "lbdata.hh"
+#include "lbpathtest.hh"
+
+using namespace std;
+
+LBPathTest::LBPathTest() :
+ _send_sock(0),
+ _recv_sock(0),
+ _packet_id(0)
+{
+ struct protoent *ppe = getprotobyname("icmp");
+ _send_sock = socket(PF_INET, SOCK_RAW, ppe->p_proto);
+ if (_send_sock < 0){
+ cerr << "LBPathTest::LBPathTest(): no send sock: " << _send_sock << endl;
+ syslog(LOG_ERR, "wan_lb: failed to acquired socket");
+ _send_sock = 0;
+ return;
+ }
+
+ //set options for broadcasting.
+ int val = 1;
+ setsockopt(_send_sock, SOL_SOCKET, SO_BROADCAST, &val, 4);
+ setsockopt(_send_sock, SOL_SOCKET, SO_REUSEADDR, &val, 4);
+
+ struct sockaddr_in addr;
+ memset( &addr, 0, sizeof( struct sockaddr_in ));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = 0;
+
+ _recv_sock = socket(PF_INET, SOCK_RAW, ppe->p_proto);
+ if (_recv_sock < 0) {
+ cerr << "LBPathTest::LBPathTest(): no recv sock: " << _recv_sock << endl;
+ syslog(LOG_ERR, "wan_lb: failed to acquired socket");
+ _recv_sock = 0;
+ return;
+ }
+ if (bind(_recv_sock, (struct sockaddr*)&addr, sizeof(addr))==-1) {
+ cerr << "failed on bind" << endl;
+ syslog(LOG_ERR, "wan_lb: failed to bind recv sock");
+ }
+}
+
+LBPathTest::~LBPathTest()
+{
+ if (_recv_sock)
+ close(_recv_sock);
+
+ if (_send_sock)
+ close(_send_sock);
+}
+
+void
+LBPathTest::start(LBData &lb_data)
+{
+#ifdef DEBUG
+ cout << "LBPathTest::start(): starting health test. client ct: " << lb_data._iface_health_coll.size() << endl;
+#endif
+
+ map<int,PktData> results;
+
+ struct timeval send_time;
+ gettimeofday(&send_time,NULL);
+
+ int ct = 0;
+ //iterate over packets and send
+ LBData::InterfaceHealthIter iter = lb_data._iface_health_coll.begin();
+ while (iter != lb_data._iface_health_coll.end()) {
+#ifdef DEBUG
+ cout << "LBPathTest::start(): sending ping test for: " << iter->first << " for " << iter->second._ping_target << endl;
+#endif
+ _packet_id = ++_packet_id % 32767;
+ send(iter->first, iter->second._ping_target, _packet_id);
+ results.insert(pair<int,PktData>(_packet_id,PktData(iter->first,-1)));
+
+ ++ct;
+ ++iter;
+ }
+
+ //use gettimeofday to calculate time to millisecond
+
+ //use sysinfo to make sure we don't get stuck in a loop with timechange
+ struct sysinfo si;
+ sysinfo(&si);
+ //for now hardcode to 5 second overall timeout
+ int timeout = si.uptime + 5; //seconds
+ int cur_time = si.uptime;
+
+ //then iterate over recv socket and receive and record
+ while (ct > 0 && cur_time < timeout) {
+ int id = receive();
+#ifdef DEBUG
+ cout << "LBPathTest::start(): " << id << endl;
+#endif
+ //update current time for comparison
+ sysinfo(&si);
+ timeval recv_time;
+ gettimeofday(&recv_time,NULL);
+ cur_time = si.uptime;
+ map<int,PktData>::iterator r_iter = results.find(id);
+ if (r_iter != results.end()) {
+
+ //calculate time in milliseconds
+ int secs = 0;
+ int msecs = recv_time.tv_usec - send_time.tv_usec;
+ if (msecs < 0) {
+ secs = recv_time.tv_sec - send_time.tv_sec - 1;
+ }
+ else {
+ secs = recv_time.tv_sec - send_time.tv_sec;
+ }
+ //time in milliseconds below
+ int rtt = abs(msecs) / 1000 + 1000 * secs;
+
+ LBData::InterfaceHealthIter iter = lb_data._iface_health_coll.find(r_iter->second._iface);
+ if (iter != lb_data._iface_health_coll.end()) {
+ //check to see if this returned in the configured time, otherwise apply timeout
+#ifdef DEBUG
+ cout << "LBPathTest::start(): received pkt: " << iter->first << ", rtt: " << rtt << endl;
+#endif
+ if (rtt < iter->second._ping_resp_time) {
+ iter->second.put(rtt);
+ }
+ else {
+ iter->second.put(-1);
+ }
+ }
+ results.erase(r_iter);
+ --ct;
+ }
+ }
+
+ //we're done waiting, mark the rest as non-responsive
+ map<int,PktData>::iterator r_iter = results.begin();
+ while (r_iter != results.end()) {
+ LBData::InterfaceHealthIter iter = lb_data._iface_health_coll.find(r_iter->second._iface);
+ if (iter != lb_data._iface_health_coll.end()) {
+ iter->second.put(-1);
+ }
+ ++r_iter;
+ }
+
+#ifdef DEBUG
+ cout << "LBPathTest::start(): finished heath test" << endl;
+#endif
+}
+
+void
+LBPathTest::send(const string &iface, const string &target_addr, int packet_id)
+{
+ int err;
+ sockaddr_in taddr;
+ timeval send_time;
+ icmphdr *icmp_hdr;
+ int icmp_pktsize = 40;
+ char buffer[icmp_pktsize];
+
+ // bind a socket to a device name (might not work on all systems):
+ setsockopt(_send_sock, SOL_SOCKET, SO_BINDTODEVICE, iface.c_str(), iface.size());
+
+ //convert target_addr to ip addr
+ struct hostent *h = gethostbyname(target_addr.c_str());
+ if (h == NULL) {
+ cerr << "LBPathTest::send() Error in resolving hostname" << endl;
+ syslog(LOG_ERR, "wan_lb: error in resolving configured hostname: %s", target_addr.c_str());
+ return;
+ }
+
+ icmp_hdr = (struct icmphdr *)buffer;
+ icmp_hdr->type = ICMP_ECHO;
+ icmp_hdr->code = 0;
+ icmp_hdr->checksum = 0;
+ icmp_hdr->un.echo.id = htons(getpid());
+ icmp_hdr->un.echo.sequence = 0;
+ int length = sizeof(buffer);
+
+ //we'll put in time of packet sent for the heck of it, may
+ //want to use this in future tests, feel free to remove.
+ gettimeofday(&send_time, (struct timezone*)NULL);
+ char* datap = &buffer[8];
+ memcpy(datap, (char*)&send_time.tv_sec, sizeof(send_time.tv_sec));
+ datap = &buffer[12];
+ memcpy(datap, (char*)&send_time.tv_usec, sizeof(send_time.tv_usec));
+ datap = &buffer[16];
+ memcpy(datap, (char*)&packet_id, sizeof(packet_id)); //packet id
+ datap = &buffer[18];
+ int val(icmp_pktsize);
+ memcpy(datap, (char*)&val, 2); //packet id
+
+ icmp_hdr->un.echo.sequence = 1;
+ icmp_hdr->checksum = 0;
+ icmp_hdr->checksum = in_checksum((unsigned short *)icmp_hdr,length>>1);
+
+ struct in_addr ia;
+ memcpy(&ia, h->h_addr_list[0], sizeof(ia));
+ unsigned long addr = ia.s_addr;
+
+ taddr.sin_addr.s_addr = addr;
+ taddr.sin_family = AF_INET;
+ bzero(&(taddr.sin_zero), 8);
+
+ //need to direct this packet out a specific interface!!!!!!!!!!!!!
+ err = sendto(_send_sock, buffer, icmp_pktsize, 0, (struct sockaddr*)&taddr, sizeof(taddr));
+#ifdef DEBUG
+ cout << "lbpathtest: sendto: " << err << ", packet id: " << packet_id << endl;
+#endif
+ if(err < 0)
+ {
+ if (errno == EBADF)
+ cout << "EBADF" << endl;
+ else if (errno == ENOTSOCK)
+ cout << "ENOTSOCK" << endl;
+ else if (errno == EFAULT)
+ cout << "EFAULT" << endl;
+ else if (errno == EMSGSIZE)
+ cout << "EMSGSIZE" << endl;
+ else if (errno == EWOULDBLOCK)
+ cout << "EWOULDBLOCK" << endl;
+ else if (errno == EAGAIN)
+ cout << "EAGAIN" << endl;
+ else if (errno == ENOBUFS)
+ cout << "ENOBUFS" << endl;
+ else if (errno == EINTR)
+ cout << "EINTR" << endl;
+ else if (errno == ENOMEM)
+ cout << "ENOMEM" << endl;
+ else if (errno == EACCES)
+ cout << "EACCES" << endl;
+ else if (errno == EINVAL)
+ cout << "EINVAL" << endl;
+ else if (errno == EPIPE)
+ cout << "EPIPE" << endl;
+ else
+ cout << "unknown error: " << errno << endl;
+
+ syslog(LOG_ERR, "wan_lb: error on sending icmp packet: %d", errno);
+ }
+}
+
+int
+LBPathTest::receive()
+{
+ int icmp_pktsize = 40;
+ char resp_buf[icmp_pktsize];
+ icmphdr *icmp_hdr;
+ timeval wait_time;
+ fd_set readfs;
+ int ret;
+
+ FD_ZERO(&readfs);
+ FD_SET(_recv_sock, &readfs);
+
+ wait_time.tv_usec = 0;
+ wait_time.tv_sec = 3; //3 second timeout
+
+ while (select(_recv_sock+1, &readfs, NULL, NULL, &wait_time) != 0)
+ {
+ ret = recv(_recv_sock, &resp_buf, icmp_pktsize, 0);
+ if (ret != -1)
+ {
+ icmp_hdr = (struct icmphdr *)(resp_buf + sizeof(iphdr));
+ if (icmp_hdr->type == ICMP_ECHOREPLY)
+ {
+#ifdef DEBUG
+ cout << "LBPathTest::receive(): " << endl;
+#endif
+ //process packet data
+ char* data;
+ int id = 0;
+ data = (char*)(&resp_buf) + 36;
+ memcpy(&id, data, sizeof(unsigned short));
+ return id;
+ }
+ }
+ }
+ return -1;
+}
+
+unsigned short
+LBPathTest::in_checksum(const unsigned short *buffer, int length) const
+{
+ unsigned long sum;
+ for (sum=0; length>0; length--)
+ sum += *buffer++;
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ~sum;
+}
+
diff --git a/src/lbpathtest.hh b/src/lbpathtest.hh
new file mode 100644
index 0000000..176bf18
--- /dev/null
+++ b/src/lbpathtest.hh
@@ -0,0 +1,73 @@
+/*
+ * Module: lbpathtest.hh
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#ifndef __LBPATHTEST_HH__
+#define __LBPATHTEST_HH__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <iostream>
+#include "lbdata.hh"
+
+using namespace std;
+
+class PktData
+{
+public:
+ PktData(string iface, int rtt) : _iface(iface),_rtt(rtt) {}
+ string _iface;
+ int _rtt;
+};
+
+class LBPathTest
+{
+public:
+ LBPathTest();
+ ~LBPathTest();
+
+ void
+ start(LBData &lb_data);
+
+private:
+ void
+ send(const string &iface, const string &target_addr, int packet_id);
+
+ int
+ receive();
+
+ unsigned short
+ in_checksum(const unsigned short *buf, int lenght) const;
+
+private:
+ int _send_sock;
+ int _recv_sock;
+ int _packet_id;
+};
+
+
+#endif //__LBPATHTEST_HH__
diff --git a/src/lbrule.hh b/src/lbrule.hh
new file mode 100644
index 0000000..b4d2683
--- /dev/null
+++ b/src/lbrule.hh
@@ -0,0 +1,5 @@
+#ifndef __LBRULE_HH__
+#define __LBRULE_HH__
+
+
+#endif //__LBRULE_HH__
diff --git a/src/loadbalance.cc b/src/loadbalance.cc
new file mode 100644
index 0000000..a48ace0
--- /dev/null
+++ b/src/loadbalance.cc
@@ -0,0 +1,110 @@
+/*
+ * Module: loadbalance.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <string>
+#include "lbpathtest.hh"
+#include "loadbalance.hh"
+
+using namespace std;
+
+/**
+ *
+ **/
+LoadBalance::LoadBalance() :
+ _cycle_interval(5000)
+{
+}
+
+/**
+ *
+ **/
+LoadBalance::~LoadBalance()
+{
+ _decision.shutdown();
+}
+
+/**
+ *
+ **/
+bool
+LoadBalance::set_conf(const string &conf)
+{
+ _lbdata_factory.load(conf);
+ _lbdata = _lbdata_factory.get();
+ if (_lbdata.error()) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ *
+ **/
+void
+LoadBalance::init()
+{
+ _decision.init(_lbdata);
+}
+
+/**
+ *
+ **/
+bool
+LoadBalance::start_cycle()
+{
+ _lbdata.reset_state_changed();
+ return true;
+}
+
+/**
+ *
+ **/
+void
+LoadBalance::health_test()
+{
+ _ph.start(_lbdata);
+}
+
+/**
+ *
+ **/
+void
+LoadBalance::apply_rules()
+{
+ _decision.run(_lbdata);
+}
+
+/**
+ *
+ **/
+void
+LoadBalance::output()
+{
+ _output.write(_lbdata);
+}
+
diff --git a/src/loadbalance.conf b/src/loadbalance.conf
new file mode 100644
index 0000000..85e6c5d
--- /dev/null
+++ b/src/loadbalance.conf
@@ -0,0 +1,50 @@
+#
+# Sample vyatta load balance configuration file.
+#
+
+health {
+ interface eth1 {
+ target 10.0.0.1
+ success-ct 2
+ failure-ct 1
+ ping-resp 100
+ }
+
+ interface eth2 {
+ target 10.0.0.1
+ success-ct 1
+ failure-ct 1
+ ping-resp 1000
+ }
+}
+
+rule 1 {
+ protocol udp
+ interface eth1 {
+ weight 1
+ }
+ interface eth2 {
+ weight 2
+ }
+}
+
+rule 2 {
+ protocol tcp
+ source {
+ address 1.1.1.1
+ port-number 2222
+ }
+ interface eth1 {
+ weight 1
+ }
+ interface eth2 {
+ weight 3
+ }
+}
+
+#default rule w/o protocol specified
+rule 10 {
+ interface eth2 {
+ weight 1
+ }
+} \ No newline at end of file
diff --git a/src/loadbalance.hh b/src/loadbalance.hh
new file mode 100644
index 0000000..624a3e4
--- /dev/null
+++ b/src/loadbalance.hh
@@ -0,0 +1,75 @@
+/*
+ * Module: loadbalance.hh
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#ifndef __LOADBALANCE_HH__
+#define __LOADBALANCE_HH__
+
+#include <time.h>
+
+#include <string>
+#include <map>
+
+#include "lbdatafactory.hh"
+#include "lbpathtest.hh"
+#include "lbdecision.hh"
+#include "lboutput.hh"
+#include "lbdata.hh"
+
+
+using namespace std;
+
+class LoadBalance
+{
+ public:
+ LoadBalance();
+ ~LoadBalance();
+
+ bool set_conf(const string &filename);
+
+ void init();
+
+ bool start_cycle();
+
+ void health_test();
+
+ void apply_rules();
+
+ void output();
+
+ //temporary stand-in for now...
+ void sleep() {::sleep(5);}
+
+ private:
+ LBDataFactory _lbdata_factory;
+ LBData _lbdata;
+ LBPathTest _ph;
+ LBDecision _decision;
+ LBOutput _output;
+ int _cycle_interval;
+};
+
+#endif //__LOADBALANCE_HH__
diff --git a/src/main.cc b/src/main.cc
new file mode 100644
index 0000000..e8d93e0
--- /dev/null
+++ b/src/main.cc
@@ -0,0 +1,138 @@
+/*
+ * Module: main.cc
+ *
+ * **** License ****
+ * Version: VPL 1.0
+ *
+ * The contents of this file are subject to the Vyatta Public License
+ * Version 1.0 ("License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.vyatta.com/vpl
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * This code was originally developed by Vyatta, Inc.
+ * Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Michael Larson
+ * Date: 2007
+ * Description:
+ *
+ * **** End License ****
+ *
+ */
+#include <signal.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <iostream>
+#include "loadbalance.hh"
+
+LoadBalance *g_lb = NULL;
+
+
+static void usage()
+{
+ cout << "lb -fh" << endl;
+ cout << "-f [file] configuration file" << endl;
+ cout << "-t load configuration file only and exit" << endl;
+ cout << "-h help" << endl;
+
+}
+
+static void sig_end(int signo)
+{
+ if (g_lb)
+ delete g_lb;
+ cerr << "End signal: " << signo << endl;
+ syslog(LOG_ERR, "wan_lb, exit signal caught, exiting..");
+ exit(0);
+}
+
+static void sig_user(int signo)
+{
+ if (g_lb)
+ delete g_lb;
+ cerr << "User signal: " << signo << endl;
+ syslog(LOG_ERR, "wan_lb, user exit signal caught, exiting..");
+ exit(0);
+}
+
+
+int main(int argc, char* argv[])
+{
+ int ch;
+ bool config_debug_mode = false;
+ string c_file;
+
+ //grab inputs
+ while ((ch = getopt(argc, argv, "f:ht")) != -1) {
+ switch (ch) {
+ case 'f':
+ c_file = optarg;
+ break;
+ case 'h':
+ usage();
+ exit(0);
+ case 't':
+ config_debug_mode = true;
+ break;
+ default:
+ usage();
+ exit(0);
+ }
+ }
+
+ //parse conf file
+ if (c_file.empty()) {
+ cout << "Configuration file is empty" << endl;
+ exit(0);
+ }
+
+ g_lb = new LoadBalance();
+
+ bool success = g_lb->set_conf(c_file);
+ if (success == false) {
+ syslog(LOG_ERR, "wan_lb: error loading configuration file: %s", c_file.c_str());
+ exit(0);
+ }
+
+ if (config_debug_mode) {
+ exit(0);
+ }
+
+#ifdef DEBUG
+ cout << "STARTING CYCLE" << endl;
+#endif
+
+ g_lb->init();
+
+
+ //signal handler here
+ // sighup...
+ signal(SIGINT, sig_end);
+ signal(SIGTERM, sig_end);
+ signal(SIGUSR1, sig_user);
+
+ //drop into event loop
+ do {
+#ifdef DEBUG
+ cout << "main.cc: starting new cycle" << endl;
+#endif
+
+ //health test
+ g_lb->health_test();
+
+ //apply rules
+ g_lb->apply_rules();
+
+ //update show output
+ g_lb->output();
+
+ g_lb->sleep();
+ } while (g_lb->start_cycle());
+ exit(0);
+}
diff --git a/src/rl_str_proc.cc b/src/rl_str_proc.cc
new file mode 100644
index 0000000..3a5d151
--- /dev/null
+++ b/src/rl_str_proc.cc
@@ -0,0 +1,82 @@
+#include "rl_str_proc.hh"
+
+using namespace std;
+
+/**
+ *
+ **/
+StrProc::StrProc(const string &in_str, const string &token)
+{
+ string tmp = in_str;
+
+ //convert tabs to spaces
+ uint32_t pos = 0;
+ string tabtospace = " ";
+ string::iterator iter = tmp.begin();
+ while ((pos = tmp.find("\t", pos)) != string::npos) {
+ tmp.replace(pos, 1, tabtospace);
+ pos += tabtospace.length();
+ }
+
+ //remove the cr
+ pos = tmp.find("\n");
+ if (pos != string::npos) {
+ tmp.replace(pos, 1, "");
+ }
+
+ //now handle the case of the multiple length token
+ //note that we are using the '~' as a token internally
+ uint32_t start = 0, end;
+ while ((start = tmp.find(token, start)) != string::npos) {
+ tmp.replace(start, token.length(), "~");
+ }
+
+
+ while ((start = tmp.find_first_not_of("~")) != string::npos) {
+ tmp = tmp.substr(start, tmp.length() - start);
+ end = tmp.find_first_of("~");
+ _str_coll.push_back(tmp.substr(0, end));
+ tmp = tmp.substr(end+1, tmp.length() - end-1);
+ if (end == string::npos) {
+ break;
+ }
+ }
+}
+
+/**
+ *
+ **/
+string
+StrProc::get(int i)
+{
+ if (uint32_t(i) >= _str_coll.size()) {
+ return string("");
+ }
+ return _str_coll[i];
+}
+
+/**
+ *
+ **/
+string
+StrProc::get(int start, int end)
+{
+ if (uint32_t(start) >= _str_coll.size()) {
+ return string("");
+ }
+
+ string tmp;
+ for (int i = start; (i < end) && (uint32_t(i) < _str_coll.size()); ++i) {
+ tmp += _str_coll[i] + " ";
+ }
+ return tmp.substr(0,tmp.length()-1);
+}
+
+/**
+ *
+ **/
+vector<string>
+StrProc::get()
+{
+ return _str_coll;
+}
diff --git a/src/rl_str_proc.hh b/src/rl_str_proc.hh
new file mode 100644
index 0000000..c59df0a
--- /dev/null
+++ b/src/rl_str_proc.hh
@@ -0,0 +1,24 @@
+#ifndef __RL_STR_PROC_HH__
+#define __RL_STR_PROC_HH__
+
+#include <vector>
+#include <string>
+
+class StrProc
+{
+public:
+ StrProc(const std::string &in, const std::string &token);
+
+ std::string get(int i);
+
+ std::string get(int start, int end);
+
+ std::vector<std::string> get();
+
+ int size() {return _str_coll.size();}
+
+private:
+ std::vector<std::string> _str_coll;
+};
+
+#endif //__RL_STR_PROC_HH__