mirror of
https://github.com/systemd/systemd.git
synced 2024-12-14 12:43:36 +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 "qdisc.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
int fair_queuing_controlled_delay_new(FairQueuingControlledDelay **ret) {
|
static int fair_queuing_controlled_delay_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||||
FairQueuingControlledDelay *fqcd = NULL;
|
FairQueuingControlledDelay *fqcd;
|
||||||
|
|
||||||
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) {
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(fqcd);
|
assert(qdisc);
|
||||||
assert(req);
|
assert(req);
|
||||||
|
|
||||||
|
fqcd = FQ_CODEL(qdisc);
|
||||||
|
|
||||||
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq_codel");
|
r = sd_netlink_message_open_container_union(req, TCA_OPTIONS, "fq_codel");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not open container TCA_OPTIONS: %m");
|
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) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
|
FairQueuingControlledDelay *fqcd;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -65,18 +57,23 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
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)) {
|
if (isempty(rvalue)) {
|
||||||
qdisc->fq_codel.limit = 0;
|
fqcd->limit = 0;
|
||||||
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = safe_atou32(rvalue, &qdisc->fq_codel.limit);
|
r = safe_atou32(rvalue, &fqcd->limit);
|
||||||
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",
|
||||||
@ -84,8 +81,13 @@ int config_parse_tc_fair_queuing_controlled_delay_limit(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
qdisc->has_fair_queuing_controlled_delay = true;
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
|
|
||||||
return 0;
|
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. */
|
* Copyright © 2019 VMware, Inc. */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sd-netlink.h"
|
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "networkd-link.h"
|
#include "qdisc.h"
|
||||||
|
|
||||||
typedef struct FairQueuingControlledDelay {
|
typedef struct FairQueuingControlledDelay {
|
||||||
|
QDisc meta;
|
||||||
uint32_t limit;
|
uint32_t limit;
|
||||||
} FairQueuingControlledDelay;
|
} FairQueuingControlledDelay;
|
||||||
|
|
||||||
int fair_queuing_controlled_delay_new(FairQueuingControlledDelay **ret);
|
DEFINE_QDISC_CAST(FQ_CODEL, FairQueuingControlledDelay);
|
||||||
int fair_queuing_controlled_delay_fill_message(Link *link, const FairQueuingControlledDelay *sfq, sd_netlink_message *req);
|
extern const QDiscVTable fq_codel_vtable;
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_limit);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tc_fair_queuing_controlled_delay_limit);
|
||||||
|
@ -13,33 +13,19 @@
|
|||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "tc-util.h"
|
#include "tc-util.h"
|
||||||
|
|
||||||
int network_emulator_new(NetworkEmulator **ret) {
|
static int network_emulator_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||||
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) {
|
|
||||||
struct tc_netem_qopt opt = {
|
struct tc_netem_qopt opt = {
|
||||||
.limit = 1000,
|
.limit = 1000,
|
||||||
};
|
};
|
||||||
|
NetworkEmulator *ne;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(ne);
|
assert(qdisc);
|
||||||
assert(req);
|
assert(req);
|
||||||
|
|
||||||
|
ne = NETEM(qdisc);
|
||||||
|
|
||||||
if (ne->limit > 0)
|
if (ne->limit > 0)
|
||||||
opt.limit = ne->limit;
|
opt.limit = ne->limit;
|
||||||
|
|
||||||
@ -82,6 +68,7 @@ int config_parse_tc_network_emulator_delay(
|
|||||||
|
|
||||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
|
NetworkEmulator *ne;
|
||||||
usec_t u;
|
usec_t u;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -90,15 +77,20 @@ int config_parse_tc_network_emulator_delay(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
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 (isempty(rvalue)) {
|
||||||
if (streq(lvalue, "NetworkEmulatorDelaySec"))
|
if (streq(lvalue, "NetworkEmulatorDelaySec"))
|
||||||
qdisc->ne.delay = USEC_INFINITY;
|
ne->delay = USEC_INFINITY;
|
||||||
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
|
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
|
||||||
qdisc->ne.jitter = USEC_INFINITY;
|
ne->jitter = USEC_INFINITY;
|
||||||
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@ -113,11 +105,10 @@ int config_parse_tc_network_emulator_delay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (streq(lvalue, "NetworkEmulatorDelaySec"))
|
if (streq(lvalue, "NetworkEmulatorDelaySec"))
|
||||||
qdisc->ne.delay = u;
|
ne->delay = u;
|
||||||
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
|
else if (streq(lvalue, "NetworkEmulatorDelayJitterSec"))
|
||||||
qdisc->ne.jitter = u;
|
ne->jitter = u;
|
||||||
|
|
||||||
qdisc->has_network_emulator = true;
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -137,6 +128,7 @@ int config_parse_tc_network_emulator_rate(
|
|||||||
|
|
||||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
|
NetworkEmulator *ne;
|
||||||
uint32_t rate;
|
uint32_t rate;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -145,12 +137,20 @@ int config_parse_tc_network_emulator_rate(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
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 (isempty(rvalue)) {
|
||||||
qdisc->ne.loss = 0;
|
if (streq(lvalue, "NetworkEmulatorLossRate"))
|
||||||
|
ne->loss = 0;
|
||||||
|
else if (streq(lvalue, "NetworkEmulatorDuplicateRate"))
|
||||||
|
ne->duplicate = 0;
|
||||||
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@ -165,9 +165,9 @@ int config_parse_tc_network_emulator_rate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (streq(lvalue, "NetworkEmulatorLossRate"))
|
if (streq(lvalue, "NetworkEmulatorLossRate"))
|
||||||
qdisc->ne.loss = rate;
|
ne->loss = rate;
|
||||||
else if (streq(lvalue, "NetworkEmulatorDuplicateRate"))
|
else if (streq(lvalue, "NetworkEmulatorDuplicateRate"))
|
||||||
qdisc->ne.duplicate = rate;
|
ne->duplicate = rate;
|
||||||
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@ -187,6 +187,7 @@ int config_parse_tc_network_emulator_packet_limit(
|
|||||||
|
|
||||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
|
NetworkEmulator *ne;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
@ -194,18 +195,23 @@ int config_parse_tc_network_emulator_packet_limit(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
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 (isempty(rvalue)) {
|
||||||
qdisc->ne.limit = 0;
|
ne->limit = 0;
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = safe_atou(rvalue, &qdisc->ne.limit);
|
r = safe_atou(rvalue, &ne->limit);
|
||||||
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 'NetworkEmulatorPacketLimit=', ignoring assignment: %s",
|
"Failed to parse 'NetworkEmulatorPacketLimit=', ignoring assignment: %s",
|
||||||
@ -216,3 +222,9 @@ int config_parse_tc_network_emulator_packet_limit(
|
|||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
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. */
|
* Copyright © 2019 VMware, Inc. */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sd-netlink.h"
|
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "networkd-link.h"
|
#include "qdisc.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
typedef struct NetworkEmulator {
|
typedef struct NetworkEmulator {
|
||||||
|
QDisc meta;
|
||||||
|
|
||||||
usec_t delay;
|
usec_t delay;
|
||||||
usec_t jitter;
|
usec_t jitter;
|
||||||
|
|
||||||
@ -17,8 +17,8 @@ typedef struct NetworkEmulator {
|
|||||||
uint32_t duplicate;
|
uint32_t duplicate;
|
||||||
} NetworkEmulator;
|
} NetworkEmulator;
|
||||||
|
|
||||||
int network_emulator_new(NetworkEmulator **ret);
|
DEFINE_QDISC_CAST(NETEM, NetworkEmulator);
|
||||||
int network_emulator_fill_message(Link *link, const NetworkEmulator *ne, sd_netlink_message *req);
|
extern const QDiscVTable netem_vtable;
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_delay);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_delay);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_rate);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tc_network_emulator_rate);
|
||||||
|
@ -13,65 +13,94 @@
|
|||||||
#include "set.h"
|
#include "set.h"
|
||||||
#include "string-util.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 *qdisc;
|
||||||
|
|
||||||
qdisc = new(QDisc, 1);
|
if (kind == _QDISC_KIND_INVALID) {
|
||||||
if (!qdisc)
|
qdisc = new(QDisc, 1);
|
||||||
return -ENOMEM;
|
if (!qdisc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
*qdisc = (QDisc) {
|
*qdisc = (QDisc) {
|
||||||
.family = AF_UNSPEC,
|
.family = AF_UNSPEC,
|
||||||
.parent = TC_H_ROOT,
|
.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);
|
*ret = TAKE_PTR(qdisc);
|
||||||
|
|
||||||
return 0;
|
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_(network_config_section_freep) NetworkConfigSection *n = NULL;
|
||||||
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
|
_cleanup_(qdisc_freep) QDisc *qdisc = NULL;
|
||||||
|
QDisc *existing;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(network);
|
assert(network);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
assert(!!filename == (section_line > 0));
|
assert(filename);
|
||||||
|
assert(section_line > 0);
|
||||||
|
|
||||||
if (filename) {
|
r = network_config_section_new(filename, section_line, &n);
|
||||||
r = network_config_section_new(filename, section_line, &n);
|
if (r < 0)
|
||||||
if (r < 0)
|
return r;
|
||||||
return r;
|
|
||||||
|
|
||||||
qdisc = ordered_hashmap_get(network->qdiscs_by_section, n);
|
existing = ordered_hashmap_get(network->qdiscs_by_section, n);
|
||||||
if (qdisc) {
|
if (existing) {
|
||||||
*ret = TAKE_PTR(qdisc);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = qdisc_new(&qdisc);
|
r = qdisc_new(kind, &qdisc);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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_free(ordered_hashmap_remove(network->qdiscs_by_section, n));
|
||||||
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);
|
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;
|
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) {
|
int qdisc_configure(Link *link, QDisc *qdisc) {
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||||
_cleanup_free_ char *tca_kind = NULL;
|
|
||||||
char *p;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
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");
|
return log_link_error_errno(link, r, "Could not set tcm_handle message: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qdisc->has_network_emulator) {
|
if (QDISC_VTABLE(qdisc)) {
|
||||||
r = free_and_strdup(&tca_kind, "netem");
|
r = sd_netlink_message_append_string(req, TCA_KIND, QDISC_VTABLE(qdisc)->tca_kind);
|
||||||
if (r < 0)
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
} else {
|
||||||
|
r = sd_netlink_message_append_string(req, TCA_KIND, qdisc->tca_kind);
|
||||||
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);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Could not append TCA_KIND attribute: %m");
|
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) {
|
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
|
||||||
unsigned i;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(qdisc);
|
assert(qdisc);
|
||||||
@ -207,15 +200,8 @@ int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) {
|
|||||||
if (section_is_invalid(qdisc->section))
|
if (section_is_invalid(qdisc->section))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
i = qdisc->has_network_emulator + qdisc->has_token_buffer_filter + qdisc->has_stochastic_fairness_queueing;
|
if (QDISC_VTABLE(qdisc) && QDISC_VTABLE(qdisc)->verify) {
|
||||||
if (i > 1)
|
r = QDISC_VTABLE(qdisc)->verify(qdisc);
|
||||||
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 (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -260,7 +246,7 @@ int config_parse_tc_qdiscs_parent(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -3,44 +3,65 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "fq-codel.h"
|
|
||||||
#include "netem.h"
|
|
||||||
#include "networkd-link.h"
|
#include "networkd-link.h"
|
||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "networkd-util.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 {
|
typedef struct QDisc {
|
||||||
NetworkConfigSection *section;
|
NetworkConfigSection *section;
|
||||||
Network *network;
|
Network *network;
|
||||||
|
|
||||||
Link *link;
|
|
||||||
|
|
||||||
int family;
|
int family;
|
||||||
|
|
||||||
uint32_t handle;
|
uint32_t handle;
|
||||||
uint32_t parent;
|
uint32_t parent;
|
||||||
|
|
||||||
char *tca_kind;
|
char *tca_kind;
|
||||||
bool has_network_emulator:1;
|
QDiscKind kind;
|
||||||
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;
|
|
||||||
} QDisc;
|
} 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);
|
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_configure(Link *link, QDisc *qdisc);
|
||||||
|
|
||||||
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
|
int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact);
|
||||||
|
|
||||||
DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free);
|
DEFINE_NETWORK_SECTION_FUNCTIONS(QDisc, qdisc_free);
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_qdiscs_parent);
|
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 "sfq.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
int stochastic_fairness_queueing_new(StochasticFairnessQueueing **ret) {
|
static int stochastic_fairness_queueing_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||||
StochasticFairnessQueueing *sfq = NULL;
|
StochasticFairnessQueueing *sfq;
|
||||||
|
|
||||||
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) {
|
|
||||||
struct tc_sfq_qopt_v1 opt = {};
|
struct tc_sfq_qopt_v1 opt = {};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(sfq);
|
assert(qdisc);
|
||||||
assert(req);
|
assert(req);
|
||||||
|
|
||||||
|
sfq = SFQ(qdisc);
|
||||||
|
|
||||||
opt.v0.perturb_period = sfq->perturb_period / USEC_PER_SEC;
|
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));
|
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) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
|
StochasticFairnessQueueing *sfq;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -61,18 +53,23 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
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)) {
|
if (isempty(rvalue)) {
|
||||||
qdisc->sfq.perturb_period = 0;
|
sfq->perturb_period = 0;
|
||||||
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = parse_sec(rvalue, &qdisc->sfq.perturb_period);
|
r = parse_sec(rvalue, &sfq->perturb_period);
|
||||||
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",
|
||||||
@ -80,8 +77,13 @@ int config_parse_tc_stochastic_fairness_queueing_perturb_period(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
qdisc->has_stochastic_fairness_queueing = true;
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
|
|
||||||
return 0;
|
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. */
|
* Copyright © 2019 VMware, Inc. */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sd-netlink.h"
|
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "networkd-link.h"
|
#include "qdisc.h"
|
||||||
|
#include "time-util.h"
|
||||||
|
|
||||||
typedef struct StochasticFairnessQueueing {
|
typedef struct StochasticFairnessQueueing {
|
||||||
|
QDisc meta;
|
||||||
|
|
||||||
usec_t perturb_period;
|
usec_t perturb_period;
|
||||||
} StochasticFairnessQueueing;
|
} StochasticFairnessQueueing;
|
||||||
|
|
||||||
int stochastic_fairness_queueing_new(StochasticFairnessQueueing **ret);
|
DEFINE_QDISC_CAST(SFQ, StochasticFairnessQueueing);
|
||||||
int stochastic_fairness_queueing_fill_message(Link *link, const StochasticFairnessQueueing *sfq, sd_netlink_message *req);
|
extern const QDiscVTable sfq_vtable;
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_stochastic_fairness_queueing_perturb_period);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tc_stochastic_fairness_queueing_perturb_period);
|
||||||
|
@ -15,27 +15,18 @@
|
|||||||
#include "tc-util.h"
|
#include "tc-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int token_buffer_filter_new(TokenBufferFilter **ret) {
|
static int token_buffer_filter_fill_message(Link *link, QDisc *qdisc, sd_netlink_message *req) {
|
||||||
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) {
|
|
||||||
uint32_t rtab[256], ptab[256];
|
uint32_t rtab[256], ptab[256];
|
||||||
struct tc_tbf_qopt opt = {};
|
struct tc_tbf_qopt opt = {};
|
||||||
|
TokenBufferFilter *tbf;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(tbf);
|
assert(qdisc);
|
||||||
assert(req);
|
assert(req);
|
||||||
|
|
||||||
|
tbf = TBF(qdisc);
|
||||||
|
|
||||||
opt.rate.rate = tbf->rate >= (1ULL << 32) ? ~0U : tbf->rate;
|
opt.rate.rate = tbf->rate >= (1ULL << 32) ? ~0U : tbf->rate;
|
||||||
opt.peakrate.rate = tbf->peak_rate >= (1ULL << 32) ? ~0U : tbf->peak_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;
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
|
TokenBufferFilter *tbf;
|
||||||
uint64_t k;
|
uint64_t k;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -141,23 +133,28 @@ int config_parse_tc_token_buffer_filter_size(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
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 (isempty(rvalue)) {
|
||||||
if (streq(lvalue, "TokenBufferFilterRate"))
|
if (streq(lvalue, "TokenBufferFilterRate"))
|
||||||
qdisc->tbf.rate = 0;
|
tbf->rate = 0;
|
||||||
else if (streq(lvalue, "TokenBufferFilterBurst"))
|
else if (streq(lvalue, "TokenBufferFilterBurst"))
|
||||||
qdisc->tbf.burst = 0;
|
tbf->burst = 0;
|
||||||
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
|
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
|
||||||
qdisc->tbf.limit = 0;
|
tbf->limit = 0;
|
||||||
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
|
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
|
||||||
qdisc->tbf.mtu = 0;
|
tbf->mtu = 0;
|
||||||
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
|
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
|
||||||
qdisc->tbf.mpu = 0;
|
tbf->mpu = 0;
|
||||||
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
|
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
|
||||||
qdisc->tbf.peak_rate = 0;
|
tbf->peak_rate = 0;
|
||||||
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@ -172,19 +169,18 @@ int config_parse_tc_token_buffer_filter_size(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (streq(lvalue, "TokenBufferFilterRate"))
|
if (streq(lvalue, "TokenBufferFilterRate"))
|
||||||
qdisc->tbf.rate = k / 8;
|
tbf->rate = k / 8;
|
||||||
else if (streq(lvalue, "TokenBufferFilterBurst"))
|
else if (streq(lvalue, "TokenBufferFilterBurst"))
|
||||||
qdisc->tbf.burst = k;
|
tbf->burst = k;
|
||||||
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
|
else if (streq(lvalue, "TokenBufferFilterLimitSize"))
|
||||||
qdisc->tbf.limit = k;
|
tbf->limit = k;
|
||||||
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
|
else if (streq(lvalue, "TokenBufferFilterMPUBytes"))
|
||||||
qdisc->tbf.mpu = k;
|
tbf->mpu = k;
|
||||||
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
|
else if (streq(lvalue, "TokenBufferFilterMTUBytes"))
|
||||||
qdisc->tbf.mtu = k;
|
tbf->mtu = k;
|
||||||
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
|
else if (streq(lvalue, "TokenBufferFilterPeakRate"))
|
||||||
qdisc->tbf.peak_rate = k / 8;
|
tbf->peak_rate = k / 8;
|
||||||
|
|
||||||
qdisc->has_token_buffer_filter = true;
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -204,6 +200,7 @@ int config_parse_tc_token_buffer_filter_latency(
|
|||||||
|
|
||||||
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
_cleanup_(qdisc_free_or_set_invalidp) QDisc *qdisc = NULL;
|
||||||
Network *network = data;
|
Network *network = data;
|
||||||
|
TokenBufferFilter *tbf;
|
||||||
usec_t u;
|
usec_t u;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -212,12 +209,17 @@ int config_parse_tc_token_buffer_filter_latency(
|
|||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
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)
|
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 (isempty(rvalue)) {
|
||||||
qdisc->tbf.latency = 0;
|
tbf->latency = 0;
|
||||||
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@ -231,44 +233,52 @@ int config_parse_tc_token_buffer_filter_latency(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
qdisc->tbf.latency = u;
|
tbf->latency = u;
|
||||||
|
|
||||||
qdisc->has_token_buffer_filter = true;
|
|
||||||
qdisc = NULL;
|
qdisc = NULL;
|
||||||
|
|
||||||
return 0;
|
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)
|
if (tbf->limit > 0 && tbf->latency > 0)
|
||||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"%s: Specifying both TokenBufferFilterLimitSize= and TokenBufferFilterLatencySec= is not allowed. "
|
"%s: Specifying both TokenBufferFilterLimitSize= and TokenBufferFilterLatencySec= is not allowed. "
|
||||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||||
section->filename, section->line);
|
qdisc->section->filename, qdisc->section->line);
|
||||||
|
|
||||||
if (tbf->limit == 0 && tbf->latency == 0)
|
if (tbf->limit == 0 && tbf->latency == 0)
|
||||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"%s: Either TokenBufferFilterLimitSize= or TokenBufferFilterLatencySec= is required. "
|
"%s: Either TokenBufferFilterLimitSize= or TokenBufferFilterLatencySec= is required. "
|
||||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||||
section->filename, section->line);
|
qdisc->section->filename, qdisc->section->line);
|
||||||
|
|
||||||
if (tbf->rate == 0)
|
if (tbf->rate == 0)
|
||||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"%s: TokenBufferFilterRate= is mandatory. "
|
"%s: TokenBufferFilterRate= is mandatory. "
|
||||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||||
section->filename, section->line);
|
qdisc->section->filename, qdisc->section->line);
|
||||||
|
|
||||||
if (tbf->burst == 0)
|
if (tbf->burst == 0)
|
||||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"%s: TokenBufferFilterBurst= is mandatory. "
|
"%s: TokenBufferFilterBurst= is mandatory. "
|
||||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||||
section->filename, section->line);
|
qdisc->section->filename, qdisc->section->line);
|
||||||
|
|
||||||
if (tbf->peak_rate > 0 && tbf->mtu == 0)
|
if (tbf->peak_rate > 0 && tbf->mtu == 0)
|
||||||
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"%s: TokenBufferFilterMTUBytes= is mandatory when TokenBufferFilterPeakRate= is specified. "
|
"%s: TokenBufferFilterMTUBytes= is mandatory when TokenBufferFilterPeakRate= is specified. "
|
||||||
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
"Ignoring [TrafficControlQueueingDiscipline] section from line %u.",
|
||||||
section->filename, section->line);
|
qdisc->section->filename, qdisc->section->line);
|
||||||
|
|
||||||
return 0;
|
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. */
|
* Copyright © 2019 VMware, Inc. */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "sd-netlink.h"
|
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "networkd-link.h"
|
#include "qdisc.h"
|
||||||
#include "networkd-util.h"
|
#include "time-util.h"
|
||||||
#include "tc-util.h"
|
|
||||||
|
|
||||||
typedef struct TokenBufferFilter {
|
typedef struct TokenBufferFilter {
|
||||||
|
QDisc meta;
|
||||||
|
|
||||||
uint64_t rate;
|
uint64_t rate;
|
||||||
uint64_t peak_rate;
|
uint64_t peak_rate;
|
||||||
uint32_t burst;
|
uint32_t burst;
|
||||||
@ -19,9 +18,8 @@ typedef struct TokenBufferFilter {
|
|||||||
size_t mpu;
|
size_t mpu;
|
||||||
} TokenBufferFilter;
|
} TokenBufferFilter;
|
||||||
|
|
||||||
int token_buffer_filter_new(TokenBufferFilter **ret);
|
DEFINE_QDISC_CAST(TBF, TokenBufferFilter);
|
||||||
int token_buffer_filter_fill_message(Link *link, const TokenBufferFilter *tbf, sd_netlink_message *req);
|
extern const QDiscVTable tbf_vtable;
|
||||||
int token_buffer_filter_section_verify(const TokenBufferFilter *tbf, const NetworkConfigSection *section);
|
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_latency);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_latency);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_size);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tc_token_buffer_filter_size);
|
||||||
|
Loading…
Reference in New Issue
Block a user