Sophie

Sophie

distrib > Mageia > 7 > armv7hl > by-pkgid > 48803323d43fd57d74f0b73febd7a1f3 > files > 3

quagga-contrib-1.2.4-2.mga7.armv7hl.rpm

#!/bin/bash

# Public domain, not copyrighted..

set -u

# number of bgpd instances, not more than 255 at this point.  At least 3 are
# needed to connect in a ring.
NUM=7

# The NUM peers can be connected in a ring topology.
#
# This sets the proportion of other peers that each peer should be
# configured to connect to E.g., 20 means each BGP instance will peer with
# 20% of the other peers before and after it in the ring.  So 10% of the
# peers prior to this instance in the ring, and 10% of the following peers. 
# 100 should lead to a full-mesh, for an odd total number of peers.
#
# A value of 1 will result in each instance having at least 2 peers in the ring.
#
# A value of 0 will disable creating a ring, in which case the only peers 
# configured will be those in the EXPEERS list.
PEERPROP=100

# number of routes each BGP instance should advertise
ADV=10
# First octet to use for the IPv4 advertisements.  The advertisements
# will be /32s under this /8.  E.g.  ADVPREF=10 will mean
# 10.x.y.z/32's are advertised.
ADVPREF=10

# Base VTY port to allocate Quagga telnet vtys from. VTYBASE+ID will be
# the port.
VTYBASE=2610
# Base ASN to allocate ASNs to instances.
ASBASE=64500
PREFIX=192.168.145.
#PREFIX=3ffe:123:456::
ADDRPLEN=32
CONFBASE=/tmp
PIDBASE=/var/run/quagga
USER=quagga
GROUP=quagga

# MRAI to specify, where an implementation supports it.
MRAI=1
# Connect retry timer
CONNECTRETRY=1

# The binary locations for BGP instances. 
declare -A BGP_BINS=(
	[quagga]=/usr/sbin/bgpd
	[bird]=/usr/sbin/bird
	[birdgit]=/home/paul/code/bird/bird
	[quaggagit]=/home/paul/code/quagga/bgpd/bgpd
	[exabgp]=/home/paul/code/exabgp/sbin/exabgp
)

# Configuration generation functions for the BGP instances.
declare -A BGP_CONFIGGEN=(
	[quagga]=quagga_config
	[quaggagit]=quagga_config
	[bird]=bird_config
	[birdgit]=bird_config
	[exabgp]=exabgp_config
)

# Launch functions for the BGP instances.
declare -A BGP_LAUNCH=(
	[quagga]=quagga_launch
	[quaggagit]=quagga_launch
	[bird]=bird_launch
	[birdgit]=bird_launch
	[quaggagit]=quagga_launch
	[exabgp]=exabgp_launch
)

# the instances to run, in the order they should appear in the ring
# (repeated over until there are $NUM instances).  The value must exist as a
# key into the above two arrays.
declare -a BGP_INSTANCES=(
	quagga
	bird
	quaggagit
	exabgp
)

# Peers to configure, that are external to this script. One list of IPs, with
# corresponding list of their ASes.
#
# e.g.:
#EXPEERS=(192.168.147.{1..10})
#EXPEERASES=($(seq $((ASBASE+11)) $(($ASBASE+20))))

EXPEERS=()
EXPEERASES=()

############################################################################
# Can override any of the above from a supplied file with declarations
CONFWRITE=Y
if [ $# -gt 0 ] ; then
	echo "multiple-bgpd.sh: sourcing config from $1"
	[ -f "$1" ] && . "$1"
	
	# keep config, if exists
	[ $# -gt 1 ] && [ "$2" = "k" ] && CONFWRITE=N	
fi

############################################################################
# Internal variables.

# Number of peers for each instance to peer with
PEERNUM=$(( ($NUM-1) * $PEERPROP / 100  ))
[ "$PEERNUM" -gt $(($NUM-1)) ] && PEERNUM=$(($NUM-1))

# the 'range', i.e.  how many of the previous and next peers in the ring to
# connect to
PEERRANGE=$(( $PEERNUM/2 ))
[ "$PEERPROP" -gt 0 -a "$NUM" -ge 3 -a  "$PEERRANGE" -le 0 ] && PEERRANGE=1

# and a convenience expansion
PEEREXP=""
if [ "$PEERRANGE" -gt 0 ]; then
	PEEREXP=($(seq -${PEERRANGE} ${PEERRANGE}))
	# dont need 0
	unset PEEREXP[PEERRANGE]
fi

#echo ${PEEREXP[@]}

############################################################################
## helpers

# translate instance ID to its address.
id2addr () {
	local ID=$1
	echo ${PREFIX}${ID}
}

# return the ID of a peer, in terms of an offset on the given instance's ID.
#
# E.g., given an ID of 1 and an offset of -1, if there are 10 instances overall,
# this will return 10.
peeridoff () {
	local ID=$1
	local OFF=$2
	echo $(( (($ID + $OFF - 1  + $NUM) % $NUM) + 1  ))
}

# return IPv4 address to advertise, for given instance ID and number.
advipaddr () {
	local ID=$1
	local N=$2
	echo "$ADVPREF.$(( ($N >> 16) %256 )).$(( ($N >> 8) % 256 )).$(( $N % 256  ))"
}

############################################################################
# launch functions
#
# do not daemonise, so that all launched instances can be killed by killing
# the script.
#

quagga_launch () {
	local ID=$1
	local ASN=$2
	local ADDR=$3
	local BIN=$4
	local CONF=$5
	${BIN} -i "${PIDBASE}"/bgpd${ID}.pid \
		   -l ${ADDR} \
		   -f "${CONF}" \
		   -u $USER -g $GROUP \
		   -P $((${VTYBASE}+${ID}))
}

exabgp_launch () {
	local ID=$1
	local ASN=$2
	local ADDR=$3
	local BIN=$4
	local CONF=$5
	
	env exabgp.api.file="${PIDBASE}"/exabgp${ID}.ctl \
	exabgp.daemon.pid="${PIDBASE}"/bgpd${ID}.pid \
	exabgp.daemon.daemonize=false \
	exabgp.tcp.bind=${ADDR} \
	exabgp.log.enable=false \
	exabgp.daemon.user=quagga \
	${BIN} ${CONF}
}

bird_launch () {
	local ID=$1
	local ASN=$2
	local ADDR=$3
	local BIN=$4
	local CONF=$5
	${BIN} -P "${PIDBASE}"/bird${ID}.pid \
		   -c "${CONF}" \
		   -s "${PIDBASE}"/bird${ID}.ctl \
		   -f
}

#######################################################################
#
# functions to write the configuration for instances
#

exabgp_config () {
	local ID=$1
	local ASN=$2
	local ADDR=$3
	
	local N
	local P
	
	cat <<- EOF
		group default {
		  local-address $ADDR;
		  local-as $ASN;
		  router-id $ADDR;
		  
		  capability {
		    asn4 enable;
		  }
	EOF
	
	for N in $(seq 1 $ADV) ; do
		echo "  static {"
		echo "    route `advipaddr $ID $N`/32 {"
		echo "      next-hop $ADDR;"
		echo "    }"
		echo "  }" 
	done

	for P in ${PEEREXP[@]};  do
		[ "$P" -eq 0 ] && continue;
		
		#local PID=$(( (($ID + $P - 1  + $NUM) % $NUM) + 1  ))
		local PID=`peeridoff $ID $P`
		#local PADDR="${PREFIX}${PID}"
		local PADDR=`id2addr $PID`
		local PAS=$((${ASBASE} + $PID))
		
		echo "  neighbor $PADDR {"
		#echo "    local-address $ADDR;"
		#echo "    local-as $ASN;"
		#echo "    graceful-restart;"
		#echo "    router-id $ADDR;"
		echo "    peer-as $PAS;"
		echo "  }"
	done
	
	for P in ${!EXPEERS[@]};  do
		echo "  neighbor ${EXPEERS[$P]} {"
		echo "    peer-as ${EXPEERASES[$P]};"
		echo "  }"
	done
	
	cat <<- EOF
		}
	EOF
}

quagga_config () {
	local ID=$1
	local ASN=$2
	local ADDR=$3
	
	local N
	local P
	
	# Edit config to suit.
	cat <<- EOF
		password foo
		service advanced-vty
		!
		router bgp ${ASN}
		 bgp router-id ${ADDR}
		 !maximum-paths 32
		 !bgp bestpath as-path multipath-relax
	EOF

	for N in $(seq 1 $ADV) ; do
		echo " network `advipaddr $ID $N`/32"
	done

	cat <<- EOF
		 neighbor default peer-group
		 neighbor default update-source ${ADDR}
		 neighbor default capability orf prefix-list both
		 !neighbor default soft-reconfiguration inbound
		 neighbor default advertisement-interval $MRAI
		 neighbor default timers connect $CONNECTRETRY
		 neighbor default route-map test out
	EOF

	for P in ${PEEREXP[@]};  do
		[ "$P" -eq 0 ] && continue;
		
		local PID=`peeridoff $ID $P`
		local PADDR=`id2addr $PID`
		local PAS=$((${ASBASE} + $PID))
		echo " neighbor ${PADDR} remote-as ${PAS}"
		echo " neighbor ${PADDR} peer-group default"
	done

	for P in ${!EXPEERS[@]};  do
		echo " neighbor ${EXPEERS[$P]} remote-as ${EXPEERASES[$P]}"
		echo " neighbor ${EXPEERS[$P]} peer-group default"
	done

	cat <<- EOF
		!
		 address-family ipv6
		 network 3ffe:${ID}::/48
		 network 3ffe:${ID}:1::/48 pathlimit 1
		 network 3ffe:${ID}:2::/48 pathlimit 3
		 network 3ffe:${ID}:3::/48 pathlimit 3
		 neighbor default activate
		 neighbor default capability orf prefix-list both
		 neighbor default default-originate
		 neighbor default route-map test out
	EOF

	for P in ${PEEREXP[@]};  do
		[ "$P" -eq 0 ] && continue;
		
		local PID=`peeridoff $ID $P`
		local PADDR=`id2addr $PID`
		local PAS=$((${ASBASE} + $PID))
		echo " neighbor ${PADDR} peer-group default"
	done

	cat <<- EOF
		 exit-address-family
		!
		! bgpd still has problems with extcommunity rt/soo
		route-map test permit 10
		 set extcommunity rt ${ASN}:1
		 set extcommunity soo ${ASN}:2
		 set community ${ASN}:1
		!
		line vty
		 exec-timeout 0 0
		!
		end
	EOF
}

bird_config () {
	local ID=$1
	local ASN=$2
	local ADDR=$3

	cat <<- EOF
		#log "/var/log/bird.log" all;
		#debug protocols all;

		# Override router ID
		router id ${ADDR};
		listen bgp address ${ADDR};
		
		protocol kernel { device routes; import all; }
		protocol device { import all; }
		
		function avoid_martians()
		prefix set martians;
		{
		  martians = [ 
		  	       224.0.0.0/4+, 240.0.0.0/4+
		  	     ];

		  # Avoid RFC1918 and similar networks
		  if net ~ martians then return false;
		  return true;
		}
		
		filter import_filter
		{
		  if ! (avoid_martians()) then reject;
		  accept;
		}
		
		filter set_comm
		{
		  bgp_community.add ((${ASN}, 1));
		  accept;
		}
		
		template bgp peer_conf {
		  local as ${ASN};
		  source address ${ADDR};
		  import filter import_filter;
		  export filter set_comm;
		  multihop;
		}
	EOF
	
	local P;
	
	for P in ${PEEREXP[@]};  do
		[ "$P" -eq 0 ] && continue;
		
		local PID=`peeridoff $ID $P`
		local PADDR=`id2addr $PID`
		local PAS=$((${ASBASE} + $PID))
		echo "protocol bgp from peer_conf {"
		echo " neighbor ${PADDR} as  ${PAS};"
		echo "}"
	done
	
	for P in ${!EXPEERS[@]};  do
		echo "protocol bgp from peer_conf {"
		echo " neighbor ${EXPEERS[$P]} as ${EXPEERASES[$P]};"
		echo "}"
	done
	
	
	for N in $(seq 1 $ADV) ; do
		echo " network `advipaddr $ID $N`/32"
	done
}

#######################################################################

for ID in $(seq 1 $NUM); do
	BGP_INST=${BGP_INSTANCES[${ID} % ${#BGP_INSTANCES[@]}]}
	BGPBIN=${BGP_BINS[$BGP_INST]}
	CONF="${CONFBASE}"/${BGP_INST}_bgpd${ID}.conf
	ASN=$(($ASBASE + ${ID}))
	ADDR=`id2addr $ID`
	
	#if [ ! -e "$CONF" ] ; then
	if [ ! -e "$CONF" -o "$CONFWRITE" = "Y" ] ; then 
		${BGP_CONFIGGEN[$BGP_INST]} $ID $ASN $ADDR > "$CONF"
		chown $USER:$GROUP "$CONF"
	fi
	# You may want to automatically add configure a local address
	# on a loop interface.
	#
	# Solaris: ifconfig vni${H} plumb ${ADDR}/${ADDRPLEN} up
	# Linux:
	#ip address add ${ADDR}/${ADDRPLEN} dev lo 2> /dev/null
	
	ip link add dummy${ID} type dummy 2> /dev/null
	ip link set dev dummy${ID} up
	ip address add ${ADDR}/${ADDRPLEN} dev dummy${ID} 2> /dev/null
	
	${BGP_LAUNCH[$BGP_INST]} $ID $ASN $ADDR $BGPBIN $CONF &
	
	sleep 0.1
done

echo "multiple-bgpd.sh: waiting..."

wait