cloudstack/scripts/vm/network/vnet/modifyvxlan-evpn.sh

164 lines
4.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Use BGP+EVPN for VXLAN with CloudStack instead of Multicast
#
# The default 'modifyvxlan.sh' script from CloudStack uses Multicast instead of EVPN for VXLAN
# In order to use this script and thus utilize BGP+EVPN, symlink this file:
#
# cd /usr/share
# ln -s cloudstack-common/scripts/vm/network/vnet/modifyvxlan-evpn.sh modifyvxlan.sh
#
#
# CloudStack will not handle the BGP configuration nor communication, the operator of the hypervisor will
# need to configure the properly.
#
# Frrouting is recommend to be used on the hypervisor to establish BGP sessions with upstream routers and
# exchange BGP+EVPN information.
#
# More information about BGP and EVPN with FRR: https://vincent.bernat.ch/en/blog/2017-vxlan-bgp-evpn
#
DSTPORT=4789
# We bind our VXLAN tunnel IP(v4) on Loopback device 'lo'
DEV="lo"
usage() {
echo "Usage: $0: -o <op>(add | delete) -v <vxlan id> -p <pif> -b <bridge name> (-6)"
}
localAddr() {
local FAMILY=$1
if [[ -z "$FAMILY" || $FAMILY == "inet" ]]; then
ip -4 -o addr show scope global dev ${DEV} | awk 'NR==1 {gsub("/[0-9]+", "") ; print $4}'
fi
if [[ "$FAMILY" == "inet6" ]]; then
ip -6 -o addr show scope global dev ${DEV} | awk 'NR==1 {gsub("/[0-9]+", "") ; print $4}'
fi
}
addVxlan() {
local VNI=$1
local PIF=$2
local VXLAN_BR=$3
local FAMILY=$4
local VXLAN_DEV=vxlan${VNI}
local ADDR=$(localAddr ${FAMILY})
echo "local addr for VNI ${VNI} is ${ADDR}"
if [[ ! -d /sys/class/net/${VXLAN_DEV} ]]; then
ip -f ${FAMILY} link add ${VXLAN_DEV} type vxlan id ${VNI} local ${ADDR} dstport ${DSTPORT} nolearning
ip link set ${VXLAN_DEV} up
sysctl -qw net.ipv6.conf.${VXLAN_DEV}.disable_ipv6=1
fi
if [[ ! -d /sys/class/net/$VXLAN_BR ]]; then
ip link add name ${VXLAN_BR} type bridge
ip link set ${VXLAN_BR} up
sysctl -qw net.ipv6.conf.${VXLAN_BR}.disable_ipv6=1
fi
bridge link show|grep ${VXLAN_BR}|awk '{print $2}'|grep "^${VXLAN_DEV}\$" > /dev/null
if [[ $? -gt 0 ]]; then
ip link set ${VXLAN_DEV} master ${VXLAN_BR}
fi
}
deleteVxlan() {
local VNI=$1
local PIF=$2
local VXLAN_BR=$3
local FAMILY=$4
local VXLAN_DEV=vxlan${VNI}
ip link set ${VXLAN_DEV} nomaster
ip link delete ${VXLAN_DEV}
ip link set ${VXLAN_BR} down
ip link delete ${VXLAN_BR} type bridge
}
OP=
VNI=
FAMILY=inet
option=$@
while getopts 'o:v:p:b:6' OPTION
do
case $OPTION in
o) oflag=1
OP="$OPTARG"
;;
v) vflag=1
VNI="$OPTARG"
;;
p) pflag=1
PIF="$OPTARG"
;;
b) bflag=1
BRNAME="$OPTARG"
;;
6)
FAMILY=inet6
;;
?) usage
exit 2
;;
esac
done
if [[ "$oflag$vflag$pflag$bflag" != "1111" ]]; then
usage
exit 2
fi
lsmod|grep ^vxlan >& /dev/null
if [[ $? -gt 0 ]]; then
modprobe=`modprobe vxlan 2>&1`
if [[ $? -gt 0 ]]; then
echo "Failed to load vxlan kernel module: $modprobe"
exit 1
fi
fi
#
# Add a lockfile to prevent this script from running twice on the same host
# this can cause a race condition
#
LOCKFILE=/var/run/cloud/vxlan.lock
(
flock -x -w 10 200 || exit 1
if [[ "$OP" == "add" ]]; then
addVxlan ${VNI} ${PIF} ${BRNAME} ${FAMILY}
if [[ $? -gt 0 ]]; then
exit 1
fi
elif [[ "$OP" == "delete" ]]; then
deleteVxlan ${VNI} ${PIF} ${BRNAME} ${FAMILY}
fi
) 200>${LOCKFILE}