1#!/usr/bin/ksh
2#
3# This file and its contents are supplied under the terms of the
4# Common Development and Distribution License ("CDDL"), version 1.0.
5# You may only use this file in accordance with the terms of version
6# 1.0 of the CDDL.
7#
8# A full copy of the text of the CDDL should have accompanied this
9# source.  A copy of the CDDL is also available via the Internet at
10# http://www.illumos.org/license/CDDL.
11
12#
13# Copyright 2019 Joyent, Inc.
14#
15
16#
17# Usage:
18#
19#     ip_forwarding.ksh -bcflnpuv <client> <router> <server>
20#
21#     Where client, router, and server are the names of three native
22#     zones. The user must create and start these zones; but other
23#     than that there is no special configuration required for them.
24#
25#     -b	Place server and router on same underlying simnet, causing
26#		them to talk via MAC-loopback.
27#
28#     -c	Run cleanup only.
29#
30#     -f	Enable Tx ULP hardware checksum.
31#
32#     -l	Enable TCP LSO.
33#
34#     -n	No cleanup: the various artifacts created by this script will
35#               remain after execution.
36#
37#     -p	Enabled partial Tx ULP hardware checksum.
38#
39#     -r	Enable Rx IPv4 header checksum offload.
40#
41#     -u	Run UDP tests.
42#
43#     -v	Vebose mode.
44#
45
46if [[ -z $NET_TESTS ]]; then
47	echo "NET_TESTS not set" >&2
48	exit 1
49fi
50
51. $NET_TESTS/tests/net_common
52
53function cleanup
54{
55	if ((nt_cleanup == 0)); then
56		dbg "skipping cleanup"
57		return 0
58	fi
59
60	rm -rf ${nt_tdirprefix}*
61	zlogin $nt_client rm -rf ${nt_tdirprefix}*
62	zlogin $nt_server rm -rf ${nt_tdirprefix}*
63
64	rm_route $nt_client $nt_server_ip $nt_server_subnet $nt_client_router_ip
65	rm_route $nt_server $nt_client_ip $nt_client_subnet $nt_server_router_ip
66	rm_route6 $nt_client $nt_server_ip6 $nt_server_subnet6 \
67		  $nt_client_router_ip6
68	rm_route6 $nt_server $nt_client_ip6 $nt_client_subnet6 \
69		  $nt_server_router_ip6
70
71	ip_fwd_disable $nt_router
72
73	delete_addr $nt_client ipft_client0 v4
74	delete_addr $nt_router ipft_client_r0 v4
75	delete_addr $nt_router ipft_server_r0 v4
76	delete_addr $nt_server ipft_server0 v4
77
78	delete_addr $nt_client ipft_client0 v6
79	delete_addr $nt_router ipft_client_r0 v6
80	delete_addr $nt_router ipft_server_r0 v6
81	delete_addr $nt_server ipft_server0 v6
82
83	delete_if $nt_client ipft_client0
84	delete_if $nt_router ipft_client_r0
85	delete_if $nt_router ipft_server_r0
86	delete_if $nt_server ipft_server0
87
88	delete_vnic ipft_client0 0 $nt_client
89	delete_vnic ipft_client_r0 0 $nt_router
90	delete_vnic ipft_server_r0 5 $nt_router
91	delete_vnic ipft_server0 5 $nt_server
92
93	for nt_name in ${nt_nics[@]}; do
94		delete_simnet $nt_name
95	done
96}
97
98function usage
99{
100	echo "$nt_tname -bcflnpruv <client> <router> <server>" >&2
101}
102
103#
104# Set test defaults.
105#
106nt_tname=${NT_TNAME:-$(basename $0)}
107nt_loopback=0
108nt_ulp_full=0
109nt_ulp_partial=0
110nt_tcp_lso=0
111nt_udp=0
112nt_rx_ip_cksum=0
113nt_cleanup=1
114nt_cleanup_only=0
115
116nt_tdirprefix=/var/tmp/${nt_tname}
117nt_tdir=${nt_tdirprefix}.$$
118nt_dfile=${nt_tdir}/${nt_tname}.data
119nt_efile=${nt_tdir}/${nt_tname}-expected-sha1
120nt_rfile=${nt_tdir}/${nt_tname}-received-sha1
121nt_ofile=${nt_tdir}/${nt_tname}-received
122nt_client_subnet=192.168.77.0/24
123nt_client_ip=192.168.77.2
124nt_client_router_ip=192.168.77.1
125nt_server_subnet=192.168.88.0/24
126nt_server_ip=192.168.88.2
127nt_server_router_ip=192.168.88.1
128nt_port=7774
129nt_client_subnet6=fd00:0:1:4d::2/64
130nt_client_ip6=fd00:0:1:4d::2
131nt_client_router_ip6=fd00:0:1:4d::1
132nt_server_subnet6=fd00:0:1:58::/64
133nt_server_router_ip6=fd00:0:1:58::1
134nt_server_ip6=fd00:0:1:58::2
135nt_port6=7776
136nt_bridge=ipft_switch
137typeset -A nt_nics
138
139while getopts "bcflnpruv" opt; do
140	case $opt in
141	b)
142		nt_loopback=1
143		;;
144	c)
145		nt_cleanup_only=1
146		;;
147	f)
148		nt_ulp_full=1
149		;;
150	l)
151		nt_tcp_lso=1
152		;;
153	n)
154		nt_cleanup=0
155		;;
156	p)
157		nt_ulp_partial=1
158		;;
159	r)
160		nt_rx_ip_cksum=1
161		;;
162	u)
163		nt_udp=1
164		;;
165	v)
166		DEBUG=1
167		;;
168	esac
169done
170
171shift $((OPTIND - 1))
172
173if ((nt_ulp_partial == 1)) && ((nt_ulp_full == 1)); then
174	fail "both partial and full checksum enabled"
175fi
176
177if (( $# != 3 )); then
178	usage
179	fail "wrong number of arguments"
180fi
181
182nt_client=$1
183nt_router=$2
184nt_server=$3
185
186if [[ "$nt_client" == "$nt_router" || "$nt_router" == "$nt_server" ||
187	      "$nt_client" == "$nt_server" ]]; then
188	fail "all zones must be unique"
189fi
190
191dbg "client zone: $nt_client"
192dbg "router zone: $nt_router"
193dbg "server zone: $nt_server"
194
195BAIL=1
196zone_exists $nt_client || fail "zone $nt_client not found"
197zone_exists $nt_router || fail "zone $nt_router not found"
198zone_exists $nt_server || fail "zone $nt_server not found"
199
200zone_running $nt_client
201zone_running $nt_router
202zone_running $nt_server
203
204if ! zlogin $nt_client ls /usr/bin/socat > /dev/null; then
205	fail "zone $nt_client missing socat"
206fi
207
208if ! zlogin $nt_server ls /usr/bin/socat > /dev/null; then
209	fail "zone $nt_client missing socat"
210fi
211
212if ((nt_loopback == 0)); then
213	nt_nics[0]=ipft_client_nic0
214	nt_nics[1]=ipft_router_nic0
215	nt_nics[2]=ipft_router_nic1
216	nt_nics[3]=ipft_server_nic0
217else
218	nt_nics[0]=ipft_nic0
219	nt_nics[1]=ipft_nic1
220fi
221
222#
223# Make a best effort to cleanup artifacts from a previous run.
224#
225if ((nt_cleanup_only == 1)); then
226	dbg "performing cleanup only"
227	BAIL=0
228	cleanup
229	BAIL=1
230	exit 0
231fi
232
233if ! mkdir $nt_tdir; then
234	fail "failed to mkdir $nt_tdir in GZ"
235fi
236dbg "created dir $nt_tdir in GZ"
237if ! zlogin $nt_client mkdir $nt_tdir; then
238	fail "failed to mkdir $nt_tdir in $nt_client"
239fi
240dbg "created dir $nt_tdir in $nt_client"
241if ! zlogin $nt_server mkdir $nt_tdir; then
242	fail "failed to mkdir $nt_tdir in $nt_server"
243fi
244dbg "created dir $nt_tdir in $nt_server"
245
246trap cleanup ERR
247
248for nt_name in ${nt_nics[@]}; do
249	create_simnet $nt_name
250done
251
252if ((nt_loopback == 0)); then
253	link_simnets ${nt_nics[0]} ${nt_nics[1]}
254	link_simnets ${nt_nics[2]} ${nt_nics[3]}
255else
256	link_simnets ${nt_nics[0]} ${nt_nics[1]}
257fi
258
259for nt_name in ${nt_nics[@]}; do
260	if ((nt_ulp_partial == 1)); then
261		set_linkprop $nt_name _tx_ulp_cksum partial
262	fi
263
264	if ((nt_ulp_full == 1)); then
265		set_linkprop $nt_name _tx_ulp_cksum fullv4
266	fi
267
268	if ((nt_ulp_full == 1)) || ((nt_ulp_partial == 1)); then
269		set_linkprop $nt_name _tx_ipv4_cksum on
270	fi
271
272	if ((nt_tcp_lso == 1)); then
273		set_linkprop $nt_name _lso on
274	fi
275
276	if ((nt_rx_ip_cksum == 1)); then
277		set_linkprop $nt_name _rx_ipv4_cksum on
278	fi
279done
280
281if ((nt_loopback == 0)); then
282	create_vnic ipft_client0 ipft_client_nic0 0 $nt_client
283	create_vnic ipft_client_r0 ipft_router_nic0 0 $nt_router
284	create_vnic ipft_server_r0 ipft_router_nic1 5 $nt_router
285	create_vnic ipft_server0 ipft_server_nic0 5 $nt_server
286else
287	create_vnic ipft_client0 ipft_nic0 0 $nt_client
288	create_vnic ipft_client_r0 ipft_nic1 0 $nt_router
289	create_vnic ipft_server_r0 ipft_nic1 5 $nt_router
290	create_vnic ipft_server0 ipft_nic1 5 $nt_server
291fi
292
293ip_fwd_enable $nt_router
294
295create_addr $nt_client ipft_client0 $nt_client_ip/24
296create_addr $nt_router ipft_client_r0 $nt_client_router_ip/24
297create_addr $nt_router ipft_server_r0 $nt_server_router_ip/24
298create_addr $nt_server ipft_server0 $nt_server_ip/24
299
300add_route $nt_client $nt_server_ip $nt_server_subnet $nt_client_router_ip
301add_route $nt_server $nt_client_ip $nt_client_subnet $nt_server_router_ip
302
303create_addr6 $nt_client ipft_client0 $nt_client_ip6
304create_addr6 $nt_router ipft_client_r0 $nt_client_router_ip6
305create_addr6 $nt_router ipft_server_r0 $nt_server_router_ip6
306create_addr6 $nt_server ipft_server0 $nt_server_ip6
307
308add_route6 $nt_client $nt_server_ip6 $nt_server_subnet6 $nt_client_router_ip6
309add_route6 $nt_server $nt_client_ip6 $nt_client_subnet6 $nt_server_router_ip6
310
311dd if=/dev/urandom of=$nt_dfile bs=1024 count=1024 > /dev/null 2>&1
312if (($? != 0)); then
313	fail "failed to create data file: $nt_dfile"
314else
315	dbg "created data file: $nt_dfile"
316fi
317
318digest -a sha1 $nt_dfile > $nt_efile
319
320# ================================================================
321# client -> server
322# ================================================================
323ping $nt_client $nt_client_ip $nt_server_ip
324ping $nt_client $nt_client_ip6 $nt_server_ip6
325
326start_server $nt_server TCP4 $nt_server_ip $nt_port $nt_ofile
327nt_listener_ppid=$!
328
329# Give the server time to start.
330sleep 1
331
332dbg "sending 1M $nt_client ($nt_client_ip) -> $nt_server ($nt_server_ip)"
333zlogin $nt_client /usr/bin/socat -b 8192 STDIN \
334       TCP4:$nt_server_ip:$nt_port,connect-timeout=5 < $nt_dfile
335
336if (($? != 0)); then
337	pkill -TERM -P $nt_listener_ppid
338	fail "failed to run socat client"
339else
340	dbg "sent 1M $nt_client ($nt_client_ip) -> $nt_server ($nt_server_ip)"
341fi
342
343#
344# The client may have exited but make sure to give the server time to
345# exit and finish computing the SHA1.
346#
347dbg "waiting for listener $nt_listener_ppid"
348wait_for_pid $nt_listener_ppid 5
349dbg "listener $nt_listener_ppid exited"
350
351digest -a sha1 /zones/$nt_server/root/$nt_ofile > $nt_rfile
352
353if ! diff $nt_efile $nt_rfile; then
354	fail "SHA1 comparison failed"
355else
356	dbg "SHA1 comparison passed"
357fi
358
359start_server $nt_server TCP6 $nt_server_ip6 $nt_port6 $nt_rfile
360listener_ppid=$!
361
362# Give the server time to start.
363sleep 1
364
365zlogin $nt_client /usr/bin/socat -b 8192 STDIN \
366       TCP6:[${nt_server_ip6}]:$nt_port6,connect-timeout=5 < $nt_dfile
367
368if (($? != 0)); then
369	pkill -TERM -P $nt_listener_ppid
370	fail "failed to run socat client IPv6"
371else
372	dbg "sent 1M $nt_client ($nt_client_ip6)" \
373	    "-> $nt_server ($nt_server_ip6) IPv6"
374fi
375
376#
377# The client may have exited but make sure to give the server time to
378# exit and finish computing the SHA1.
379#
380dbg "waiting for listener $nt_listener_ppid"
381wait_for_pid $nt_listener_ppid 5
382dbg "listener $nt_listener_ppid exited"
383
384digest -a sha1 /zones/$nt_server/root/$nt_ofile > $nt_rfile
385
386if ! diff $nt_efile $nt_rfile; then
387	fail "SHA1 comparison failed"
388else
389	dbg "SHA1 comparison passed"
390fi
391
392if ((nt_udp == 1)); then
393	ping_udp $nt_client $nt_client_ip $nt_server_ip 256 3
394	ping_udp $nt_client $nt_client_ip6 $nt_server_ip6 256 3
395
396	#
397	# Test IP fragmentation by sending a larger-than-MTU datagram.
398	# You can verify fragmentation is happening by dtracing the
399	# various "Frag" and "Reasm" mibs.
400	#
401	dbg "test IP fragmentation $nt_client_ip -> $nt_server_ip"
402	ping_udp $nt_client $nt_client_ip $nt_server_ip $((1024 * 16)) 3
403
404	dbg "test IPv6 fragmentation $nt_client_ip6 -> $nt_server_ip6"
405	ping_udp $nt_client $nt_client_ip6 $nt_server_ip6 $((1024 * 16)) 3
406fi
407
408# ================================================================
409# server -> client
410# ================================================================
411ping $nt_server $nt_server_ip $nt_client_ip
412ping $nt_server $nt_server_ip6 $nt_client_ip6
413
414start_server $nt_client TCP4 $nt_client_ip $nt_port $nt_ofile
415nt_listener_ppid=$!
416
417# Give the listener time to start.
418sleep 1
419
420zlogin $nt_server /usr/bin/socat -b 8192 STDIN \
421       TCP4:$nt_client_ip:$nt_port,bind=$nt_server_ip,connect-timeout=5 \
422       < $nt_dfile
423
424if (($? != 0)); then
425	pkill -TERM -P $nt_listener_ppid
426	fail "failed to run socat client"
427else
428	dbg "sent 1M $nt_server ($nt_server_ip) -> $nt_client ($nt_client_ip)"
429fi
430
431#
432# The client may have exited but make sure to give the server time to
433# exit and finish computing the SHA1.
434#
435dbg "waiting for listener $nt_listener_ppid"
436wait_for_pid $nt_listener_ppid 5
437dbg "listener $nt_listener_ppid exited"
438
439digest -a sha1 /zones/$nt_client/root/$nt_ofile > $nt_rfile
440
441if ! diff $nt_efile $nt_rfile; then
442	fail "SHA1 comparison failed"
443else
444	dbg "SHA1 comparison passed"
445fi
446
447start_server $nt_client TCP6 $nt_client_ip6 $nt_port6 $nt_ofile
448nt_listener_ppid=$!
449
450# Give the listener time to start.
451sleep 1
452
453zlogin $nt_server /usr/bin/socat -b 8192 STDIN \
454       TCP6:[$nt_client_ip6]:$nt_port6,connect-timeout=5 < $nt_dfile
455
456if (($? != 0)); then
457	pkill -TERM -P $nt_listener_ppid
458	fail "failed to run socat client IPv6"
459else
460	dbg "sent 1M $nt_server ($nt_server_ip6) -> $nt_client ($nt_client_ip6)"
461fi
462
463#
464# The client may have exited but make sure to give the server time to
465# exit and finish computing the SHA1.
466#
467dbg "waiting for listener $nt_listener_ppid"
468wait_for_pid $nt_listener_ppid 5
469dbg "server $nt_listener_ppid exited"
470
471digest -a sha1 /zones/$nt_client/root/$nt_ofile > $nt_rfile
472
473if ! diff $nt_efile $nt_rfile; then
474	fail "SHA1 comparison failed"
475else
476	dbg "SHA1 comparison passed"
477fi
478
479if ((nt_udp == 1)); then
480	ping_udp $nt_server $nt_server_ip $nt_client_ip 256 3
481	ping_udp $nt_server $nt_server_ip6 $nt_client_ip6 256 3
482
483	#
484	# Test IP fragmentation by sending a larger-than-MTU datagram.
485	# You can verify fragmentation is happening by dtracing the
486	# various "Frag" and "Reasm" mibs.
487	#
488	dbg "test IP fragmentation $nt_server_ip -> $nt_client_ip"
489	ping_udp $nt_server $nt_server_ip $nt_client_ip $((1024 * 16)) 3
490
491	dbg "test IPv6 fragmentation $nt_server_ip6 -> $nt_client_ip6"
492	ping_udp $nt_server $nt_server_ip6 $nt_client_ip6 $((1024 * 16)) 3
493fi
494
495cleanup
496echo "PASS [$nt_tname]"
497