xref: /freebsd/tests/sys/netinet/output.sh (revision a91a2465)
1#!/usr/bin/env atf-sh
2#-
3# SPDX-License-Identifier: BSD-2-Clause
4#
5# Copyright (c) 2020 Alexander V. Chernikov
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28#
29
30. $(atf_get_srcdir)/../common/vnet.subr
31
32atf_test_case "output_tcp_setup_success" "cleanup"
33output_tcp_setup_success_head()
34{
35
36	atf_set descr 'Test valid IPv4 TCP output'
37	atf_set require.user root
38}
39
40output_tcp_setup_success_body()
41{
42
43	vnet_init
44
45	net_src="192.0.2."
46	net_dst="192.0.2."
47	ip_src="${net_src}1"
48	ip_dst="${net_dst}2"
49	plen=24
50	text="testtesttst"
51	port=4242
52
53	script_name=`dirname $0`/../common/net_receiver.py
54	script_name=`realpath ${script_name}`
55	jname="v4t-output_tcp_setup_success"
56
57	epair=$(vnet_mkepair)
58
59	vnet_mkjail ${jname}a ${epair}a
60	jexec ${jname}a ifconfig ${epair}a up
61	jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen}
62
63	vnet_mkjail ${jname}b ${epair}b
64	jexec ${jname}b ifconfig ${epair}b up
65
66	jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen}
67
68	# run listener
69	args="--family inet --ports ${port} --match_str ${text}"
70	echo jexec ${jname}b ${script_name} ${args}
71	jexec ${jname}b ${script_name} --test_name "test_listen_tcp" ${args} &
72	cmd_pid=$!
73
74	# wait for the script init
75	counter=0
76	while [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; do
77		sleep 0.01
78		counter=$((counter+1))
79		if [ ${counter} -ge 50 ]; then break; fi
80	done
81	if [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; then
82		echo "App setup failed"
83		exit 1
84	fi
85
86	# run sender
87	echo -n "${text}" | jexec ${jname}a nc -N ${ip_dst} ${port}
88	exit_code=$?
89	if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi
90
91	wait ${cmd_pid}
92	exit_code=$?
93	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
94}
95
96output_tcp_setup_success_cleanup()
97{
98	vnet_cleanup
99}
100
101
102atf_test_case "output_udp_setup_success" "cleanup"
103output_udp_setup_success_head()
104{
105
106	atf_set descr 'Test valid IPv4 UDP output'
107	atf_set require.user root
108}
109
110output_udp_setup_success_body()
111{
112
113	vnet_init
114
115	net_src="192.0.2."
116	net_dst="192.0.2."
117	ip_src="${net_src}1"
118	ip_dst="${net_dst}2"
119	plen=24
120	text="testtesttst"
121	port=4242
122
123	script_name=`dirname $0`/../common/net_receiver.py
124	script_name=`realpath ${script_name}`
125	jname="v4t-output_udp_setup_success"
126
127	epair=$(vnet_mkepair)
128
129	vnet_mkjail ${jname}a ${epair}a
130	jexec ${jname}a ifconfig ${epair}a up
131	jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen}
132
133	vnet_mkjail ${jname}b ${epair}b
134	jexec ${jname}b ifconfig ${epair}b up
135	jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen}
136
137	# run listener
138	args="--family inet --ports ${port} --match_str ${text}"
139	echo jexec ${jname}b ${script_name} ${args}
140	jexec ${jname}b ${script_name} --test_name "test_listen_udp" ${args} &
141	cmd_pid=$!
142
143	# wait for the script init
144	counter=0
145	while [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; do
146		sleep 0.1
147		counterc=$((counter+1))
148		if [ ${counter} -ge 50 ]; then break; fi
149	done
150	if [ `jexec ${jname}b sockstat -4qlp ${port} | wc -l` != "1" ]; then
151		echo "App setup failed"
152		exit 1
153	fi
154
155	# run sender
156	# TODO: switch from nc to some alternative to avoid 1-second delay
157	echo -n "${text}" | jexec ${jname}a nc -uNw1 ${ip_dst} ${port}
158	exit_code=$?
159	if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi
160
161	wait ${cmd_pid}
162	exit_code=$?
163	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
164}
165
166output_udp_setup_success_cleanup()
167{
168	vnet_cleanup
169}
170
171atf_test_case "output_raw_success" "cleanup"
172output_raw_success_head()
173{
174
175	atf_set descr 'Test valid IPv4 raw output'
176	atf_set require.user root
177}
178
179output_raw_success_body()
180{
181
182	vnet_init
183
184	net_src="192.0.2."
185	net_dst="192.0.2."
186	ip_src="${net_src}1"
187	ip_dst="${net_dst}2"
188	plen=24
189
190	script_name=`dirname $0`/../common/net_receiver.py
191	script_name=`realpath ${script_name}`
192	jname="v4t-output_raw_success"
193
194	epair=$(vnet_mkepair)
195
196	vnet_mkjail ${jname}a ${epair}a
197	jexec ${jname}a ifconfig ${epair}a up
198	jexec ${jname}a ifconfig ${epair}a inet ${ip_src}/${plen}
199
200	vnet_mkjail ${jname}b ${epair}b
201	jexec ${jname}b ifconfig ${epair}b up
202
203	jexec ${jname}b ifconfig ${epair}b inet ${ip_dst}/${plen}
204
205	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
206}
207
208output_raw_success_cleanup()
209{
210	vnet_cleanup
211}
212
213# Multipath tests are done the following way:
214#            epair0
215# jailA lo <        > lo jailB
216#            epair1
217# jailA has 2 routes towards /24 prefix on jailB loopback, via 2 epairs
218# jailB has 1 route towards /24 prefix on jailA loopback, via epair0
219#
220# jailA initiates connections/sends packets towards IPs on jailB loopback.
221# Script then compares amount of packets sent via epair0 and epair1
222
223mpath_check()
224{
225	if [ `sysctl -iW net.route.multipath | wc -l` != "1" ]; then
226		atf_skip "This test requires ROUTE_MPATH enabled"
227	fi
228}
229
230mpath_enable()
231{
232	jexec $1 sysctl net.route.multipath=1
233	if [ $? != 0 ]; then
234		atf_fail "Setting multipath in jail $1 failed".
235	fi
236}
237
238atf_test_case "output_tcp_flowid_mpath_success" "cleanup"
239output_tcp_flowid_mpath_success_head()
240{
241
242	atf_set descr 'Test valid IPv4 TCP output flowid generation'
243	atf_set require.user root
244}
245
246output_tcp_flowid_mpath_success_body()
247{
248	vnet_init
249	mpath_check
250
251	net_src="192.0.2."
252	net_dst="198.51.100."
253	ip_src="${net_src}1"
254	ip_dst="${net_dst}1"
255	plen=24
256	text="testtesttst"
257
258	script_name=`dirname $0`/../common/net_receiver.py
259	script_name=`realpath ${script_name}`
260	jname="v4t-output_tcp_flowid_mpath_success"
261
262	epair0=$(vnet_mkepair)
263	epair1=$(vnet_mkepair)
264	lo_src=$(vnet_mkloopback)
265	lo_dst=$(vnet_mkloopback)
266
267	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
268	mpath_enable ${jname}a
269	# Setup transit IPv4 networks
270	jexec ${jname}a ifconfig ${epair0}a up
271	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
272	jexec ${jname}a ifconfig ${epair1}a up
273	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
274	jexec ${jname}a ifconfig ${lo_src} up
275
276	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
277	jexec ${jname}b ifconfig ${epair0}b up
278	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
279	jexec ${jname}b ifconfig ${epair1}b up
280	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
281	jexec ${jname}b ifconfig ${lo_dst} up
282
283	# DST ips/ports to test
284	ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251"
285	ports="53540 49743 43067 9131 16734 5150 14379 40292 20634 51302 3387 24387 9282 14275 42103 26881 42461 29520 45714 11096"
286
287	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
288
289	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
290	for i in ${ips}; do
291		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
292	done
293
294	# Add routes
295	# A -> towards B via epair0a
296	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
297	# A -> towards B via epair1a
298	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
299
300	# B towards A via epair0b
301	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
302
303	# Base setup verification
304	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
305
306	# run listener
307	num_ports=`echo ${ports} | wc -w`
308	num_ips=`echo ${ips} | wc -w`
309	count_examples=$((num_ports*num_ips))
310	listener_ports=`echo ${ports} | tr ' ' '\n' | sort -n | tr '\n' ',' | sed -e 's?,$??'`
311	args="--family inet --ports ${listener_ports} --count ${count_examples} --match_str ${text}"
312	echo jexec ${jname}b ${script_name} ${args}
313	jexec ${jname}b ${script_name} --test_name "test_listen_tcp" ${args} &
314	cmd_pid=$!
315
316	# wait for the app init
317	counter=0
318	init=0
319	while [ ${counter} -le 50 ]; do
320		_ports=`jexec ${jname}b sockstat -4ql | awk "\\\$3 == ${cmd_pid} {print \\\$6}"|awk -F: "{print \\\$2}" | sort -n | tr '\n' ','`
321		if [ "${_ports}" = "${listener_ports}," ]; then
322			init=1
323			break;
324		fi
325	done
326	if [ ${init} -eq 0 ]; then
327		jexec ${jname}b sockstat -6ql | awk "\$3 == ${cmd_pid}"
328		echo "App setup failed"
329		exit 1
330	fi
331	echo "App setup done"
332
333	# run sender
334	for _ip in ${ips}; do
335		ip="${net_dst}${_ip}"
336		for port in ${ports}; do
337			echo -n "${text}" | jexec ${jname}a nc -nN ${ip} ${port}
338			exit_code=$?
339			if [ $exit_code -ne 0 ]; then atf_fail "sender exit code $exit_code" ; fi
340		done
341	done
342
343	wait ${cmd_pid}
344	exit_code=$?
345	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
346
347	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
348	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
349	if [ ${pkt_0} -le 10 ]; then
350		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
351	fi
352	if [ ${pkt_1} -le 10 ]; then
353		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
354		exit 1
355	fi
356	echo "TCP Balancing: 1: ${pkt_0} 2: ${pkt_1}"
357}
358
359output_tcp_flowid_mpath_success_cleanup()
360{
361	vnet_cleanup
362}
363
364atf_test_case "output_udp_flowid_mpath_success" "cleanup"
365output_udp_flowid_mpath_success_head()
366{
367
368	atf_set descr 'Test valid IPv4 UDP output flowid generation'
369	atf_set require.user root
370}
371
372output_udp_flowid_mpath_success_body()
373{
374
375	vnet_init
376	mpath_check
377
378	# Note this test will spawn around ~100 nc processes
379
380	net_src="192.0.2."
381	net_dst="198.51.100."
382	ip_src="${net_src}1"
383	ip_dst="${net_dst}1"
384	plen=24
385	text="testtesttst"
386
387	script_name=`dirname $0`/../common/net_receiver.py
388	script_name=`realpath ${script_name}`
389	jname="v4t-output_udp_flowid_mpath_success"
390
391	epair0=$(vnet_mkepair)
392	epair1=$(vnet_mkepair)
393	lo_src=$(vnet_mkloopback)
394	lo_dst=$(vnet_mkloopback)
395
396	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
397	mpath_enable ${jname}a
398	# Setup transit IPv4 networks
399	jexec ${jname}a ifconfig ${epair0}a up
400	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
401	jexec ${jname}a ifconfig ${epair1}a up
402	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
403	jexec ${jname}a ifconfig ${lo_src} up
404
405	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
406	jexec ${jname}b ifconfig ${epair0}b up
407	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
408	jexec ${jname}b ifconfig ${epair1}b up
409	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
410	jexec ${jname}b ifconfig ${lo_dst} up
411
412	# DST ips/ports to test
413	ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251"
414	ports="53540 49743 43067 9131 16734 5150 14379 40292 20634 51302 3387 24387 9282 14275 42103 26881 42461 29520 45714 11096"
415
416	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
417
418	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
419	for i in ${ips}; do
420		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
421	done
422
423	# Add routes
424	# A -> towards B via epair0a
425	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
426	# A -> towards B via epair1a
427	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
428
429	# B towards A via epair0b
430	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
431
432	# Base setup verification
433	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
434
435	# run listener
436	num_ports=`echo ${ports} | wc -w`
437	num_ips=`echo ${ips} | wc -w`
438	count_examples=$((num_ports*num_ips))
439	listener_ports=`echo ${ports} | tr ' ' '\n' | sort -n | tr '\n' ',' | sed -e 's?,$??'`
440	args="--family inet --ports ${listener_ports} --count ${count_examples} --match_str ${text}"
441	echo jexec ${jname}b ${script_name} ${args}
442	jexec ${jname}b ${script_name} --test_name "test_listen_udp" ${args} &
443	cmd_pid=$!
444
445	# wait for the app init
446	counter=0
447	init=0
448	while [ ${counter} -le 50 ]; do
449		_ports=`jexec ${jname}b sockstat -4ql | awk "\\\$3 == ${cmd_pid} {print \\\$6}"|awk -F: "{print \\\$2}" | sort -n | tr '\n' ','`
450		if [ "${_ports}" = "${listener_ports}," ]; then
451			init=1
452			break;
453		fi
454	done
455	if [ ${init} -eq 0 ]; then
456		jexec ${jname}b sockstat -4ql | awk "\$3 == ${cmd_pid}"
457		echo "App setup failed"
458		exit 1
459	fi
460	echo "App setup done"
461
462	# run sender
463	for _ip in ${ips}; do
464		ip="${net_dst}${_ip}"
465		for port in ${ports}; do
466			# XXX: switch to something that allows immediate exit
467			echo -n "${text}" | jexec ${jname}a nc -nuNw1 ${ip} ${port} &
468			sleep 0.01
469		done
470	done
471
472	wait ${cmd_pid}
473	exit_code=$?
474	if [ $exit_code -ne 0 ]; then atf_fail "receiver exit code $exit_code" ; fi
475
476	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
477	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
478	if [ ${pkt_0} -le 10 ]; then
479		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
480	fi
481	if [ ${pkt_1} -le 10 ]; then
482		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
483	fi
484	echo "UDP BALANCING: 1: ${pkt_0} 2: ${pkt_1}"
485}
486
487output_udp_flowid_mpath_success_cleanup()
488{
489	vnet_cleanup
490}
491
492atf_test_case "output_raw_flowid_mpath_success" "cleanup"
493output_raw_flowid_mpath_success_head()
494{
495
496	atf_set descr 'Test valid IPv4 raw output flowid generation'
497	atf_set require.user root
498}
499
500output_raw_flowid_mpath_success_body()
501{
502
503	vnet_init
504	mpath_check
505
506	net_src="192.0.2."
507	net_dst="198.51.100."
508	ip_src="${net_src}1"
509	ip_dst="${net_dst}1"
510	plen=24
511	text="testtesttst"
512
513	jname="v4t-output_raw_flowid_mpath_success"
514
515	epair0=$(vnet_mkepair)
516	epair1=$(vnet_mkepair)
517	lo_src=$(vnet_mkloopback)
518	lo_dst=$(vnet_mkloopback)
519
520	vnet_mkjail ${jname}a ${epair0}a ${epair1}a ${lo_src}
521	mpath_enable ${jname}a
522	# Setup transit IPv4 networks
523	jexec ${jname}a ifconfig ${epair0}a up
524	jexec ${jname}a ifconfig ${epair0}a inet 203.0.113.1/30
525	jexec ${jname}a ifconfig ${epair1}a up
526	jexec ${jname}a ifconfig ${epair1}a inet 203.0.113.5/30
527	jexec ${jname}a ifconfig ${lo_src} up
528
529	vnet_mkjail ${jname}b ${epair0}b ${epair1}b ${lo_dst}
530	jexec ${jname}b ifconfig ${epair0}b up
531	jexec ${jname}b ifconfig ${epair0}b inet 203.0.113.2/30
532	jexec ${jname}b ifconfig ${epair1}b up
533	jexec ${jname}b ifconfig ${epair1}b inet 203.0.113.6/30
534	jexec ${jname}b ifconfig ${lo_dst} up
535
536	# DST ips/ports to test
537	ips="4 29 48 53 55 61 71 80 84 87 90 91 119 131 137 153 154 158 162 169 169 171 176 187 197 228 233 235 236 237 245 251"
538
539	jexec ${jname}a ifconfig ${lo_src} inet ${ip_src}/32
540
541	jexec ${jname}b ifconfig ${lo_dst} inet ${ip_dst}/32
542	for i in ${ips}; do
543		jexec ${jname}b ifconfig ${lo_dst} alias ${net_dst}${i}/32
544	done
545
546	# Add routes
547	# A -> towards B via epair0a
548	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.2
549	# A -> towards B via epair1a
550	jexec ${jname}a route add -4 -net ${net_dst}0/${plen} 203.0.113.6
551
552	# B towards A via epair0b
553	jexec ${jname}b route add -4 -net ${net_src}0/${plen} 203.0.113.1
554
555	# Base setup verification
556	atf_check -o match:'1 packets transmitted, 1 packets received' jexec ${jname}a ping -nc1 ${ip_dst}
557
558	# run sender
559	valid_message='1 packets transmitted, 1 packets received'
560	for _ip in ${ips}; do
561		ip="${net_dst}${_ip}"
562		atf_check -o match:"${valid_message}" jexec ${jname}a ping -nc1 ${ip}
563	done
564
565	pkt_0=`jexec ${jname}a netstat -Wf link -I ${epair0}a | head | awk '$1!~/^Name/{print$8}'`
566	pkt_1=`jexec ${jname}a netstat -Wf link -I ${epair1}a | head | awk '$1!~/^Name/{print$8}'`
567
568	jexec ${jname}a netstat -bWf link -I ${epair0}a
569	jexec ${jname}a netstat -bWf link -I ${epair1}a
570	if [ ${pkt_0} -le 10 ]; then
571		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
572	fi
573	if [ ${pkt_1} -le 10 ]; then
574		atf_fail "Balancing failure: 1: ${pkt_0} 2: ${pkt_1}"
575	fi
576	echo "RAW BALANCING: 1: ${pkt_0} 2: ${pkt_1}"
577}
578
579output_raw_flowid_mpath_success_cleanup()
580{
581	vnet_cleanup
582}
583
584atf_init_test_cases()
585{
586	atf_add_test_case "output_tcp_setup_success"
587	atf_add_test_case "output_udp_setup_success"
588	atf_add_test_case "output_raw_success"
589	atf_add_test_case "output_tcp_flowid_mpath_success"
590	atf_add_test_case "output_udp_flowid_mpath_success"
591	atf_add_test_case "output_raw_flowid_mpath_success"
592}
593
594