# Copyright (c) 2007-2008 Roy Marples # Released under the 2-clause BSD license. bridge_depend() { before interface macnet program brctl } _config_vars="$_config_vars bridge bridge_add brctl" _is_bridge() { [ -d /sys/class/net/"${1:-${IFACE}}"/bridge ] return $? } _is_bridge_port() { [ -d /sys/class/net/"${1:-${IFACE}}"/brport ] return $? } _bridge_ports() { for x in /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 opts="$(_get_array "brctl_${IFVAR}")" # brif is used for dynamic add eval brif=\$bridge_add_${IFVAR} # 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\} if [ -z "${brif}" -a "${brctl_unset}" = 'y' ]; 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 ! brctl addbr "${IFACE}"; 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. local IFS="$__IFS" for x in ${opts}; do unset IFS set -- ${x} x=$1 shift set -- "${x}" "${IFACE}" "$@" brctl "$@" done unset IFS # New configuration set mechanism, matches bonding for x in /sys/class/net/"${IFACE}"/bridge/*; do [ -f "${x}" ] || continue n=${x##*/} eval s=\$${n}_${IFVAR} if [ -n "${s}" ]; then einfo "Setting ${n}: ${s}" echo "${s}" >"${x}" || \ eerror "Failed to configure $n (${n}_${IFVAR})" fi 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 _set_flag promisc _up if ! brctl addif "${BR_IFACE}" "${x}"; then _set_flag -promisc eend 1 return 1 fi # Per-interface bridge settings for x in /sys/class/net/"${IFACE}"/brport/*; do [ -f "${x}" ] || continue n=${x##*/} eval s=\$${n}_${IFVAR} if [ -n "${s}" ]; then einfo "Setting ${n}@${IFACE}: ${s}" echo "${s}" >"${x}" || \ eerror "Failed to configure $n (${n}_${IFVAR})" fi done eend 0 done eoutdent fi ) || return 1 # Bring up the bridge _up } bridge_post_stop() { local port= ports= delete=false extra= if _is_bridge "${IFACE}"; then ebegin "Destroying bridge ${IFACE}" _down for x in /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" [ -d ${brport_dir} ] || return 0 iface=$(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 brctl delif "${iface}" "${port}" eend $? done if ${delete}; then eoutdent brctl delbr "${iface}" eend $? fi return 0 }