aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorRobin H. Johnson <robbat2@orbis-terrarum.net>2010-12-11 12:26:31 -0800
committerRobin H. Johnson <robbat2@orbis-terrarum.net>2010-12-11 12:26:38 -0800
commitdbb5af2023910c43b4780852fada099cb94cae96 (patch)
tree8ee09bb1b3fa26b8164c484d4a8aa2753e026f70 /net
parent900d54b0fcb3510dfa8fe63eb496e2a198c5c6b9 (diff)
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.sh109
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