First implementation of HFSC queuing discipline

This commit is contained in:
Tom Eastep 2009-05-23 17:04:39 -07:00
parent 4cf2c1b59f
commit 787caa7f32

View File

@ -157,6 +157,7 @@ our @deferred_rules;
# redirected => [ <dev1>, <dev2>, ... ]
# nextclass => <number>
# occurs => Has one or more occurring classes
# qdisc => htb|hfsc
# }
#
our @tcdevices;
@ -173,6 +174,8 @@ our $sticky;
# mark => <mark> ,
# number => <number> ,
# rate => <rate> ,
# umax => <umax> ,
# dmax => <dmax> ,
# ceiling => <ceiling> ,
# priority => <priority> ,
# occurs => <number> # 0 means that this is a class generated by another class with occurs > 1
@ -472,7 +475,7 @@ sub validate_tc_device( ) {
fatal_error "Duplicate INTERFACE ($device)" if $tcdevices{$device};
fatal_error "Invalid INTERFACE name ($device)" if $device =~ /[:+]/;
my ( $classify, $pfifo, $flow) = (0, 0, '' );
my ( $classify, $pfifo, $flow, $qdisc ) = (0, 0, '', 'htb' );
if ( $options ne '-' ) {
for my $option ( split_list1 $options, 'option' ) {
@ -484,6 +487,10 @@ sub validate_tc_device( ) {
} elsif ( $option eq 'pfifo' ) {
fatal_error "The 'pfifo'' option is not allowed with 'flow='" if $flow;
$pfifo = 1;
} elsif ( $option eq 'hfsc' ) {
$qdisc = 'hfsc';
} elsif ( $option eq 'htb' ) {
$qdisc = 'htb';
} else {
fatal_error "Unknown device option ($option)";
}
@ -506,16 +513,17 @@ sub validate_tc_device( ) {
fatal_error "IN-BANDWIDTH must be zero for REDIRECTED devices" if $rdevref->{in_bandwidth} ne '0kbit';
}
$tcdevices{$device} = { in_bandwidth => rate_to_kbit( $inband ) . 'kbit' ,
out_bandwidth => rate_to_kbit( $outband ) . 'kbit' ,
$tcdevices{$device} = { in_bandwidth => rate_to_kbit( $inband ) . 'kbit',
out_bandwidth => rate_to_kbit( $outband ) . 'kbit',
number => $devnumber,
classify => $classify ,
flow => $flow ,
pfifo => $pfifo ,
classify => $classify,
flow => $flow,
pfifo => $pfifo,
tablenumber => 1 ,
redirected => \@redirected ,
redirected => \@redirected,
default => 0,
nextclass => 2,
qdisc => $qdisc,
} ,
push @tcdevices, $device;
@ -545,6 +553,21 @@ sub convert_rate( $$$ ) {
$rate;
}
sub convert_delay( $ ) {
my $delay = shift;
return 0 unless $delay;
return $1 if $delay =~ /^(\d+)(ms)?$/;
fatal_error "Invalid Delay ($delay)";
}
sub convert_size( $ ) {
my $size = shift;
return '' unless $size;
return $1 if $size =~ /^(\d+)b?$/;
fatal_error "Invalid Size ($size)";
}
sub dev_by_number( $ ) {
my $dev = $_[0];
my $devnum = uc $dev;
@ -644,8 +667,25 @@ sub validate_tc_class( ) {
$parentref->{leaf} = 0;
}
my ( $umax, $dmax ) = ( '', '' );
if ( $devref->{qdisc} eq 'hfsc' ) {
( my $trate , $dmax, $umax , my $rest ) = split ':', $rate , 4;
fatal_error "Invalid RATE ($rate)" if defined $rest;
$rate = convert_rate ( $full, $trate, 'RATE' );
$dmax = convert_delay( $dmax );
$umax = convert_size( $umax );
fatal_error "A umax or dmax value must be specified for an hfsc class" unless $umax || $dmax;
} else {
$rate = convert_rate ( $full, $rate, 'RATE' );
}
$tcref->{$classnumber} = { tos => [] ,
rate => convert_rate( $full, $rate, 'RATE' ) ,
rate => $rate ,
umax => $umax ,
dmax => $dmax ,
ceiling => convert_rate( $full, $ceil, 'CEIL' ) ,
priority => $prio eq '-' ? 1 : $prio ,
mark => $markval ,
@ -960,11 +1000,17 @@ sub setup_traffic_shaping() {
emit ( "${dev}_exists=Yes",
"qt \$TC qdisc del dev $device root",
"qt \$TC qdisc del dev $device ingress",
"run_tc qdisc add dev $device root handle $devnum: htb default $defmark r2q $r2q",
"${dev}_mtu=\$(get_device_mtu $device)",
"${dev}_mtu1=\$(get_device_mtu1 $device)",
"run_tc class add dev $device parent $devnum: classid $devnum:1 htb rate $devref->{out_bandwidth} \$${dev}_mtu1"
);
"${dev}_mtu1=\$(get_device_mtu1 $device)"
);
if ( $devref->{qdisc} eq 'htb' ) {
emit ( "run_tc qdisc add dev $device root handle $devnum: htb default $defmark r2q $r2q" ,
"run_tc class add dev $device parent $devnum: classid $devnum:1 htb rate $devref->{out_bandwidth} \$${dev}_mtu1" );
} else {
emit ( "run_tc qdisc add dev $device root handle $devnum: hfsc default $defmark" ,
"run_tc class add dev $device parent $devnum: classid $devnum:1 hfsc sc rate $devref->{out_bandwidth} ul rate $devref->{out_bandwidth}" );
}
if ( $devref->{occurs} ) {
#
@ -1046,9 +1092,36 @@ sub setup_traffic_shaping() {
$lastdevice = $device;
}
emit ( "[ \$${dev}_mtu -gt $quantum ] && quantum=\$${dev}_mtu || quantum=$quantum",
"run_tc class add dev $device parent $devref->{number}:$parent classid $classid htb rate $rate ceil $tcref->{ceiling}kbit prio $tcref->{priority} \$${dev}_mtu1 quantum \$quantum" );
emit ( "[ \$${dev}_mtu -gt $quantum ] && quantum=\$${dev}_mtu || quantum=$quantum" );
if ( $devref->{qdisc} eq 'htb' ) {
emit ( "run_tc class add dev $device parent $devref->{number}:$parent classid $classid htb rate $rate ceil $tcref->{ceiling}kbit prio $tcref->{priority} \$${dev}_mtu1 quantum \$quantum" );
} else {
my $umax = $tcref->{umax};
my $dmax = $tcref->{dmax};
unless ( $dmax ) {
#
# We must calculate the dmax but we know that umax has been specified
#
my $packetbits = 8 * $umax;
my $rateinbits = 1000 * $tcref->{rate};
my $fullinbytes = $devref->{out_bandwidth};
$fullinbytes =~ s/kbit//;
my $fullinbits = 1000 * $fullinbytes;
my $packetspersecond = $rateinbits / $packetbits;
my $totaldelayinms = 1000 * ( 1 - ( $rateinbits / $fullinbits ) );
#
# In this calculation, '3' is a magic number. We can adjust it as necessary as we learn about this QDISC
#
$dmax = int( 3 * $totaldelayinms / $packetspersecond );
}
$umax = $umax ? "${umax}b" : "\$${dev}_mtu";
emit ( "run_tc class add dev $device parent $devref->{number}:$parent classid $classid hfsc sc umax $umax dmax ${dmax}ms rate $rate ul rate $tcref->{ceiling}kbit" );
}
emit( "run_tc qdisc add dev $device parent $classid handle ${classnum}: sfq quantum \$quantum limit 127 perturb 10" ) if $tcref->{leaf} && ! $tcref->{pfifo};
#
# add filters