# Copyright (c) 2007-2008 Roy Marples # Released under the 2-clause BSD license. # shellcheck shell=sh disable=SC1008 bridge_depend() { before interface macnet program brctl ip } _config_vars="$_config_vars bridge bridge_add brctl" _is_bridge() { _netns [ -d /sys/class/net/"${1:-${IFACE}}"/bridge ] return $? } _is_bridge_port() { _netns [ -d /sys/class/net/"${1:-${IFACE}}"/brport ] return $? } _bridge_ports() { for x in $(_netns glob /sys/class/net/"${1:-${IFACE}}"/brif/\*); do n=${x##*/} echo $n done } bridge_pre_start() { local brif= oiface="${IFACE}" e= x= # ports is for static add local ports="$(_get_array "bridge_${IFVAR}")" # old config options local brctl_opts="$(_get_array "brctl_${IFVAR}")" # brif is used for dynamic add eval brif=\$bridge_add_${IFVAR} local do_iproute2=false do_brctl=false if [ -n "${brctl_opts}" ] && type brctl >/dev/null 2>&1; then do_brctl=true elif type ip >/dev/null 2>&1; then do_iproute2=true elif type brctl >/dev/null 2>&1; then do_brctl=true fi # we need a way to if the bridge exists in a variable name, not just the # contents of a variable. Eg if somebody has only bridge_add_eth0='br0', # with no other lines mentioning br0. eval bridge_unset=\${bridge_${IFVAR}-y\} eval brctl_unset=\${brctl_${IFVAR}-y\} eval bridge_force_unset=\${bridge_force_${IFVAR}-y\} if [ -z "${brif}" -a "${brctl_unset}${bridge_force_unset}" = 'yy' ]; then if [ -z "${ports}" -a "${bridge_unset}" = "y" ]; then #eerror "Misconfigured static bridge detected (see net.example)" return 0 fi fi # If the bridge was already up, we should clear it [ "${bridge_unset}" != "y" ] && bridge_post_stop ( # Normalize order of variables if [ -z "${ports}" -a -n "${brif}" ]; then # Dynamic mode detected ports="${IFACE}" IFACE="${brif}" IFVAR=$(shell_var "${IFACE}") else # Static mode detected ports="${ports}" metric=1000 fi if ! _is_bridge ; then ebegin "Creating bridge ${IFACE}" if ${do_iproute2}; then _netns ip link add "${IFACE}" type bridge rc=$? elif ${do_brctl}; then brctl addbr "${IFACE}" rc=$? else eerror "Neither iproute2 nor brctl has been found, please install" eerror "either \"iproute2\" or \"brctl\"." rc=1 fi if [ ${rc} != 0 ]; then eend 1 return 1 fi fi # TODO: does this reset the bridge every time we add a interface to the # bridge? We should probably NOT do that. # Old configuration set mechanism # Only a very limited subset of the options are available in the old # configuration method. The sysfs interface is in the next block instead. if ${do_brctl}; then if [ -n "${brctl_opts}" ]; then ewarn "brctl options are deprecated please migrate to sysfs options" ewarn "map of important options is available at https://wiki.gentoo.org/wiki/Netifrc/Brctl_Migration" local IFS="$__IFS" for x in ${brctl_opts}; do unset IFS set -- ${x} x=$1 shift set -- "${x}" "${IFACE}" "$@" brctl "$@" done unset IFS fi fi # New configuration set mechanism, matches bonding for x in $(_netns glob /sys/class/net/"${IFACE}"/bridge/\*); do [ -f "${x}" ] || continue n=${x##*/} # keep no prefix for backward compatibility for prefix in "" bridge_; do eval s=\$${prefix}${n}_${IFVAR} if [ -n "${s}" ]; then [ -z "${prefix}" ] && ewarn "sysfs key '${n}_${IFVAR}' should be prefixed, please add bridge_ prefix." einfo "Setting ${n}: ${s}" _netns echo "${s}" \>"${x}" || \ eerror "Failed to configure $n (${n}_${IFVAR})" fi done done if [ -n "${ports}" ]; then einfo "Adding ports to ${IFACE}" eindent local BR_IFACE="${IFACE}" for x in ${ports}; do ebegin "${x}" local IFACE="${x}" local IFVAR=$(shell_var "${IFACE}") if ! _exists "${IFACE}" ; then eerror "Cannot add non-existent interface ${IFACE} to ${BR_IFACE}" return 1 fi # The interface is known to exist now local disable_ipv6="/proc/sys/net/ipv6/conf/${IFACE}/disable_ipv6" [ -f "${disable_ipv6}" ] && printf '1\n' > "${disable_ipv6}" _up if ${do_iproute2}; then _netns ip link set "${x}" master "${BR_IFACE}" elif ${do_brctl}; then brctl addif "${BR_IFACE}" "${x}" fi if [ $? != 0 ]; then eend 1 return 1 fi # Per-interface bridge settings for x in $(_netns glob /sys/class/net/"${IFACE}"/brport/\*); do [ -f "${x}" ] || continue n=${x##*/} for prefix in "" brport_; do eval s=\$${prefix}${n}_${IFVAR} if [ -n "${s}" ]; then [ -z "${prefix}" ] && ewarn "sysfs key '${n}_${IFVAR}' should be prefixed, please add brport_ prefix." einfo "Setting ${n}@${IFACE}: ${s}" _netns echo "${s}" \>"${x}" || \ eerror "Failed to configure $n (${n}_${IFVAR})" fi done done eend 0 done eoutdent fi ) || return 1 # Bring up the bridge _set_flag promisc _up } bridge_post_stop() { local port= ports= delete=false extra= if _is_bridge "${IFACE}"; then ebegin "Destroying bridge ${IFACE}" _down for x in $(_netns glob /sys/class/net/"${IFACE}"/brif/\*); do [ -s $x ] || continue n=${x##*/} ports="${ports} ${n}" done delete=true iface=${IFACE} eindent else # We are taking down an interface that is part of a bridge maybe ports="${IFACE}" local brport_dir="/sys/class/net/${IFACE}/brport" _netns [ -d ${brport_dir} ] || return 0 iface=$(_netns readlink ${brport_dir}/bridge) iface=${iface##*/} [ -z "${iface}" ] && return 0 extra=" from ${iface}" fi for port in ${ports}; do ebegin "Removing port ${port}${extra}" local IFACE="${port}" _set_flag -promisc if type ip > /dev/null 2>&1; then _netns ip link set "${port}" nomaster else brctl delif "${iface}" "${port}" fi eend $? done if ${delete}; then eoutdent if type ip > /dev/null 2>&1; then _netns ip link del "${iface}" else brctl delbr "${iface}" fi eend $? fi return 0 }