1#!/bin/sh
2# This script sets up an Ethernet bridging network across multiple
3# Ethernet interfaces using the ng_bridge(4) and ng_ether(4) netgraph
4# node types.
5#
6# To use this script:
7#
8# 0. Make your own copy of this example script.
9#
10# 1. Give your bridging network a name by editing the definition of
11#    ${BRIDGE_NAME} below. It must be a valid netgraph node name.
12#
13# 2. Edit the definitions of ${BRIDGE_IFACES} and ${LOCAL_IFACES}
14#    as described below to define your bridging interfaces.
15#
16# 3. Run this script with "start" as the command line argument.
17#
18# 4. Examine bridging statistics by running this script with "stats"
19#    as the command line argument.
20#
21# 5. Stop bridging by running this script with "stop" as the
22#    command line argument.
23#
24# To run multiple independent bridging networks, create multiple
25# copies of this script with different variable definitions.
26#
27# To make a "brouted" network, with IP being routed and other protocols being
28# bridged, add all the interface in the BRIDGE_IFACES to the LOCAL_IFACES.
29# If you just want a normal bridge, just one will be enough.
30# In some cases you may want some combination.
31#
32
33# Give each bridging network a unique name here.
34
35BRIDGE_NAME="bnet0"
36
37# List the names of the interfaces that you want to bridge across
38# here in ${BRIDGE_IFACES}. If you want to include the local host
39# machine as well then set ${LOCAL_IFACES} as well (they may also be
40# listed in ${BRIDGE_IFACES}). Of course, any ${LOCAL_IFACE} must
41# be ifconfig(8)ured separately. If you don't want a ${LOCAL_IFACE}
42# then assign it the empty string.
43
44BRIDGE_IFACES="de0 fxp0 fxp1"
45LOCAL_IFACES="fxp0 fxp1"
46
47#####################################################################
48#### Everything below this point should not need to be modified. ####
49#####################################################################
50
51# Routine to verify node's existence.
52bridge_verify() {
53	ngctl info ${BRIDGE_NAME}: >/dev/null 2>&1
54	if [ $? -ne 0 ]; then
55		echo "${BRIDGE_NAME}: bridge network not found"
56		exit 1
57	fi
58}
59
60# Routine to get and display link stats.
61bridge_linkstats() {
62	STATS=`ngctl msg ${BRIDGE_NAME}: getstats $1`
63	if [ $? -ne 0 ]; then
64		exit 1
65	fi
66	echo "${STATS}" | fmt 2 | awk '/=/ { fl=index($0, "="); \
67	    printf "%20s = %s\n", substr($0, 0, fl - 1), substr($0, fl + 1); }'
68}
69
70# Start/restart routine.
71bridge_start() {
72
73	# Load netgraph KLD's as necessary.
74	for KLD in ng_ether ng_bridge; do
75		if ! kldstat -v | grep -qw ${KLD}; then
76			echo -n "Loading ${KLD}.ko... "
77			kldload ${KLD} || exit 1
78			echo "done"
79		fi
80	done
81
82	# Reset all interfaces.
83	bridge_stop
84
85	# Verify all interfaces exist.
86	for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
87		if ! ngctl info ${ETHER}: >/dev/null 2>&1; then
88			echo "Error: interface ${ETHER} does not exist"
89			exit 1
90		fi
91		ifconfig ${ETHER} up || exit 1
92	done
93
94	# Create new ng_bridge(4) node, attached to the first interface.
95	FIRSTIF=`echo ${BRIDGE_IFACES} | awk '{ print $1 }'`
96	ngctl mkpeer ${FIRSTIF}: bridge lower link0 || exit 1
97	ngctl name ${FIRSTIF}:lower ${BRIDGE_NAME} || exit 1
98
99	# Attach other interfaces as well.
100	LINKNUM=0
101	for ETHER in ${BRIDGE_IFACES}; do
102		if [ ${LINKNUM} != 0 ]; then
103			ngctl connect ${ETHER}: ${BRIDGE_NAME}: \
104			    lower link${LINKNUM} || exit 1
105		fi
106		LINKNUM=`expr ${LINKNUM} + 1`
107	done
108
109	# Hook up local interface, if any.
110	for LOCAL_IFACE in ${LOCAL_IFACES}; do
111		ngctl connect ${LOCAL_IFACE}: ${BRIDGE_NAME}: \
112		    upper link${LINKNUM} || exit 1
113		LINKNUM=`expr ${LINKNUM} + 1`
114	done
115
116	# Set all interfaces in promiscuous mode and don't overwrite src addr.
117	for ETHER in ${BRIDGE_IFACES}; do
118		ngctl msg ${ETHER}: setpromisc 1 || exit 1
119		ngctl msg ${ETHER}: setautosrc 0 || exit 1
120	done
121}
122
123# Stop routine.
124bridge_stop() {
125	ngctl kill ${BRIDGE_NAME}: >/dev/null 2>&1
126	for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
127		ngctl kill ${ETHER}: >/dev/null 2>&1
128	done
129}
130
131# Stats routine.
132bridge_stats() {
133
134	# Make sure node exists.
135	bridge_verify
136
137	echo ""
138	echo "Statistics for bridging network ${BRIDGE_NAME}:"
139	echo ""
140	LINKNUM=0
141	for ETHER in ${BRIDGE_IFACES}; do
142		echo "Network interface ${ETHER}:"
143		bridge_linkstats ${LINKNUM}
144		LINKNUM=`expr ${LINKNUM} + 1`
145	done
146	for LOCAL_IFACE in ${LOCAL_IFACES}; do
147		echo "Local host interface ${LOCAL_IFACE}:"
148		bridge_linkstats ${LINKNUM}
149		LINKNUM=`expr ${LINKNUM} + 1`
150	done
151}
152
153# Main entry point.
154case $1 in
155	start)
156		bridge_start
157		;;
158	stats)
159		bridge_verify
160		bridge_stats
161		;;
162	stop)
163		bridge_verify
164		bridge_stop
165		;;
166	*)
167		echo "usage: $0 [ start | stop | stats ]"
168		exit 1
169esac
170