--- /dev/null
+#
+# Copyright (C) 2016-2017 Mauro Mozzarelli
+#
+# This is free software, licensed under the GNU General Public License
+# See /LICENSE for more information.
+#
+# AUTHOR: Mauro Mozzarelli <mauro@ezplanet.org>
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=ipvsadm
+PKG_VERSION:=1.29
+PKG_MAINTAINER:=Mauro Mozzarelli <mauro@ezplanet.org>
+PKG_LICENSE:=GPL-1.0
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=https://www.kernel.org/pub/linux/utils/kernel/ipvsadm/
+PKG_HASH:=c3de4a21d90a02c621f0c72ee36a7aa27374b6f29fd4178f33fbf71b4c66c149
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/ipvsadm
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=IP Virtual Server Configuration Manager
+ URL:=http://www.linuxvirtualserver.org
+ DEPENDS:= +kmod-nf-ipvs +libnl-tiny +libpopt +wget
+endef
+
+define Package/ipvsadm/description
+ IPVS (IP Virtual Server) implements transport-layer load balancing inside
+ the Linux kernel, so called Layer-4 switching. ipvsadm is used to set up,
+ maintain or inspect the virtual server table in the Linux kernel.
+ The Linux Virtual Server can be used to build scalable network services
+ based on a cluster of two or more nodes.
+endef
+
+
+TARGET_CFLAGS += \
+ -I$(STAGING_DIR)/usr/include/libnl-tiny \
+ -D_GNU_SOURCE -DLIBIPVS_USE_NL \
+ $(FPIC)
+
+MAKE_FLAGS += \
+ LIBS="-lnl-tiny -lpopt" \
+ HAVE_NL=0
+
+define Build/Compile
+ $(MAKE) $(MAKE_FLAGS) $(CONFIGURE_VARS) -C $(PKG_BUILD_DIR)/libipvs libipvs.a
+ $(MAKE) $(MAKE_FLAGS) $(CONFIGURE_VARS) -C $(PKG_BUILD_DIR) ipvsadm
+endef
+
+define Package/ipvsadm/install
+ $(INSTALL_DIR) $(1)/sbin
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ipvsadm $(1)/sbin/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ipvsadm-save $(1)/sbin/
+ $(INSTALL_BIN) $(PKG_BUILD_DIR)/ipvsadm-restore $(1)/sbin/
+
+ $(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d $(1)/usr/sbin
+ $(INSTALL_DATA) ./files/etc/config/ipvs $(1)/etc/config/
+ $(INSTALL_BIN) ./files/etc/init.d/ipvsadm $(1)/etc/init.d/
+ $(INSTALL_BIN) ./files/usr/sbin/checkRealServers $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,ipvsadm))
--- /dev/null
+# Sample Configuration v2.1
+#
+# please see the documentation at www.linuxvirtualserver.org to learn how to
+# configure real servers.
+# This configuration is used by /etc/init.d/ipvsadm to setup and load balance
+# virtual servers to available real servers.
+# A cron job is used to activate/deactivate real servers based on their availability (ping)
+#
+# If virtual and real servers have internet static IPs, the wan interface must be part of a static IP Subnet
+# ipvsadm is fully functional for manual configuration
+
+config vipvs globals
+ option enabled '0'
+# role master|slave
+ option role 'master'
+# If my role is backup, specify the master's IP for IPs failover
+ # option role 'backup'
+# master is a list of IPs pointing to the master for heartbeat checks
+# if the mater IP is unreachable the backup server takes over the floating IPs
+ # option master 'X.X.X.X'
+# multicast interface
+ option interface 'lan'
+# synchronization id: if 0 or not specified synchronize with all servers
+ option syncid '0'
+# if an alias number is not specified in virtual, aliases are created by default starting from 100
+# alias offset specifies a custom offset 0 to 100
+ option alias_offset '0'
+
+# for each vip an alias ip is initialized on the wan/lan router interface
+# the vip must not be the same as the router's ip
+config virtual 'virtual_example'
+ option enabled 0
+ option vip '192.168.10.10'
+ option interface lan
+ option alias 10
+ option scheduler 'wlc'
+# persistent: if set, 0=default timeout of 300s any other number specifies a custom timeout
+ option persistent '1'
+# list of real servers associated with this virtual server
+ list real 'real_example'
+
+# lists protocols/ports for related virtual server with name admin
+config virtual_example
+ option protocol tcp
+ option src_port 80
+ option dest_port 80
+
+config virtual_example
+ option protocol udp
+# if only 'port' is specified then source and destination ports are the same
+# port 0 means all ports are forwarded to the real servers
+ option port 0
+
+# configure options specific to a real server
+# must have ip with _ instead of dots to comply with uci syntax. The script re-converts these to IP
+# packet_forwarding (direct, tunnel, nat), weight (numeric), u_threshold (numeric), l_threshold (numeric)
+config real 'real_example'
+ option ipaddr '192.168.10.100'
+ option packet_forwarding 'direct'
+ option weight '1'
+# probe method ping or wget if wget specify URL path
+ option probe_method 'wget'
+ option probe_url 'index.html'
--- /dev/null
+#!/bin/sh /etc/rc.common
+
+################################################################################
+# ipvsadm v2.1
+# Author: Mauro Mozzarelli <mauro@ezplanet.org>
+# License: Released under the LGPL (GNU Lesser General Public License)
+# Description: builds ipvs configuration from uci openwrt parameters
+# load/unload ip_vs kernel modules
+# start/stop ipvs scheduler
+# start/stop cron job scheduler
+# Dependencies: /etc/config/ipvs; ipvsadm; ip_vs Kernel modules; cron
+# Notes: Firewall must be configured separately
+# Configuration files in /tmp/ipvsadm.d:
+# virt.* = virtual servers
+# *.stop = real server in down state ipvs table
+# *.start = real server in up state ipvs table
+# vserv.* = virtual servers ipvs table
+################################################################################
+
+START=70
+STOP=10
+
+USE_PROCD=1
+
+BASE_DIR=/tmp/ipvsadm.d
+TMP_DIR=$BASE_DIR
+REAL_SERVERS=realServers
+KERNEL_RELEASE=`uname -r`
+MODULES=/lib/modules/$KERNEL_RELEASE
+IPVSMOD=ip_vs
+SCHED=rr
+# Reserve first 100 aliases for automated allocation
+ALIAS_NEXT=100
+# Cron job used to check if real servers are available and update ipvs
+# scheduler accordingly
+CRON_SCHEDULER='* * * * * /usr/sbin/checkRealServers # IPVS_SCHEDULER'
+
+# Get parameters for real servers (repetitive cycle)
+get_real_parameters () {
+ real=$1
+ ip=`uci -q get ipvs.$real.ipaddr`
+ param=`uci -q get ipvs.$real.packet_forwarding`
+ case $param in
+ direct) param="-g" ;;
+ tunnel) param="-i" ;;
+ nat) param="-m" ;;
+ esac
+ for i in weight u_threshold l_threshold; do
+ value=`uci -q get ipvs.$real.$i`
+ case $i in
+ weight) switch="-w" ;;
+ u_threshold) switch="-x" ;;
+ l_threshold) switch="-y" ;;
+ esac
+ if [ ! -z $value ]; then
+ let $value 2>/dev/null
+ isNumeric=$?
+ if [ $isNumeric -eq 0 ]; then
+ param="$param $switch $value"
+ else
+ param="$param $switch"
+ fi
+ fi
+ done
+ echo $param
+}
+
+# Check if real server is in the list and add if not present
+update_real_server () {
+ r_ipaddr=`uci -q get ipvs.$1.ipaddr`
+ gotit=0
+ for s in `cat $BASE_DIR/$REAL_SERVERS`; do
+ if [ $r == $s ]; then
+ gotit=1
+ break
+ fi
+ done
+ if [ $gotit -eq 0 ]; then
+ echo $r >> $BASE_DIR/$REAL_SERVERS
+ fi
+ echo $r_ipaddr
+}
+
+get_schedulers () {
+ for i in $1; do
+ schedulers=`uci -q get ipvs.${i}.scheduler`
+ done
+ schedulers=`echo $schedulers|xargs -n1|sort -u|xargs`
+ echo $schedulers
+}
+
+get_real_servers () {
+ for i in `uci show ipvs|grep "=real"`; do
+ s=${i%=*}
+ s="${s##*.}"
+ reals="$reals $s"
+ done
+}
+
+get_virtual_servers () {
+ for i in `uci show ipvs|grep "=virtual"`; do
+ s=${i%=*}
+ s="${s##*.}"
+ virtuals="$virtuals $s"
+ done
+ echo $virtuals
+}
+
+start_service () {
+
+ enabled=`uci -q get ipvs.globals.enabled`
+ case $enabled in
+ 0)
+ exit
+ ;;
+ 1)
+ ;;
+ *)
+ echo Invalid initialization parameter: enabled=$enabled
+ exit
+ ;;
+ esac
+ if [ -d $BASE_DIR ]; then
+ cd $BASE_DIR
+ else
+ mkdir -p $BASE_DIR
+ cd $BASE_DIR
+ fi
+ rm -f $BASE_DIR/*
+ rm -f $TMP_DIR/*.down
+ touch $BASE_DIR/$REAL_SERVERS
+ modprobe $IPVSMOD
+ virtuals="$(get_virtual_servers)"
+ schedulers="$(get_schedulers $virtuals)"
+ cm=0
+ for i in $schedulers; do
+ cm=$((cm+1))
+ modprobe ${IPVSMOD}_$i
+ done
+ # Default to SCHED if no schedulers
+ if [ $cm -eq 0 ]; then
+ modprobe ${IPVSMOD}_${SCHED}
+ fi
+ offset=`uci -q get ipvs.globals.alias_offset`
+ if [ ! -z "$offset" ]; then
+ let $offset 2>/dev/null
+ isNumeric=$?
+ if [ $isNumeric -eq 0 ]; then
+ ALIAS_NEXT=$offset
+ fi
+ fi
+ cv=0
+ for virtual in $virtuals ; do
+ enabled=`uci get ipvs.${virtual}.enabled`
+ if [ $enabled -eq 0 ]; then
+ continue
+ fi
+ vip=`uci get ipvs.${virtual}.vip`
+ interface=`uci get ipvs.${virtual}.interface`
+ device=`uci -P /var/state get network.${interface}.ifname`
+ ipaddr=`uci -P /var/state get network.${interface}.ipaddr`
+ alias=`uci -q get ipvs.${virtual}.alias`
+ scheduler=`uci -q get ipvs.${virtual}.scheduler`
+ persistent=`uci -q get ipvs.${virtual}.persistent`
+ v_params=`uci -q get ipvs.${virtual}.parameters`
+ # ifconfig: get alias number or use a the default
+ if [ "$vip" != "$ipaddr" ] ; then
+ let $alias 2>/dev/null
+ isNumeric=$?
+ if [ -z "$alias" ] || [ $isNumeric -gt 0 ]; then
+ alias=$ALIAS_NEXT
+ let ALIAS_NEXT=$ALIAS_NEXT+1
+ fi
+ echo "ifconfig $device:$alias $vip netmask 255.255.255.255 up" >> $BASE_DIR/ifconfig_${interface}_up.sh
+ echo "ifconfig $device:$alias down" >> $BASE_DIR/ifconfig_${interface}_down.sh
+ fi
+ if [ -z "$scheduler" ]; then
+ scheduler=$SCHED
+ fi
+ if [ ! -z $persistent ]; then
+ let $persistent 2>/dev/null
+ isNumeric=$?
+ # if numeric and greater than 0 set timeout to value, otherwise use default
+ if [ $isNumeric -eq 0 ] && [ $persistent -gt 0 ]; then
+ persistent="-p $persistent"
+ else
+ persistent="-p"
+ fi
+ fi
+ #
+ real=`uci -q get ipvs.${virtual}.real`
+ if [ ! -z "$real" -a "$real" != " " ]; then
+ vip_done=no
+ for r in $real; do
+ r_ipaddr="$(update_real_server $r)"
+ r_params="$(get_real_parameters $r)"
+ cd=0
+ while [ x`uci -q get ipvs.@${virtual}[$cd]` == x$virtual ]; do
+ protocol=`uci -q get ipvs.@$virtual[$cd].protocol`
+ src_port=`uci -q get ipvs.@$virtual[$cd].src_port`
+ dest_port=`uci -q get ipvs.@$virtual[$cd].dest_port`
+ case $protocol in
+ tcp)
+ protocol="-t"
+ ;;
+ udp)
+ protocol="-u"
+ ;;
+ *)
+ # Default to tcp protocol
+ protocol="-t"
+ ;;
+ esac
+ if [ -z $src_port ]; then
+ port=`uci -q get ipvs.@$virtual[$cd].port`
+ if [ -z $port ]; then
+ port=0
+ fi
+ src_port=$port
+ fi
+ if [ -z $dest_port ]; then
+ dest_port=$src_port
+ fi
+ if [ x$vip_done == x'no' ];then
+ echo "-A $protocol $vip:$src_port -s $scheduler $persistent $v_params" >> $BASE_DIR/vserv.start.$interface
+ echo "-D $protocol $vip:$src_port" >> $BASE_DIR/vserv.stop.$interface
+ fi
+ echo "-a $protocol $vip:$src_port -r $r_ipaddr:$dest_port $r_params" >> $BASE_DIR/$r.start
+ echo "-d $protocol $vip:$src_port -r $r_ipaddr" >> $BASE_DIR/$r.stop
+ cd=$((cd+1))
+ done
+ vip_done=yes
+ done
+ fi
+ let cv=$cv+1
+ done
+ for i in `cat $BASE_DIR/$REAL_SERVERS`; do
+ date > $TMP_DIR/$i.down
+ done
+ for i in ${BASE_DIR}/vserv.start.* ; do
+ ipvsadm -R < $i
+ done
+
+ grole=`uci -q get ipvs.globals.role`
+ gintf=`uci -q get ipvs.globals.interface`
+ gsync=`uci -q get ipvs.globals.syncid`
+ if [ ! -z $gsync ]; then
+ if [ $gsync -gt 0 ]; then
+ gsync="--syncid $gsync"
+ fi
+ fi
+ if [ $grole == 'master' ] ; then
+ for i in ${BASE_DIR}/ifconfig_*_up.sh ; do
+ /bin/sh $i
+ done
+ fi
+ ipvsadm --start-daemon $grole --mcast-interface `uci -P /var/state get network.$gintf.ifname` $gsync
+ if [ $? -gt 0 ]; then
+ logger -p info "ERROR: IPVSADM daemon failed to start"
+ exit
+ fi
+ logger -p info "IPVSADM daemon started as $grole"
+
+ # Clean up any left over crontab entry
+ # Add real server check scheduler to cron
+ (crontab -l|grep -v IPVS_SCHEDULER ; echo "$CRON_SCHEDULER")|crontab -
+}
+
+stop_service () {
+ if [ -d ${BASE_DIR} ]; then
+ for i in ${BASE_DIR}/*.stop ; do
+ ipvsadm -R < $i
+ done
+ for i in ${BASE_DIR}/vserv.stop.* ; do
+ ipvsadm -R < $i
+ done
+ for i in ${BASE_DIR}/ifconfig_*_down.sh ; do
+ /bin/sh $i
+ done
+ ipvsadm --stop-daemon `uci -q get ipvs.globals.role`
+ rm -f $TMP_DIR/*.down
+ rm -rf $BASE_DIR
+ fi
+ virtuals="$(get_virtual_servers)"
+ schedulers="$(get_schedulers $virtuals)"
+ for m in $schedulers; do
+ rmmod ${IPVSMOD}_${m}
+ done
+ # Default to SCHED if no schedulers
+ if [ -z $m ]; then
+ rmmod ${IPVSMOD}_${SCHED}
+ fi
+ rmmod $IPVSMOD
+ crontab -l |grep -v IPVS_SCHEDULER|crontab -
+}
--- /dev/null
+#!/bin/sh
+################################################################################
+# Author: Mauro Mozzarelli <mauro@ezplanet.org>
+# License: Released under the LGPL (GNU Lesser General Public License)
+# Description: checks whether a real server is up and running and if it is
+# then it starts the services
+# if this is the backup, monitor the master and float VIPs
+# Dependencies: /tmp/ipvsadm.d
+# configuration files created by /etc/init.d/ipvsadm
+# virt.* = virtual servers
+# *.stop = real server in down state ipvs table
+# *.start = real server in up state ipvs table
+# *.down = real server down status
+# ifconfig_${interface}_up acquire IPs
+# ifconfig_${interface}_down.sh release IPs
+################################################################################
+
+BASE_DIR=/tmp/ipvsadm.d
+TMP_DIR=$BASE_DIR
+REAL_SERVERS=realServers
+LOGFILE=/tmp/loadbalancer.log
+LOCKFILE=/tmp/ipvs_master.lock
+PROBE_COUNT=3
+
+logthis () {
+ MSG=$1
+ logger -p info $MSG
+ echo "`date +'%F %T'` - $MSG" >> $LOGFILE
+}
+
+### main ###
+
+role=`uci -q get ipvs.globals.role`
+if [ $role == 'backup' ] ; then
+ master=`uci -q get ipvs.globals.master`
+ RESULT=0
+ COUNT=0
+ for i in $master ; do
+ ping -qc 3 $i > /dev/null
+ RESULT=$(($RESULT + $?))
+ COUNT=$(($COUNT + 1))
+ done
+ if [ $COUNT -eq $RESULT ]; then
+ if [ ! -f $LOCKFILE ] ; then
+ logthis "Load Balancer $master is DOWN"
+ for i in ${BASE_DIR}/ifconfig_*_up.sh ; do
+ /bin/sh $i
+ done
+ date > $LOCKFILE
+ logthis "Master Load Balancer $master is DOWN: acquired floating IPs"
+ fi
+ else
+ if [ -f $LOCKFILE ] ; then
+ logthis "Load Balancer $master is UP"
+ for i in ${BASE_DIR}/ifconfig_*_down.sh ; do
+ /bin/sh $i
+ done
+ rm -f $LOCKFILE
+ logthis "Master Load Balancer $master is UP: released floating IPs"
+ fi
+ fi
+fi
+if [ -f $BASE_DIR/$REAL_SERVERS ]; then
+ for i in `cat $BASE_DIR/$REAL_SERVERS`; do
+ s_ipaddr=`uci -q get ipvs.$i.ipaddr`
+ s_probe_method=`uci -q get ipvs.$i.probe_method`
+ case $s_probe_method in
+ ping)
+ ping -qc $PROBE_COUNT $s_ipaddr > /dev/null
+ ;;
+ wget)
+ s_probe_url=`uci -q get ipvs.$i.probe_url`
+ wget -q -O /dev/null http://$s_ipaddr/$s_probe_url
+ ;;
+ esac
+ RESULT=$?
+ if [ $RESULT -gt 0 ]; then
+ if [ ! -f $TMP_DIR/$i.down ]; then
+ ipvsadm -R < $BASE_DIR/$i.stop
+ date > $TMP_DIR/$i.down
+ logthis "IPVS Server $i is down"
+ fi
+ else
+ if [ -f $TMP_DIR/$i.down ]; then
+ ipvsadm -R < $BASE_DIR/$i.start
+ rm $TMP_DIR/$i.down
+ logthis "IPVS Server $i $s_ipaddr is on-line"
+ fi
+ fi
+ done
+fi
--- /dev/null
+--- a/Makefile
++++ b/Makefile
+@@ -84,7 +84,7 @@ DEFINES += $(shell if [ ! -f ../ip_vs.h
+ all: libs ipvsadm
+
+ libs:
+- make -C libipvs
++ $(MAKE) -C libipvs
+
+ ipvsadm: $(OBJS) $(STATIC_LIBS)
+ $(CC) $(CFLAGS) -o $@ $^ $(LIBS)
+--- a/libipvs/Makefile
++++ b/libipvs/Makefile
+@@ -1,5 +1,6 @@
+ # Makefile for libipvs
+
++AR = ar
+ CC = gcc
+ CFLAGS = -Wall -Wunused -Wstrict-prototypes -g -fPIC
+ ifneq (0,$(HAVE_NL))
+@@ -17,11 +18,13 @@ INCLUDE += $(shell if [ -f ../../ip_vs.
+ echo "-I../../."; fi;)
+ DEFINES = $(shell if [ ! -f ../../ip_vs.h ]; then \
+ echo "-DHAVE_NET_IP_VS_H"; fi;)
++ifneq (0,$(HAVE_NL))
+ DEFINES += $(shell if which pkg-config > /dev/null 2>&1; then \
+ if pkg-config --exists libnl-3.0; then :; \
+ elif pkg-config --exists libnl-2.0; then :; \
+ elif pkg-config --exists libnl-1; \
+ then echo "-DFALLBACK_LIBNL1"; fi; fi)
++endif
+
+ .PHONY = all clean install dist distclean rpm rpms
+ STATIC_LIB = libipvs.a
+@@ -30,7 +33,7 @@ SHARED_LIB = libipvs.so
+ all: $(STATIC_LIB) $(SHARED_LIB)
+
+ $(STATIC_LIB): libipvs.o ip_vs_nl_policy.o
+- ar rv $@ $^
++ $(AR) rv $@ $^
+
+ $(SHARED_LIB): libipvs.o ip_vs_nl_policy.o
+ $(CC) -shared -Wl,-soname,$@ -o $@ $^
--- /dev/null
+diff -Naur a/ipvsadm-restore b/ipvsadm-restore
+--- a/ipvsadm-restore 2015-02-09 05:26:39.000000000 +0000
++++ b/ipvsadm-restore 2016-03-06 11:38:29.400884795 +0000
+@@ -1,4 +1,4 @@
+-#!/bin/bash
++#!/bin/sh
+ # ipvsadm-restore - Restore IPVS rules
+ #
+ # A very simple wrapper to restore IPVS rules
+@@ -11,6 +11,8 @@
+ # This file:
+ #
+ # ChangeLog
++# M. Mozzarelli : Amended to use /bin/sh for compatibility
++# : with embedded systems using busybox
+ # Horms : Clear IPVS rules before adding from STDIN
+ # Horms : Filter out "^#"
+ #
+diff -Naur a/ipvsadm-save b/ipvsadm-save
+--- a/ipvsadm-save 2015-02-09 05:26:39.000000000 +0000
++++ b/ipvsadm-save 2016-03-06 11:39:07.369444537 +0000
+@@ -1,4 +1,4 @@
+-#!/bin/bash
++#!/bin/sh
+ # ipvsadm-save - Save IPVS rules
+ #
+ # A very simple wrapper to save IPVS rules
+@@ -12,6 +12,8 @@
+ #
+ # ChangeLog
+ #
++# M. Mozzarelli : Amended to use /bin/sh for compatibility
++# : with embedded systems using busybox
+ # Wensong Zhang : Added the "-n" option and the help()
+ #
+