Files
vm-bhyve/lib/vm-switch
benoitc d940e51c49 add netgraph switch support
This change add simiular support to VALE for netgraph switches. Switches
must be configured manually. Devices will be added using the bhyve
support of netgraph.

Link Num of a peer in the bridge is found by iterrating all devices
already setup in. (Similiar hack is found in jail example).
2022-04-18 06:17:19 +02:00

442 lines
14 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.
# switch libraries
#
. "${LIB}/vm-switch-netgraph"
. "${LIB}/vm-switch-manual"
. "${LIB}/vm-switch-standard"
. "${LIB}/vm-switch-vale"
. "${LIB}/vm-switch-vxlan"
# create switches from rc list on init
# this should run once per boot to make sure switches from the
# configuration file have bridge interfaces. If any new switches are
# created, the create function takes care of setting them up
#
switch::init(){
local _switchlist _switch _type
config::core::get "_switchlist" "switch_list"
if [ -n "${_switchlist}" ]; then
for _switch in ${_switchlist}; do
# get the switch type
config::core::get "_type" "type_${_switch}"
case "${_type}" in
vxlan) switch::vxlan::init "${_switch}" ;;
manual) switch::manual::init "${_switch}" ;;
vale) ;;
netgraph) ;;
*) switch::standard::init "${_switch}" ;;
esac
done
fi
}
# list switches configured
#
switch::list(){
local _switchlist _switch _type
local _id _format="%s^%s^%s^%s^%s^%s^%s^%s\n"
config::core::get "_switchlist" "switch_list"
{
printf "${_format}" "NAME" "TYPE" "IFACE" "ADDRESS" "PRIVATE" "MTU" "VLAN" "PORTS"
if [ -n "${_switchlist}" ]; then
for _switch in ${_switchlist}; do
# get the switch type
config::core::get "_type" "type_${_switch}"
case "${_type}" in
netgraph) switch::netgraph::show "${_switch}" "${_format}" ;;
vale) switch::vale::show "${_switch}" "${_format}" ;;
vxlan) switch::vxlan::show "${_switch}" "${_format}" ;;
manual) switch::manual::show "${_switch}" "${_format}" ;;
*) switch::standard::show "${_switch}" "${_format}" ;;
esac
done
fi
} | column -ts^
}
# create a new virtual switch
#
# @param string _switch name of the switch to create
#
switch::create(){
local _switch
local _type="standard"
local _list _curr _vlan _if _bridge _addr _mtu _priv
# process options
while getopts t:i:n:b:a:m:p _opt; do
case ${_opt} in
t) _type="${OPTARG}" ;;
i) _if="${OPTARG}" ;;
n) _vlan="${OPTARG}" ;;
b) _bridge="${OPTARG}" ;;
a) _addr="${OPTARG}" ;;
m) _mtu="${OPTARG}" ;;
p) _priv="yes" ;;
*) util::usage ;;
esac
done
shift $((OPTIND - 1))
_switch="$1"
# check for a valid switch name
util::check_name "${_switch}" || util::err "invalid switch name - '${_switch}'"
# make sure it's not an existing name
config::core::get "_list" "switch_list"
for _curr in ${_list}; do
[ "${_switch}" = "${_curr}" ] && util::err "switch ${_switch} already exists"
done
# check vlan number
if [ -n "${_vlan}" ]; then
echo "${_vlan}" | egrep -qs '^[0-9]{1,4}$'
[ $? -eq 0 ] || util::err "invalid vlan number"
[ ${_vlan} -ge 4095 ] && util::err "invalid vlan number"
fi
# check address
if [ -n "${_addr}" ]; then
echo "${_addr}" | egrep -qs '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}$'
[ $? -eq 0 ] || util::err "address must be supplied in CIDR notation (a.b.c.d/prefix-len)"
fi
# check mtu
if [ -n "${_mtu}" ]; then
echo "${_mtu}" | egrep -qs '^[0-9]{3,4}$'
[ $? -eq 0 ] || util::err "invalid mtu"
[ ${_mtu} -gt 9000 ] && util::err "invalid mtu"
fi
# check switch type
case "${_type}" in
standard) switch::standard::create ;;
manual) switch::manual::create ;;
netgraph) switch::netgraph:create ;;
vale) switch::vale::create ;;
vxlan) switch::vxlan::create ;;
*) util::err "invalid switch type - '${_type}'" ;;
esac
}
# destroy a switch
# remove from configuration and unload any interfaces we created
#
# @param string _switch name of the switch to remove
#
switch::remove(){
local _switch="$1"
local _type
[ -z "${_switch}" ] && util::usage
# get the type of switch
config::core::get "_type" "type_${_switch}"
case "${_type}" in
standard) switch::standard::remove "${_switch}" ;;
manual) switch::manual::remove "${_switch}" ;;
netgraph) switch::netgraph::remove "${_switch}" ;;
vale) switch::vale::remove "${_switch}" ;;
vxlan) switch::vxlan::remove "${_switch}" ;;
*) util::err "unable to remove switch of unknown type" ;;
esac
# remove all configuration if there's no error
if [ $? -eq 0 ]; then
config::core::remove "switch_list" "${_switch}"
config::core::remove "ports_${_switch} vlan_${_switch} nat_${_switch} type_${_switch}"
config::core::remove "addr_${_switch} private_${_switch} mtu_${_switch}"
else
util::err "failed to remove virtual switch"
fi
# make sure the exit status indicates success,
# even if config::core::remove did not
return 0
}
# add a new interface to a switch
#
# @param string _switch name of the switch
# @param string _if the interface to add
#
switch::add_member(){
local _switch="$1"
local _if="$2"
local _type
[ -z "${_switch}" -o -z "${_if}" ] && util::usage
# get the type of switch
config::core::get "_type" "type_${_switch}"
case "${_type}" in
standard) switch::standard::add_member "${_switch}" "${_if}" ;;
manual) switch::manual::add_member "${_switch}" "${_if}" ;;
netgraph) switch::netgraph::add_member "${_switch}" "${_if}" ;;
vale) switch::vale::add_member "${_switch}" "${_if}" ;;
vxlan) switch::vxlan::add_member "${_switch}" "${_if}" ;;
*) util::err "unable to configure switch of unknown type" ;;
esac
}
# remove a member interface from a virtual switch
#
# @param string _switch name of the switch
# @param string _if the interface to remove
#
switch::remove_member(){
local _switch="$1"
local _if="$2"
local _type
[ -z "${_switch}" -o -z "${_if}" ] && util::usage
# get the type of switch
config::core::get "_type" "type_${_switch}"
case "${_type}" in
standard) switch::standard::remove_member "${_switch}" "${_if}" ;;
manual) switch::manual::remove_member "${_switch}" "${_if}" ;;
netgraph) switch::netgraph::remove_member "${_switch}" "${_if}" ;;
vale) switch::vale::remove_member "${_switch}" "${_if}" ;;
vxlan) switch::vxlan::remove_member "${_switch}" "${_if}" ;;
*) util::err "unable to configure switch of unknown type" ;;
esac
}
# change the vlan number on a virtual switch
#
# @param string _switch name of the switch
# @param int _vlan the vlan number (0 to turn vlan off)
#
switch::vlan(){
local _switch="$1"
local _vlan="$2"
local _id _type
[ -z "${_switch}" -o -z "${_vlan}" ] && util::usage
switch::id "_id" "${_switch}"
switch::type "_type" "${_switch}"
[ -z "${_id}" ] && util::err "unable to locate specified virtual switch"
echo "${_vlan}" | egrep -qs '^[0-9]{1,4}$'
[ $? -eq 0 ] || util::err "invalid vlan number"
[ ${_vlan} -ge 4095 ] && util::err "invalid vlan number"
case "${_type}" in
standard) switch::standard::vlan "${_switch}" "${_vlan}" ;;
manual) switch::manual::vlan "${_switch}" "${_vlan}" ;;
netgraph) switch::netgraph::vlan "${_switch}" "${_vlan}" ;;
vale) switch::vale::vlan "${_switch}" "${_vlan}" ;;
vxlan) switch::vxlan::vlan "${_switch}" "${_vlan}" ;;
*) util::err "unable to configure switch of unknown type" ;;
esac
}
# enable or diable private flag on a switch
# note that we don't update existing interfaces; this
# makes things easy for us and any guests booted after
# will get the new setting
#
# @param string _switch the switch to update
# @param string _priv on,yes|off,no
#
switch::private(){
local _switch="$1"
local _priv="$2"
local _type
# try to get switch type
[ -z "${_switch}" -o -z "${_priv}" ] && util::usage
switch::type "_type" "${_switch}" || util::err "specified switch does not appear to be valid"
case "${_type}" in
standard|manual|vxlan)
if util::yesno "${_priv}"; then
config::core::set "private_${_switch}" "yes"
else
config::core::set "private_${_switch}" "no"
fi
;;
netgraph)
util::err "unable to configure private mode on netgraph switches"
;;
vale)
util::err "unable to configure private mode on vale switches"
;;
*)
util::err "unable to configure switch of unknown type"
;;
esac
}
# enable or disable nat functionality on a virtual switch
#
# @param string _switch name of the switch
# @param string _nat on|off
#
switch::nat(){
util::warn "internal nat support is currently disabled"
util::warn "please add an address to the virtual switch and configure your firewall for NAT manually"
}
# set or remove ip address from a virtual switch
#
# @param string _switch name of the switch
# @param string _addr the ip address to add (or "none" to remove
#
switch::address(){
local _switch="$1"
local _addr="$2"
local _id _type
[ -z "${_switch}" ] && util::usage
switch::id "_id" "${_switch}"
switch::type "_type" "${_switch}"
[ -z "${_id}" ] && util::err "unable to locate specified virtual switch"
# check address
if [ -n "${_addr}" ] && [ "${_addr}" != "none" ]; then
echo "${_addr}" | egrep -qs '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}$'
[ $? -eq 0 ] || util::err "address must be supplied in CIDR notation (a.b.c.d/prefix-len)"
fi
case "${_type}" in
standard) switch::standard::address "${_switch}" "${_addr}" ;;
manual) ;&
netgraph) ;&
vale) ;&
vxlan) util::err "feature not currently supported on switches of this type" ;;
*) util::err "unable to configure switch of unknown type" ;;
esac
}
# return the type for a switch
#
# @param string _var variable to put type into
# @param string _switch the switch name
#
switch::type(){
local _var="$1"
local _switch="$2"
[ -z "${_switch}" ] && return 1
config::core::get "${_var}" "type_${_switch}" "standard"
}
# check if a switch is configured for private members
#
# @param string _switch switch name
# @return succes (0) if it's private
#
switch::is_private(){
local _switch="$1"
local _priv
config::core::get "_priv" "private_${_switch}"
util::yesno "${_priv}"
}
# get the bridge id for a virtual switch
#
# @param string _var variable to put name into
# @param string _switch the name of the switch
#
switch::id(){
local _var="$1"
local _switch="$2"
local _type
[ -z "${_switch}" ] && return 1
# get switch type
config::core::get "_type" "type_${_switch}"
case "${_type}" in
vale) switch::vale::id "${_var}" "${_switch}" ;;
netgraph) switch::netgraph::id "${_var}" "${_switch}" ;;
manual) switch::manual::id "${_var}" "${_switch}" ;;
*) switch::standard::id "${_var}" "${_switch}" ;;
esac
}
# get a virt interface id for a port/switch
#
# @param string _var variable name to put result into
# @param string _switch switch name to get id for
#
switch::__viid(){
local _hash=$(md5 -qs "${2}" | cut -c1-5)
setvar "$1" "viid-${_hash}@"
}
# retrieve interface name, given a switch name
# we convert to viid then look for the matching group
#
# @param string _var variable to put interface name into
# @param string _switch the switch name
#
switch::find(){
local _var="$1"
local _switch="$2"
local _viid _name
switch::__viid "_viid" "${_switch}"
_name=$(ifconfig -g "${_viid}" 2>/dev/null)
[ -n "${_name}" ] && setvar "${_var}" "${_name}"
}
# mark an interface with a unique viid
# i say unique, its 5 chars from an md5 hash which
# should be enough for half a dozen switches
#
# @parem string _switch switch name
# @param string _iface interface to mark
#
switch::set_viid(){
local _switch="$1"
local _iface="$2"
local _viid
switch::__viid "_viid" "${_switch}"
ifconfig "${_iface}" group "${_viid}" >/dev/null 2>&1
}