diff options
| author | Robin H. Johnson <robbat2@orbis-terrarum.net> | 2010-12-11 12:26:31 -0800 | 
|---|---|---|
| committer | Robin H. Johnson <robbat2@orbis-terrarum.net> | 2010-12-11 12:26:38 -0800 | 
| commit | dbb5af2023910c43b4780852fada099cb94cae96 (patch) | |
| tree | 8ee09bb1b3fa26b8164c484d4a8aa2753e026f70 /net | |
| parent | 900d54b0fcb3510dfa8fe63eb496e2a198c5c6b9 (diff) | |
| download | openrc-dbb5af2023910c43b4780852fada099cb94cae96.tar.xz | |
Revamp of bridging code.
- Use sysfs to read bridge information from the system instead of
  parsing the brctl outputs.
- Allow setting of all bridge configuration parameters using new sysfs
  methods, modelled after bonding configuration. Also works for per-port
  bridge interface parameters.
- Document pre-starting an empty bridge for dynamic add.
- Check for interface existence before adding to bridge.
- Should fix bug #293046, #309185.
Diffstat (limited to 'net')
| -rw-r--r-- | net/bridge.sh | 109 | 
1 files changed, 84 insertions, 25 deletions
diff --git a/net/bridge.sh b/net/bridge.sh index 7456a5be..2f6711e6 100644 --- a/net/bridge.sh +++ b/net/bridge.sh @@ -11,34 +11,61 @@ _config_vars="$_config_vars bridge bridge_add brctl"  _is_bridge()  { -	# Ignore header line so as to allow for bridges named 'bridge' -	brctl show 2>/dev/null | sed '1,1d' | grep -q "^${IFACE}[[:space:]]" +	[ -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= iface="${IFACE}" e= x= +	local brif= oiface="${IFACE}" e= x=  	local ports="$(_get_array "bridge_${IFVAR}")"  	local opts="$(_get_array "brctl_${IFVAR}")" +	# brif is used for dynamic add  	eval brif=\$bridge_add_${IFVAR} -	eval x=\${bridge_${IFVAR}-y\} -	if [ -z "${brif}" -a -z "${opts}" ]; then -		[ -n "${ports}" -o "${x}" != "y" ] || return 0 +	# ports is for static add +	eval bridge_unset=\${bridge_${IFVAR}-y\} +	eval brctl_unset=\${brctl_${IFVAR}-y\} +	 +	# If we are not doing dynamic add on $IFACE, check for static ports. +	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 -	[ -n "${ports}" ] && bridge_post_stop +	# 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 +	if ! _is_bridge ; then  		ebegin "Creating bridge ${IFACE}"  		if ! brctl addbr "${IFACE}"; then  			eend 1 @@ -46,6 +73,12 @@ bridge_pre_start()  		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 @@ -57,21 +90,50 @@ bridge_pre_start()  	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 OIFACE="${IFACE}" +		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 "${OIFACE}" "${x}"; then +			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 @@ -86,27 +148,24 @@ bridge_post_stop()  {  	local port= ports= delete=false extra= -	if _is_bridge; then +	if _is_bridge "${IFACE}"; then  		ebegin "Destroying bridge ${IFACE}"  		_down -		# Ignore header line so as to allow for bridges named 'bridge' -		ports="$(brctl show 2>/dev/null | \ -			sed -n -e '1,1d' -e '/^'"${IFACE}"'[[:space:]]/,/^\S/ { /^\('"${IFACE}"'[[:space:]]\|\t\)/s/^.*\t//p }')" +		for x in /sys/class/net/"${IFACE}"/brif/*; do +			[ -s $x ] || continue +			n=${x##*/} +			ports="${ports} ${n}" +		done  		delete=true  		iface=${IFACE}  		eindent  	else -		# Work out if we're added to a bridge for removal or not -		# Ignore header line so as to allow for bridges named 'bridge' -		eval set -- $(brctl show 2>/dev/null | sed -e '1,1d' -e "s/'/'\\\\''/g" -e "s/$/'/g" -e "s/^/'/g") -		local line= -		for line; do -			set -- ${line} -			if [ "$3" = "${IFACE}" ]; then -				iface=$1 -				break -			fi -		done +		# 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  | 
