ipvsadm: add Virtual Server Administration Tool
authorMauro Mozzarelli <mauro@ezplanet.org>
Tue, 7 Mar 2017 18:27:37 +0000 (18:27 +0000)
committerJo-Philipp Wich <jo@mein.io>
Wed, 14 Aug 2019 05:56:57 +0000 (07:56 +0200)
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. The active node
of the cluster redirects service requests to a collection of server hosts
that will actually perform the services.

Supported features include two protocols (TCP and UDP), three packet-
forwarding methods (NAT, tunneling, and direct routing), and eight load
balancing algorithms (round robin, weighted round robin, least-connection,
weighted least-connection, locality-based least-connection, locality-based
least-connection with replication, destination-hashing, and source-hashing).

This change adds the following:
- ipvsadm: kernel netfilter Virtual Server Load Balancer administration tool
- VS load balancer lede configuration file
- VS load balancer lede init script
- VS load balancer automated monitoring and failover tool

Signed-off-by: Mauro Mozzarelli <mauro@ezplanet.org>
[Jo-Philipp Wich: rewrap commit message, reword subject, rewrap package
                  description, reset PKG_RELEASE, remove commented flags,
                  use explicit INSTALL_BIN instead of chmod, make cross-
                  compile safe, rework compile steps]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
package/network/utils/ipvsadm/Makefile [new file with mode: 0644]
package/network/utils/ipvsadm/files/etc/config/ipvs [new file with mode: 0644]
package/network/utils/ipvsadm/files/etc/init.d/ipvsadm [new file with mode: 0644]
package/network/utils/ipvsadm/files/usr/sbin/checkRealServers [new file with mode: 0644]
package/network/utils/ipvsadm/patches/900-cross-compile-fixes.patch [new file with mode: 0644]
package/network/utils/ipvsadm/patches/901-do-not-hardcode-bash.patch [new file with mode: 0644]

diff --git a/package/network/utils/ipvsadm/Makefile b/package/network/utils/ipvsadm/Makefile
new file mode 100644 (file)
index 0000000..b930c07
--- /dev/null
@@ -0,0 +1,68 @@
+#
+# 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))
diff --git a/package/network/utils/ipvsadm/files/etc/config/ipvs b/package/network/utils/ipvsadm/files/etc/config/ipvs
new file mode 100644 (file)
index 0000000..15c1ce9
--- /dev/null
@@ -0,0 +1,63 @@
+# 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'
diff --git a/package/network/utils/ipvsadm/files/etc/init.d/ipvsadm b/package/network/utils/ipvsadm/files/etc/init.d/ipvsadm
new file mode 100644 (file)
index 0000000..fa193ef
--- /dev/null
@@ -0,0 +1,295 @@
+#!/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 -
+}
diff --git a/package/network/utils/ipvsadm/files/usr/sbin/checkRealServers b/package/network/utils/ipvsadm/files/usr/sbin/checkRealServers
new file mode 100644 (file)
index 0000000..9e29273
--- /dev/null
@@ -0,0 +1,91 @@
+#!/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
diff --git a/package/network/utils/ipvsadm/patches/900-cross-compile-fixes.patch b/package/network/utils/ipvsadm/patches/900-cross-compile-fixes.patch
new file mode 100644 (file)
index 0000000..92cfc19
--- /dev/null
@@ -0,0 +1,43 @@
+--- 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 $@ $^
diff --git a/package/network/utils/ipvsadm/patches/901-do-not-hardcode-bash.patch b/package/network/utils/ipvsadm/patches/901-do-not-hardcode-bash.patch
new file mode 100644 (file)
index 0000000..7e297e2
--- /dev/null
@@ -0,0 +1,36 @@
+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()
+ #