166512Sarchie#!/bin/sh
266512Sarchie# $FreeBSD$
366512Sarchie# This script sets up an Ethernet bridging network across multiple
466512Sarchie# Ethernet interfaces using the ng_bridge(4) and ng_ether(4) netgraph
566512Sarchie# node types.
666512Sarchie#
766512Sarchie# To use this script:
866512Sarchie#
9156313Sschweikh# 0. Make your own copy of this example script.
1066512Sarchie#
1166512Sarchie# 1. Give your bridging network a name by editing the definition of
1266512Sarchie#    ${BRIDGE_NAME} below. It must be a valid netgraph node name.
1366512Sarchie#
1494477Sjulian# 2. Edit the definitions of ${BRIDGE_IFACES} and ${LOCAL_IFACES}
1566512Sarchie#    as described below to define your bridging interfaces.
1666512Sarchie#
1766512Sarchie# 3. Run this script with "start" as the command line argument.
1866512Sarchie#
1966512Sarchie# 4. Examine bridging statistics by running this script with "stats"
2066512Sarchie#    as the command line argument.
2166512Sarchie#
2266512Sarchie# 5. Stop bridging by running this script with "stop" as the
2366512Sarchie#    command line argument.
2466512Sarchie#
2566512Sarchie# To run multiple independent bridging networks, create multiple
2666512Sarchie# copies of this script with different variable definitions.
2794477Sjulian#
2894477Sjulian# To make a "brouted" network, with IP being routed and other protocols being
2994477Sjulian# bridged, add all the interface in the BRIDGE_IFACES to the LOCAL_IFACES.
30156313Sschweikh# If you just want a normal bridge, just one will be enough.
31156313Sschweikh# In some cases you may want some combination.
32156313Sschweikh#
3366512Sarchie
34156313Sschweikh# Give each bridging network a unique name here.
3566512Sarchie
3666512SarchieBRIDGE_NAME="bnet0"
3766512Sarchie
3866512Sarchie# List the names of the interfaces that you want to bridge across
3966512Sarchie# here in ${BRIDGE_IFACES}. If you want to include the local host
4094477Sjulian# machine as well then set ${LOCAL_IFACES} as well (they may also be
4166512Sarchie# listed in ${BRIDGE_IFACES}). Of course, any ${LOCAL_IFACE} must
4266512Sarchie# be ifconfig(8)ured separately. If you don't want a ${LOCAL_IFACE}
43222179Suqs# then assign it the empty string.
4466512Sarchie
4594477SjulianBRIDGE_IFACES="de0 fxp0 fxp1"
4694477SjulianLOCAL_IFACES="fxp0 fxp1"
4766512Sarchie
48156313Sschweikh#####################################################################
49156313Sschweikh#### Everything below this point should not need to be modified. ####
50156313Sschweikh#####################################################################
5166512Sarchie
52156313Sschweikh# Routine to verify node's existence.
5366512Sarchiebridge_verify() {
5466512Sarchie	ngctl info ${BRIDGE_NAME}: >/dev/null 2>&1
5566512Sarchie	if [ $? -ne 0 ]; then
5666512Sarchie		echo "${BRIDGE_NAME}: bridge network not found"
5766512Sarchie		exit 1
5866512Sarchie	fi
5966512Sarchie}
6066512Sarchie
61156313Sschweikh# Routine to get and display link stats.
6266512Sarchiebridge_linkstats() {
6366512Sarchie	STATS=`ngctl msg ${BRIDGE_NAME}: getstats $1`
6466512Sarchie	if [ $? -ne 0 ]; then
6566512Sarchie		exit 1
6666512Sarchie	fi
6766512Sarchie	echo "${STATS}" | fmt 2 | awk '/=/ { fl=index($0, "="); \
6866512Sarchie	    printf "%20s = %s\n", substr($0, 0, fl - 1), substr($0, fl + 1); }'
6966512Sarchie}
7066512Sarchie
71156313Sschweikh# Start/restart routine.
7266512Sarchiebridge_start() {
7366512Sarchie
74156313Sschweikh	# Load netgraph KLD's as necessary.
7566512Sarchie	for KLD in ng_ether ng_bridge; do
76156313Sschweikh		if ! kldstat -v | grep -qw ${KLD}; then
7766512Sarchie			echo -n "Loading ${KLD}.ko... "
7866512Sarchie			kldload ${KLD} || exit 1
7966512Sarchie			echo "done"
8066512Sarchie		fi
8166512Sarchie	done
8266512Sarchie
83156313Sschweikh	# Reset all interfaces.
8466512Sarchie	bridge_stop
8566512Sarchie
86156313Sschweikh	# Verify all interfaces exist.
8794477Sjulian	for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
88156313Sschweikh		if ! ngctl info ${ETHER}: >/dev/null 2>&1; then
8966512Sarchie			echo "Error: interface ${ETHER} does not exist"
9066512Sarchie			exit 1
9166512Sarchie		fi
9266512Sarchie		ifconfig ${ETHER} up || exit 1
9366512Sarchie	done
9466512Sarchie
95156313Sschweikh	# Create new ng_bridge(4) node, attached to the first interface.
9666512Sarchie	FIRSTIF=`echo ${BRIDGE_IFACES} | awk '{ print $1 }'`
9766512Sarchie	ngctl mkpeer ${FIRSTIF}: bridge lower link0 || exit 1
9866512Sarchie	ngctl name ${FIRSTIF}:lower ${BRIDGE_NAME} || exit 1
9966512Sarchie
100156313Sschweikh	# Attach other interfaces as well.
10166512Sarchie	LINKNUM=0
10266512Sarchie	for ETHER in ${BRIDGE_IFACES}; do
10366512Sarchie		if [ ${LINKNUM} != 0 ]; then
10466512Sarchie			ngctl connect ${ETHER}: ${BRIDGE_NAME}: \
10566512Sarchie			    lower link${LINKNUM} || exit 1
10666512Sarchie		fi
10766512Sarchie		LINKNUM=`expr ${LINKNUM} + 1`
10866512Sarchie	done
10966512Sarchie
110156313Sschweikh	# Hook up local interface, if any.
11194477Sjulian	for LOCAL_IFACE in ${LOCAL_IFACES}; do
11266512Sarchie		ngctl connect ${LOCAL_IFACE}: ${BRIDGE_NAME}: \
11366512Sarchie		    upper link${LINKNUM} || exit 1
11494477Sjulian		LINKNUM=`expr ${LINKNUM} + 1`
11594477Sjulian	done
11666512Sarchie
117156313Sschweikh	# Set all interfaces in promiscuous mode and don't overwrite src addr.
11866512Sarchie	for ETHER in ${BRIDGE_IFACES}; do
11966512Sarchie		ngctl msg ${ETHER}: setpromisc 1 || exit 1
12066512Sarchie		ngctl msg ${ETHER}: setautosrc 0 || exit 1
12166512Sarchie	done
12266512Sarchie}
12366512Sarchie
124156313Sschweikh# Stop routine.
12566512Sarchiebridge_stop() {
12666512Sarchie	ngctl kill ${BRIDGE_NAME}: >/dev/null 2>&1
12794477Sjulian	for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
12866512Sarchie		ngctl kill ${ETHER}: >/dev/null 2>&1
12966512Sarchie	done
13066512Sarchie}
13166512Sarchie
132156313Sschweikh# Stats routine.
13366512Sarchiebridge_stats() {
13466512Sarchie
135156313Sschweikh	# Make sure node exists.
13666512Sarchie	bridge_verify
13766512Sarchie
13866512Sarchie	echo ""
13966512Sarchie	echo "Statistics for bridging network ${BRIDGE_NAME}:"
14066512Sarchie	echo ""
14166512Sarchie	LINKNUM=0
14266512Sarchie	for ETHER in ${BRIDGE_IFACES}; do
14366512Sarchie		echo "Network interface ${ETHER}:"
14466512Sarchie		bridge_linkstats ${LINKNUM}
14566512Sarchie		LINKNUM=`expr ${LINKNUM} + 1`
14666512Sarchie	done
14794477Sjulian	for LOCAL_IFACE in ${LOCAL_IFACES}; do
14879035Sdd		echo "Local host interface ${LOCAL_IFACE}:"
14966512Sarchie		bridge_linkstats ${LINKNUM}
15094477Sjulian		LINKNUM=`expr ${LINKNUM} + 1`
15194477Sjulian	done
15266512Sarchie}
15366512Sarchie
154156313Sschweikh# Main entry point.
15566512Sarchiecase $1 in
15666512Sarchie	start)
15766512Sarchie		bridge_start
15866512Sarchie		;;
15966512Sarchie	stats)
16066512Sarchie		bridge_verify
16166512Sarchie		bridge_stats
16266512Sarchie		;;
16366512Sarchie	stop)
16466512Sarchie		bridge_verify
16566512Sarchie		bridge_stop
16666512Sarchie		;;
16766512Sarchie	*)
168156313Sschweikh		echo "usage: $0 [ start | stop | stats ]"
16966512Sarchie		exit 1
17066512Sarchieesac
171