mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #29490 from yuwata/network-tc-fixes
network: several fixes for traffic control support
This commit is contained in:
@@ -716,7 +716,7 @@ int manager_load_config(Manager *m) {
|
||||
return manager_build_dhcp_pd_subnet_ids(m);
|
||||
}
|
||||
|
||||
static int manager_enumerate_internal(
|
||||
int manager_enumerate_internal(
|
||||
Manager *m,
|
||||
sd_netlink *nl,
|
||||
sd_netlink_message *req,
|
||||
@@ -775,17 +775,18 @@ static int manager_enumerate_qdisc(Manager *m) {
|
||||
}
|
||||
|
||||
static int manager_enumerate_tclass(Manager *m) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
Link *link;
|
||||
int r = 0;
|
||||
|
||||
assert(m);
|
||||
assert(m->rtnl);
|
||||
|
||||
r = sd_rtnl_message_new_traffic_control(m->rtnl, &req, RTM_GETTCLASS, 0, 0, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* TC class can be enumerated only per link. See tc_dump_tclass() in net/sched/sched_api.c. */
|
||||
|
||||
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_tclass);
|
||||
HASHMAP_FOREACH(link, m->links_by_index)
|
||||
RET_GATHER(r, link_enumerate_tclass(link, 0));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int manager_enumerate_addresses(Manager *m) {
|
||||
|
||||
@@ -113,6 +113,11 @@ int manager_start(Manager *m);
|
||||
|
||||
int manager_load_config(Manager *m);
|
||||
|
||||
int manager_enumerate_internal(
|
||||
Manager *m,
|
||||
sd_netlink *nl,
|
||||
sd_netlink_message *req,
|
||||
int (*process)(sd_netlink *, sd_netlink_message *, Manager *));
|
||||
int manager_enumerate(Manager *m);
|
||||
|
||||
int manager_set_hostname(Manager *m, const char *hostname);
|
||||
|
||||
@@ -19,27 +19,27 @@
|
||||
#include "tc-util.h"
|
||||
|
||||
const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX] = {
|
||||
[QDISC_KIND_BFIFO] = &bfifo_vtable,
|
||||
[QDISC_KIND_CAKE] = &cake_vtable,
|
||||
[QDISC_KIND_CODEL] = &codel_vtable,
|
||||
[QDISC_KIND_DRR] = &drr_vtable,
|
||||
[QDISC_KIND_ETS] = &ets_vtable,
|
||||
[QDISC_KIND_FQ] = &fq_vtable,
|
||||
[QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
|
||||
[QDISC_KIND_FQ_PIE] = &fq_pie_vtable,
|
||||
[QDISC_KIND_GRED] = &gred_vtable,
|
||||
[QDISC_KIND_HHF] = &hhf_vtable,
|
||||
[QDISC_KIND_HTB] = &htb_vtable,
|
||||
[QDISC_KIND_NETEM] = &netem_vtable,
|
||||
[QDISC_KIND_PIE] = &pie_vtable,
|
||||
[QDISC_KIND_QFQ] = &qfq_vtable,
|
||||
[QDISC_KIND_PFIFO] = &pfifo_vtable,
|
||||
[QDISC_KIND_PFIFO_FAST] = &pfifo_fast_vtable,
|
||||
[QDISC_KIND_BFIFO] = &bfifo_vtable,
|
||||
[QDISC_KIND_CAKE] = &cake_vtable,
|
||||
[QDISC_KIND_CODEL] = &codel_vtable,
|
||||
[QDISC_KIND_DRR] = &drr_vtable,
|
||||
[QDISC_KIND_ETS] = &ets_vtable,
|
||||
[QDISC_KIND_FQ] = &fq_vtable,
|
||||
[QDISC_KIND_FQ_CODEL] = &fq_codel_vtable,
|
||||
[QDISC_KIND_FQ_PIE] = &fq_pie_vtable,
|
||||
[QDISC_KIND_GRED] = &gred_vtable,
|
||||
[QDISC_KIND_HHF] = &hhf_vtable,
|
||||
[QDISC_KIND_HTB] = &htb_vtable,
|
||||
[QDISC_KIND_NETEM] = &netem_vtable,
|
||||
[QDISC_KIND_PIE] = &pie_vtable,
|
||||
[QDISC_KIND_QFQ] = &qfq_vtable,
|
||||
[QDISC_KIND_PFIFO] = &pfifo_vtable,
|
||||
[QDISC_KIND_PFIFO_FAST] = &pfifo_fast_vtable,
|
||||
[QDISC_KIND_PFIFO_HEAD_DROP] = &pfifo_head_drop_vtable,
|
||||
[QDISC_KIND_SFB] = &sfb_vtable,
|
||||
[QDISC_KIND_SFQ] = &sfq_vtable,
|
||||
[QDISC_KIND_TBF] = &tbf_vtable,
|
||||
[QDISC_KIND_TEQL] = &teql_vtable,
|
||||
[QDISC_KIND_SFB] = &sfb_vtable,
|
||||
[QDISC_KIND_SFQ] = &sfq_vtable,
|
||||
[QDISC_KIND_TBF] = &tbf_vtable,
|
||||
[QDISC_KIND_TEQL] = &teql_vtable,
|
||||
};
|
||||
|
||||
static int qdisc_new(QDiscKind kind, QDisc **ret) {
|
||||
@@ -262,23 +262,15 @@ static void log_qdisc_debug(QDisc *qdisc, Link *link, const char *str) {
|
||||
strna(qdisc_get_tca_kind(qdisc)));
|
||||
}
|
||||
|
||||
int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *kind, QDisc **ret) {
|
||||
int link_find_qdisc(Link *link, uint32_t handle, const char *kind, QDisc **ret) {
|
||||
QDisc *qdisc;
|
||||
|
||||
assert(link);
|
||||
|
||||
handle = TC_H_MAJ(handle);
|
||||
|
||||
SET_FOREACH(qdisc, link->qdiscs) {
|
||||
if (qdisc->handle != handle)
|
||||
continue;
|
||||
|
||||
if (qdisc->parent != parent)
|
||||
continue;
|
||||
|
||||
if (qdisc->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
if (!qdisc_exists(qdisc))
|
||||
continue;
|
||||
|
||||
@@ -293,6 +285,33 @@ int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *ki
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
QDisc* qdisc_drop(QDisc *qdisc) {
|
||||
TClass *tclass;
|
||||
Link *link;
|
||||
|
||||
assert(qdisc);
|
||||
|
||||
link = ASSERT_PTR(qdisc->link);
|
||||
|
||||
/* also drop all child classes assigned to the qdisc. */
|
||||
SET_FOREACH(tclass, link->tclasses) {
|
||||
if (TC_H_MAJ(tclass->classid) != qdisc->handle)
|
||||
continue;
|
||||
|
||||
tclass_drop(tclass);
|
||||
}
|
||||
|
||||
qdisc_enter_removed(qdisc);
|
||||
|
||||
if (qdisc->state == 0) {
|
||||
log_qdisc_debug(qdisc, link, "Forgetting");
|
||||
qdisc = qdisc_free(qdisc);
|
||||
} else
|
||||
log_qdisc_debug(qdisc, link, "Removed");
|
||||
|
||||
return qdisc;
|
||||
}
|
||||
|
||||
static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, QDisc *qdisc) {
|
||||
int r;
|
||||
|
||||
@@ -354,9 +373,15 @@ static bool qdisc_is_ready_to_configure(QDisc *qdisc, Link *link) {
|
||||
return false;
|
||||
|
||||
/* TC_H_CLSACT == TC_H_INGRESS */
|
||||
if (!IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT) &&
|
||||
link_find_tclass(link, qdisc->parent, NULL) < 0)
|
||||
return false;
|
||||
if (!IN_SET(qdisc->parent, TC_H_ROOT, TC_H_CLSACT)) {
|
||||
if (TC_H_MIN(qdisc->parent) == 0) {
|
||||
if (link_find_qdisc(link, qdisc->parent, NULL, NULL) < 0)
|
||||
return false;
|
||||
} else {
|
||||
if (link_find_tclass(link, qdisc->parent, NULL) < 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (QDISC_VTABLE(qdisc) &&
|
||||
QDISC_VTABLE(qdisc)->is_ready &&
|
||||
@@ -509,17 +534,20 @@ int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Ma
|
||||
qdisc = TAKE_PTR(tmp);
|
||||
}
|
||||
|
||||
if (!m->enumerating) {
|
||||
/* Some kind of QDisc (e.g. tbf) also create an implicit class under the qdisc, but
|
||||
* the kernel may not notify about the class. Hence, we need to enumerate classes. */
|
||||
r = link_enumerate_tclass(link, qdisc->handle);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to enumerate TClass, ignoring: %m");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTM_DELQDISC:
|
||||
if (qdisc) {
|
||||
qdisc_enter_removed(qdisc);
|
||||
if (qdisc->state == 0) {
|
||||
log_qdisc_debug(qdisc, link, "Forgetting");
|
||||
qdisc_free(qdisc);
|
||||
} else
|
||||
log_qdisc_debug(qdisc, link, "Removed");
|
||||
} else
|
||||
if (qdisc)
|
||||
qdisc_drop(qdisc);
|
||||
else
|
||||
log_qdisc_debug(tmp, link, "Kernel removed unknown");
|
||||
|
||||
break;
|
||||
|
||||
@@ -77,7 +77,9 @@ DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(QDisc, qdisc);
|
||||
QDisc* qdisc_free(QDisc *qdisc);
|
||||
int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret);
|
||||
|
||||
int link_find_qdisc(Link *link, uint32_t handle, uint32_t parent, const char *kind, QDisc **qdisc);
|
||||
QDisc* qdisc_drop(QDisc *qdisc);
|
||||
|
||||
int link_find_qdisc(Link *link, uint32_t handle, const char *kind, QDisc **qdisc);
|
||||
|
||||
int link_request_qdisc(Link *link, QDisc *qdisc);
|
||||
|
||||
|
||||
@@ -223,9 +223,6 @@ int link_find_tclass(Link *link, uint32_t classid, TClass **ret) {
|
||||
if (tclass->classid != classid)
|
||||
continue;
|
||||
|
||||
if (tclass->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
if (!tclass_exists(tclass))
|
||||
continue;
|
||||
|
||||
@@ -255,6 +252,33 @@ static void log_tclass_debug(TClass *tclass, Link *link, const char *str) {
|
||||
strna(tclass_get_tca_kind(tclass)));
|
||||
}
|
||||
|
||||
TClass* tclass_drop(TClass *tclass) {
|
||||
QDisc *qdisc;
|
||||
Link *link;
|
||||
|
||||
assert(tclass);
|
||||
|
||||
link = ASSERT_PTR(tclass->link);
|
||||
|
||||
/* Also drop all child qdiscs assigned to the class. */
|
||||
SET_FOREACH(qdisc, link->qdiscs) {
|
||||
if (qdisc->parent != tclass->classid)
|
||||
continue;
|
||||
|
||||
qdisc_drop(qdisc);
|
||||
}
|
||||
|
||||
tclass_enter_removed(tclass);
|
||||
|
||||
if (tclass->state == 0) {
|
||||
log_tclass_debug(tclass, link, "Forgetting");
|
||||
tclass = tclass_free(tclass);
|
||||
} else
|
||||
log_tclass_debug(tclass, link, "Removed");
|
||||
|
||||
return tclass;
|
||||
}
|
||||
|
||||
static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, TClass *tclass) {
|
||||
int r;
|
||||
|
||||
@@ -315,7 +339,7 @@ static bool tclass_is_ready_to_configure(TClass *tclass, Link *link) {
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
return false;
|
||||
|
||||
return link_find_qdisc(link, tclass->classid, tclass->parent, tclass_get_tca_kind(tclass), NULL) >= 0;
|
||||
return link_find_qdisc(link, TC_H_MAJ(tclass->classid), tclass_get_tca_kind(tclass), NULL) >= 0;
|
||||
}
|
||||
|
||||
static int tclass_process_request(Request *req, Link *link, TClass *tclass) {
|
||||
@@ -464,14 +488,9 @@ int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, M
|
||||
break;
|
||||
|
||||
case RTM_DELTCLASS:
|
||||
if (tclass) {
|
||||
tclass_enter_removed(tclass);
|
||||
if (tclass->state == 0) {
|
||||
log_tclass_debug(tclass, link, "Forgetting");
|
||||
tclass_free(tclass);
|
||||
} else
|
||||
log_tclass_debug(tclass, link, "Removed");
|
||||
} else
|
||||
if (tclass)
|
||||
(void) tclass_drop(tclass);
|
||||
else
|
||||
log_tclass_debug(tmp, link, "Kernel removed unknown");
|
||||
|
||||
break;
|
||||
@@ -483,6 +502,21 @@ int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, M
|
||||
return 1;
|
||||
}
|
||||
|
||||
int link_enumerate_tclass(Link *link, uint32_t parent) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
|
||||
r = sd_rtnl_message_new_traffic_control(link->manager->rtnl, &req, RTM_GETTCLASS, link->ifindex, 0, parent);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return manager_enumerate_internal(link->manager, link->manager->rtnl, req, manager_rtnl_process_tclass);
|
||||
}
|
||||
|
||||
static int tclass_section_verify(TClass *tclass) {
|
||||
int r;
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@ DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(TClass, tclass);
|
||||
TClass* tclass_free(TClass *tclass);
|
||||
int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret);
|
||||
|
||||
TClass* tclass_drop(TClass *tclass);
|
||||
|
||||
int link_find_tclass(Link *link, uint32_t classid, TClass **ret);
|
||||
|
||||
int link_request_tclass(Link *link, TClass *tclass);
|
||||
@@ -65,6 +67,7 @@ int link_request_tclass(Link *link, TClass *tclass);
|
||||
void network_drop_invalid_tclass(Network *network);
|
||||
|
||||
int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
|
||||
int link_enumerate_tclass(Link *link, uint32_t parent);
|
||||
|
||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(TClass, tclass_free);
|
||||
|
||||
|
||||
@@ -14,3 +14,8 @@ BurstBytes=5000
|
||||
LatencySec=70msec
|
||||
PeakRate=100G
|
||||
MTUBytes=1000000
|
||||
|
||||
[PFIFO]
|
||||
Parent=35:0
|
||||
Handle=0037
|
||||
PacketLimit=100000
|
||||
|
||||
Reference in New Issue
Block a user