mirror of
https://github.com/systemd/systemd.git
synced 2024-12-13 20:23:48 +08:00
Merge pull request #14309 from yuwata/network-tc-vtable
network: tc: introduce QDiscVTable
This commit is contained in:
commit
288a4787a5
@ -10,25 +10,16 @@
|
||||
#include "qdisc.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int fair_queuing_controlled_delay_new(FairQueuingControlledDelay **ret) {
|
||||
FairQueuingControlledDelay *fqcd = NULL;
|
||||
|
||||
fqcd = new0(FairQueuingControlledDelay, 1);
|
||||
if (!fqcd)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(fqcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fair_queuing_controlled_delay_fill_message(Link *link, const FairQueuingControlledDelay *fqcd, sd_netlink_message *req) {
|
||||
static int fair_queuing_controlled_delay_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
FairQueuingControlledDelay *fqcd;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(fqcd);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
fqcd = FQ_CODEL(qdisc);
|
||||
|
||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq_codel");
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
|
||||
@ -57,6 +48,7 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
FairQueuingControlledDelay *fqcd;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
@ -65,18 +57,23 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(QDISC_KIND_FQ_CODEL, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
fqcd = FQ_CODEL(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
qdisc->fq_codel.limit = 0;
|
||||
fqcd->limit = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &qdisc->fq_codel.limit);
|
||||
r = safe_atou32(rvalue, &fqcd->limit);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
@ -84,8 +81,13 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdisc->has_fair_queuing_controlled_delay = true;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable fq_codel_vtable = {
|
||||
.object_size = sizeof(FairQueuingControlledDelay),
|
||||
.tca_kind = "fq_codel",
|
||||
.fill_message = fair_queuing_controlled_delay_fill_message,
|
||||
};
|
||||
|
@ -2,16 +2,15 @@
|
||||
* Copyright © 2019 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-link.h"
|
||||
#include "qdisc.h"
|
||||
|
||||
typedef struct FairQueuingControlledDelay {
|
||||
QDisc meta;
|
||||
uint32_t limit;
|
||||
} FairQueuingControlledDelay;
|
||||
|
||||
int fair_queuing_controlled_delay_new(FairQueuingControlledDelay **ret);
|
||||
int fair_queuing_controlled_delay_fill_message(Link *link, const FairQueuingControlledDelay *sfq, sd_netlink_message *req);
|
||||
DEFINE_QDISC_CAST(FQ_CODEL, FairQueuingControlledDelay);
|
||||
extern const QDiscVTable fq_codel_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_limit);
|
||||
|
@ -13,33 +13,19 @@
|
||||
#include "string-util.h"
|
||||
#include "tc-util.h"
|
||||
|
||||
int network_emulator_new(NetworkEmulator **ret) {
|
||||
NetworkEmulator *ne = NULL;
|
||||
|
||||
ne = new(NetworkEmulator, 1);
|
||||
if (!ne)
|
||||
return -ENOMEM;
|
||||
|
||||
*ne = (NetworkEmulator) {
|
||||
.delay = USEC_INFINITY,
|
||||
.jitter = USEC_INFINITY,
|
||||
};
|
||||
|
||||
*ret = TAKE_PTR(ne);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int network_emulator_fill_message(Link *link, const NetworkEmulator *ne, sd_netlink_message *req) {
|
||||
static int network_emulator_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
struct tc_netem_qopt opt = {
|
||||
.limit = 1000,
|
||||
};
|
||||
NetworkEmulator *ne;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(ne);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
ne = NETEM(qdisc);
|
||||
|
||||
if (ne->limit > 0)
|
||||
opt.limit = ne->limit;
|
||||
|
||||
@ -82,6 +68,7 @@ int config_parse_tc_network_emulator_delay(
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
Network *network = data;
|
||||
NetworkEmulator *ne;
|
||||
usec_t u;
|
||||
int r;
|
||||
|
||||
@ -90,15 +77,20 @@ int config_parse_tc_network_emulator_delay(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(QDISC_KIND_NETEM, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
ne = NETEM(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
if (streq(lvalue, "NetworkEmulatorDelaySec"))
|
||||
qdisc->ne.delay = USEC_INFINITY;
|
||||
ne->delay = USEC_INFINITY;
|
||||
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
|
||||
qdisc->ne.jitter = USEC_INFINITY;
|
||||
ne->jitter = USEC_INFINITY;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
@ -113,11 +105,10 @@ int config_parse_tc_network_emulator_delay(
|
||||
}
|
||||
|
||||
if (streq(lvalue, "NetworkEmulatorDelaySec"))
|
||||
qdisc->ne.delay = u;
|
||||
ne->delay = u;
|
||||
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
|
||||
qdisc->ne.jitter = u;
|
||||
ne->jitter = u;
|
||||
|
||||
qdisc->has_network_emulator = true;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
@ -137,6 +128,7 @@ int config_parse_tc_network_emulator_rate(
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
Network *network = data;
|
||||
NetworkEmulator *ne;
|
||||
uint32_t rate;
|
||||
int r;
|
||||
|
||||
@ -145,12 +137,20 @@ int config_parse_tc_network_emulator_rate(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(QDISC_KIND_NETEM, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
ne = NETEM(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
qdisc->ne.loss = 0;
|
||||
if (streq(lvalue, "NetworkEmulatorLossRate"))
|
||||
ne->loss = 0;
|
||||
else if (streq(lvalue, "NetworkEmulatorDuplicateRate"))
|
||||
ne->duplicate = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
@ -165,9 +165,9 @@ int config_parse_tc_network_emulator_rate(
|
||||
}
|
||||
|
||||
if (streq(lvalue, "NetworkEmulatorLossRate"))
|
||||
qdisc->ne.loss = rate;
|
||||
ne->loss = rate;
|
||||
else if (streq(lvalue, "NetworkEmulatorDuplicateRate"))
|
||||
qdisc->ne.duplicate = rate;
|
||||
ne->duplicate = rate;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
@ -187,6 +187,7 @@ int config_parse_tc_network_emulator_packet_limit(
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
Network *network = data;
|
||||
NetworkEmulator *ne;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
@ -194,18 +195,23 @@ int config_parse_tc_network_emulator_packet_limit(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(QDISC_KIND_NETEM, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
ne = NETEM(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
qdisc->ne.limit = 0;
|
||||
ne->limit = 0;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou(rvalue, &qdisc->ne.limit);
|
||||
r = safe_atou(rvalue, &ne->limit);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse 'NetworkEmulatorPacketLimit=', ignoring assignment: %s",
|
||||
@ -216,3 +222,9 @@ int config_parse_tc_network_emulator_packet_limit(
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable netem_vtable = {
|
||||
.object_size = sizeof(NetworkEmulator),
|
||||
.tca_kind = "netem",
|
||||
.fill_message = network_emulator_fill_message,
|
||||
};
|
||||
|
@ -2,13 +2,13 @@
|
||||
* Copyright © 2019 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-link.h"
|
||||
#include "qdisc.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct NetworkEmulator {
|
||||
QDisc meta;
|
||||
|
||||
usec_t delay;
|
||||
usec_t jitter;
|
||||
|
||||
@ -17,8 +17,8 @@ typedef struct NetworkEmulator {
|
||||
uint32_t duplicate;
|
||||
} NetworkEmulator;
|
||||
|
||||
int network_emulator_new(NetworkEmulator **ret);
|
||||
int network_emulator_fill_message(Link *link, const NetworkEmulator *ne, sd_netlink_message *req);
|
||||
DEFINE_QDISC_CAST(NETEM, NetworkEmulator);
|
||||
extern const QDiscVTable netem_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_delay);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_rate);
|
||||
|
@ -13,65 +13,94 @@
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
|
||||
static int qdisc_new(QDisc **ret) {
|
||||
const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
|
||||
[QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
|
||||
[QDISC_KIND_NETEM] = &netem_vtable,
|
||||
[QDISC_KIND_SFQ] = &sfq_vtable,
|
||||
[QDISC_KIND_TBF] = &tbf_vtable,
|
||||
};
|
||||
|
||||
static int qdisc_new(QDiscKind kind, QDisc **ret) {
|
||||
QDisc *qdisc;
|
||||
|
||||
qdisc = new(QDisc, 1);
|
||||
if (!qdisc)
|
||||
return -ENOMEM;
|
||||
if (kind == _QDISC_KIND_INVALID) {
|
||||
qdisc = new(QDisc, 1);
|
||||
if (!qdisc)
|
||||
return -ENOMEM;
|
||||
|
||||
*qdisc = (QDisc) {
|
||||
.family = AF_UNSPEC,
|
||||
.parent = TC_H_ROOT,
|
||||
};
|
||||
*qdisc = (QDisc) {
|
||||
.family = AF_UNSPEC,
|
||||
.parent = TC_H_ROOT,
|
||||
.kind = kind,
|
||||
};
|
||||
} else {
|
||||
qdisc = malloc0(qdisc_vtable[kind]->object_size);
|
||||
if (!qdisc)
|
||||
return -ENOMEM;
|
||||
|
||||
qdisc->family = AF_UNSPEC;
|
||||
qdisc->parent = TC_H_ROOT;
|
||||
qdisc->kind = kind;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(qdisc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDisc **ret) {
|
||||
int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret) {
|
||||
_cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
|
||||
QDisc *existing;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
assert(!!filename == (section_line > 0));
|
||||
assert(filename);
|
||||
assert(section_line > 0);
|
||||
|
||||
if (filename) {
|
||||
r = network_config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = network_config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
qdisc = ordered_hashmap_get(network->qdiscs_by_section, n);
|
||||
if (qdisc) {
|
||||
*ret = TAKE_PTR(qdisc);
|
||||
existing = ordered_hashmap_get(network->qdiscs_by_section, n);
|
||||
if (existing) {
|
||||
if (existing->kind != _QDISC_KIND_INVALID &&
|
||||
kind != _QDISC_KIND_INVALID &&
|
||||
existing->kind != kind)
|
||||
return -EINVAL;
|
||||
|
||||
if (existing->kind == kind || kind == _QDISC_KIND_INVALID) {
|
||||
*ret = existing;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = qdisc_new(&qdisc);
|
||||
r = qdisc_new(kind, &qdisc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
qdisc->network = network;
|
||||
if (existing) {
|
||||
qdisc->family = existing->family;
|
||||
qdisc->handle = existing->handle;
|
||||
qdisc->parent = existing->parent;
|
||||
qdisc->tca_kind = TAKE_PTR(existing->tca_kind);
|
||||
|
||||
if (filename) {
|
||||
qdisc->section = TAKE_PTR(n);
|
||||
|
||||
r = ordered_hashmap_ensure_allocated(&network->qdiscs_by_section, &network_config_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_hashmap_put(network->qdiscs_by_section, qdisc->section, qdisc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
qdisc_free(ordered_hashmap_remove(network->qdiscs_by_section, n));
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(qdisc);
|
||||
qdisc->network = network;
|
||||
qdisc->section = TAKE_PTR(n);
|
||||
|
||||
r = ordered_hashmap_ensure_allocated(&network->qdiscs_by_section, &network_config_hash_ops);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ordered_hashmap_put(network->qdiscs_by_section, qdisc->section, qdisc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(qdisc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -116,8 +145,6 @@ static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
|
||||
int qdisc_configure(Link *link, QDisc *qdisc) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
_cleanup_free_ char *tca_kind = NULL;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@ -139,49 +166,16 @@ int qdisc_configure(Link *link, QDisc *qdisc) {
|
||||
return log_link_error_errno(link, r, "Could not set tcm_handle message: %m");
|
||||
}
|
||||
|
||||
if (qdisc->has_network_emulator) {
|
||||
r = free_and_strdup(&tca_kind, "netem");
|
||||
if (QDISC_VTABLE(qdisc)) {
|
||||
r = sd_netlink_message_append_string(req, TCA_KIND, QDISC_VTABLE(qdisc)->tca_kind);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m");
|
||||
|
||||
r = network_emulator_fill_message(link, &qdisc->ne, req);
|
||||
r = QDISC_VTABLE(qdisc)->fill_message(link, qdisc, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (qdisc->has_token_buffer_filter) {
|
||||
r = free_and_strdup(&tca_kind, "tbf");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = token_buffer_filter_fill_message(link, &qdisc->tbf, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (qdisc->has_stochastic_fairness_queueing) {
|
||||
r = free_and_strdup(&tca_kind, "sfq");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = stochastic_fairness_queueing_fill_message(link, &qdisc->sfq, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (qdisc->has_fair_queuing_controlled_delay) {
|
||||
r = free_and_strdup(&tca_kind, "fq_codel");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = fair_queuing_controlled_delay_fill_message(link, &qdisc->fq_codel, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
p = tca_kind ?:qdisc->tca_kind;
|
||||
if (p) {
|
||||
r = sd_netlink_message_append_string(req, TCA_KIND, p);
|
||||
} else {
|
||||
r = sd_netlink_message_append_string(req, TCA_KIND, qdisc->tca_kind);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m");
|
||||
}
|
||||
@ -197,7 +191,6 @@ int qdisc_configure(Link *link, QDisc *qdisc) {
|
||||
}
|
||||
|
||||
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
assert(qdisc);
|
||||
@ -207,15 +200,8 @@ int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
|
||||
if (section_is_invalid(qdisc->section))
|
||||
return -EINVAL;
|
||||
|
||||
i = qdisc->has_network_emulator + qdisc->has_token_buffer_filter + qdisc->has_stochastic_fairness_queueing;
|
||||
if (i > 1)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: TrafficControlQueueingDiscipline section has more than one type of discipline. "
|
||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||
qdisc->section->filename, qdisc->section->line);
|
||||
|
||||
if (qdisc->has_token_buffer_filter) {
|
||||
r = token_buffer_filter_section_verify(&qdisc->tbf, qdisc->section);
|
||||
if (QDISC_VTABLE(qdisc) && QDISC_VTABLE(qdisc)->verify) {
|
||||
r = QDISC_VTABLE(qdisc)->verify(qdisc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -260,7 +246,7 @@ int config_parse_tc_qdiscs_parent(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(_QDISC_KIND_INVALID, network, filename, section_line, &qdisc);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -3,44 +3,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "fq-codel.h"
|
||||
#include "netem.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
#include "sfq.h"
|
||||
#include "tbf.h"
|
||||
|
||||
typedef enum QDiscKind {
|
||||
QDISC_KIND_FQ_CODEL,
|
||||
QDISC_KIND_NETEM,
|
||||
QDISC_KIND_SFQ,
|
||||
QDISC_KIND_TBF,
|
||||
_QDISC_KIND_MAX,
|
||||
_QDISC_KIND_INVALID = -1,
|
||||
} QDiscKind;
|
||||
|
||||
typedef struct QDisc {
|
||||
NetworkConfigSection *section;
|
||||
Network *network;
|
||||
|
||||
Link *link;
|
||||
|
||||
int family;
|
||||
|
||||
uint32_t handle;
|
||||
uint32_t parent;
|
||||
|
||||
char *tca_kind;
|
||||
bool has_network_emulator:1;
|
||||
bool has_token_buffer_filter:1;
|
||||
bool has_stochastic_fairness_queueing:1;
|
||||
bool has_fair_queuing_controlled_delay:1;
|
||||
|
||||
NetworkEmulator ne;
|
||||
TokenBufferFilter tbf;
|
||||
StochasticFairnessQueueing sfq;
|
||||
FairQueuingControlledDelay fq_codel;
|
||||
QDiscKind kind;
|
||||
} QDisc;
|
||||
|
||||
typedef struct QDiscVTable {
|
||||
size_t object_size;
|
||||
const char *tca_kind;
|
||||
int (*fill_message)(Link *link, QDisc *qdisc, sd_netlink_message *m);
|
||||
int (*verify)(QDisc *qdisc);
|
||||
} QDiscVTable;
|
||||
|
||||
extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX];
|
||||
|
||||
#define QDISC_VTABLE(q) ((q)->kind != _QDISC_KIND_INVALID ? qdisc_vtable[(q)->kind] : NULL)
|
||||
|
||||
/* For casting a qdisc into the various qdisc kinds */
|
||||
#define DEFINE_QDISC_CAST(UPPERCASE, MixedCase) \
|
||||
static inline MixedCase* UPPERCASE(QDisc *q) { \
|
||||
if (_unlikely_(!q || q->kind != QDISC_KIND_##UPPERCASE)) \
|
||||
return NULL; \
|
||||
\
|
||||
return (MixedCase*) q; \
|
||||
}
|
||||
|
||||
/* For casting the various qdisc kinds into a qdisc */
|
||||
#define QDISC(q) (&(q)->meta)
|
||||
|
||||
void qdisc_free(QDisc *qdisc);
|
||||
int qdisc_new_static(Network *network, const char *filename, unsigned section_line, QDisc **ret);
|
||||
int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret);
|
||||
|
||||
int qdisc_configure(Link *link, QDisc *qdisc);
|
||||
|
||||
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
|
||||
|
||||
DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_qdiscs_parent);
|
||||
|
||||
#include "fq-codel.h"
|
||||
#include "netem.h"
|
||||
#include "sfq.h"
|
||||
#include "tbf.h"
|
||||
|
@ -11,26 +11,17 @@
|
||||
#include "sfq.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int stochastic_fairness_queueing_new(StochasticFairnessQueueing **ret) {
|
||||
StochasticFairnessQueueing *sfq = NULL;
|
||||
|
||||
sfq = new0(StochasticFairnessQueueing, 1);
|
||||
if (!sfq)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(sfq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stochastic_fairness_queueing_fill_message(Link *link, const StochasticFairnessQueueing *sfq, sd_netlink_message *req) {
|
||||
static int stochastic_fairness_queueing_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
StochasticFairnessQueueing *sfq;
|
||||
struct tc_sfq_qopt_v1 opt = {};
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(sfq);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
sfq = SFQ(qdisc);
|
||||
|
||||
opt.v0.perturb_period = sfq->perturb_period / USEC_PER_SEC;
|
||||
|
||||
r = sd_netlink_message_append_data(req, TCA_OPTIONS, &opt, sizeof(struct tc_sfq_qopt_v1));
|
||||
@ -53,6 +44,7 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
StochasticFairnessQueueing *sfq;
|
||||
Network *network = data;
|
||||
int r;
|
||||
|
||||
@ -61,18 +53,23 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(QDISC_KIND_SFQ, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
sfq = SFQ(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
qdisc->sfq.perturb_period = 0;
|
||||
sfq->perturb_period = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_sec(rvalue, &qdisc->sfq.perturb_period);
|
||||
r = parse_sec(rvalue, &sfq->perturb_period);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse '%s=', ignoring assignment: %s",
|
||||
@ -80,8 +77,13 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdisc->has_stochastic_fairness_queueing = true;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable sfq_vtable = {
|
||||
.object_size = sizeof(StochasticFairnessQueueing),
|
||||
.tca_kind = "sfq",
|
||||
.fill_message = stochastic_fairness_queueing_fill_message,
|
||||
};
|
||||
|
@ -2,16 +2,17 @@
|
||||
* Copyright © 2019 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-link.h"
|
||||
#include "qdisc.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct StochasticFairnessQueueing {
|
||||
QDisc meta;
|
||||
|
||||
usec_t perturb_period;
|
||||
} StochasticFairnessQueueing;
|
||||
|
||||
int stochastic_fairness_queueing_new(StochasticFairnessQueueing **ret);
|
||||
int stochastic_fairness_queueing_fill_message(Link *link, const StochasticFairnessQueueing *sfq, sd_netlink_message *req);
|
||||
DEFINE_QDISC_CAST(SFQ, StochasticFairnessQueueing);
|
||||
extern const QDiscVTable sfq_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_stochastic_fairness_queueing_perturb_period);
|
||||
|
@ -15,27 +15,18 @@
|
||||
#include "tc-util.h"
|
||||
#include "util.h"
|
||||
|
||||
int token_buffer_filter_new(TokenBufferFilter **ret) {
|
||||
TokenBufferFilter *ne = NULL;
|
||||
|
||||
ne = new0(TokenBufferFilter, 1);
|
||||
if (!ne)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(ne);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req) {
|
||||
static int token_buffer_filter_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||
uint32_t rtab[256], ptab[256];
|
||||
struct tc_tbf_qopt opt = {};
|
||||
TokenBufferFilter *tbf;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(tbf);
|
||||
assert(qdisc);
|
||||
assert(req);
|
||||
|
||||
tbf = TBF(qdisc);
|
||||
|
||||
opt.rate.rate = tbf->rate >= (1ULL << 32) ? ~0U : tbf->rate;
|
||||
opt.peakrate.rate = tbf->peak_rate >= (1ULL << 32) ? ~0U : tbf->peak_rate;
|
||||
|
||||
@ -133,6 +124,7 @@ int config_parse_tc_token_buffer_filter_size(
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
Network *network = data;
|
||||
TokenBufferFilter *tbf;
|
||||
uint64_t k;
|
||||
int r;
|
||||
|
||||
@ -141,23 +133,28 @@ int config_parse_tc_token_buffer_filter_size(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(QDISC_KIND_TBF, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
tbf = TBF(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
if (streq(lvalue, "TokenBufferFilterRate"))
|
||||
qdisc->tbf.rate = 0;
|
||||
tbf->rate = 0;
|
||||
else if (streq(lvalue, "TokenBufferFilterBurst"))
|
||||
qdisc->tbf.burst = 0;
|
||||
tbf->burst = 0;
|
||||
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
|
||||
qdisc->tbf.limit = 0;
|
||||
tbf->limit = 0;
|
||||
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
|
||||
qdisc->tbf.mtu = 0;
|
||||
tbf->mtu = 0;
|
||||
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
|
||||
qdisc->tbf.mpu = 0;
|
||||
tbf->mpu = 0;
|
||||
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
|
||||
qdisc->tbf.peak_rate = 0;
|
||||
tbf->peak_rate = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
@ -172,19 +169,18 @@ int config_parse_tc_token_buffer_filter_size(
|
||||
}
|
||||
|
||||
if (streq(lvalue, "TokenBufferFilterRate"))
|
||||
qdisc->tbf.rate = k / 8;
|
||||
tbf->rate = k / 8;
|
||||
else if (streq(lvalue, "TokenBufferFilterBurst"))
|
||||
qdisc->tbf.burst = k;
|
||||
tbf->burst = k;
|
||||
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
|
||||
qdisc->tbf.limit = k;
|
||||
tbf->limit = k;
|
||||
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
|
||||
qdisc->tbf.mpu = k;
|
||||
tbf->mpu = k;
|
||||
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
|
||||
qdisc->tbf.mtu = k;
|
||||
tbf->mtu = k;
|
||||
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
|
||||
qdisc->tbf.peak_rate = k / 8;
|
||||
tbf->peak_rate = k / 8;
|
||||
|
||||
qdisc->has_token_buffer_filter = true;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
@ -204,6 +200,7 @@ int config_parse_tc_token_buffer_filter_latency(
|
||||
|
||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||
Network *network = data;
|
||||
TokenBufferFilter *tbf;
|
||||
usec_t u;
|
||||
int r;
|
||||
|
||||
@ -212,12 +209,17 @@ int config_parse_tc_token_buffer_filter_latency(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = qdisc_new_static(network, filename, section_line, &qdisc);
|
||||
r = qdisc_new_static(QDISC_KIND_TBF, network, filename, section_line, &qdisc);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"More than one kind of queueing discipline, ignoring assignment: %m");
|
||||
|
||||
tbf = TBF(qdisc);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
qdisc->tbf.latency = 0;
|
||||
tbf->latency = 0;
|
||||
|
||||
qdisc = NULL;
|
||||
return 0;
|
||||
@ -231,44 +233,52 @@ int config_parse_tc_token_buffer_filter_latency(
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdisc->tbf.latency = u;
|
||||
tbf->latency = u;
|
||||
|
||||
qdisc->has_token_buffer_filter = true;
|
||||
qdisc = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int token_buffer_filter_section_verify(const TokenBufferFilter *tbf, const NetworkConfigSection *section) {
|
||||
static int token_buffer_filter_verify(QDisc *qdisc) {
|
||||
TokenBufferFilter *tbf = TBF(qdisc);
|
||||
|
||||
if (tbf->limit > 0 && tbf->latency > 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Specifying both TokenBufferFilterLimitSize= and TokenBufferFilterLatencySec= is not allowed. "
|
||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||
section->filename, section->line);
|
||||
qdisc->section->filename, qdisc->section->line);
|
||||
|
||||
if (tbf->limit == 0 && tbf->latency == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: Either TokenBufferFilterLimitSize= or TokenBufferFilterLatencySec= is required. "
|
||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||
section->filename, section->line);
|
||||
qdisc->section->filename, qdisc->section->line);
|
||||
|
||||
if (tbf->rate == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: TokenBufferFilterRate= is mandatory. "
|
||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||
section->filename, section->line);
|
||||
qdisc->section->filename, qdisc->section->line);
|
||||
|
||||
if (tbf->burst == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: TokenBufferFilterBurst= is mandatory. "
|
||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||
section->filename, section->line);
|
||||
qdisc->section->filename, qdisc->section->line);
|
||||
|
||||
if (tbf->peak_rate > 0 && tbf->mtu == 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: TokenBufferFilterMTUBytes= is mandatory when TokenBufferFilterPeakRate= is specified. "
|
||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||
section->filename, section->line);
|
||||
qdisc->section->filename, qdisc->section->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const QDiscVTable tbf_vtable = {
|
||||
.object_size = sizeof(TokenBufferFilter),
|
||||
.tca_kind = "tbf",
|
||||
.fill_message = token_buffer_filter_fill_message,
|
||||
.verify = token_buffer_filter_verify
|
||||
};
|
||||
|
@ -2,14 +2,13 @@
|
||||
* Copyright © 2019 VMware, Inc. */
|
||||
#pragma once
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-util.h"
|
||||
#include "tc-util.h"
|
||||
#include "qdisc.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct TokenBufferFilter {
|
||||
QDisc meta;
|
||||
|
||||
uint64_t rate;
|
||||
uint64_t peak_rate;
|
||||
uint32_t burst;
|
||||
@ -19,9 +18,8 @@ typedef struct TokenBufferFilter {
|
||||
size_t mpu;
|
||||
} TokenBufferFilter;
|
||||
|
||||
int token_buffer_filter_new(TokenBufferFilter **ret);
|
||||
int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req);
|
||||
int token_buffer_filter_section_verify(const TokenBufferFilter *tbf, const NetworkConfigSection *section);
|
||||
DEFINE_QDISC_CAST(TBF, TokenBufferFilter);
|
||||
extern const QDiscVTable tbf_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_latency);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_size);
|
||||
|
Loading…
Reference in New Issue
Block a user