1 #!/bin/bash 2 # SPDX-License-Identifier: GPL-2.0 3 # 4 # Copyright (c) 2019 David Ahern <dsahern@gmail.com>. All rights reserved. 5 # Copyright (c) 2020 Michael Jeanson <mjeanson@efficios.com>. All rights reserved. 6 # 7 # Requires CONFIG_NET_VRF, CONFIG_VETH, CONFIG_BRIDGE and CONFIG_NET_NS. 8 # 9 # 10 # Symmetric routing topology 11 # 12 # blue red 13 # +----+ .253 +----+ .253 +----+ 14 # | h1 |-------------------| r1 |-------------------| h2 | 15 # +----+ .1 +----+ .2 +----+ 16 # 172.16.1/24 172.16.2/24 17 # 2001:db8:16:1/64 2001:db8:16:2/64 18 # 19 # 20 # Route from h1 to h2 and back goes through r1, incoming vrf blue has a route 21 # to the outgoing vrf red for the n2 network and red has a route back to n1. 22 # The red VRF interface has a MTU of 1400. 23 # 24 # The first test sends a ping with a ttl of 1 from h1 to h2 and parses the 25 # output of the command to check that a ttl expired error is received. 26 # 27 # The second test runs traceroute from h1 to h2 and parses the output to check 28 # for a hop on r1. 29 # 30 # The third test sends a ping with a packet size of 1450 from h1 to h2 and 31 # parses the output of the command to check that a fragmentation error is 32 # received. 33 # 34 # 35 # Asymmetric routing topology 36 # 37 # This topology represents a customer setup where the issue with icmp errors 38 # and VRF route leaking was initialy reported. The MTU test isn't done here 39 # because of the lack of a return route in the red VRF. 40 # 41 # blue red 42 # .253 +----+ .253 43 # +----| r1 |----+ 44 # | +----+ | 45 # +----+ | | +----+ 46 # | h1 |--------------+ +--------------| h2 | 47 # +----+ .1 | | .2 +----+ 48 # 172.16.1/24 | +----+ | 172.16.2/24 49 # 2001:db8:16:1/64 +----| r2 |----+ 2001:db8:16:2/64 50 # .254 +----+ .254 51 # 52 # 53 # Route from h1 to h2 goes through r1, incoming vrf blue has a route to the 54 # outgoing vrf red for the n2 network but red doesn't have a route back to n1. 55 # Route from h2 to h1 goes through r2. 56 # 57 # The objective is to check that the incoming vrf routing table is selected 58 # to send an ICMP error back to the source when the ttl of a packet reaches 1 59 # while it is forwarded between different vrfs. 60 61 source lib.sh 62 VERBOSE=0 63 PAUSE_ON_FAIL=no 64 DEFAULT_TTYPE=sym 65 66 H1_N1=172.16.1.0/24 67 H1_N1_6=2001:db8:16:1::/64 68 69 H1_N1_IP=172.16.1.1 70 R1_N1_IP=172.16.1.253 71 R2_N1_IP=172.16.1.254 72 73 H1_N1_IP6=2001:db8:16:1::1 74 R1_N1_IP6=2001:db8:16:1::253 75 R2_N1_IP6=2001:db8:16:1::254 76 77 H2_N2=172.16.2.0/24 78 H2_N2_6=2001:db8:16:2::/64 79 80 H2_N2_IP=172.16.2.2 81 R1_N2_IP=172.16.2.253 82 R2_N2_IP=172.16.2.254 83 84 H2_N2_IP6=2001:db8:16:2::2 85 R1_N2_IP6=2001:db8:16:2::253 86 R2_N2_IP6=2001:db8:16:2::254 87 88 ################################################################################ 89 # helpers 90 91 log_section() 92 { 93 echo 94 echo "###########################################################################" 95 echo "$*" 96 echo "###########################################################################" 97 echo 98 } 99 100 log_test() 101 { 102 local rc=$1 103 local expected=$2 104 local msg="$3" 105 106 if [ "${rc}" -eq "${expected}" ]; then 107 printf "TEST: %-60s [ OK ]\n" "${msg}" 108 nsuccess=$((nsuccess+1)) 109 else 110 ret=1 111 nfail=$((nfail+1)) 112 printf "TEST: %-60s [FAIL]\n" "${msg}" 113 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then 114 echo 115 echo "hit enter to continue, 'q' to quit" 116 read -r a 117 [ "$a" = "q" ] && exit 1 118 fi 119 fi 120 } 121 122 run_cmd() 123 { 124 local cmd="$*" 125 local out 126 local rc 127 128 if [ "$VERBOSE" = "1" ]; then 129 echo "COMMAND: $cmd" 130 fi 131 132 # shellcheck disable=SC2086 133 out=$(eval $cmd 2>&1) 134 rc=$? 135 if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then 136 echo "$out" 137 fi 138 139 [ "$VERBOSE" = "1" ] && echo 140 141 return $rc 142 } 143 144 run_cmd_grep() 145 { 146 local grep_pattern="$1" 147 shift 148 local cmd="$*" 149 local out 150 local rc 151 152 if [ "$VERBOSE" = "1" ]; then 153 echo "COMMAND: $cmd" 154 fi 155 156 # shellcheck disable=SC2086 157 out=$(eval $cmd 2>&1) 158 if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then 159 echo "$out" 160 fi 161 162 echo "$out" | grep -q "$grep_pattern" 163 rc=$? 164 165 [ "$VERBOSE" = "1" ] && echo 166 167 return $rc 168 } 169 170 ################################################################################ 171 # setup and teardown 172 173 cleanup() 174 { 175 cleanup_ns $h1 $h2 $r1 $r2 176 } 177 178 setup_vrf() 179 { 180 local ns=$1 181 182 ip -netns "${ns}" rule del pref 0 183 ip -netns "${ns}" rule add pref 32765 from all lookup local 184 ip -netns "${ns}" -6 rule del pref 0 185 ip -netns "${ns}" -6 rule add pref 32765 from all lookup local 186 } 187 188 create_vrf() 189 { 190 local ns=$1 191 local vrf=$2 192 local table=$3 193 194 ip -netns "${ns}" link add "${vrf}" type vrf table "${table}" 195 ip -netns "${ns}" link set "${vrf}" up 196 ip -netns "${ns}" route add vrf "${vrf}" unreachable default metric 8192 197 ip -netns "${ns}" -6 route add vrf "${vrf}" unreachable default metric 8192 198 199 ip -netns "${ns}" addr add 127.0.0.1/8 dev "${vrf}" 200 ip -netns "${ns}" -6 addr add ::1 dev "${vrf}" nodad 201 } 202 203 setup_sym() 204 { 205 local ns 206 207 # make sure we are starting with a clean slate 208 cleanup 209 210 # 211 # create nodes as namespaces 212 setup_ns h1 h2 r1 213 for ns in $h1 $h2 $r1; do 214 if echo $ns | grep -q h[12]-; then 215 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 216 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 217 else 218 ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 219 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 220 fi 221 done 222 223 # 224 # create interconnects 225 # 226 ip -netns $h1 link add eth0 type veth peer name r1h1 227 ip -netns $h1 link set r1h1 netns $r1 name eth0 up 228 229 ip -netns $h2 link add eth0 type veth peer name r1h2 230 ip -netns $h2 link set r1h2 netns $r1 name eth1 up 231 232 # 233 # h1 234 # 235 ip -netns $h1 addr add dev eth0 ${H1_N1_IP}/24 236 ip -netns $h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad 237 ip -netns $h1 link set eth0 up 238 239 # h1 to h2 via r1 240 ip -netns $h1 route add ${H2_N2} via ${R1_N1_IP} dev eth0 241 ip -netns $h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0 242 243 # 244 # h2 245 # 246 ip -netns $h2 addr add dev eth0 ${H2_N2_IP}/24 247 ip -netns $h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad 248 ip -netns $h2 link set eth0 up 249 250 # h2 to h1 via r1 251 ip -netns $h2 route add default via ${R1_N2_IP} dev eth0 252 ip -netns $h2 -6 route add default via ${R1_N2_IP6} dev eth0 253 254 # 255 # r1 256 # 257 setup_vrf $r1 258 create_vrf $r1 blue 1101 259 create_vrf $r1 red 1102 260 ip -netns $r1 link set mtu 1400 dev eth1 261 ip -netns $r1 link set eth0 vrf blue up 262 ip -netns $r1 link set eth1 vrf red up 263 ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24 264 ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad 265 ip -netns $r1 addr add dev eth1 ${R1_N2_IP}/24 266 ip -netns $r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad 267 268 # Route leak from blue to red 269 ip -netns $r1 route add vrf blue ${H2_N2} dev red 270 ip -netns $r1 -6 route add vrf blue ${H2_N2_6} dev red 271 272 # Route leak from red to blue 273 ip -netns $r1 route add vrf red ${H1_N1} dev blue 274 ip -netns $r1 -6 route add vrf red ${H1_N1_6} dev blue 275 276 277 # Wait for ip config to settle 278 sleep 2 279 } 280 281 setup_asym() 282 { 283 local ns 284 285 # make sure we are starting with a clean slate 286 cleanup 287 288 # 289 # create nodes as namespaces 290 setup_ns h1 h2 r1 r2 291 for ns in $h1 $h2 $r1 $r2; do 292 if echo $ns | grep -q h[12]-; then 293 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0 294 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1 295 else 296 ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1 297 ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1 298 fi 299 done 300 301 # 302 # create interconnects 303 # 304 ip -netns $h1 link add eth0 type veth peer name r1h1 305 ip -netns $h1 link set r1h1 netns $r1 name eth0 up 306 307 ip -netns $h1 link add eth1 type veth peer name r2h1 308 ip -netns $h1 link set r2h1 netns $r2 name eth0 up 309 310 ip -netns $h2 link add eth0 type veth peer name r1h2 311 ip -netns $h2 link set r1h2 netns $r1 name eth1 up 312 313 ip -netns $h2 link add eth1 type veth peer name r2h2 314 ip -netns $h2 link set r2h2 netns $r2 name eth1 up 315 316 # 317 # h1 318 # 319 ip -netns $h1 link add br0 type bridge 320 ip -netns $h1 link set br0 up 321 ip -netns $h1 addr add dev br0 ${H1_N1_IP}/24 322 ip -netns $h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad 323 ip -netns $h1 link set eth0 master br0 up 324 ip -netns $h1 link set eth1 master br0 up 325 326 # h1 to h2 via r1 327 ip -netns $h1 route add ${H2_N2} via ${R1_N1_IP} dev br0 328 ip -netns $h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0 329 330 # 331 # h2 332 # 333 ip -netns $h2 link add br0 type bridge 334 ip -netns $h2 link set br0 up 335 ip -netns $h2 addr add dev br0 ${H2_N2_IP}/24 336 ip -netns $h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad 337 ip -netns $h2 link set eth0 master br0 up 338 ip -netns $h2 link set eth1 master br0 up 339 340 # h2 to h1 via r2 341 ip -netns $h2 route add default via ${R2_N2_IP} dev br0 342 ip -netns $h2 -6 route add default via ${R2_N2_IP6} dev br0 343 344 # 345 # r1 346 # 347 setup_vrf $r1 348 create_vrf $r1 blue 1101 349 create_vrf $r1 red 1102 350 ip -netns $r1 link set mtu 1400 dev eth1 351 ip -netns $r1 link set eth0 vrf blue up 352 ip -netns $r1 link set eth1 vrf red up 353 ip -netns $r1 addr add dev eth0 ${R1_N1_IP}/24 354 ip -netns $r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad 355 ip -netns $r1 addr add dev eth1 ${R1_N2_IP}/24 356 ip -netns $r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad 357 358 # Route leak from blue to red 359 ip -netns $r1 route add vrf blue ${H2_N2} dev red 360 ip -netns $r1 -6 route add vrf blue ${H2_N2_6} dev red 361 362 # No route leak from red to blue 363 364 # 365 # r2 366 # 367 ip -netns $r2 addr add dev eth0 ${R2_N1_IP}/24 368 ip -netns $r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad 369 ip -netns $r2 addr add dev eth1 ${R2_N2_IP}/24 370 ip -netns $r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad 371 372 # Wait for ip config to settle 373 sleep 2 374 } 375 376 check_connectivity() 377 { 378 ip netns exec $h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1 379 log_test $? 0 "Basic IPv4 connectivity" 380 return $? 381 } 382 383 check_connectivity6() 384 { 385 ip netns exec $h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1 386 log_test $? 0 "Basic IPv6 connectivity" 387 return $? 388 } 389 390 check_traceroute() 391 { 392 if [ ! -x "$(command -v traceroute)" ]; then 393 echo "SKIP: Could not run IPV4 test without traceroute" 394 return 1 395 fi 396 } 397 398 check_traceroute6() 399 { 400 if [ ! -x "$(command -v traceroute6)" ]; then 401 echo "SKIP: Could not run IPV6 test without traceroute6" 402 return 1 403 fi 404 } 405 406 ipv4_traceroute() 407 { 408 local ttype="$1" 409 410 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 411 412 log_section "IPv4 ($ttype route): VRF ICMP error route lookup traceroute" 413 414 check_traceroute || return 415 416 setup_"$ttype" 417 418 check_connectivity || return 419 420 run_cmd_grep "${R1_N1_IP}" ip netns exec $h1 traceroute ${H2_N2_IP} 421 log_test $? 0 "Traceroute reports a hop on r1" 422 } 423 424 ipv4_traceroute_asym() 425 { 426 ipv4_traceroute asym 427 } 428 429 ipv6_traceroute() 430 { 431 local ttype="$1" 432 433 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 434 435 log_section "IPv6 ($ttype route): VRF ICMP error route lookup traceroute" 436 437 check_traceroute6 || return 438 439 setup_"$ttype" 440 441 check_connectivity6 || return 442 443 run_cmd_grep "${R1_N1_IP6}" ip netns exec $h1 traceroute6 ${H2_N2_IP6} 444 log_test $? 0 "Traceroute6 reports a hop on r1" 445 } 446 447 ipv6_traceroute_asym() 448 { 449 ipv6_traceroute asym 450 } 451 452 ipv4_ping_ttl() 453 { 454 local ttype="$1" 455 456 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 457 458 log_section "IPv4 ($ttype route): VRF ICMP ttl error route lookup ping" 459 460 setup_"$ttype" 461 462 check_connectivity || return 463 464 run_cmd_grep "Time to live exceeded" ip netns exec $h1 ping -t1 -c1 -W2 ${H2_N2_IP} 465 log_test $? 0 "Ping received ICMP ttl exceeded" 466 } 467 468 ipv4_ping_ttl_asym() 469 { 470 ipv4_ping_ttl asym 471 } 472 473 ipv4_ping_frag() 474 { 475 local ttype="$1" 476 477 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 478 479 log_section "IPv4 ($ttype route): VRF ICMP fragmentation error route lookup ping" 480 481 setup_"$ttype" 482 483 check_connectivity || return 484 485 run_cmd_grep "Frag needed" ip netns exec $h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP} 486 log_test $? 0 "Ping received ICMP Frag needed" 487 } 488 489 ipv4_ping_frag_asym() 490 { 491 ipv4_ping_frag asym 492 } 493 494 ipv6_ping_ttl() 495 { 496 local ttype="$1" 497 498 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 499 500 log_section "IPv6 ($ttype route): VRF ICMP ttl error route lookup ping" 501 502 setup_"$ttype" 503 504 check_connectivity6 || return 505 506 run_cmd_grep "Time exceeded: Hop limit" ip netns exec $h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6} 507 log_test $? 0 "Ping received ICMP Hop limit" 508 } 509 510 ipv6_ping_ttl_asym() 511 { 512 ipv6_ping_ttl asym 513 } 514 515 ipv6_ping_frag() 516 { 517 local ttype="$1" 518 519 [ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE" 520 521 log_section "IPv6 ($ttype route): VRF ICMP fragmentation error route lookup ping" 522 523 setup_"$ttype" 524 525 check_connectivity6 || return 526 527 run_cmd_grep "Packet too big" ip netns exec $h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6} 528 log_test $? 0 "Ping received ICMP Packet too big" 529 } 530 531 ipv6_ping_frag_asym() 532 { 533 ipv6_ping_frag asym 534 } 535 536 ipv4_ping_local() 537 { 538 log_section "IPv4 (sym route): VRF ICMP local error route lookup ping" 539 540 setup_sym 541 542 check_connectivity || return 543 544 run_cmd ip netns exec $r1 ip vrf exec blue ping -c1 -w1 ${H2_N2_IP} 545 log_test $? 0 "VRF ICMP local IPv4" 546 } 547 548 ipv4_tcp_local() 549 { 550 log_section "IPv4 (sym route): VRF tcp local connection" 551 552 setup_sym 553 554 check_connectivity || return 555 556 run_cmd nettest -s -O "$h2" -l ${H2_N2_IP} -I eth0 -3 eth0 & 557 sleep 1 558 run_cmd nettest -N "$r1" -d blue -r ${H2_N2_IP} 559 log_test $? 0 "VRF tcp local connection IPv4" 560 } 561 562 ipv4_udp_local() 563 { 564 log_section "IPv4 (sym route): VRF udp local connection" 565 566 setup_sym 567 568 check_connectivity || return 569 570 run_cmd nettest -s -D -O "$h2" -l ${H2_N2_IP} -I eth0 -3 eth0 & 571 sleep 1 572 run_cmd nettest -D -N "$r1" -d blue -r ${H2_N2_IP} 573 log_test $? 0 "VRF udp local connection IPv4" 574 } 575 576 ipv6_ping_local() 577 { 578 log_section "IPv6 (sym route): VRF ICMP local error route lookup ping" 579 580 setup_sym 581 582 check_connectivity6 || return 583 584 run_cmd ip netns exec $r1 ip vrf exec blue ${ping6} -c1 -w1 ${H2_N2_IP6} 585 log_test $? 0 "VRF ICMP local IPv6" 586 } 587 588 ipv6_tcp_local() 589 { 590 log_section "IPv6 (sym route): VRF tcp local connection" 591 592 setup_sym 593 594 check_connectivity6 || return 595 596 run_cmd nettest -s -6 -O "$h2" -l ${H2_N2_IP6} -I eth0 -3 eth0 & 597 sleep 1 598 run_cmd nettest -6 -N "$r1" -d blue -r ${H2_N2_IP6} 599 log_test $? 0 "VRF tcp local connection IPv6" 600 } 601 602 ipv6_udp_local() 603 { 604 log_section "IPv6 (sym route): VRF udp local connection" 605 606 setup_sym 607 608 check_connectivity6 || return 609 610 run_cmd nettest -s -6 -D -O "$h2" -l ${H2_N2_IP6} -I eth0 -3 eth0 & 611 sleep 1 612 run_cmd nettest -6 -D -N "$r1" -d blue -r ${H2_N2_IP6} 613 log_test $? 0 "VRF udp local connection IPv6" 614 } 615 616 ################################################################################ 617 # usage 618 619 usage() 620 { 621 cat <<EOF 622 usage: ${0##*/} OPTS 623 624 -4 Run IPv4 tests only 625 -6 Run IPv6 tests only 626 -t TEST Run only TEST 627 -p Pause on fail 628 -v verbose mode (show commands and output) 629 EOF 630 } 631 632 ################################################################################ 633 # main 634 635 # Some systems don't have a ping6 binary anymore 636 command -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping) 637 638 check_gen_prog "nettest" 639 640 TESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_local ipv4_tcp_local 641 ipv4_udp_local ipv4_ping_ttl_asym ipv4_traceroute_asym" 642 TESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_local ipv6_tcp_local ipv6_udp_local 643 ipv6_ping_ttl_asym ipv6_traceroute_asym" 644 645 ret=0 646 nsuccess=0 647 nfail=0 648 649 while getopts :46t:pvh o 650 do 651 case $o in 652 4) TESTS=ipv4;; 653 6) TESTS=ipv6;; 654 t) TESTS=$OPTARG;; 655 p) PAUSE_ON_FAIL=yes;; 656 v) VERBOSE=1;; 657 h) usage; exit 0;; 658 *) usage; exit 1;; 659 esac 660 done 661 662 # 663 # show user test config 664 # 665 if [ -z "$TESTS" ]; then 666 TESTS="$TESTS_IPV4 $TESTS_IPV6" 667 elif [ "$TESTS" = "ipv4" ]; then 668 TESTS="$TESTS_IPV4" 669 elif [ "$TESTS" = "ipv6" ]; then 670 TESTS="$TESTS_IPV6" 671 fi 672 673 for t in $TESTS 674 do 675 case $t in 676 ipv4_ping_ttl|ping) ipv4_ping_ttl;;& 677 ipv4_ping_ttl_asym|ping) ipv4_ping_ttl_asym;;& 678 ipv4_traceroute|traceroute) ipv4_traceroute;;& 679 ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;& 680 ipv4_ping_frag|ping) ipv4_ping_frag;;& 681 ipv4_ping_local|ping) ipv4_ping_local;;& 682 ipv4_tcp_local) ipv4_tcp_local;;& 683 ipv4_udp_local) ipv4_udp_local;;& 684 685 ipv6_ping_ttl|ping) ipv6_ping_ttl;;& 686 ipv6_ping_ttl_asym|ping) ipv6_ping_ttl_asym;;& 687 ipv6_traceroute|traceroute) ipv6_traceroute;;& 688 ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;& 689 ipv6_ping_frag|ping) ipv6_ping_frag;;& 690 ipv6_ping_local|ping) ipv6_ping_local;;& 691 ipv6_tcp_local) ipv6_tcp_local;;& 692 ipv6_udp_local) ipv6_udp_local;;& 693 694 # setup namespaces and config, but do not run any tests 695 setup_sym|setup) setup_sym; exit 0;; 696 setup_asym) setup_asym; exit 0;; 697 698 help) echo "Test names: $TESTS"; exit 0;; 699 esac 700 done 701 702 cleanup 703 704 printf "\nTests passed: %3d\n" ${nsuccess} 705 printf "Tests failed: %3d\n" ${nfail} 706 707 exit $ret
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.