multiple-bgpd.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. #!/bin/bash
  2. # Public domain, not copyrighted..
  3. set -u
  4. # number of bgpd instances, not more than 255 at this point. At least 3 are
  5. # needed to connect in a ring.
  6. NUM=7
  7. # The NUM peers can be connected in a ring topology.
  8. #
  9. # This sets the proportion of other peers that each peer should be
  10. # configured to connect to E.g., 20 means each BGP instance will peer with
  11. # 20% of the other peers before and after it in the ring. So 10% of the
  12. # peers prior to this instance in the ring, and 10% of the following peers.
  13. # 100 should lead to a full-mesh, for an odd total number of peers.
  14. #
  15. # A value of 1 will result in each instance having at least 2 peers in the ring.
  16. #
  17. # A value of 0 will disable creating a ring, in which case the only peers
  18. # configured will be those in the EXPEERS list.
  19. PEERPROP=100
  20. # number of routes each BGP instance should advertise
  21. ADV=10
  22. # First octet to use for the IPv4 advertisements. The advertisements
  23. # will be /32s under this /8. E.g. ADVPREF=10 will mean
  24. # 10.x.y.z/32's are advertised.
  25. ADVPREF=10
  26. # Base VTY port to allocate Quagga telnet vtys from. VTYBASE+ID will be
  27. # the port.
  28. VTYBASE=2610
  29. # Base ASN to allocate ASNs to instances.
  30. ASBASE=64500
  31. PREFIX=192.168.145.
  32. #PREFIX=3ffe:123:456::
  33. ADDRPLEN=32
  34. CONFBASE=/tmp
  35. PIDBASE=/var/run/quagga
  36. USER=quagga
  37. GROUP=quagga
  38. # MRAI to specify, where an implementation supports it.
  39. MRAI=1
  40. # Connect retry timer
  41. CONNECTRETRY=1
  42. # The binary locations for BGP instances.
  43. declare -A BGP_BINS=(
  44. [quagga]=/usr/sbin/bgpd
  45. [bird]=/usr/sbin/bird
  46. [birdgit]=/home/paul/code/bird/bird
  47. [quaggagit]=/home/paul/code/quagga/bgpd/bgpd
  48. [exabgp]=/home/paul/code/exabgp/sbin/exabgp
  49. )
  50. # Configuration generation functions for the BGP instances.
  51. declare -A BGP_CONFIGGEN=(
  52. [quagga]=quagga_config
  53. [quaggagit]=quagga_config
  54. [bird]=bird_config
  55. [birdgit]=bird_config
  56. [exabgp]=exabgp_config
  57. )
  58. # Launch functions for the BGP instances.
  59. declare -A BGP_LAUNCH=(
  60. [quagga]=quagga_launch
  61. [quaggagit]=quagga_launch
  62. [bird]=bird_launch
  63. [birdgit]=bird_launch
  64. [quaggagit]=quagga_launch
  65. [exabgp]=exabgp_launch
  66. )
  67. # the instances to run, in the order they should appear in the ring
  68. # (repeated over until there are $NUM instances). The value must exist as a
  69. # key into the above two arrays.
  70. declare -a BGP_INSTANCES=(
  71. quagga
  72. bird
  73. quaggagit
  74. exabgp
  75. )
  76. # Peers to configure, that are external to this script. One list of IPs, with
  77. # corresponding list of their ASes.
  78. #
  79. # e.g.:
  80. #EXPEERS=(192.168.147.{1..10})
  81. #EXPEERASES=($(seq $((ASBASE+11)) $(($ASBASE+20))))
  82. EXPEERS=()
  83. EXPEERASES=()
  84. ############################################################################
  85. # Can override any of the above from a supplied file with declarations
  86. CONFWRITE=Y
  87. if [ $# -gt 0 ] ; then
  88. echo "multiple-bgpd.sh: sourcing config from $1"
  89. [ -f "$1" ] && . "$1"
  90. # keep config, if exists
  91. [ $# -gt 1 ] && [ "$2" = "k" ] && CONFWRITE=N
  92. fi
  93. ############################################################################
  94. # Internal variables.
  95. # Number of peers for each instance to peer with
  96. PEERNUM=$(( ($NUM-1) * $PEERPROP / 100 ))
  97. [ "$PEERNUM" -gt $(($NUM-1)) ] && PEERNUM=$(($NUM-1))
  98. # the 'range', i.e. how many of the previous and next peers in the ring to
  99. # connect to
  100. PEERRANGE=$(( $PEERNUM/2 ))
  101. [ "$PEERPROP" -gt 0 -a "$NUM" -ge 3 -a "$PEERRANGE" -le 0 ] && PEERRANGE=1
  102. # and a convenience expansion
  103. PEEREXP=""
  104. if [ "$PEERRANGE" -gt 0 ]; then
  105. PEEREXP=($(seq -${PEERRANGE} ${PEERRANGE}))
  106. # dont need 0
  107. unset PEEREXP[PEERRANGE]
  108. fi
  109. #echo ${PEEREXP[@]}
  110. ############################################################################
  111. ## helpers
  112. # translate instance ID to its address.
  113. id2addr () {
  114. local ID=$1
  115. echo ${PREFIX}${ID}
  116. }
  117. # return the ID of a peer, in terms of an offset on the given instance's ID.
  118. #
  119. # E.g., given an ID of 1 and an offset of -1, if there are 10 instances overall,
  120. # this will return 10.
  121. peeridoff () {
  122. local ID=$1
  123. local OFF=$2
  124. echo $(( (($ID + $OFF - 1 + $NUM) % $NUM) + 1 ))
  125. }
  126. # return IPv4 address to advertise, for given instance ID and number.
  127. advipaddr () {
  128. local ID=$1
  129. local N=$2
  130. echo "$ADVPREF.$(( ($N >> 16) %256 )).$(( ($N >> 8) % 256 )).$(( $N % 256 ))"
  131. }
  132. ############################################################################
  133. # launch functions
  134. #
  135. # do not daemonise, so that all launched instances can be killed by killing
  136. # the script.
  137. #
  138. quagga_launch () {
  139. local ID=$1
  140. local ASN=$2
  141. local ADDR=$3
  142. local BIN=$4
  143. local CONF=$5
  144. ${BIN} -i "${PIDBASE}"/bgpd${ID}.pid \
  145. -l ${ADDR} \
  146. -f "${CONF}" \
  147. -u $USER -g $GROUP \
  148. -P $((${VTYBASE}+${ID}))
  149. }
  150. exabgp_launch () {
  151. local ID=$1
  152. local ASN=$2
  153. local ADDR=$3
  154. local BIN=$4
  155. local CONF=$5
  156. env exabgp.api.file="${PIDBASE}"/exabgp${ID}.ctl \
  157. exabgp.daemon.pid="${PIDBASE}"/bgpd${ID}.pid \
  158. exabgp.daemon.daemonize=false \
  159. exabgp.tcp.bind=${ADDR} \
  160. exabgp.log.enable=false \
  161. exabgp.daemon.user=quagga \
  162. ${BIN} ${CONF}
  163. }
  164. bird_launch () {
  165. local ID=$1
  166. local ASN=$2
  167. local ADDR=$3
  168. local BIN=$4
  169. local CONF=$5
  170. ${BIN} -P "${PIDBASE}"/bird${ID}.pid \
  171. -c "${CONF}" \
  172. -s "${PIDBASE}"/bird${ID}.ctl \
  173. -f
  174. }
  175. #######################################################################
  176. #
  177. # functions to write the configuration for instances
  178. #
  179. exabgp_config () {
  180. local ID=$1
  181. local ASN=$2
  182. local ADDR=$3
  183. local N
  184. local P
  185. cat <<- EOF
  186. group default {
  187. local-address $ADDR;
  188. local-as $ASN;
  189. router-id $ADDR;
  190. capability {
  191. asn4 enable;
  192. }
  193. EOF
  194. for N in $(seq 1 $ADV) ; do
  195. echo " static {"
  196. echo " route `advipaddr $ID $N`/32 {"
  197. echo " next-hop $ADDR;"
  198. echo " }"
  199. echo " }"
  200. done
  201. for P in ${PEEREXP[@]}; do
  202. [ "$P" -eq 0 ] && continue;
  203. #local PID=$(( (($ID + $P - 1 + $NUM) % $NUM) + 1 ))
  204. local PID=`peeridoff $ID $P`
  205. #local PADDR="${PREFIX}${PID}"
  206. local PADDR=`id2addr $PID`
  207. local PAS=$((${ASBASE} + $PID))
  208. echo " neighbor $PADDR {"
  209. #echo " local-address $ADDR;"
  210. #echo " local-as $ASN;"
  211. #echo " graceful-restart;"
  212. #echo " router-id $ADDR;"
  213. echo " peer-as $PAS;"
  214. echo " }"
  215. done
  216. for P in ${!EXPEERS[@]}; do
  217. echo " neighbor ${EXPEERS[$P]} {"
  218. echo " peer-as ${EXPEERASES[$P]};"
  219. echo " }"
  220. done
  221. cat <<- EOF
  222. }
  223. EOF
  224. }
  225. quagga_config () {
  226. local ID=$1
  227. local ASN=$2
  228. local ADDR=$3
  229. local N
  230. local P
  231. # Edit config to suit.
  232. cat <<- EOF
  233. password foo
  234. service advanced-vty
  235. !
  236. router bgp ${ASN}
  237. bgp router-id ${ADDR}
  238. !maximum-paths 32
  239. !bgp bestpath as-path multipath-relax
  240. EOF
  241. for N in $(seq 1 $ADV) ; do
  242. echo " network `advipaddr $ID $N`/32"
  243. done
  244. cat <<- EOF
  245. neighbor default peer-group
  246. neighbor default update-source ${ADDR}
  247. neighbor default capability orf prefix-list both
  248. !neighbor default soft-reconfiguration inbound
  249. neighbor default advertisement-interval $MRAI
  250. neighbor default timers connect $CONNECTRETRY
  251. neighbor default route-map test out
  252. EOF
  253. for P in ${PEEREXP[@]}; do
  254. [ "$P" -eq 0 ] && continue;
  255. local PID=`peeridoff $ID $P`
  256. local PADDR=`id2addr $PID`
  257. local PAS=$((${ASBASE} + $PID))
  258. echo " neighbor ${PADDR} remote-as ${PAS}"
  259. echo " neighbor ${PADDR} peer-group default"
  260. done
  261. for P in ${!EXPEERS[@]}; do
  262. echo " neighbor ${EXPEERS[$P]} remote-as ${EXPEERASES[$P]}"
  263. echo " neighbor ${EXPEERS[$P]} peer-group default"
  264. done
  265. cat <<- EOF
  266. !
  267. address-family ipv6
  268. network 3ffe:${ID}::/48
  269. network 3ffe:${ID}:1::/48 pathlimit 1
  270. network 3ffe:${ID}:2::/48 pathlimit 3
  271. network 3ffe:${ID}:3::/48 pathlimit 3
  272. neighbor default activate
  273. neighbor default capability orf prefix-list both
  274. neighbor default default-originate
  275. neighbor default route-map test out
  276. EOF
  277. for P in ${PEEREXP[@]}; do
  278. [ "$P" -eq 0 ] && continue;
  279. local PID=`peeridoff $ID $P`
  280. local PADDR=`id2addr $PID`
  281. local PAS=$((${ASBASE} + $PID))
  282. echo " neighbor ${PADDR} peer-group default"
  283. done
  284. cat <<- EOF
  285. exit-address-family
  286. !
  287. ! bgpd still has problems with extcommunity rt/soo
  288. route-map test permit 10
  289. set extcommunity rt ${ASN}:1
  290. set extcommunity soo ${ASN}:2
  291. set community ${ASN}:1
  292. !
  293. line vty
  294. exec-timeout 0 0
  295. !
  296. end
  297. EOF
  298. }
  299. bird_config () {
  300. local ID=$1
  301. local ASN=$2
  302. local ADDR=$3
  303. cat <<- EOF
  304. #log "/var/log/bird.log" all;
  305. #debug protocols all;
  306. # Override router ID
  307. router id ${ADDR};
  308. listen bgp address ${ADDR};
  309. protocol kernel { device routes; import all; }
  310. protocol device { import all; }
  311. function avoid_martians()
  312. prefix set martians;
  313. {
  314. martians = [
  315. 224.0.0.0/4+, 240.0.0.0/4+
  316. ];
  317. # Avoid RFC1918 and similar networks
  318. if net ~ martians then return false;
  319. return true;
  320. }
  321. filter import_filter
  322. {
  323. if ! (avoid_martians()) then reject;
  324. accept;
  325. }
  326. filter set_comm
  327. {
  328. bgp_community.add ((${ASN}, 1));
  329. accept;
  330. }
  331. template bgp peer_conf {
  332. local as ${ASN};
  333. source address ${ADDR};
  334. import filter import_filter;
  335. export filter set_comm;
  336. multihop;
  337. }
  338. EOF
  339. local P;
  340. for P in ${PEEREXP[@]}; do
  341. [ "$P" -eq 0 ] && continue;
  342. local PID=`peeridoff $ID $P`
  343. local PADDR=`id2addr $PID`
  344. local PAS=$((${ASBASE} + $PID))
  345. echo "protocol bgp from peer_conf {"
  346. echo " neighbor ${PADDR} as ${PAS};"
  347. echo "}"
  348. done
  349. for P in ${!EXPEERS[@]}; do
  350. echo "protocol bgp from peer_conf {"
  351. echo " neighbor ${EXPEERS[$P]} as ${EXPEERASES[$P]};"
  352. echo "}"
  353. done
  354. for N in $(seq 1 $ADV) ; do
  355. echo " network `advipaddr $ID $N`/32"
  356. done
  357. }
  358. #######################################################################
  359. for ID in $(seq 1 $NUM); do
  360. BGP_INST=${BGP_INSTANCES[${ID} % ${#BGP_INSTANCES[@]}]}
  361. BGPBIN=${BGP_BINS[$BGP_INST]}
  362. CONF="${CONFBASE}"/${BGP_INST}_bgpd${ID}.conf
  363. ASN=$(($ASBASE + ${ID}))
  364. ADDR=`id2addr $ID`
  365. #if [ ! -e "$CONF" ] ; then
  366. if [ ! -e "$CONF" -o "$CONFWRITE" = "Y" ] ; then
  367. ${BGP_CONFIGGEN[$BGP_INST]} $ID $ASN $ADDR > "$CONF"
  368. chown $USER:$GROUP "$CONF"
  369. fi
  370. # You may want to automatically add configure a local address
  371. # on a loop interface.
  372. #
  373. # Solaris: ifconfig vni${H} plumb ${ADDR}/${ADDRPLEN} up
  374. # Linux:
  375. #ip address add ${ADDR}/${ADDRPLEN} dev lo 2> /dev/null
  376. ip link add dummy${ID} type dummy 2> /dev/null
  377. ip link set dev dummy${ID} up
  378. ip address add ${ADDR}/${ADDRPLEN} dev dummy${ID} 2> /dev/null
  379. ${BGP_LAUNCH[$BGP_INST]} $ID $ASN $ADDR $BGPBIN $CONF &
  380. sleep 0.1
  381. done
  382. echo "multiple-bgpd.sh: waiting..."
  383. wait