diff --git a/scripts/vm/network/vnet/modifyvxlan-evpn.sh b/scripts/vm/network/vnet/modifyvxlan-evpn.sh new file mode 100644 index 00000000000..6728fcb780a --- /dev/null +++ b/scripts/vm/network/vnet/modifyvxlan-evpn.sh @@ -0,0 +1,163 @@ +#!/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 (add | delete) -v -p -b (-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}