mirror of
https://github.com/systemd/systemd.git
synced 2025-01-25 10:04:04 +03:00
parent
120b5c0bbe
commit
d9eacc1cdd
@ -3209,6 +3209,14 @@
|
|||||||
to the class. Defaults to unset.</para>
|
to the class. Defaults to unset.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>RateToQuantum=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Takes an unsigned integer. The DRR quantums are calculated by dividing the value
|
||||||
|
configured in <varname>Rate=</varname> by <varname>RateToQuantum=</varname>.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@ -3225,7 +3233,33 @@
|
|||||||
<term><varname>Priority=</varname></term>
|
<term><varname>Priority=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>Specifies the priority of the class. In the round-robin process, classes with the lowest
|
<para>Specifies the priority of the class. In the round-robin process, classes with the lowest
|
||||||
priority field are tried for packets first. This setting is mandatory.</para>
|
priority field are tried for packets first.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>QuantumBytes=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Specifies how many bytes to serve from leaf at once. When suffixed with K, M, or G, the
|
||||||
|
specified size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of
|
||||||
|
1024.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>MTUBytes=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Specifies the maximum packet size we create. When suffixed with K, M, or G, the specified
|
||||||
|
size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1024.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>OverheadBytes=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Takes an unsigned integer which specifies per-packet size overhead used in rate
|
||||||
|
computations. When suffixed with K, M, or G, the specified size is parsed as Kilobytes,
|
||||||
|
Megabytes, or Gigabytes, respectively, to the base of 1024.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
@ -3247,6 +3281,24 @@
|
|||||||
is used.</para>
|
is used.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>BufferBytes=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Specifies the maximum bytes burst which can be accumulated during idle period. When suffixed
|
||||||
|
with K, M, or G, the specified size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively,
|
||||||
|
to the base of 1024.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>CeilBufferBytes=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>Specifies the maximum bytes burst for ceil which can be accumulated during idle period.
|
||||||
|
When suffixed with K, M, or G, the specified size is parsed as Kilobytes, Megabytes, or Gigabytes,
|
||||||
|
respectively, to the base of 1024.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -352,11 +352,17 @@ HeavyHitterFilter.PacketLimit, config_parse_heavy_hitter_filter_pa
|
|||||||
HierarchyTokenBucket.Parent, config_parse_qdisc_parent, QDISC_KIND_HTB, 0
|
HierarchyTokenBucket.Parent, config_parse_qdisc_parent, QDISC_KIND_HTB, 0
|
||||||
HierarchyTokenBucket.Handle, config_parse_qdisc_handle, QDISC_KIND_HTB, 0
|
HierarchyTokenBucket.Handle, config_parse_qdisc_handle, QDISC_KIND_HTB, 0
|
||||||
HierarchyTokenBucket.DefaultClass, config_parse_hierarchy_token_bucket_default_class, QDISC_KIND_HTB, 0
|
HierarchyTokenBucket.DefaultClass, config_parse_hierarchy_token_bucket_default_class, QDISC_KIND_HTB, 0
|
||||||
|
HierarchyTokenBucket.RateToQuantum, config_parse_hierarchy_token_bucket_u32, QDISC_KIND_HTB, 0
|
||||||
HierarchyTokenBucketClass.Parent, config_parse_tclass_parent, TCLASS_KIND_HTB, 0
|
HierarchyTokenBucketClass.Parent, config_parse_tclass_parent, TCLASS_KIND_HTB, 0
|
||||||
HierarchyTokenBucketClass.ClassId, config_parse_tclass_classid, TCLASS_KIND_HTB, 0
|
HierarchyTokenBucketClass.ClassId, config_parse_tclass_classid, TCLASS_KIND_HTB, 0
|
||||||
HierarchyTokenBucketClass.Priority, config_parse_hierarchy_token_bucket_u32, TCLASS_KIND_HTB, 0
|
HierarchyTokenBucketClass.Priority, config_parse_hierarchy_token_bucket_class_u32, TCLASS_KIND_HTB, 0
|
||||||
HierarchyTokenBucketClass.Rate, config_parse_hierarchy_token_bucket_rate, TCLASS_KIND_HTB, 0
|
HierarchyTokenBucketClass.QuantumBytes, config_parse_hierarchy_token_bucket_class_size, TCLASS_KIND_HTB, 0
|
||||||
HierarchyTokenBucketClass.CeilRate, config_parse_hierarchy_token_bucket_rate, TCLASS_KIND_HTB, 0
|
HierarchyTokenBucketClass.MTUBytes, config_parse_hierarchy_token_bucket_class_size, TCLASS_KIND_HTB, 0
|
||||||
|
HierarchyTokenBucketClass.OverheadBytes, config_parse_hierarchy_token_bucket_class_size, TCLASS_KIND_HTB, 0
|
||||||
|
HierarchyTokenBucketClass.Rate, config_parse_hierarchy_token_bucket_class_rate, TCLASS_KIND_HTB, 0
|
||||||
|
HierarchyTokenBucketClass.CeilRate, config_parse_hierarchy_token_bucket_class_rate, TCLASS_KIND_HTB, 0
|
||||||
|
HierarchyTokenBucketClass.BufferBytes, config_parse_hierarchy_token_bucket_class_size, TCLASS_KIND_HTB, 0
|
||||||
|
HierarchyTokenBucketClass.CeilBufferBytes, config_parse_hierarchy_token_bucket_class_size, TCLASS_KIND_HTB, 0
|
||||||
NetworkEmulator.Parent, config_parse_qdisc_parent, QDISC_KIND_NETEM, 0
|
NetworkEmulator.Parent, config_parse_qdisc_parent, QDISC_KIND_NETEM, 0
|
||||||
NetworkEmulator.Handle, config_parse_qdisc_handle, QDISC_KIND_NETEM, 0
|
NetworkEmulator.Handle, config_parse_qdisc_handle, QDISC_KIND_NETEM, 0
|
||||||
NetworkEmulator.DelaySec, config_parse_network_emulator_delay, QDISC_KIND_NETEM, 0
|
NetworkEmulator.DelaySec, config_parse_network_emulator_delay, QDISC_KIND_NETEM, 0
|
||||||
|
@ -11,10 +11,12 @@
|
|||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "tc-util.h"
|
#include "tc-util.h"
|
||||||
|
|
||||||
|
#define HTB_DEFAULT_RATE_TO_QUANTUM 10
|
||||||
|
#define HTB_DEFAULT_MTU 1600 /* Ethernet packet length */
|
||||||
|
|
||||||
static int hierarchy_token_bucket_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
static int hierarchy_token_bucket_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||||
HierarchyTokenBucket *htb;
|
HierarchyTokenBucket *htb;
|
||||||
struct tc_htb_glob opt = {
|
struct tc_htb_glob opt = {
|
||||||
.rate2quantum = 10,
|
|
||||||
.version = 3,
|
.version = 3,
|
||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
@ -25,6 +27,7 @@ static int hierarchy_token_bucket_fill_message(Link *link, QDisc *qdisc, sd_netl
|
|||||||
|
|
||||||
htb = HTB(qdisc);
|
htb = HTB(qdisc);
|
||||||
|
|
||||||
|
opt.rate2quantum = htb->rate_to_quantum;
|
||||||
opt.defcls = htb->default_class;
|
opt.defcls = htb->default_class;
|
||||||
|
|
||||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "htb");
|
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "htb");
|
||||||
@ -92,16 +95,80 @@ int config_parse_hierarchy_token_bucket_default_class(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_hierarchy_token_bucket_u32(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
|
HierarchyTokenBucket *htb;
|
||||||
|
Network *network = data;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = qdisc_new_static(QDISC_KIND_HTB, network, filename, section_line, &qdisc);
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0)
|
||||||
|
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
|
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||||
|
|
||||||
|
htb = HTB(qdisc);
|
||||||
|
|
||||||
|
if (isempty(rvalue)) {
|
||||||
|
htb->rate_to_quantum = HTB_DEFAULT_RATE_TO_QUANTUM;
|
||||||
|
|
||||||
|
qdisc = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = safe_atou32(rvalue, &htb->rate_to_quantum);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
|
"Failed to parse '%s=', ignoring assignment: %s",
|
||||||
|
lvalue, rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qdisc = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hierarchy_token_bucket_init(QDisc *qdisc) {
|
||||||
|
HierarchyTokenBucket *htb;
|
||||||
|
|
||||||
|
assert(qdisc);
|
||||||
|
|
||||||
|
htb = HTB(qdisc);
|
||||||
|
|
||||||
|
htb->rate_to_quantum = HTB_DEFAULT_RATE_TO_QUANTUM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const QDiscVTable htb_vtable = {
|
const QDiscVTable htb_vtable = {
|
||||||
.object_size = sizeof(HierarchyTokenBucket),
|
.object_size = sizeof(HierarchyTokenBucket),
|
||||||
.tca_kind = "htb",
|
.tca_kind = "htb",
|
||||||
.fill_message = hierarchy_token_bucket_fill_message,
|
.fill_message = hierarchy_token_bucket_fill_message,
|
||||||
|
.init = hierarchy_token_bucket_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int hierarchy_token_bucket_class_fill_message(Link *link, TClass *tclass, sd_netlink_message *req) {
|
static int hierarchy_token_bucket_class_fill_message(Link *link, TClass *tclass, sd_netlink_message *req) {
|
||||||
HierarchyTokenBucketClass *htb;
|
HierarchyTokenBucketClass *htb;
|
||||||
struct tc_htb_opt opt = {};
|
struct tc_htb_opt opt = {};
|
||||||
uint32_t rtab[256], ctab[256], mtu = 1600; /* Ethernet packet length */
|
uint32_t rtab[256], ctab[256];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -110,25 +177,26 @@ static int hierarchy_token_bucket_class_fill_message(Link *link, TClass *tclass,
|
|||||||
|
|
||||||
htb = TCLASS_TO_HTB(tclass);
|
htb = TCLASS_TO_HTB(tclass);
|
||||||
|
|
||||||
if (htb->ceil_rate == 0)
|
|
||||||
htb->ceil_rate = htb->rate;
|
|
||||||
|
|
||||||
opt.prio = htb->priority;
|
opt.prio = htb->priority;
|
||||||
|
opt.quantum = htb->quantum;
|
||||||
opt.rate.rate = (htb->rate >= (1ULL << 32)) ? ~0U : htb->rate;
|
opt.rate.rate = (htb->rate >= (1ULL << 32)) ? ~0U : htb->rate;
|
||||||
opt.ceil.rate = (htb->ceil_rate >= (1ULL << 32)) ? ~0U : htb->ceil_rate;
|
opt.ceil.rate = (htb->ceil_rate >= (1ULL << 32)) ? ~0U : htb->ceil_rate;
|
||||||
r = tc_transmit_time(htb->rate, mtu, &opt.buffer);
|
opt.rate.overhead = htb->overhead;
|
||||||
|
opt.ceil.overhead = htb->overhead;
|
||||||
|
|
||||||
|
r = tc_transmit_time(htb->rate, htb->buffer, &opt.buffer);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to calculate buffer size: %m");
|
return log_link_error_errno(link, r, "Failed to calculate buffer size: %m");
|
||||||
|
|
||||||
r = tc_transmit_time(htb->ceil_rate, mtu, &opt.cbuffer);
|
r = tc_transmit_time(htb->ceil_rate, htb->ceil_buffer, &opt.cbuffer);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to calculate ceil buffer size: %m");
|
return log_link_error_errno(link, r, "Failed to calculate ceil buffer size: %m");
|
||||||
|
|
||||||
r = tc_fill_ratespec_and_table(&opt.rate, rtab, mtu);
|
r = tc_fill_ratespec_and_table(&opt.rate, rtab, htb->mtu);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to calculate rate table: %m");
|
return log_link_error_errno(link, r, "Failed to calculate rate table: %m");
|
||||||
|
|
||||||
r = tc_fill_ratespec_and_table(&opt.ceil, ctab, mtu);
|
r = tc_fill_ratespec_and_table(&opt.ceil, ctab, htb->mtu);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to calculate ceil rate table: %m");
|
return log_link_error_errno(link, r, "Failed to calculate ceil rate table: %m");
|
||||||
|
|
||||||
@ -166,7 +234,7 @@ static int hierarchy_token_bucket_class_fill_message(Link *link, TClass *tclass,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_hierarchy_token_bucket_u32(
|
int config_parse_hierarchy_token_bucket_class_u32(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
unsigned line,
|
unsigned line,
|
||||||
@ -181,6 +249,7 @@ int config_parse_hierarchy_token_bucket_u32(
|
|||||||
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
|
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
|
||||||
HierarchyTokenBucketClass *htb;
|
HierarchyTokenBucketClass *htb;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
|
uint32_t v;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
@ -197,12 +266,11 @@ int config_parse_hierarchy_token_bucket_u32(
|
|||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
htb->priority = 0;
|
htb->priority = 0;
|
||||||
|
|
||||||
tclass = NULL;
|
tclass = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = safe_atou32(rvalue, &htb->priority);
|
r = safe_atou32(rvalue, &v);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"Failed to parse '%s=', ignoring assignment: %s",
|
"Failed to parse '%s=', ignoring assignment: %s",
|
||||||
@ -210,12 +278,93 @@ int config_parse_hierarchy_token_bucket_u32(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
htb->priority = v;
|
||||||
tclass = NULL;
|
tclass = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_hierarchy_token_bucket_rate(
|
int config_parse_hierarchy_token_bucket_class_size(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
_cleanup_(tclass_free_or_set_invalidp) TClass *tclass = NULL;
|
||||||
|
HierarchyTokenBucketClass *htb;
|
||||||
|
Network *network = data;
|
||||||
|
uint64_t v;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = tclass_new_static(TCLASS_KIND_HTB, network, filename, section_line, &tclass);
|
||||||
|
if (r < 0)
|
||||||
|
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
|
"Failed to create traffic control class, ignoring assignment: %m");
|
||||||
|
|
||||||
|
htb = TCLASS_TO_HTB(tclass);
|
||||||
|
|
||||||
|
if (isempty(rvalue)) {
|
||||||
|
if (streq(lvalue, "QuantumBytes"))
|
||||||
|
htb->quantum = 0;
|
||||||
|
else if (streq(lvalue, "MTUBytes"))
|
||||||
|
htb->mtu = HTB_DEFAULT_MTU;
|
||||||
|
else if (streq(lvalue, "OverheadBytes"))
|
||||||
|
htb->overhead = 0;
|
||||||
|
else if (streq(lvalue, "BufferBytes"))
|
||||||
|
htb->buffer = 0;
|
||||||
|
else if (streq(lvalue, "CeilBufferBytes"))
|
||||||
|
htb->ceil_buffer = 0;
|
||||||
|
else
|
||||||
|
assert_not_reached("Invalid lvalue");
|
||||||
|
|
||||||
|
tclass = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = parse_size(rvalue, 1024, &v);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
|
"Failed to parse '%s=', ignoring assignment: %s",
|
||||||
|
lvalue, rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((streq(lvalue, "OverheadBytes") && v > UINT16_MAX) || v > UINT32_MAX) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||||
|
"Invalid '%s=', ignoring assignment: %s",
|
||||||
|
lvalue, rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(lvalue, "QuantumBytes"))
|
||||||
|
htb->quantum = v;
|
||||||
|
else if (streq(lvalue, "OverheadBytes"))
|
||||||
|
htb->overhead = v;
|
||||||
|
else if (streq(lvalue, "MTUBytes"))
|
||||||
|
htb->mtu = v;
|
||||||
|
else if (streq(lvalue, "BufferBytes"))
|
||||||
|
htb->buffer = v;
|
||||||
|
else if (streq(lvalue, "CeilBufferBytes"))
|
||||||
|
htb->ceil_buffer = v;
|
||||||
|
else
|
||||||
|
assert_not_reached("Invalid lvalue");
|
||||||
|
|
||||||
|
tclass = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse_hierarchy_token_bucket_class_rate(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
unsigned line,
|
unsigned line,
|
||||||
@ -272,8 +421,53 @@ int config_parse_hierarchy_token_bucket_rate(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hierarchy_token_bucket_class_init(TClass *tclass) {
|
||||||
|
HierarchyTokenBucketClass *htb;
|
||||||
|
|
||||||
|
assert(tclass);
|
||||||
|
|
||||||
|
htb = TCLASS_TO_HTB(tclass);
|
||||||
|
|
||||||
|
htb->mtu = HTB_DEFAULT_MTU;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hierarchy_token_bucket_class_verify(TClass *tclass) {
|
||||||
|
HierarchyTokenBucketClass *htb;
|
||||||
|
uint32_t hz;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(tclass);
|
||||||
|
|
||||||
|
htb = TCLASS_TO_HTB(tclass);
|
||||||
|
|
||||||
|
if (htb->rate == 0)
|
||||||
|
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"%s: Rate= is mandatory. "
|
||||||
|
"Ignoring [HierarchyTokenBucketClass] section from line %u.",
|
||||||
|
tclass->section->filename, tclass->section->line);
|
||||||
|
|
||||||
|
/* if CeilRate= setting is missing, use the same as Rate= */
|
||||||
|
if (htb->ceil_rate == 0)
|
||||||
|
htb->ceil_rate = htb->rate;
|
||||||
|
|
||||||
|
r = tc_init(NULL, &hz);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to read /proc/net/psched: %m");
|
||||||
|
|
||||||
|
if (htb->buffer == 0)
|
||||||
|
htb->buffer = htb->rate / hz + htb->mtu;
|
||||||
|
if (htb->ceil_buffer == 0)
|
||||||
|
htb->ceil_buffer = htb->ceil_rate / hz + htb->mtu;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const TClassVTable htb_tclass_vtable = {
|
const TClassVTable htb_tclass_vtable = {
|
||||||
.object_size = sizeof(HierarchyTokenBucketClass),
|
.object_size = sizeof(HierarchyTokenBucketClass),
|
||||||
.tca_kind = "htb",
|
.tca_kind = "htb",
|
||||||
.fill_message = hierarchy_token_bucket_class_fill_message,
|
.fill_message = hierarchy_token_bucket_class_fill_message,
|
||||||
|
.init = hierarchy_token_bucket_class_init,
|
||||||
|
.verify = hierarchy_token_bucket_class_verify,
|
||||||
};
|
};
|
||||||
|
@ -9,23 +9,31 @@ typedef struct HierarchyTokenBucket {
|
|||||||
QDisc meta;
|
QDisc meta;
|
||||||
|
|
||||||
uint32_t default_class;
|
uint32_t default_class;
|
||||||
|
uint32_t rate_to_quantum;
|
||||||
} HierarchyTokenBucket;
|
} HierarchyTokenBucket;
|
||||||
|
|
||||||
DEFINE_QDISC_CAST(HTB, HierarchyTokenBucket);
|
DEFINE_QDISC_CAST(HTB, HierarchyTokenBucket);
|
||||||
extern const QDiscVTable htb_vtable;
|
extern const QDiscVTable htb_vtable;
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_default_class);
|
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_default_class);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_u32);
|
||||||
|
|
||||||
typedef struct HierarchyTokenBucketClass {
|
typedef struct HierarchyTokenBucketClass {
|
||||||
TClass meta;
|
TClass meta;
|
||||||
|
|
||||||
uint32_t priority;
|
uint32_t priority;
|
||||||
|
uint32_t quantum;
|
||||||
|
uint32_t mtu;
|
||||||
|
uint16_t overhead;
|
||||||
uint64_t rate;
|
uint64_t rate;
|
||||||
|
uint32_t buffer;
|
||||||
uint64_t ceil_rate;
|
uint64_t ceil_rate;
|
||||||
|
uint32_t ceil_buffer;
|
||||||
} HierarchyTokenBucketClass;
|
} HierarchyTokenBucketClass;
|
||||||
|
|
||||||
DEFINE_TCLASS_CAST(HTB, HierarchyTokenBucketClass);
|
DEFINE_TCLASS_CAST(HTB, HierarchyTokenBucketClass);
|
||||||
extern const TClassVTable htb_tclass_vtable;
|
extern const TClassVTable htb_tclass_vtable;
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_u32);
|
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_class_u32);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_rate);
|
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_class_size);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_hierarchy_token_bucket_class_rate);
|
||||||
|
@ -8,38 +8,46 @@
|
|||||||
#include "tc-util.h"
|
#include "tc-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
static int tc_init(double *ticks_in_usec) {
|
int tc_init(double *ret_ticks_in_usec, uint32_t *ret_hz) {
|
||||||
uint32_t clock_resolution, ticks_to_usec, usec_to_ticks;
|
static double ticks_in_usec = -1;
|
||||||
_cleanup_free_ char *line = NULL;
|
static uint32_t hz;
|
||||||
double clock_factor;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = read_one_line_file("/proc/net/psched", &line);
|
if (ticks_in_usec < 0) {
|
||||||
if (r < 0)
|
uint32_t clock_resolution, ticks_to_usec, usec_to_ticks;
|
||||||
return r;
|
_cleanup_free_ char *line = NULL;
|
||||||
|
double clock_factor;
|
||||||
|
int r;
|
||||||
|
|
||||||
r = sscanf(line, "%08x%08x%08x", &ticks_to_usec, &usec_to_ticks, &clock_resolution);
|
r = read_one_line_file("/proc/net/psched", &line);
|
||||||
if (r < 3)
|
if (r < 0)
|
||||||
return -EIO;
|
return r;
|
||||||
|
|
||||||
clock_factor = (double) clock_resolution / USEC_PER_SEC;
|
r = sscanf(line, "%08x%08x%08x%08x", &ticks_to_usec, &usec_to_ticks, &clock_resolution, &hz);
|
||||||
*ticks_in_usec = (double) ticks_to_usec / usec_to_ticks * clock_factor;
|
if (r < 4)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
clock_factor = (double) clock_resolution / USEC_PER_SEC;
|
||||||
|
ticks_in_usec = (double) ticks_to_usec / usec_to_ticks * clock_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_ticks_in_usec)
|
||||||
|
*ret_ticks_in_usec = ticks_in_usec;
|
||||||
|
if (ret_hz)
|
||||||
|
*ret_hz = hz;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tc_time_to_tick(usec_t t, uint32_t *ret) {
|
int tc_time_to_tick(usec_t t, uint32_t *ret) {
|
||||||
static double ticks_in_usec = -1;
|
double ticks_in_usec;
|
||||||
usec_t a;
|
usec_t a;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
if (ticks_in_usec < 0) {
|
r = tc_init(&ticks_in_usec, NULL);
|
||||||
r = tc_init(&ticks_in_usec);
|
if (r < 0)
|
||||||
if (r < 0)
|
return r;
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
a = t * ticks_in_usec;
|
a = t * ticks_in_usec;
|
||||||
if (a > UINT32_MAX)
|
if (a > UINT32_MAX)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
|
int tc_init(double *ret_ticks_in_usec, uint32_t *ret_hz);
|
||||||
int tc_time_to_tick(usec_t t, uint32_t *ret);
|
int tc_time_to_tick(usec_t t, uint32_t *ret);
|
||||||
int parse_tc_percent(const char *s, uint32_t *percent);
|
int parse_tc_percent(const char *s, uint32_t *percent);
|
||||||
int tc_transmit_time(uint64_t rate, uint32_t size, uint32_t *ret);
|
int tc_transmit_time(uint64_t rate, uint32_t size, uint32_t *ret);
|
||||||
|
@ -378,12 +378,18 @@ Id=
|
|||||||
Parent=
|
Parent=
|
||||||
Handle=
|
Handle=
|
||||||
DefaultClass=
|
DefaultClass=
|
||||||
|
RateToQuantum=
|
||||||
[HierarchyTokenBucketClass]
|
[HierarchyTokenBucketClass]
|
||||||
Parent=
|
Parent=
|
||||||
ClassId=
|
ClassId=
|
||||||
Priority=
|
Priority=
|
||||||
|
QuantumBytes=
|
||||||
|
MTUBytes=
|
||||||
|
OverheadBytes=
|
||||||
Rate=
|
Rate=
|
||||||
CeilRate=
|
CeilRate=
|
||||||
|
BufferBytes=
|
||||||
|
CeilBufferBytes=
|
||||||
[BFIFO]
|
[BFIFO]
|
||||||
Parent=
|
Parent=
|
||||||
Handle=
|
Handle=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user