123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- #!/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
|