Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/sched: act_police: more accurate MTU policing

in current Linux, MTU policing does not take into account that packets at
the TC ingress have the L2 header pulled. Thus, the same TC police action
(with the same value of tcfp_mtu) behaves differently for ingress/egress.
In addition, the full GSO size is compared to tcfp_mtu: as a consequence,
the policer drops GSO packets even when individual segments have the L2 +
L3 + L4 + payload length below the configured valued of tcfp_mtu.

Improve the accuracy of MTU policing as follows:
- account for mac_len for non-GSO packets at TC ingress.
- compare MTU threshold with the segmented size for GSO packets.
Also, add a kselftest that verifies the correct behavior.

Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Davide Caratti and committed by
David S. Miller
4ddc844e 2618a0da

+67 -1
+15 -1
net/sched/act_police.c
··· 239 239 return err; 240 240 } 241 241 242 + static bool tcf_police_mtu_check(struct sk_buff *skb, u32 limit) 243 + { 244 + u32 len; 245 + 246 + if (skb_is_gso(skb)) 247 + return skb_gso_validate_mac_len(skb, limit); 248 + 249 + len = qdisc_pkt_len(skb); 250 + if (skb_at_tc_ingress(skb)) 251 + len += skb->mac_len; 252 + 253 + return len <= limit; 254 + } 255 + 242 256 static int tcf_police_act(struct sk_buff *skb, const struct tc_action *a, 243 257 struct tcf_result *res) 244 258 { ··· 275 261 goto inc_overlimits; 276 262 } 277 263 278 - if (qdisc_pkt_len(skb) <= p->tcfp_mtu) { 264 + if (tcf_police_mtu_check(skb, p->tcfp_mtu)) { 279 265 if (!p->rate_present && !p->pps_present) { 280 266 ret = p->tcfp_result; 281 267 goto end;
+52
tools/testing/selftests/net/forwarding/tc_police.sh
··· 37 37 police_tx_mirror_test 38 38 police_pps_rx_test 39 39 police_pps_tx_test 40 + police_mtu_rx_test 41 + police_mtu_tx_test 40 42 " 41 43 NUM_NETIFS=6 42 44 source tc_common.sh ··· 346 344 police_pps_common_test "police pps on tx" 347 345 348 346 tc filter del dev $rp2 egress protocol ip pref 1 handle 101 flower 347 + } 348 + 349 + police_mtu_common_test() { 350 + RET=0 351 + 352 + local test_name=$1; shift 353 + local dev=$1; shift 354 + local direction=$1; shift 355 + 356 + tc filter add dev $dev $direction protocol ip pref 1 handle 101 flower \ 357 + dst_ip 198.51.100.1 ip_proto udp dst_port 54321 \ 358 + action police mtu 1042 conform-exceed drop/ok 359 + 360 + # to count "conform" packets 361 + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ 362 + dst_ip 198.51.100.1 ip_proto udp dst_port 54321 \ 363 + action drop 364 + 365 + mausezahn $h1 -a own -b $(mac_get $rp1) -A 192.0.2.1 -B 198.51.100.1 \ 366 + -t udp sp=12345,dp=54321 -p 1001 -c 10 -q 367 + 368 + mausezahn $h1 -a own -b $(mac_get $rp1) -A 192.0.2.1 -B 198.51.100.1 \ 369 + -t udp sp=12345,dp=54321 -p 1000 -c 3 -q 370 + 371 + tc_check_packets "dev $dev $direction" 101 13 372 + check_err $? "wrong packet counter" 373 + 374 + # "exceed" packets 375 + local overlimits_t0=$(tc_rule_stats_get ${dev} 1 ${direction} .overlimits) 376 + test ${overlimits_t0} = 10 377 + check_err $? "wrong overlimits, expected 10 got ${overlimits_t0}" 378 + 379 + # "conform" packets 380 + tc_check_packets "dev $h2 ingress" 101 3 381 + check_err $? "forwarding error" 382 + 383 + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower 384 + tc filter del dev $dev $direction protocol ip pref 1 handle 101 flower 385 + 386 + log_test "$test_name" 387 + } 388 + 389 + police_mtu_rx_test() 390 + { 391 + police_mtu_common_test "police mtu (rx)" $rp1 ingress 392 + } 393 + 394 + police_mtu_tx_test() 395 + { 396 + police_mtu_common_test "police mtu (tx)" $rp2 egress 349 397 } 350 398 351 399 setup_prepare()