1 #!/bin/bash 2 # SPDX-License-Identifier: GPL-2.0 3 4 # +------------------+ 5 # | H1 (v$h1) | 6 # | 2001:db8:1::2/64 | 7 # | 198.51.100.2/28 | 8 # | $h1 + | 9 # +-------------|----+ 10 # | 11 # +-------------|-------------------------------+ 12 # | SW1 | | 13 # | $rp1 + | 14 # | 198.51.100.1/28 | 15 # | 2001:db8:1::1/64 | 16 # | | 17 # | 2001:db8:2::1/64 2001:db8:3::1/64 | 18 # | 198.51.100.17/28 198.51.100.33/28 | 19 # | $rp2 + $rp3 + | 20 # +--------------|--------------------------|---+ 21 # | | 22 # | | 23 # +--------------|---+ +--------------|---+ 24 # | H2 (v$h2) | | | H3 (v$h3) | | 25 # | $h2 + | | $h3 + | 26 # | 198.51.100.18/28 | | 198.51.100.34/28 | 27 # | 2001:db8:2::2/64 | | 2001:db8:3::2/64 | 28 # +------------------+ +------------------+ 29 # 30 31 ALL_TESTS="mcast_v4 mcast_v6 rpf_v4 rpf_v6 unres_v4 unres_v6" 32 NUM_NETIFS=6 33 source lib.sh 34 source tc_common.sh 35 36 require_command $MCD 37 require_command $MC_CLI 38 table_name=selftests 39 40 h1_create() 41 { 42 simple_if_init $h1 198.51.100.2/28 2001:db8:1::2/64 43 44 ip route add 198.51.100.16/28 vrf v$h1 nexthop via 198.51.100.1 45 ip route add 198.51.100.32/28 vrf v$h1 nexthop via 198.51.100.1 46 47 ip route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::1 48 ip route add 2001:db8:3::/64 vrf v$h1 nexthop via 2001:db8:1::1 49 50 tc qdisc add dev $h1 ingress 51 } 52 53 h1_destroy() 54 { 55 tc qdisc del dev $h1 ingress 56 57 ip route del 2001:db8:3::/64 vrf v$h1 58 ip route del 2001:db8:2::/64 vrf v$h1 59 60 ip route del 198.51.100.32/28 vrf v$h1 61 ip route del 198.51.100.16/28 vrf v$h1 62 63 simple_if_fini $h1 198.51.100.2/28 2001:db8:1::2/64 64 } 65 66 h2_create() 67 { 68 simple_if_init $h2 198.51.100.18/28 2001:db8:2::2/64 69 70 ip route add 198.51.100.0/28 vrf v$h2 nexthop via 198.51.100.17 71 ip route add 198.51.100.32/28 vrf v$h2 nexthop via 198.51.100.17 72 73 ip route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1 74 ip route add 2001:db8:3::/64 vrf v$h2 nexthop via 2001:db8:2::1 75 76 tc qdisc add dev $h2 ingress 77 } 78 79 h2_destroy() 80 { 81 tc qdisc del dev $h2 ingress 82 83 ip route del 2001:db8:3::/64 vrf v$h2 84 ip route del 2001:db8:1::/64 vrf v$h2 85 86 ip route del 198.51.100.32/28 vrf v$h2 87 ip route del 198.51.100.0/28 vrf v$h2 88 89 simple_if_fini $h2 198.51.100.18/28 2001:db8:2::2/64 90 } 91 92 h3_create() 93 { 94 simple_if_init $h3 198.51.100.34/28 2001:db8:3::2/64 95 96 ip route add 198.51.100.0/28 vrf v$h3 nexthop via 198.51.100.33 97 ip route add 198.51.100.16/28 vrf v$h3 nexthop via 198.51.100.33 98 99 ip route add 2001:db8:1::/64 vrf v$h3 nexthop via 2001:db8:3::1 100 ip route add 2001:db8:2::/64 vrf v$h3 nexthop via 2001:db8:3::1 101 102 tc qdisc add dev $h3 ingress 103 } 104 105 h3_destroy() 106 { 107 tc qdisc del dev $h3 ingress 108 109 ip route del 2001:db8:2::/64 vrf v$h3 110 ip route del 2001:db8:1::/64 vrf v$h3 111 112 ip route del 198.51.100.16/28 vrf v$h3 113 ip route del 198.51.100.0/28 vrf v$h3 114 115 simple_if_fini $h3 198.51.100.34/28 2001:db8:3::2/64 116 } 117 118 router_create() 119 { 120 ip link set dev $rp1 up 121 ip link set dev $rp2 up 122 ip link set dev $rp3 up 123 124 ip address add 198.51.100.1/28 dev $rp1 125 ip address add 198.51.100.17/28 dev $rp2 126 ip address add 198.51.100.33/28 dev $rp3 127 128 ip address add 2001:db8:1::1/64 dev $rp1 129 ip address add 2001:db8:2::1/64 dev $rp2 130 ip address add 2001:db8:3::1/64 dev $rp3 131 132 tc qdisc add dev $rp3 ingress 133 } 134 135 router_destroy() 136 { 137 tc qdisc del dev $rp3 ingress 138 139 ip address del 2001:db8:3::1/64 dev $rp3 140 ip address del 2001:db8:2::1/64 dev $rp2 141 ip address del 2001:db8:1::1/64 dev $rp1 142 143 ip address del 198.51.100.33/28 dev $rp3 144 ip address del 198.51.100.17/28 dev $rp2 145 ip address del 198.51.100.1/28 dev $rp1 146 147 ip link set dev $rp3 down 148 ip link set dev $rp2 down 149 ip link set dev $rp1 down 150 } 151 152 start_mcd() 153 { 154 SMCROUTEDIR="$(mktemp -d)" 155 156 for ((i = 1; i <= $NUM_NETIFS; ++i)); do 157 echo "phyint ${NETIFS[p$i]} enable" >> \ 158 $SMCROUTEDIR/$table_name.conf 159 done 160 161 $MCD -N -I $table_name -f $SMCROUTEDIR/$table_name.conf \ 162 -P $SMCROUTEDIR/$table_name.pid 163 } 164 165 kill_mcd() 166 { 167 pkill $MCD 168 rm -rf $SMCROUTEDIR 169 } 170 171 setup_prepare() 172 { 173 h1=${NETIFS[p1]} 174 rp1=${NETIFS[p2]} 175 176 rp2=${NETIFS[p3]} 177 h2=${NETIFS[p4]} 178 179 rp3=${NETIFS[p5]} 180 h3=${NETIFS[p6]} 181 182 start_mcd 183 184 vrf_prepare 185 186 h1_create 187 h2_create 188 h3_create 189 190 router_create 191 192 forwarding_enable 193 } 194 195 cleanup() 196 { 197 pre_cleanup 198 199 forwarding_restore 200 201 router_destroy 202 203 h3_destroy 204 h2_destroy 205 h1_destroy 206 207 vrf_cleanup 208 209 kill_mcd 210 } 211 212 create_mcast_sg() 213 { 214 local if_name=$1; shift 215 local s_addr=$1; shift 216 local mcast=$1; shift 217 local dest_ifs=${@} 218 219 $MC_CLI -I $table_name add $if_name $s_addr $mcast $dest_ifs 220 } 221 222 delete_mcast_sg() 223 { 224 local if_name=$1; shift 225 local s_addr=$1; shift 226 local mcast=$1; shift 227 local dest_ifs=${@} 228 229 $MC_CLI -I $table_name remove $if_name $s_addr $mcast $dest_ifs 230 } 231 232 mcast_v4() 233 { 234 # Add two interfaces to an MC group, send a packet to the MC group and 235 # verify packets are received on both. Then delete the route and verify 236 # packets are no longer received. 237 238 RET=0 239 240 tc filter add dev $h2 ingress protocol ip pref 1 handle 122 flower \ 241 dst_ip 225.1.2.3 action drop 242 tc filter add dev $h3 ingress protocol ip pref 1 handle 133 flower \ 243 dst_ip 225.1.2.3 action drop 244 245 create_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3 246 247 # Send frames with the corresponding L2 destination address. 248 $MZ $h1 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \ 249 -A 198.51.100.2 -B 225.1.2.3 -q 250 251 tc_check_packets "dev $h2 ingress" 122 5 252 check_err $? "Multicast not received on first host" 253 tc_check_packets "dev $h3 ingress" 133 5 254 check_err $? "Multicast not received on second host" 255 256 delete_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3 257 258 $MZ $h1 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \ 259 -A 198.51.100.2 -B 225.1.2.3 -q 260 261 tc_check_packets "dev $h2 ingress" 122 5 262 check_err $? "Multicast received on host although deleted" 263 tc_check_packets "dev $h3 ingress" 133 5 264 check_err $? "Multicast received on second host although deleted" 265 266 tc filter del dev $h3 ingress protocol ip pref 1 handle 133 flower 267 tc filter del dev $h2 ingress protocol ip pref 1 handle 122 flower 268 269 log_test "mcast IPv4" 270 } 271 272 mcast_v6() 273 { 274 # Add two interfaces to an MC group, send a packet to the MC group and 275 # verify packets are received on both. Then delete the route and verify 276 # packets are no longer received. 277 278 RET=0 279 280 tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 122 flower \ 281 dst_ip ff0e::3 action drop 282 tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 133 flower \ 283 dst_ip ff0e::3 action drop 284 285 create_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3 286 287 # Send frames with the corresponding L2 destination address. 288 $MZ $h1 -6 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 \ 289 -b 33:33:00:00:00:03 -A 2001:db8:1::2 -B ff0e::3 -q 290 291 tc_check_packets "dev $h2 ingress" 122 5 292 check_err $? "Multicast not received on first host" 293 tc_check_packets "dev $h3 ingress" 133 5 294 check_err $? "Multicast not received on second host" 295 296 delete_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3 297 298 $MZ $h1 -6 -c 5 -p 128 -t udp -a 00:11:22:33:44:55 \ 299 -b 33:33:00:00:00:03 -A 2001:db8:1::2 -B ff0e::3 -q 300 301 tc_check_packets "dev $h2 ingress" 122 5 302 check_err $? "Multicast received on first host although deleted" 303 tc_check_packets "dev $h3 ingress" 133 5 304 check_err $? "Multicast received on second host although deleted" 305 306 tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 133 flower 307 tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 122 flower 308 309 log_test "mcast IPv6" 310 } 311 312 rpf_v4() 313 { 314 # Add a multicast route from first router port to the other two. Send 315 # matching packets and test that both hosts receive them. Then, send 316 # the same packets via the third router port and test that they do not 317 # reach any host due to RPF check. A filter with 'skip_hw' is added to 318 # test that devices capable of multicast routing offload trap those 319 # packets. The filter is essentialy a NOP in other scenarios. 320 321 RET=0 322 323 tc filter add dev $h1 ingress protocol ip pref 1 handle 1 flower \ 324 dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop 325 tc filter add dev $h2 ingress protocol ip pref 1 handle 1 flower \ 326 dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop 327 tc filter add dev $h3 ingress protocol ip pref 1 handle 1 flower \ 328 dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop 329 tc filter add dev $rp3 ingress protocol ip pref 1 handle 1 flower \ 330 skip_hw dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action pass 331 332 create_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3 333 334 $MZ $h1 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 335 -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \ 336 -A 198.51.100.2 -B 225.1.2.3 -q 337 338 tc_check_packets "dev $h2 ingress" 1 5 339 check_err $? "Multicast not received on first host" 340 tc_check_packets "dev $h3 ingress" 1 5 341 check_err $? "Multicast not received on second host" 342 343 $MZ $h3 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 344 -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \ 345 -A 198.51.100.2 -B 225.1.2.3 -q 346 347 tc_check_packets "dev $h1 ingress" 1 0 348 check_err $? "Multicast received on first host when should not" 349 tc_check_packets "dev $h2 ingress" 1 5 350 check_err $? "Multicast received on second host when should not" 351 tc_check_packets "dev $rp3 ingress" 1 5 352 check_err $? "Packets not trapped due to RPF check" 353 354 delete_mcast_sg $rp1 198.51.100.2 225.1.2.3 $rp2 $rp3 355 356 tc filter del dev $rp3 ingress protocol ip pref 1 handle 1 flower 357 tc filter del dev $h3 ingress protocol ip pref 1 handle 1 flower 358 tc filter del dev $h2 ingress protocol ip pref 1 handle 1 flower 359 tc filter del dev $h1 ingress protocol ip pref 1 handle 1 flower 360 361 log_test "RPF IPv4" 362 } 363 364 rpf_v6() 365 { 366 RET=0 367 368 tc filter add dev $h1 ingress protocol ipv6 pref 1 handle 1 flower \ 369 dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop 370 tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 1 flower \ 371 dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop 372 tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 1 flower \ 373 dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop 374 tc filter add dev $rp3 ingress protocol ipv6 pref 1 handle 1 flower \ 375 skip_hw dst_ip ff0e::3 ip_proto udp dst_port 12345 action pass 376 377 create_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3 378 379 $MZ $h1 -6 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 380 -a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \ 381 -A 2001:db8:1::2 -B ff0e::3 -q 382 383 tc_check_packets "dev $h2 ingress" 1 5 384 check_err $? "Multicast not received on first host" 385 tc_check_packets "dev $h3 ingress" 1 5 386 check_err $? "Multicast not received on second host" 387 388 $MZ $h3 -6 -c 5 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 389 -a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \ 390 -A 2001:db8:1::2 -B ff0e::3 -q 391 392 tc_check_packets "dev $h1 ingress" 1 0 393 check_err $? "Multicast received on first host when should not" 394 tc_check_packets "dev $h2 ingress" 1 5 395 check_err $? "Multicast received on second host when should not" 396 tc_check_packets "dev $rp3 ingress" 1 5 397 check_err $? "Packets not trapped due to RPF check" 398 399 delete_mcast_sg $rp1 2001:db8:1::2 ff0e::3 $rp2 $rp3 400 401 tc filter del dev $rp3 ingress protocol ipv6 pref 1 handle 1 flower 402 tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 1 flower 403 tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 1 flower 404 tc filter del dev $h1 ingress protocol ipv6 pref 1 handle 1 flower 405 406 log_test "RPF IPv6" 407 } 408 409 unres_v4() 410 { 411 # Send a multicast packet not corresponding to an installed route, 412 # causing the kernel to queue the packet for resolution and emit an 413 # IGMPMSG_NOCACHE notification. smcrouted will react to this 414 # notification by consulting its (*, G) list and installing an (S, G) 415 # route, which will be used to forward the queued packet. 416 417 RET=0 418 419 tc filter add dev $h2 ingress protocol ip pref 1 handle 1 flower \ 420 dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop 421 tc filter add dev $h3 ingress protocol ip pref 1 handle 1 flower \ 422 dst_ip 225.1.2.3 ip_proto udp dst_port 12345 action drop 423 424 # Forwarding should fail before installing a matching (*, G). 425 $MZ $h1 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 426 -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \ 427 -A 198.51.100.2 -B 225.1.2.3 -q 428 429 tc_check_packets "dev $h2 ingress" 1 0 430 check_err $? "Multicast received on first host when should not" 431 tc_check_packets "dev $h3 ingress" 1 0 432 check_err $? "Multicast received on second host when should not" 433 434 # Create (*, G). Will not be installed in the kernel. 435 create_mcast_sg $rp1 0.0.0.0 225.1.2.3 $rp2 $rp3 436 437 $MZ $h1 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 438 -a 00:11:22:33:44:55 -b 01:00:5e:01:02:03 \ 439 -A 198.51.100.2 -B 225.1.2.3 -q 440 441 tc_check_packets "dev $h2 ingress" 1 1 442 check_err $? "Multicast not received on first host" 443 tc_check_packets "dev $h3 ingress" 1 1 444 check_err $? "Multicast not received on second host" 445 446 delete_mcast_sg $rp1 0.0.0.0 225.1.2.3 $rp2 $rp3 447 448 tc filter del dev $h3 ingress protocol ip pref 1 handle 1 flower 449 tc filter del dev $h2 ingress protocol ip pref 1 handle 1 flower 450 451 log_test "Unresolved queue IPv4" 452 } 453 454 unres_v6() 455 { 456 # Send a multicast packet not corresponding to an installed route, 457 # causing the kernel to queue the packet for resolution and emit an 458 # MRT6MSG_NOCACHE notification. smcrouted will react to this 459 # notification by consulting its (*, G) list and installing an (S, G) 460 # route, which will be used to forward the queued packet. 461 462 RET=0 463 464 tc filter add dev $h2 ingress protocol ipv6 pref 1 handle 1 flower \ 465 dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop 466 tc filter add dev $h3 ingress protocol ipv6 pref 1 handle 1 flower \ 467 dst_ip ff0e::3 ip_proto udp dst_port 12345 action drop 468 469 # Forwarding should fail before installing a matching (*, G). 470 $MZ $h1 -6 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 471 -a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \ 472 -A 2001:db8:1::2 -B ff0e::3 -q 473 474 tc_check_packets "dev $h2 ingress" 1 0 475 check_err $? "Multicast received on first host when should not" 476 tc_check_packets "dev $h3 ingress" 1 0 477 check_err $? "Multicast received on second host when should not" 478 479 # Create (*, G). Will not be installed in the kernel. 480 create_mcast_sg $rp1 :: ff0e::3 $rp2 $rp3 481 482 $MZ $h1 -6 -c 1 -p 128 -t udp "ttl=10,sp=54321,dp=12345" \ 483 -a 00:11:22:33:44:55 -b 33:33:00:00:00:03 \ 484 -A 2001:db8:1::2 -B ff0e::3 -q 485 486 tc_check_packets "dev $h2 ingress" 1 1 487 check_err $? "Multicast not received on first host" 488 tc_check_packets "dev $h3 ingress" 1 1 489 check_err $? "Multicast not received on second host" 490 491 delete_mcast_sg $rp1 :: ff0e::3 $rp2 $rp3 492 493 tc filter del dev $h3 ingress protocol ipv6 pref 1 handle 1 flower 494 tc filter del dev $h2 ingress protocol ipv6 pref 1 handle 1 flower 495 496 log_test "Unresolved queue IPv6" 497 } 498 499 trap cleanup EXIT 500 501 setup_prepare 502 setup_wait 503 504 tests_run 505 506 exit $EXIT_STATUS
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.