|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Licensed to the Apache Software Foundation (ASF) under one |
| 3 | +# or more contributor license agreements. See the NOTICE file |
| 4 | +# distributed with this work for additional information |
| 5 | +# regarding copyright ownership. The ASF licenses this file |
| 6 | +# to you under the Apache License, Version 2.0 (the |
| 7 | +# "License"); you may not use this file except in compliance |
| 8 | +# with the License. You may obtain a copy of the License at |
| 9 | +# |
| 10 | +# http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | +# |
| 12 | +# Unless required by applicable law or agreed to in writing, |
| 13 | +# software distributed under the License is distributed on an |
| 14 | +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | +# KIND, either express or implied. See the License for the |
| 16 | +# specific language governing permissions and limitations |
| 17 | +# under the License. |
| 18 | + |
| 19 | +# |
| 20 | +# Use BGP+EVPN for VXLAN with CloudStack instead of Multicast |
| 21 | +# |
| 22 | +# The default 'modifyvxlan.sh' script from CloudStack uses Multicast instead of EVPN for VXLAN |
| 23 | +# In order to use this script and thus utilize BGP+EVPN, symlink this file: |
| 24 | +# |
| 25 | +# cd /usr/share |
| 26 | +# ln -s cloudstack-common/scripts/vm/network/vnet/modifyvxlan-evpn.sh modifyvxlan.sh |
| 27 | +# |
| 28 | +# |
| 29 | +# CloudStack will not handle the BGP configuration nor communication, the operator of the hypervisor will |
| 30 | +# need to configure the properly. |
| 31 | +# |
| 32 | +# Frrouting is recommend to be used on the hypervisor to establish BGP sessions with upstream routers and |
| 33 | +# exchange BGP+EVPN information. |
| 34 | +# |
| 35 | +# More information about BGP and EVPN with FRR: https://vincent.bernat.ch/en/blog/2017-vxlan-bgp-evpn |
| 36 | +# |
| 37 | + |
| 38 | +DSTPORT=4789 |
| 39 | + |
| 40 | +# We bind our VXLAN tunnel IP(v4) on Loopback device 'lo' |
| 41 | +DEV="lo" |
| 42 | + |
| 43 | +usage() { |
| 44 | + echo "Usage: $0: -o <op>(add | delete) -v <vxlan id> -p <pif> -b <bridge name> (-6)" |
| 45 | +} |
| 46 | + |
| 47 | +localAddr() { |
| 48 | + local FAMILY=$1 |
| 49 | + |
| 50 | + if [[ -z "$FAMILY" || $FAMILY == "inet" ]]; then |
| 51 | + ip -4 -o addr show scope global dev ${DEV} | awk 'NR==1 {gsub("/[0-9]+", "") ; print $4}' |
| 52 | + fi |
| 53 | + |
| 54 | + if [[ "$FAMILY" == "inet6" ]]; then |
| 55 | + ip -6 -o addr show scope global dev ${DEV} | awk 'NR==1 {gsub("/[0-9]+", "") ; print $4}' |
| 56 | + fi |
| 57 | +} |
| 58 | + |
| 59 | +addVxlan() { |
| 60 | + local VNI=$1 |
| 61 | + local PIF=$2 |
| 62 | + local VXLAN_BR=$3 |
| 63 | + local FAMILY=$4 |
| 64 | + local VXLAN_DEV=vxlan${VNI} |
| 65 | + local ADDR=$(localAddr ${FAMILY}) |
| 66 | + |
| 67 | + echo "local addr for VNI ${VNI} is ${ADDR}" |
| 68 | + |
| 69 | + if [[ ! -d /sys/class/net/${VXLAN_DEV} ]]; then |
| 70 | + ip -f ${FAMILY} link add ${VXLAN_DEV} type vxlan id ${VNI} local ${ADDR} dstport ${DSTPORT} nolearning |
| 71 | + ip link set ${VXLAN_DEV} up |
| 72 | + sysctl -qw net.ipv6.conf.${VXLAN_DEV}.disable_ipv6=1 |
| 73 | + fi |
| 74 | + |
| 75 | + if [[ ! -d /sys/class/net/$VXLAN_BR ]]; then |
| 76 | + ip link add name ${VXLAN_BR} type bridge |
| 77 | + ip link set ${VXLAN_BR} up |
| 78 | + sysctl -qw net.ipv6.conf.${VXLAN_BR}.disable_ipv6=1 |
| 79 | + fi |
| 80 | + |
| 81 | + bridge link show|grep ${VXLAN_BR}|awk '{print $2}'|grep "^${VXLAN_DEV}\$" > /dev/null |
| 82 | + if [[ $? -gt 0 ]]; then |
| 83 | + ip link set ${VXLAN_DEV} master ${VXLAN_BR} |
| 84 | + fi |
| 85 | +} |
| 86 | + |
| 87 | +deleteVxlan() { |
| 88 | + local VNI=$1 |
| 89 | + local PIF=$2 |
| 90 | + local VXLAN_BR=$3 |
| 91 | + local FAMILY=$4 |
| 92 | + local VXLAN_DEV=vxlan${VNI} |
| 93 | + |
| 94 | + ip link set ${VXLAN_DEV} nomaster |
| 95 | + ip link delete ${VXLAN_DEV} |
| 96 | + |
| 97 | + ip link set ${VXLAN_BR} down |
| 98 | + ip link delete ${VXLAN_BR} type bridge |
| 99 | +} |
| 100 | + |
| 101 | +OP= |
| 102 | +VNI= |
| 103 | +FAMILY=inet |
| 104 | +option=$@ |
| 105 | + |
| 106 | +while getopts 'o:v:p:b:6' OPTION |
| 107 | +do |
| 108 | + case $OPTION in |
| 109 | + o) oflag=1 |
| 110 | + OP="$OPTARG" |
| 111 | + ;; |
| 112 | + v) vflag=1 |
| 113 | + VNI="$OPTARG" |
| 114 | + ;; |
| 115 | + p) pflag=1 |
| 116 | + PIF="$OPTARG" |
| 117 | + ;; |
| 118 | + b) bflag=1 |
| 119 | + BRNAME="$OPTARG" |
| 120 | + ;; |
| 121 | + 6) |
| 122 | + FAMILY=inet6 |
| 123 | + ;; |
| 124 | + ?) usage |
| 125 | + exit 2 |
| 126 | + ;; |
| 127 | + esac |
| 128 | +done |
| 129 | + |
| 130 | +if [[ "$oflag$vflag$pflag$bflag" != "1111" ]]; then |
| 131 | + usage |
| 132 | + exit 2 |
| 133 | +fi |
| 134 | + |
| 135 | +lsmod|grep ^vxlan >& /dev/null |
| 136 | +if [[ $? -gt 0 ]]; then |
| 137 | + modprobe=`modprobe vxlan 2>&1` |
| 138 | + if [[ $? -gt 0 ]]; then |
| 139 | + echo "Failed to load vxlan kernel module: $modprobe" |
| 140 | + exit 1 |
| 141 | + fi |
| 142 | +fi |
| 143 | + |
| 144 | + |
| 145 | +# |
| 146 | +# Add a lockfile to prevent this script from running twice on the same host |
| 147 | +# this can cause a race condition |
| 148 | +# |
| 149 | + |
| 150 | +LOCKFILE=/var/run/cloud/vxlan.lock |
| 151 | + |
| 152 | +( |
| 153 | + flock -x -w 10 200 || exit 1 |
| 154 | + if [[ "$OP" == "add" ]]; then |
| 155 | + addVxlan ${VNI} ${PIF} ${BRNAME} ${FAMILY} |
| 156 | + |
| 157 | + if [[ $? -gt 0 ]]; then |
| 158 | + exit 1 |
| 159 | + fi |
| 160 | + elif [[ "$OP" == "delete" ]]; then |
| 161 | + deleteVxlan ${VNI} ${PIF} ${BRNAME} ${FAMILY} |
| 162 | + fi |
| 163 | +) 200>${LOCKFILE} |
0 commit comments