summaryrefslogtreecommitdiff
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
parent900d54b0fcb3510dfa8fe63eb496e2a198c5c6b9 (diff)
downloadopenrc-dbb5af2023910c43b4780852fada099cb94cae96.tar.gz
openrc-dbb5af2023910c43b4780852fada099cb94cae96.tar.bz2
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.
-rw-r--r--TODO2
-rw-r--r--doc/net.example.Linux.in12
-rw-r--r--net/bridge.sh109
3 files changed, 98 insertions, 25 deletions
diff --git a/TODO b/TODO
index d04785b..e008fca 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,5 @@
- ensure all forks block, restore and unblock signals. needs review
- add support somehow for optional translations
+
+- oldnet[bridging]: Review setting of bridge configuration on dynamic interface add
diff --git a/doc/net.example.Linux.in b/doc/net.example.Linux.in
index 4ebe1a7..582c161 100644
--- a/doc/net.example.Linux.in
+++ b/doc/net.example.Linux.in
@@ -805,6 +805,18 @@
#sethello 0
#stp off"
+# You can also configure the bridge or bridge members via sysfs on 2.6 kernels
+# or newer. See the kernel bridge documentation for a description of these
+# options.
+#stp_state_br0="0"
+#forward_delay_br0="10"
+#hairpin_mode_eth0="1"
+
+# If you want to start an empty bridge, and then dynmically add ports to it you
+# MUST set the following variables (with the correct interface name).
+# If you get the error "Misconfigured static bridge detected", this means you.
+#bridge_br0=''
+
#-----------------------------------------------------------------------------
# RFC 2684 Bridge Support
# For RFC 2684 bridge support emerge net-misc/br2684ctl
diff --git a/net/bridge.sh b/net/bridge.sh
index 7456a5b..2f6711e 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