From: Yu Watanabe Date: Tue, 25 Jan 2022 23:42:22 +0000 (+0900) Subject: network: tc: monitor qdisc and tclass X-Git-Tag: v251-rc1~322^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=828a81a93783248be15683c9639b85098f331328;p=thirdparty%2Fsystemd.git network: tc: monitor qdisc and tclass --- diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index addf0d4afee..db55b467f80 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -269,12 +269,10 @@ static Link *link_free(Link *link) { link_dns_settings_clear(link); link->routes = set_free(link->routes); - link->nexthops = set_free(link->nexthops); - link->neighbors = set_free(link->neighbors); - link->addresses = set_free(link->addresses); + link->traffic_control = set_free(link->traffic_control); link->dhcp_pd_prefixes = set_free(link->dhcp_pd_prefixes); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 7ccb31df791..23a893449f2 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -108,6 +108,7 @@ typedef struct Link { Set *neighbors; Set *routes; Set *nexthops; + Set *traffic_control; sd_dhcp_client *dhcp_client; sd_dhcp_lease *dhcp_lease; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 3261f289e91..fab0b4094c3 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -45,12 +45,14 @@ #include "ordered-set.h" #include "path-lookup.h" #include "path-util.h" +#include "qdisc.h" #include "selinux-util.h" #include "set.h" #include "signal-util.h" #include "stat-util.h" #include "strv.h" #include "sysctl-util.h" +#include "tclass.h" #include "tmpfile-util.h" /* use 128 MB for receive socket kernel queue. */ @@ -311,6 +313,22 @@ static int manager_connect_rtnl(Manager *m) { if (r < 0) return r; + r = netlink_add_match(m->rtnl, NULL, RTM_NEWQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); + if (r < 0) + return r; + + r = netlink_add_match(m->rtnl, NULL, RTM_DELQDISC, &manager_rtnl_process_qdisc, NULL, m, "network-rtnl_process_qdisc"); + if (r < 0) + return r; + + r = netlink_add_match(m->rtnl, NULL, RTM_NEWTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); + if (r < 0) + return r; + + r = netlink_add_match(m->rtnl, NULL, RTM_DELTCLASS, &manager_rtnl_process_tclass, NULL, m, "network-rtnl_process_tclass"); + if (r < 0) + return r; + r = netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); if (r < 0) return r; @@ -671,6 +689,34 @@ static int manager_enumerate_links(Manager *m) { return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link); } +static int manager_enumerate_qdisc(Manager *m) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + int r; + + assert(m); + assert(m->rtnl); + + r = sd_rtnl_message_new_traffic_control(m->rtnl, &req, RTM_GETQDISC, 0, 0, 0); + if (r < 0) + return r; + + return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_qdisc); +} + +static int manager_enumerate_tclass(Manager *m) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + int r; + + 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; + + return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_tclass); +} + static int manager_enumerate_addresses(Manager *m) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -797,6 +843,14 @@ int manager_enumerate(Manager *m) { if (r < 0) return log_error_errno(r, "Could not enumerate links: %m"); + r = manager_enumerate_qdisc(m); + if (r < 0) + return log_error_errno(r, "Could not enumerate QDisc: %m"); + + r = manager_enumerate_tclass(m); + if (r < 0) + return log_error_errno(r, "Could not enumerate TClass: %m"); + r = manager_enumerate_addresses(m); if (r < 0) return log_error_errno(r, "Could not enumerate addresses: %m"); diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index f0e643b9aed..11c092d4bf7 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -54,6 +54,7 @@ static int qdisc_new(QDiscKind kind, QDisc **ret) { .kind = kind, }; } else { + assert(kind >= 0 && kind < _QDISC_KIND_MAX); qdisc = malloc0(qdisc_vtable[kind]->object_size); if (!qdisc) return -ENOMEM; @@ -140,10 +141,94 @@ QDisc* qdisc_free(QDisc *qdisc) { config_section_free(qdisc->section); + if (qdisc->link) + set_remove(qdisc->link->traffic_control, TC(qdisc)); + free(qdisc->tca_kind); return mfree(qdisc); } +static const char *qdisc_get_tca_kind(const QDisc *qdisc) { + assert(qdisc); + + return (QDISC_VTABLE(qdisc) && QDISC_VTABLE(qdisc)->tca_kind) ? + QDISC_VTABLE(qdisc)->tca_kind : qdisc->tca_kind; +} + +void qdisc_hash_func(const QDisc *qdisc, struct siphash *state) { + assert(qdisc); + assert(state); + + siphash24_compress(&qdisc->handle, sizeof(qdisc->handle), state); + siphash24_compress(&qdisc->parent, sizeof(qdisc->parent), state); + siphash24_compress_string(qdisc_get_tca_kind(qdisc), state); +} + +int qdisc_compare_func(const QDisc *a, const QDisc *b) { + int r; + + assert(a); + assert(b); + + r = CMP(a->handle, b->handle); + if (r != 0) + return r; + + r = CMP(a->parent, b->parent); + if (r != 0) + return r; + + return strcmp_ptr(qdisc_get_tca_kind(a), qdisc_get_tca_kind(b)); +} + +static int qdisc_get(Link *link, const QDisc *in, QDisc **ret) { + TrafficControl *existing; + int r; + + assert(link); + assert(in); + + r = traffic_control_get(link, TC(in), &existing); + if (r < 0) + return r; + + if (ret) + *ret = TC_TO_QDISC(existing); + return 0; +} + +static int qdisc_add(Link *link, QDisc *qdisc) { + int r; + + assert(link); + assert(qdisc); + + r = traffic_control_add(link, TC(qdisc)); + if (r < 0) + return r; + + qdisc->link = link; + return 0; +} + +static void log_qdisc_debug(QDisc *qdisc, Link *link, const char *str) { + _cleanup_free_ char *state = NULL; + + assert(qdisc); + assert(str); + + if (!DEBUG_LOGGING) + return; + + (void) network_config_state_to_string_alloc(qdisc->state, &state); + + log_link_debug(link, "%s %s QDisc (%s): handle=%"PRIx32":%"PRIx32", parent=%"PRIx32":%"PRIx32", kind=%s", + str, strna(network_config_source_to_string(qdisc->source)), strna(state), + TC_H_MAJ(qdisc->handle) >> 16, TC_H_MIN(qdisc->handle), + TC_H_MAJ(qdisc->parent) >> 16, TC_H_MIN(qdisc->parent), + strna(qdisc_get_tca_kind(qdisc))); +} + static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -216,6 +301,113 @@ int qdisc_configure(Link *link, QDisc *qdisc) { return 0; } +int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { + _cleanup_(qdisc_freep) QDisc *tmp = NULL; + QDisc *qdisc = NULL; + Link *link; + uint16_t type; + int ifindex, r; + + assert(rtnl); + assert(message); + assert(m); + + if (sd_netlink_message_is_error(message)) { + r = sd_netlink_message_get_errno(message); + if (r < 0) + log_message_warning_errno(message, r, "rtnl: failed to receive QDisc message, ignoring"); + + return 0; + } + + r = sd_netlink_message_get_type(message, &type); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get message type, ignoring: %m"); + return 0; + } else if (!IN_SET(type, RTM_NEWQDISC, RTM_DELQDISC)) { + log_warning("rtnl: received unexpected message type %u when processing QDisc, ignoring.", type); + return 0; + } + + r = sd_rtnl_message_traffic_control_get_ifindex(message, &ifindex); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received QDisc message with invalid ifindex %d, ignoring.", ifindex); + return 0; + } + + if (link_get_by_index(m, ifindex, &link) < 0) { + if (!m->enumerating) + log_warning("rtnl: received QDisc for link '%d' we don't know about, ignoring.", ifindex); + return 0; + } + + r = qdisc_new(_QDISC_KIND_INVALID, &tmp); + if (r < 0) + return log_oom(); + + r = sd_rtnl_message_traffic_control_get_handle(message, &tmp->handle); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received QDisc message without handle, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_traffic_control_get_parent(message, &tmp->parent); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received QDisc message without parent, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_string_strdup(message, TCA_KIND, &tmp->tca_kind); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received QDisc message without kind, ignoring: %m"); + return 0; + } + + (void) qdisc_get(link, tmp, &qdisc); + + switch (type) { + case RTM_NEWQDISC: + if (qdisc) { + qdisc_enter_configured(qdisc); + log_qdisc_debug(qdisc, link, "Received remembered"); + } else { + qdisc_enter_configured(tmp); + log_qdisc_debug(tmp, link, "Received new"); + + r = qdisc_add(link, tmp); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to remember QDisc, ignoring: %m"); + return 0; + } + + qdisc = TAKE_PTR(tmp); + } + + 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 + log_qdisc_debug(tmp, link, "Kernel removed unknown"); + + break; + + default: + assert_not_reached(); + } + + return 1; +} + int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact) { int r; diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index 8329d18b4f5..29ceb50183c 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -37,8 +37,11 @@ typedef enum QDiscKind { typedef struct QDisc { TrafficControl meta; - ConfigSection *section; + Link *link; Network *network; + ConfigSection *section; + NetworkConfigSource source; + NetworkConfigState state; uint32_t handle; uint32_t parent; @@ -73,12 +76,19 @@ extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX]; /* For casting the various qdisc kinds into a qdisc */ #define QDISC(q) (&(q)->meta) +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); +void qdisc_hash_func(const QDisc *qdic, struct siphash *state); +int qdisc_compare_func(const QDisc *a, const QDisc *b); + int qdisc_configure(Link *link, QDisc *qdisc); int qdisc_section_verify(QDisc *qdisc, bool *has_root, bool *has_clsact); +int manager_rtnl_process_qdisc(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); + DEFINE_SECTION_CLEANUP_FUNCTIONS(QDisc, qdisc_free); DEFINE_TC_CAST(QDISC, QDisc); diff --git a/src/network/tc/tc.c b/src/network/tc/tc.c index c0f6989b1b6..55d1b0c9371 100644 --- a/src/network/tc/tc.c +++ b/src/network/tc/tc.c @@ -21,6 +21,83 @@ void traffic_control_free(TrafficControl *tc) { } } +void traffic_control_hash_func(const TrafficControl *tc, struct siphash *state) { + assert(tc); + assert(state); + + siphash24_compress(&tc->kind, sizeof(tc->kind), state); + + switch (tc->kind) { + case TC_KIND_QDISC: + qdisc_hash_func(TC_TO_QDISC_CONST(tc), state); + break; + case TC_KIND_TCLASS: + tclass_hash_func(TC_TO_TCLASS_CONST(tc), state); + break; + default: + assert_not_reached(); + } +} + +int traffic_control_compare_func(const TrafficControl *a, const TrafficControl *b) { + int r; + + assert(a); + assert(b); + + r = CMP(a->kind, b->kind); + if (r != 0) + return r; + + switch (a->kind) { + case TC_KIND_QDISC: + return qdisc_compare_func(TC_TO_QDISC_CONST(a), TC_TO_QDISC_CONST(b)); + case TC_KIND_TCLASS: + return tclass_compare_func(TC_TO_TCLASS_CONST(a), TC_TO_TCLASS_CONST(b)); + default: + assert_not_reached(); + } +} + +DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( + traffic_control_hash_ops, + TrafficControl, + traffic_control_hash_func, + traffic_control_compare_func, + traffic_control_free); + +int traffic_control_get(Link *link, const TrafficControl *in, TrafficControl **ret) { + TrafficControl *existing; + + assert(link); + assert(in); + + existing = set_get(link->traffic_control, in); + if (!existing) + return -ENOENT; + + if (ret) + *ret = existing; + return 0; +} + +int traffic_control_add(Link *link, TrafficControl *tc) { + int r; + + assert(link); + assert(tc); + + /* This must be called only from qdisc_add() or tclass_add(). */ + + r = set_ensure_put(&link->traffic_control, &traffic_control_hash_ops, tc); + if (r < 0) + return r; + if (r == 0) + return -EEXIST; + + return 0; +} + static int traffic_control_configure(Link *link, TrafficControl *tc) { assert(link); assert(tc); diff --git a/src/network/tc/tc.h b/src/network/tc/tc.h index badd5227c6f..954dcd39f9c 100644 --- a/src/network/tc/tc.h +++ b/src/network/tc/tc.h @@ -16,12 +16,18 @@ typedef struct TrafficControl { } TrafficControl; /* For casting a tc into the various tc kinds */ -#define DEFINE_TC_CAST(UPPERCASE, MixedCase) \ - static inline MixedCase* TC_TO_##UPPERCASE(TrafficControl *tc) { \ - if (_unlikely_(!tc || tc->kind != TC_KIND_##UPPERCASE)) \ - return NULL; \ - \ - return (MixedCase*) tc; \ +#define DEFINE_TC_CAST(UPPERCASE, MixedCase) \ + static inline MixedCase* TC_TO_##UPPERCASE(TrafficControl *tc) { \ + if (_unlikely_(!tc || tc->kind != TC_KIND_##UPPERCASE)) \ + return NULL; \ + \ + return (MixedCase*) tc; \ + } \ + static inline const MixedCase* TC_TO_##UPPERCASE##_CONST(const TrafficControl *tc) { \ + if (_unlikely_(!tc || tc->kind != TC_KIND_##UPPERCASE)) \ + return NULL; \ + \ + return (const MixedCase*) tc; \ } /* For casting the various tc kinds into a tc */ @@ -30,3 +36,9 @@ typedef struct TrafficControl { void traffic_control_free(TrafficControl *tc); int link_configure_traffic_control(Link *link); void network_drop_invalid_traffic_control(Network *network); + +void traffic_control_hash_func(const TrafficControl *tc, struct siphash *state); +int traffic_control_compare_func(const TrafficControl *a, const TrafficControl *b); + +int traffic_control_get(Link *link, const TrafficControl *in, TrafficControl **ret); +int traffic_control_add(Link *link, TrafficControl *tc); diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index 860d8c997a9..cd61b42c4e2 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -25,18 +25,31 @@ static int tclass_new(TClassKind kind, TClass **ret) { _cleanup_(tclass_freep) TClass *tclass = NULL; int r; - tclass = malloc0(tclass_vtable[kind]->object_size); - if (!tclass) - return -ENOMEM; - - tclass->meta.kind = TC_KIND_TCLASS, - tclass->parent = TC_H_ROOT; - tclass->kind = kind; + if (kind == _TCLASS_KIND_INVALID) { + tclass = new(TClass, 1); + if (!tclass) + return -ENOMEM; + + *tclass = (TClass) { + .meta.kind = TC_KIND_TCLASS, + .parent = TC_H_ROOT, + .kind = kind, + }; + } else { + assert(kind >= 0 && kind < _TCLASS_KIND_MAX); + tclass = malloc0(tclass_vtable[kind]->object_size); + if (!tclass) + return -ENOMEM; + + tclass->meta.kind = TC_KIND_TCLASS; + tclass->parent = TC_H_ROOT; + tclass->kind = kind; - if (TCLASS_VTABLE(tclass)->init) { - r = TCLASS_VTABLE(tclass)->init(tclass); - if (r < 0) - return r; + if (TCLASS_VTABLE(tclass)->init) { + r = TCLASS_VTABLE(tclass)->init(tclass); + if (r < 0) + return r; + } } *ret = TAKE_PTR(tclass); @@ -99,9 +112,94 @@ TClass* tclass_free(TClass *tclass) { config_section_free(tclass->section); + if (tclass->link) + set_remove(tclass->link->traffic_control, TC(tclass)); + + free(tclass->tca_kind); return mfree(tclass); } +static const char *tclass_get_tca_kind(const TClass *tclass) { + assert(tclass); + + return (TCLASS_VTABLE(tclass) && TCLASS_VTABLE(tclass)->tca_kind) ? + TCLASS_VTABLE(tclass)->tca_kind : tclass->tca_kind; +} + +void tclass_hash_func(const TClass *tclass, struct siphash *state) { + assert(tclass); + assert(state); + + siphash24_compress(&tclass->classid, sizeof(tclass->classid), state); + siphash24_compress(&tclass->parent, sizeof(tclass->parent), state); + siphash24_compress_string(tclass_get_tca_kind(tclass), state); +} + +int tclass_compare_func(const TClass *a, const TClass *b) { + int r; + + assert(a); + assert(b); + + r = CMP(a->classid, b->classid); + if (r != 0) + return r; + + r = CMP(a->parent, b->parent); + if (r != 0) + return r; + + return strcmp_ptr(tclass_get_tca_kind(a), tclass_get_tca_kind(b)); +} + +static int tclass_get(Link *link, const TClass *in, TClass **ret) { + TrafficControl *existing; + int r; + + assert(link); + assert(in); + + r = traffic_control_get(link, TC(in), &existing); + if (r < 0) + return r; + + if (ret) + *ret = TC_TO_TCLASS(existing); + return 0; +} + +static int tclass_add(Link *link, TClass *tclass) { + int r; + + assert(link); + assert(tclass); + + r = traffic_control_add(link, TC(tclass)); + if (r < 0) + return r; + + tclass->link = link; + return 0; +} + +static void log_tclass_debug(TClass *tclass, Link *link, const char *str) { + _cleanup_free_ char *state = NULL; + + assert(tclass); + assert(str); + + if (!DEBUG_LOGGING) + return; + + (void) network_config_state_to_string_alloc(tclass->state, &state); + + log_link_debug(link, "%s %s TClass (%s): classid=%"PRIx32":%"PRIx32", parent=%"PRIx32":%"PRIx32", kind=%s", + str, strna(network_config_source_to_string(tclass->source)), strna(state), + TC_H_MAJ(tclass->classid) >> 16, TC_H_MIN(tclass->classid), + TC_H_MAJ(tclass->parent) >> 16, TC_H_MIN(tclass->parent), + strna(tclass_get_tca_kind(tclass))); +} + static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; @@ -162,6 +260,113 @@ int tclass_configure(Link *link, TClass *tclass) { return 0; } +int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { + _cleanup_(tclass_freep) TClass *tmp = NULL; + TClass *tclass = NULL; + Link *link; + uint16_t type; + int ifindex, r; + + assert(rtnl); + assert(message); + assert(m); + + if (sd_netlink_message_is_error(message)) { + r = sd_netlink_message_get_errno(message); + if (r < 0) + log_message_warning_errno(message, r, "rtnl: failed to receive TClass message, ignoring"); + + return 0; + } + + r = sd_netlink_message_get_type(message, &type); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get message type, ignoring: %m"); + return 0; + } else if (!IN_SET(type, RTM_NEWTCLASS, RTM_DELTCLASS)) { + log_warning("rtnl: received unexpected message type %u when processing TClass, ignoring.", type); + return 0; + } + + r = sd_rtnl_message_traffic_control_get_ifindex(message, &ifindex); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex from message, ignoring: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received TClass message with invalid ifindex %d, ignoring.", ifindex); + return 0; + } + + if (link_get_by_index(m, ifindex, &link) < 0) { + if (!m->enumerating) + log_warning("rtnl: received TClass for link '%d' we don't know about, ignoring.", ifindex); + return 0; + } + + r = tclass_new(_TCLASS_KIND_INVALID, &tmp); + if (r < 0) + return log_oom(); + + r = sd_rtnl_message_traffic_control_get_handle(message, &tmp->classid); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received TClass message without handle, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_traffic_control_get_parent(message, &tmp->parent); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received TClass message without parent, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_string_strdup(message, TCA_KIND, &tmp->tca_kind); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received TClass message without kind, ignoring: %m"); + return 0; + } + + (void) tclass_get(link, tmp, &tclass); + + switch (type) { + case RTM_NEWTCLASS: + if (tclass) { + tclass_enter_configured(tclass); + log_tclass_debug(tclass, link, "Received remembered"); + } else { + tclass_enter_configured(tmp); + log_tclass_debug(tmp, link, "Received new"); + + r = tclass_add(link, tmp); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to remember TClass, ignoring: %m"); + return 0; + } + + tclass = TAKE_PTR(tmp); + } + + 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 + log_tclass_debug(tmp, link, "Kernel removed unknown"); + + break; + + default: + assert_not_reached(); + } + + return 1; +} + int tclass_section_verify(TClass *tclass) { int r; diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index 5f8016c1872..9e57e9566f8 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -19,13 +19,17 @@ typedef enum TClassKind { typedef struct TClass { TrafficControl meta; - ConfigSection *section; + Link *link; Network *network; + ConfigSection *section; + NetworkConfigSource source; + NetworkConfigState state; uint32_t classid; uint32_t parent; TClassKind kind; + char *tca_kind; } TClass; typedef struct TClassVTable { @@ -53,12 +57,19 @@ extern const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX]; /* For casting the various tclass kinds into a tclass */ #define TCLASS(t) (&(t)->meta) +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); +void tclass_hash_func(const TClass *tclass, struct siphash *state); +int tclass_compare_func(const TClass *a, const TClass *b); + int tclass_configure(Link *link, TClass *tclass); int tclass_section_verify(TClass *tclass); +int manager_rtnl_process_tclass(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); + DEFINE_SECTION_CLEANUP_FUNCTIONS(TClass, tclass_free); DEFINE_TC_CAST(TCLASS, TClass);