1EXTRA_CMD_ARGS="--nss"
2
3# adds a class and qdisc for a zone
4# $1: dev
5# $2: zone identifier
6add_zone() {
7	local dev=$1
8	local zone=$2
9	local classid=$(sb_gen_zone_classid ${zone})
10	local weight=$(sb_get_zone_weight ${dev} ${zone})
11	local rate=$(sb_get_zone_rate ${dev} ${zone})
12
13	# the zone class specifies the interzone weight for this zone
14	tc class add dev ${dev} \
15		parent ${BF_HANDLE_MAJOR}: \
16		classid ${BF_HANDLE_MAJOR}:${classid} \
17		nssbf rate 1000mbit burst 1000kb quantum ${weight} mtu 1514
18	[ $? = 0 ] || return $?
19
20	# if we have an upper bw limit, add a tbl
21	if [ -n "${rate}" ] && [ "${rate}" -gt 0 ]; then
22		local burst
23		local tblclassid=$(sb_gen_zone_tbl_classid ${zone})
24
25		# add the tbl
26		let burst=${rate}/10
27		tc qdisc add dev ${dev} \
28			parent ${BF_HANDLE_MAJOR}:${classid} \
29			handle ${tblclassid}: \
30			nsstbl rate ${rate} burst ${burst} mtu 1514
31		[ $? = 0 ] || return $?
32
33		# add the qdisc for background & classified
34		tc qdisc add dev ${dev} \
35			parent ${tblclassid}:1 \
36			handle ${classid}: \
37			nssbf
38		[ $? = 0 ] || return $?
39	else
40		# add the qdisc for background & classified
41		tc qdisc add dev ${dev} \
42			parent ${BF_HANDLE_MAJOR}:${classid} \
43			handle ${classid}: \
44			nssbf
45		[ $? = 0 ] || return $?
46	fi
47
48	# zone background
49	tc class add dev ${dev} \
50		parent ${classid}: \
51		classid ${classid}:${CLASSID_BACKGROUND} \
52		nssbf rate 1000mbit burst 1000kb \
53			mtu 1514 quantum ${BACKGROUND_WEIGHT}
54	[ $? = 0 ] || return $?
55
56	# zone classified
57	tc class add dev ${dev} \
58		parent ${classid}: \
59		classid ${classid}:${CLASSID_CLASSIFIED} \
60		nssbf rate 1000mbit burst 1000kb \
61			mtu 1514 quantum ${COMMITTED_WEIGHT}
62	[ $? = 0 ] || return $?
63}
64
65# sets up the qdisc structures on an interface
66# Note: this only sets a default rate on the root class, not necessarily the
67#	correct rate; qdiscman handles this when it starts up
68#
69# $1: dev
70setup_iface() {
71	local dev=$1
72	tc qdisc add dev ${dev} root \
73		handle ${PRIO_HANDLE_MAJOR}: \
74		nssprio bands 3
75	[ $? = 0 ] || return $?
76	# interactive for localhost OUTPUT.  the target qdisc is not limited
77	# by streamboost and is used for two cases (see iptables rules):
78	#   1. localhost to LAN so the UI is responsive.
79	#   2. localhost to WAN for the bandwidth tester ports only so the
80	#      tester can measure accurately.
81	add_interactive_qdisc ${dev} \
82		"${PRIO_HANDLE_MAJOR}:3" \
83		"${OUTPUT_HANDLE_MAJOR}:" "nsscodel"
84	[ $? = 0 ] || return $?
85	# base nsstbl under which all streamboost classes appear
86	tc qdisc add dev ${dev} \
87		parent ${PRIO_HANDLE_MAJOR}:2 \
88		handle ${TBF_HANDLE_MAJOR}: \
89		nsstbl rate 1000mbit burst 1000kb mtu 1514
90	[ $? = 0 ] || return $?
91
92	# subprio used to split out the guest network
93	tc qdisc add dev ${dev} \
94		parent ${TBF_HANDLE_MAJOR}:1 \
95		handle ${SUBPRIO_HANDLE_MAJOR}: \
96		nssprio bands 2
97
98	# schroot
99	tc qdisc add dev ${dev} \
100		parent ${SUBPRIO_HANDLE_MAJOR}:1 \
101		handle ${SCHROOT_HANDLE_MAJOR}: \
102		nssbf
103	[ $? = 0 ] || return $?
104
105	# global background
106	tc class add dev ${dev} \
107		parent ${SCHROOT_HANDLE_MAJOR}: \
108		classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_BACKGROUND} \
109		nssbf rate 1000mbit burst 1000kb mtu 1514
110	[ $? = 0 ] || return $?
111
112	# default for unclassified flows
113	tc class add dev ${dev} \
114		parent ${SCHROOT_HANDLE_MAJOR}: \
115		classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_DEFAULT} \
116		nssbf rate 1000mbit burst 1000kb mtu 1514
117	[ $? = 0 ] || return $?
118	add_interactive_qdisc ${dev} \
119		"${SCHROOT_HANDLE_MAJOR}:${CLASSID_DEFAULT}" \
120		"${CLASSID_DEFAULT}:" "nsscodel" "set_default"
121	[ $? = 0 ] || return $?
122
123	# localhost class for traffic originating from the router to the WAN
124	tc class add dev ${dev} \
125		parent ${SCHROOT_HANDLE_MAJOR}: \
126		classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_LOCALHOST} \
127		nssbf rate 1000mbit burst 1000kb mtu 1514
128	[ $? = 0 ] || return $?
129	add_interactive_qdisc ${dev} \
130		"${SCHROOT_HANDLE_MAJOR}:${CLASSID_LOCALHOST}" \
131		"${CLASSID_LOCALHOST}:" "nsscodel"
132	[ $? = 0 ] || return $?
133
134	# "cheat" is for things like ICMP acceleration
135	tc class add dev ${dev} \
136		parent ${SCHROOT_HANDLE_MAJOR}: \
137		classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_ELEVATED_CHEAT} \
138		nssbf rate 1000mbit burst 1000kb mtu 1514
139	[ $? = 0 ] || return $?
140	add_interactive_qdisc ${dev} \
141		"${SCHROOT_HANDLE_MAJOR}:${CLASSID_ELEVATED_CHEAT}" \
142		"${CLASSID_ELEVATED_CHEAT}:" "nsscodel"
143	[ $? = 0 ] || return $?
144
145	# browser
146	tc class add dev ${dev} \
147		parent ${SCHROOT_HANDLE_MAJOR}: \
148		classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_ELEVATED_BROWSER} \
149		nssbf rate 1000mbit burst 1000kb mtu 1514
150	[ $? = 0 ] || return $?
151	add_interactive_qdisc ${dev} \
152		"${SCHROOT_HANDLE_MAJOR}:${CLASSID_ELEVATED_BROWSER}" \
153		"${CLASSID_ELEVATED_BROWSER}:" "nsscodel"
154	[ $? = 0 ] || return $?
155
156	# dns
157	tc class add dev ${dev} \
158		parent ${SCHROOT_HANDLE_MAJOR}: \
159		classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_ELEVATED_DNS} \
160		nssbf rate 1000mbit burst 1000kb
161	[ $? = 0 ] || return $?
162	add_interactive_qdisc ${dev} \
163		"${SCHROOT_HANDLE_MAJOR}:${CLASSID_ELEVATED_DNS}" \
164		"${CLASSID_ELEVATED_DNS}:" "nsscodel"
165	[ $? = 0 ] || return $?
166
167	# guest network
168	tc qdisc add dev ${dev} \
169		parent ${SUBPRIO_HANDLE_MAJOR}:2 \
170		handle ${GUEST_HANDLE_MAJOR}: \
171		nsstbl burst 500kbit mtu 1514 rate ${GUEST_BANDWIDTH_LIMIT:-5mbit}
172	[ $? = 0 ] || return $?
173	add_interactive_qdisc ${dev} \
174		"${GUEST_HANDLE_MAJOR}:1" \
175		"${CLASSID_GUEST}:" "nsscodel"
176	[ $? = 0 ] || return $?
177
178	# if we're configured for more than just a single default zone, then
179	# we add a qdisc for each zone under the classified qdisc so that the
180	# parent of each flow will be one of these zone qdiscs depending on
181	# which zone the flow's device is configured.  else, we do nothing
182	# special here and the classified qdisc is the parent for all flows.
183	local zonecount=$(sb_get_zone_count)
184	if [ -z "${zonecount}" ] || [ "${zonecount}" -le 1 ]; then
185		# normal qdisc structure, no zones
186
187		#
188		# global classified
189		#
190		tc class add dev ${dev} \
191			parent ${SCHROOT_HANDLE_MAJOR}: \
192			classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_CLASSIFIED} \
193			nssbf rate 1000mbit burst 1000kb mtu 1514
194		[ $? = 0 ] || return $?
195		tc qdisc add dev ${dev} \
196			parent ${SCHROOT_HANDLE_MAJOR}:${CLASSID_CLASSIFIED} \
197			handle ${BF_HANDLE_MAJOR}: \
198			nssbf
199		[ $? = 0 ] || return $?
200	else
201		local maxzoneid=$(sb_get_max_zone_id)
202		# zoned setup
203		#
204		# first we add the zone root at a weight which combines the
205		# background and classified qdiscs.  to that we attach one
206		# zone qdisc per zone. each zone qdisc has a limiter so that
207		# we can support per-zone max rates and then a classified and
208		# background qdisc with the usual weights
209
210		# add the zone root
211		local weight=$((${COMMITTED_WEIGHT}+${BACKGROUND_WEIGHT}))
212		tc class add dev ${dev} \
213			parent ${SCHROOT_HANDLE_MAJOR}: \
214			classid ${SCHROOT_HANDLE_MAJOR}:${CLASSID_ZONE_ROOT} \
215			nssbf rate 1000mbit burst 1000kb \
216				quantum ${weight} mtu 1514
217		[ $? = 0 ] || return $?
218		tc qdisc add dev ${dev} \
219			parent ${SCHROOT_HANDLE_MAJOR}:${CLASSID_ZONE_ROOT} \
220			handle ${BF_HANDLE_MAJOR}: \
221			nssbf
222		[ $? = 0 ] || return $?
223
224		# add each zone to the zone root
225		local zone=0
226		while [ "${zone}" -le "${maxzoneid}" ]; do
227			if [ $(sb_zone_is_configured ${zone}) = "0" ]; then
228				add_zone ${dev} ${zone}
229			fi
230			let zone=zone+1
231		done
232	fi
233}
234
235#
236#  sets up iptables rules
237#
238#  $1: iptables executable, e.g., 'iptables' or 'ip6tables'
239#  $2: 'A' or 'D' depending on whether to add all rules or delete them
240generic_iptables() {
241	local ipt=$1
242	local cmd=$2
243	local guest_rules=no
244
245	[ "${ipt}" = "iptables" ] && [ "$GUEST_DHCP_ENABLE" = "yes" -o "$2" = "D" ] && guest_rules="yes"
246
247	# All packets from localhost to LAN are marked to skip BWC
248	${ipt} -t mangle -${cmd} OUTPUT -o $LAN_IFACE -j CLASSIFY \
249		--set-class ${OUTPUT_HANDLE_MAJOR}:0
250
251	# If this is from localhost AND is using the aperture source
252	# ports, set the class to avoid BWC.
253	${ipt} -t mangle -${cmd} OUTPUT ! -o $LAN_IFACE -p tcp -m multiport \
254		--source-ports 321:353 -j CLASSIFY \
255		--set-class ${OUTPUT_HANDLE_MAJOR}:0
256	${ipt} -t mangle -${cmd} OUTPUT ! -o $LAN_IFACE -p tcp -m multiport \
257		--source-ports 321:353 -j RETURN
258
259	# All packets from localhost to WAN are marked
260	# Note the !LAN_IFACE logic allows us to catch any potential
261	# PPPoE interface as well
262	${ipt} -t mangle -${cmd} OUTPUT ! -o $LAN_IFACE -j CLASSIFY \
263		--set-class ${CLASSID_LOCALHOST}:0
264
265	# Guest network traffic goes somewhere else - only IPv4 is supported
266	[ "${guest_rules}" = "yes" ] && {
267		local bypass=$(ipaddr_netmask_to_cidr ${GUEST_DHCP_IPADDR} ${GUEST_DHCP_NETMASK})
268		local mark=$(printf "0x%04x%04x" 0x${BF_HANDLE_MAJOR} 0x${CLASSID_GUEST})
269		${ipt} -t mangle -${cmd} FORWARD ! -o $LAN_IFACE -s ${bypass} \
270			-j CLASSIFY --set-class "${CLASSID_GUEST}":0
271		${ipt} -t mangle -${cmd} FORWARD ! -o $LAN_IFACE -s ${bypass} \
272			-j RETURN
273		${ipt} -t mangle -${cmd} FORWARD -o $LAN_IFACE -d ${bypass} \
274			-j CLASSIFY --set-class "${CLASSID_GUEST}":0
275		${ipt} -t mangle -${cmd} FORWARD -o $LAN_IFACE -d ${bypass} \
276			-j RETURN
277	}
278
279	# Mark all forwarded packets with the global default
280	# XXX - This is not compatible with the inter-op concessions for our
281	# CS release.  ANY mark set from another source will cause SB to not
282	# perform marking. - BenM
283	# ${ipt} -t mangle -${cmd} FORWARD -j CLASSIFY \
284	#	--set-class ${CLASSID_DEFAULT}:0
285
286	# Forwarded ICMP packets go to their own queue
287	${ipt} -t mangle -${cmd} FORWARD -p icmp -m limit --limit 2/second \
288		-j CLASSIFY --set-class ${CLASSID_ELEVATED_CHEAT}:0
289
290	# DNS Elevation
291	${ipt} -t mangle -${cmd} POSTROUTING -p udp --dport 53 \
292		-j CLASSIFY --set-class ${CLASSID_ELEVATED_DNS}:0
293	${ipt} -t mangle -${cmd} POSTROUTING -p udp --dport 53 \
294		-j RETURN
295
296	# TCP Elevation
297	${ipt} -t mangle -${cmd} POSTROUTING -p tcp \
298		-m conntrack --ctorigdstport 80 -m connbytes --connbytes 0:39 \
299		--connbytes-dir both --connbytes-mode packets -j CLASSIFY \
300		--set-class ${CLASSID_ELEVATED_BROWSER}:0
301	${ipt} -t mangle -${cmd} POSTROUTING -p tcp \
302		-m conntrack --ctorigdstport 80 -m connbytes --connbytes 0:39 \
303		--connbytes-dir both --connbytes-mode packets -j RETURN
304
305	# Restore the CONNMARK to the packet
306	${ipt} -t mangle -${cmd} POSTROUTING -j CONNMARK --restore-mark
307	# Further, restore the mark to priority since filters don't work.
308	# Note, mark2prio only overwrites prio with the connmark if the prio
309	# is zero so that it won't stomp on the CLASSIFY target.
310	${ipt} -t mangle -${cmd} POSTROUTING -j mark2prio
311}
312
313setup_iptables () {
314	# call iptables to add rules
315	generic_iptables iptables A
316	generic_iptables ip6tables A
317}
318
319teardown_iptables () {
320	# call iptables to delete rules
321	generic_iptables iptables D
322	generic_iptables ip6tables D
323}
324