Merge pull request #29490 from yuwata/network-tc-fixes

network: several fixes for traffic control support
This commit is contained in:
Luca Boccassi
2023-10-08 22:31:26 +01:00
committed by GitHub
7 changed files with 138 additions and 60 deletions

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -14,3 +14,8 @@ BurstBytes=5000
LatencySec=70msec
PeakRate=100G
MTUBytes=1000000
[PFIFO]
Parent=35:0
Handle=0037
PacketLimit=100000