sch_red.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. # This test sends one stream of traffic from H1 through a TBF shaper, to a RED
  4. # within TBF shaper on $swp3. The two shapers have the same configuration, and
  5. # thus the resulting stream should fill all available bandwidth on the latter
  6. # shaper. A second stream is sent from H2 also via $swp3, and used to inject
  7. # additional traffic. Since all available bandwidth is taken, this traffic has
  8. # to go to backlog.
  9. #
  10. # +--------------------------+ +--------------------------+
  11. # | H1 | | H2 |
  12. # | + $h1 | | + $h2 |
  13. # | | 192.0.2.1/28 | | | 192.0.2.2/28 |
  14. # | | TBF 10Mbps | | | |
  15. # +-----|--------------------+ +-----|--------------------+
  16. # | |
  17. # +-----|------------------------------------------------|--------------------+
  18. # | SW | | |
  19. # | +--|------------------------------------------------|----------------+ |
  20. # | | + $swp1 + $swp2 | |
  21. # | | BR | |
  22. # | | | |
  23. # | | + $swp3 | |
  24. # | | | TBF 10Mbps / RED | |
  25. # | +--------------------------------|-----------------------------------+ |
  26. # | | |
  27. # +-----------------------------------|---------------------------------------+
  28. # |
  29. # +-----|--------------------+
  30. # | H3 | |
  31. # | + $h1 |
  32. # | 192.0.2.3/28 |
  33. # | |
  34. # +--------------------------+
  35. ALL_TESTS="
  36. ping_ipv4
  37. ecn_test
  38. ecn_nodrop_test
  39. red_test
  40. red_qevent_test
  41. ecn_qevent_test
  42. "
  43. NUM_NETIFS=6
  44. CHECK_TC="yes"
  45. source lib.sh
  46. BACKLOG=30000
  47. PKTSZ=1400
  48. h1_create()
  49. {
  50. simple_if_init $h1 192.0.2.1/28
  51. mtu_set $h1 10000
  52. tc qdisc replace dev $h1 root handle 1: tbf \
  53. rate 10Mbit burst 10K limit 1M
  54. }
  55. h1_destroy()
  56. {
  57. tc qdisc del dev $h1 root
  58. mtu_restore $h1
  59. simple_if_fini $h1 192.0.2.1/28
  60. }
  61. h2_create()
  62. {
  63. simple_if_init $h2 192.0.2.2/28
  64. mtu_set $h2 10000
  65. }
  66. h2_destroy()
  67. {
  68. mtu_restore $h2
  69. simple_if_fini $h2 192.0.2.2/28
  70. }
  71. h3_create()
  72. {
  73. simple_if_init $h3 192.0.2.3/28
  74. mtu_set $h3 10000
  75. }
  76. h3_destroy()
  77. {
  78. mtu_restore $h3
  79. simple_if_fini $h3 192.0.2.3/28
  80. }
  81. switch_create()
  82. {
  83. ip link add dev br up type bridge
  84. ip link set dev $swp1 up master br
  85. ip link set dev $swp2 up master br
  86. ip link set dev $swp3 up master br
  87. mtu_set $swp1 10000
  88. mtu_set $swp2 10000
  89. mtu_set $swp3 10000
  90. tc qdisc replace dev $swp3 root handle 1: tbf \
  91. rate 10Mbit burst 10K limit 1M
  92. ip link add name _drop_test up type dummy
  93. }
  94. switch_destroy()
  95. {
  96. ip link del dev _drop_test
  97. tc qdisc del dev $swp3 root
  98. mtu_restore $h3
  99. mtu_restore $h2
  100. mtu_restore $h1
  101. ip link set dev $swp3 down nomaster
  102. ip link set dev $swp2 down nomaster
  103. ip link set dev $swp1 down nomaster
  104. ip link del dev br
  105. }
  106. setup_prepare()
  107. {
  108. h1=${NETIFS[p1]}
  109. swp1=${NETIFS[p2]}
  110. h2=${NETIFS[p3]}
  111. swp2=${NETIFS[p4]}
  112. swp3=${NETIFS[p5]}
  113. h3=${NETIFS[p6]}
  114. h3_mac=$(mac_get $h3)
  115. vrf_prepare
  116. h1_create
  117. h2_create
  118. h3_create
  119. switch_create
  120. }
  121. cleanup()
  122. {
  123. pre_cleanup
  124. switch_destroy
  125. h3_destroy
  126. h2_destroy
  127. h1_destroy
  128. vrf_cleanup
  129. }
  130. ping_ipv4()
  131. {
  132. ping_test $h1 192.0.2.3 " from host 1"
  133. ping_test $h2 192.0.2.3 " from host 2"
  134. }
  135. get_qdisc_backlog()
  136. {
  137. qdisc_stats_get $swp3 11: .backlog
  138. }
  139. get_nmarked()
  140. {
  141. qdisc_stats_get $swp3 11: .marked
  142. }
  143. get_qdisc_npackets()
  144. {
  145. qdisc_stats_get $swp3 11: .packets
  146. }
  147. get_nmirrored()
  148. {
  149. link_stats_get _drop_test tx packets
  150. }
  151. send_packets()
  152. {
  153. local proto=$1; shift
  154. local pkts=$1; shift
  155. $MZ $h2 -p $PKTSZ -a own -b $h3_mac -A 192.0.2.2 -B 192.0.2.3 -t $proto -q -c $pkts "$@"
  156. }
  157. # This sends traffic in an attempt to build a backlog of $size. Returns 0 on
  158. # success. After 10 failed attempts it bails out and returns 1. It dumps the
  159. # backlog size to stdout.
  160. build_backlog()
  161. {
  162. local size=$1; shift
  163. local proto=$1; shift
  164. local i=0
  165. while :; do
  166. local cur=$(get_qdisc_backlog)
  167. local diff=$((size - cur))
  168. local pkts=$(((diff + PKTSZ - 1) / PKTSZ))
  169. if ((cur >= size)); then
  170. echo $cur
  171. return 0
  172. elif ((i++ > 10)); then
  173. echo $cur
  174. return 1
  175. fi
  176. send_packets $proto $pkts "$@"
  177. sleep 1
  178. done
  179. }
  180. check_marking()
  181. {
  182. local cond=$1; shift
  183. local npackets_0=$(get_qdisc_npackets)
  184. local nmarked_0=$(get_nmarked)
  185. sleep 5
  186. local npackets_1=$(get_qdisc_npackets)
  187. local nmarked_1=$(get_nmarked)
  188. local nmarked_d=$((nmarked_1 - nmarked_0))
  189. local npackets_d=$((npackets_1 - npackets_0))
  190. local pct=$((100 * nmarked_d / npackets_d))
  191. echo $pct
  192. ((pct $cond))
  193. }
  194. check_mirroring()
  195. {
  196. local cond=$1; shift
  197. local npackets_0=$(get_qdisc_npackets)
  198. local nmirrored_0=$(get_nmirrored)
  199. sleep 5
  200. local npackets_1=$(get_qdisc_npackets)
  201. local nmirrored_1=$(get_nmirrored)
  202. local nmirrored_d=$((nmirrored_1 - nmirrored_0))
  203. local npackets_d=$((npackets_1 - npackets_0))
  204. local pct=$((100 * nmirrored_d / npackets_d))
  205. echo $pct
  206. ((pct $cond))
  207. }
  208. ecn_test_common()
  209. {
  210. local name=$1; shift
  211. local limit=$1; shift
  212. local backlog
  213. local pct
  214. # Build the below-the-limit backlog using UDP. We could use TCP just
  215. # fine, but this way we get a proof that UDP is accepted when queue
  216. # length is below the limit. The main stream is using TCP, and if the
  217. # limit is misconfigured, we would see this traffic being ECN marked.
  218. RET=0
  219. backlog=$(build_backlog $((2 * limit / 3)) udp)
  220. check_err $? "Could not build the requested backlog"
  221. pct=$(check_marking "== 0")
  222. check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected == 0."
  223. log_test "$name backlog < limit"
  224. # Now push TCP, because non-TCP traffic would be early-dropped after the
  225. # backlog crosses the limit, and we want to make sure that the backlog
  226. # is above the limit.
  227. RET=0
  228. backlog=$(build_backlog $((3 * limit / 2)) tcp tos=0x01)
  229. check_err $? "Could not build the requested backlog"
  230. pct=$(check_marking ">= 95")
  231. check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected >= 95."
  232. log_test "$name backlog > limit"
  233. }
  234. do_ecn_test()
  235. {
  236. local limit=$1; shift
  237. local name=ECN
  238. $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
  239. -a own -b $h3_mac -t tcp -q tos=0x01 &
  240. sleep 1
  241. ecn_test_common "$name" $limit
  242. # Up there we saw that UDP gets accepted when backlog is below the
  243. # limit. Now that it is above, it should all get dropped, and backlog
  244. # building should fail.
  245. RET=0
  246. build_backlog $((2 * limit)) udp >/dev/null
  247. check_fail $? "UDP traffic went into backlog instead of being early-dropped"
  248. log_test "$name backlog > limit: UDP early-dropped"
  249. stop_traffic
  250. sleep 1
  251. }
  252. do_ecn_nodrop_test()
  253. {
  254. local limit=$1; shift
  255. local name="ECN nodrop"
  256. $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
  257. -a own -b $h3_mac -t tcp -q tos=0x01 &
  258. sleep 1
  259. ecn_test_common "$name" $limit
  260. # Up there we saw that UDP gets accepted when backlog is below the
  261. # limit. Now that it is above, in nodrop mode, make sure it goes to
  262. # backlog as well.
  263. RET=0
  264. build_backlog $((2 * limit)) udp >/dev/null
  265. check_err $? "UDP traffic was early-dropped instead of getting into backlog"
  266. log_test "$name backlog > limit: UDP not dropped"
  267. stop_traffic
  268. sleep 1
  269. }
  270. do_red_test()
  271. {
  272. local limit=$1; shift
  273. local backlog
  274. local pct
  275. # Use ECN-capable TCP to verify there's no marking even though the queue
  276. # is above limit.
  277. $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
  278. -a own -b $h3_mac -t tcp -q tos=0x01 &
  279. # Pushing below the queue limit should work.
  280. RET=0
  281. backlog=$(build_backlog $((2 * limit / 3)) tcp tos=0x01)
  282. check_err $? "Could not build the requested backlog"
  283. pct=$(check_marking "== 0")
  284. check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected == 0."
  285. log_test "RED backlog < limit"
  286. # Pushing above should not.
  287. RET=0
  288. backlog=$(build_backlog $((3 * limit / 2)) tcp tos=0x01)
  289. check_fail $? "Traffic went into backlog instead of being early-dropped"
  290. pct=$(check_marking "== 0")
  291. check_err $? "backlog $backlog / $limit Got $pct% marked packets, expected == 0."
  292. log_test "RED backlog > limit"
  293. stop_traffic
  294. sleep 1
  295. }
  296. do_red_qevent_test()
  297. {
  298. local limit=$1; shift
  299. local backlog
  300. local base
  301. local now
  302. local pct
  303. RET=0
  304. $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
  305. -a own -b $h3_mac -t udp -q &
  306. sleep 1
  307. tc filter add block 10 pref 1234 handle 102 matchall skip_hw \
  308. action mirred egress mirror dev _drop_test
  309. # Push to the queue until it's at the limit. The configured limit is
  310. # rounded by the qdisc, so this is the best we can do to get to the real
  311. # limit.
  312. build_backlog $((3 * limit / 2)) udp >/dev/null
  313. base=$(get_nmirrored)
  314. send_packets udp 100
  315. sleep 1
  316. now=$(get_nmirrored)
  317. ((now >= base + 100))
  318. check_err $? "Dropped packets not observed: 100 expected, $((now - base)) seen"
  319. tc filter del block 10 pref 1234 handle 102 matchall
  320. base=$(get_nmirrored)
  321. send_packets udp 100
  322. sleep 1
  323. now=$(get_nmirrored)
  324. ((now == base))
  325. check_err $? "Dropped packets still observed: 0 expected, $((now - base)) seen"
  326. log_test "RED early_dropped packets mirrored"
  327. stop_traffic
  328. sleep 1
  329. }
  330. do_ecn_qevent_test()
  331. {
  332. local limit=$1; shift
  333. local name=ECN
  334. RET=0
  335. $MZ $h1 -p $PKTSZ -A 192.0.2.1 -B 192.0.2.3 -c 0 \
  336. -a own -b $h3_mac -t tcp -q tos=0x01 &
  337. sleep 1
  338. tc filter add block 10 pref 1234 handle 102 matchall skip_hw \
  339. action mirred egress mirror dev _drop_test
  340. backlog=$(build_backlog $((2 * limit / 3)) tcp tos=0x01)
  341. check_err $? "Could not build the requested backlog"
  342. pct=$(check_mirroring "== 0")
  343. check_err $? "backlog $backlog / $limit Got $pct% mirrored packets, expected == 0."
  344. backlog=$(build_backlog $((3 * limit / 2)) tcp tos=0x01)
  345. check_err $? "Could not build the requested backlog"
  346. pct=$(check_mirroring ">= 95")
  347. check_err $? "backlog $backlog / $limit Got $pct% mirrored packets, expected >= 95."
  348. tc filter del block 10 pref 1234 handle 102 matchall
  349. log_test "ECN marked packets mirrored"
  350. stop_traffic
  351. sleep 1
  352. }
  353. install_qdisc()
  354. {
  355. local -a args=("$@")
  356. tc qdisc replace dev $swp3 parent 1:1 handle 11: red \
  357. limit 1M avpkt $PKTSZ probability 1 \
  358. min $BACKLOG max $((BACKLOG + 1)) burst 38 "${args[@]}"
  359. sleep 1
  360. }
  361. uninstall_qdisc()
  362. {
  363. tc qdisc del dev $swp3 parent 1:1
  364. }
  365. ecn_test()
  366. {
  367. install_qdisc ecn
  368. xfail_on_slow do_ecn_test $BACKLOG
  369. uninstall_qdisc
  370. }
  371. ecn_nodrop_test()
  372. {
  373. install_qdisc ecn nodrop
  374. xfail_on_slow do_ecn_nodrop_test $BACKLOG
  375. uninstall_qdisc
  376. }
  377. red_test()
  378. {
  379. install_qdisc
  380. xfail_on_slow do_red_test $BACKLOG
  381. uninstall_qdisc
  382. }
  383. red_qevent_test()
  384. {
  385. install_qdisc qevent early_drop block 10
  386. xfail_on_slow do_red_qevent_test $BACKLOG
  387. uninstall_qdisc
  388. }
  389. ecn_qevent_test()
  390. {
  391. install_qdisc ecn qevent mark block 10
  392. xfail_on_slow do_ecn_qevent_test $BACKLOG
  393. uninstall_qdisc
  394. }
  395. trap cleanup EXIT
  396. setup_prepare
  397. setup_wait
  398. tests_run
  399. exit $EXIT_STATUS