Files
vm-bhyve/lib/vm-switch-vxlan
2019-02-08 14:20:21 +00:00

194 lines
6.3 KiB
Bash

#!/bin/sh
#-------------------------------------------------------------------------+
# Copyright (C) 2016 Matt Churchyard (churchers@gmail.com)
# All rights reserved
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted providing that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# create a vxlan switch
# we create a bridge and then add the vxlan interface to it
#
# @param string _name name of the switch
#
switch::vxlan::init(){
local _name="$1"
local _id _vlan _if _maddr _addr
# see if the bridge already exists
switch::standard::id "_id" "${_name}" && return 0
# need a vlan id and interface
config::core::get "_vlan" "vlan_${_name}"
config::core::get "_if" "ports_${_name}"
[ -z "${_vlan}" -o -z "${_if}" ] && return 1
# get local address for this interface
_local=$(ifconfig ${_if} | grep "inet " | cut -d" " -f 2)
[ -z "${_local}" ] && return 1
# come up with an ip address for multicast data
switch::vxlan::__multicast "_maddr" "${_name}"
# create the vxlan interface
ifconfig "vxlan${_vlan}" create vxlanid "${_vlan}" vxlanlocal "${_local}" vxlangroup "${_maddr}" \
vxlandev "${_if}" descr "vm-vxlan-${_switch}" group vm-vlan up >/dev/null 2>&1
[ $? -eq 0 ] || return 1
# create a bridge for this switch
_id=$(ifconfig bridge create descr "vm-${_name}" group vm-switch up 2>/dev/null)
[ $? -eq 0 ] || util::err "failed to create bridge interface for switch ${_name}"
switch::set_viid "${_name}" "${_id}"
# randomise mac if feature is available
[ ${VERSION_BSD} -ge 1102000 ] && ifconfig "${_id}" link random
# bridge vxlan to our guest switch
# static route traffic for this multicast address via our specified interface
ifconfig "${_id}" addm "vxlan${_vlan}"
route add -net ${_maddr}/32 -iface ${_if} >/dev/null 2>&1
# custom address for bridge?
config::core::get "_addr" "addr_${_name}"
[ -n "${_addr}" ] && ifconfig "${_id}" inet ${_addr}
}
# show the configuration details for a vxlan switch
#
# @param string _name the switch name
# @param string _format output format
#
switch::vxlan::show(){
local _name="$1"
local _format="$2"
local _id _vlan _port _addr _priv
switch::standard::id "_id" "${_name}"
config::core::get "_vlan" "vlan_${_name}"
config::core::get "_port" "ports_${_name}"
config::core::get "_addr" "addr_${_name}"
config::core::get "_priv" "private_${_name}" "no"
printf "${_format}" "${_name}" "vxlan" "${_id:--}" "${_addr:--}" "${_priv}" "n/a" "${_vlan}" "${_port}"
}
# create a vxlan switch
#
switch::vxlan::create(){
# we must have an interface and vlan to use
[ -z "${_if}" -o -z "${_vlan}" ] && util::err "vxlan switches must be created with an interface and vlan id specified"
# store configuration
config::core::set "switch_list" "${_switch}" "1"
config::core::set "type_${_switch}" "vxlan"
config::core::set "vlan_${_switch}" "${_vlan}"
config::core::set "ports_${_switch}" "${_if}"
[ -n "${_addr}" ] && config::core::set "addr_${_switch}" "${_addr}"
[ -n "${_priv}" ] && config::core::set "private_${_switch}" "${_priv}"
config::core::load
switch::vxlan::init "${_switch}"
}
# destroy a vxlan switch
#
# @param string _switch the switch to remove
#
switch::vxlan::remove(){
local _switch="$1"
local _id _vlan _maddr
# try to get guest bridge and vxlan id
switch::standard::id "_id" "${_switch}"
[ $? -eq 0 ] || return 1
config::core::get "_vlan" "vlan_${_switch}"
[ -z "${_vlan}" ] && return 1
# get the multicast address we used for this switch
# and try to remove any route we may have added
switch::vxlan::__multicast "_maddr" "${_switch}"
route del -net "${_maddr}/32" >/dev/null 2>&1
# destroy the guest bridge
ifconfig ${_id} destroy >/dev/null 2>&1
[ $? -eq 0 ] || return 1
# destroy the vxlan
ifconfig "vxlan${_vlan}" destroy >/dev/null 2>&1
}
# add a new interface to this switch
# we only allow a single physical interface for
# vxlan switches. this must be set at creation time
# so this just reports an error
#
# @param string _switch name of the vxlan switch
# @param string _if the interface to add
#
switch::vxlan::add_member(){
util::err "vxlan interface must be configured at creation time"
}
# remove an interface from a switch
# we don't support this here
#
# @param string _switch name of the switch
# @param string _if the interface to remove
#
switch::vxlan::remove_member(){
util::err "vxlan interface must be configured at creation time"
}
# set vlan id
#
# @param string _switch name of switch
# @param int _vlan vlan id to set
#
switch::vxlan::vlan(){
util::err "vxlan id can only be set at creation time"
}
# get the multicast address for a vxlan switch
#
# @param string _var variable to put address into
# @param string _switch the switch name
#
switch::vxlan::__multicast(){
local _var="$1"
local _switch="$2"
local _hash _l_addr _octet _pos
# come up with an ip address for multicast data
_hash=$(md5 -qs "${_switch}")
_l_addr="239"
for _pos in 1-2 3-4 5-6; do
_octet=$(printf ".%d" "0x`echo "${_hash}"| cut -c ${_pos}`")
_l_addr="${_l_addr}${_octet}"
done
setvar "${_var}" "${_l_addr}"
}