router_multicast.sh 15 KB

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