diff options
-rw-r--r-- | libnm-core/nm-utils.c | 11 | ||||
-rw-r--r-- | libnm-core/tests/test-setting.c | 25 | ||||
-rw-r--r-- | src/NetworkManagerUtils.c | 7 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 129 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 28 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 10 | ||||
-rw-r--r-- | src/platform/tests/test-tc.c | 44 |
7 files changed, 201 insertions, 53 deletions
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index bcf7ebaf80..e8f4205b56 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2308,6 +2308,16 @@ static const NMVariantAttributeSpec *const tc_object_attribute_spec[] = { NULL, }; +static const NMVariantAttributeSpec *const tc_qdisc_sfq_spec[] = { + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("quantum", G_VARIANT_TYPE_UINT32, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("perturb", G_VARIANT_TYPE_INT32, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("limit", G_VARIANT_TYPE_UINT32, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("divisor", G_VARIANT_TYPE_UINT32, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("flows", G_VARIANT_TYPE_UINT32, ), + NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("depth", G_VARIANT_TYPE_UINT32, ), + NULL, +}; + static const NMVariantAttributeSpec *const tc_qdisc_fq_codel_spec[] = { NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("limit", G_VARIANT_TYPE_UINT32, ), NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("flows", G_VARIANT_TYPE_UINT32, ), @@ -2335,6 +2345,7 @@ typedef struct { static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = { &(const NMQdiscAttributeSpec) { "fq_codel", tc_qdisc_fq_codel_spec }, + &(const NMQdiscAttributeSpec) { "sfq", tc_qdisc_sfq_spec }, NULL, }; diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index ae37ec7bbd..2118937daf 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -2232,6 +2232,7 @@ test_tc_config_qdisc (void) NMTCQdisc *qdisc1, *qdisc2; char *str; GError *error = NULL; + GVariant *variant; qdisc1 = nm_tc_qdisc_new ("fq_codel", TC_H_ROOT, &error); nmtst_assert_success (qdisc1, error); @@ -2294,6 +2295,30 @@ test_tc_config_qdisc (void) nm_tc_qdisc_unref (qdisc1); nm_tc_qdisc_unref (qdisc2); + +#define CHECK_ATTRIBUTE(qdisc, name, vtype, type, value) \ + variant = nm_tc_qdisc_get_attribute (qdisc, name); \ + g_assert (variant); \ + g_assert (g_variant_is_of_type (variant, vtype)); \ + g_assert_cmpint (g_variant_get_ ## type(variant), ==, value); + + qdisc1 = nm_utils_tc_qdisc_from_str ("handle 1235 root sfq perturb 10 quantum 1480 " + "limit 9000 flows 1024 divisor 500 depth 12", + &error); + nmtst_assert_success (qdisc1, error); + + g_assert_cmpstr (nm_tc_qdisc_get_kind (qdisc1), ==, "sfq"); + g_assert (nm_tc_qdisc_get_handle (qdisc1) == TC_H_MAKE (0x1235u << 16, 0x0000u)); + g_assert (nm_tc_qdisc_get_parent (qdisc1) == TC_H_ROOT); + CHECK_ATTRIBUTE (qdisc1, "perturb", G_VARIANT_TYPE_INT32, int32, 10); + CHECK_ATTRIBUTE (qdisc1, "quantum", G_VARIANT_TYPE_UINT32, uint32, 1480); + CHECK_ATTRIBUTE (qdisc1, "limit", G_VARIANT_TYPE_UINT32, uint32, 9000); + CHECK_ATTRIBUTE (qdisc1, "flows", G_VARIANT_TYPE_UINT32, uint32, 1024); + CHECK_ATTRIBUTE (qdisc1, "divisor", G_VARIANT_TYPE_UINT32, uint32, 500); + CHECK_ATTRIBUTE (qdisc1, "depth", G_VARIANT_TYPE_UINT32, uint32, 12); + nm_tc_qdisc_unref (qdisc1); + +#undef CHECK_ATTRIBUTE } static void diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index f90ea2cc54..324e71d2d9 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1173,6 +1173,13 @@ nm_utils_qdiscs_from_tc_setting (NMPlatform *platform, GET_ATTR ("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED); GET_ATTR ("memory_limit", qdisc->fq_codel.memory_limit, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET); GET_ATTR ("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE); + } else if (nm_streq (qdisc->kind, "sfq")) { + GET_ATTR ("limit", qdisc->sfq.limit, UINT32, uint32, 0); + GET_ATTR ("flows", qdisc->sfq.flows, UINT32, uint32, 0); + GET_ATTR ("divisor", qdisc->sfq.divisor, UINT32, uint32, 0); + GET_ATTR ("perturb", qdisc->sfq.perturb_period, INT32, int32, 0); + GET_ATTR ("quantum", qdisc->sfq.quantum, UINT32, uint32, 0); + GET_ATTR ("depth", qdisc->sfq.depth, UINT32, uint32, 0); } #undef GET_ADDR diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 78e33748c1..1c3d4d2557 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3700,36 +3700,50 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only) struct nlattr *options_attr; int remaining; - nla_for_each_nested (options_attr, tb[TCA_OPTIONS], remaining) { - if (nla_len (options_attr) < sizeof (uint32_t)) - continue; - - if (nm_streq0 (obj->qdisc.kind, "fq_codel")) { - switch (nla_type (options_attr)) { - case TCA_FQ_CODEL_LIMIT: - obj->qdisc.fq_codel.limit = nla_get_u32 (options_attr); - break; - case TCA_FQ_CODEL_FLOWS: - obj->qdisc.fq_codel.flows = nla_get_u32 (options_attr); - break; - case TCA_FQ_CODEL_TARGET: - obj->qdisc.fq_codel.target = nla_get_u32 (options_attr); - break; - case TCA_FQ_CODEL_INTERVAL: - obj->qdisc.fq_codel.interval = nla_get_u32 (options_attr); - break; - case TCA_FQ_CODEL_QUANTUM: - obj->qdisc.fq_codel.quantum = nla_get_u32 (options_attr); - break; - case TCA_FQ_CODEL_CE_THRESHOLD: - obj->qdisc.fq_codel.ce_threshold = nla_get_u32 (options_attr); - break; - case TCA_FQ_CODEL_MEMORY_LIMIT: - obj->qdisc.fq_codel.memory_limit = nla_get_u32 (options_attr); - break; - case TCA_FQ_CODEL_ECN: - obj->qdisc.fq_codel.ecn = !!nla_get_u32 (options_attr); - break; + if (nm_streq0 (obj->qdisc.kind, "sfq")) { + struct tc_sfq_qopt_v1 opt = {}; + + if (tb[TCA_OPTIONS]->nla_len >= nla_attr_size (sizeof (opt))) { + memcpy (&opt, nla_data (tb[TCA_OPTIONS]), sizeof (opt)); + obj->qdisc.sfq.quantum = opt.v0.quantum; + obj->qdisc.sfq.perturb_period = opt.v0.perturb_period; + obj->qdisc.sfq.limit = opt.v0.limit; + obj->qdisc.sfq.divisor = opt.v0.divisor; + obj->qdisc.sfq.flows = opt.v0.flows; + obj->qdisc.sfq.depth = opt.depth; + } + } else { + nla_for_each_nested (options_attr, tb[TCA_OPTIONS], remaining) { + if (nla_len (options_attr) < sizeof (uint32_t)) + continue; + + if (nm_streq0 (obj->qdisc.kind, "fq_codel")) { + switch (nla_type (options_attr)) { + case TCA_FQ_CODEL_LIMIT: + obj->qdisc.fq_codel.limit = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_FLOWS: + obj->qdisc.fq_codel.flows = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_TARGET: + obj->qdisc.fq_codel.target = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_INTERVAL: + obj->qdisc.fq_codel.interval = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_QUANTUM: + obj->qdisc.fq_codel.quantum = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_CE_THRESHOLD: + obj->qdisc.fq_codel.ce_threshold = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_MEMORY_LIMIT: + obj->qdisc.fq_codel.memory_limit = nla_get_u32 (options_attr); + break; + case TCA_FQ_CODEL_ECN: + obj->qdisc.fq_codel.ecn = !!nla_get_u32 (options_attr); + break; + } } } } @@ -4651,29 +4665,42 @@ _nl_msg_new_qdisc (int nlmsg_type, NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind); - if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS))) - goto nla_put_failure; + if (nm_streq (qdisc->kind, "sfq")) { + struct tc_sfq_qopt_v1 opt = { }; - if (nm_streq (qdisc->kind, "fq_codel")) { - if (qdisc->fq_codel.limit) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_LIMIT, qdisc->fq_codel.limit); - if (qdisc->fq_codel.flows) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_FLOWS, qdisc->fq_codel.flows); - if (qdisc->fq_codel.target) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_TARGET, qdisc->fq_codel.target); - if (qdisc->fq_codel.interval) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_INTERVAL, qdisc->fq_codel.interval); - if (qdisc->fq_codel.quantum) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum); - if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold); - if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory_limit); - if (qdisc->fq_codel.ecn) - NLA_PUT_U32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn); - } + opt.v0.quantum = qdisc->sfq.quantum; + opt.v0.limit = qdisc->sfq.limit; + opt.v0.perturb_period = qdisc->sfq.perturb_period; + opt.v0.flows = qdisc->sfq.flows; + opt.v0.divisor = qdisc->sfq.divisor; + opt.depth = qdisc->sfq.depth; - nla_nest_end (msg, tc_options); + NLA_PUT (msg, TCA_OPTIONS, sizeof (opt), &opt); + } else { + if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS))) + goto nla_put_failure; + + if (nm_streq (qdisc->kind, "fq_codel")) { + if (qdisc->fq_codel.limit) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_LIMIT, qdisc->fq_codel.limit); + if (qdisc->fq_codel.flows) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_FLOWS, qdisc->fq_codel.flows); + if (qdisc->fq_codel.target) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_TARGET, qdisc->fq_codel.target); + if (qdisc->fq_codel.interval) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_INTERVAL, qdisc->fq_codel.interval); + if (qdisc->fq_codel.quantum) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum); + if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold); + if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory_limit); + if (qdisc->fq_codel.ecn) + NLA_PUT_U32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn); + } + + nla_nest_end (msg, tc_options); + } return g_steal_pointer (&msg); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 20592b1f15..7d416d5c67 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -6486,6 +6486,19 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len) nm_utils_strbuf_append (&buf, &len, " memory_limit %u", qdisc->fq_codel.memory_limit); if (qdisc->fq_codel.ecn) nm_utils_strbuf_append (&buf, &len, " ecn"); + } else if (nm_streq0 (qdisc->kind, "sfq")) { + if (qdisc->sfq.quantum) + nm_utils_strbuf_append (&buf, &len, " quantum %u", qdisc->sfq.quantum); + if (qdisc->sfq.perturb_period) + nm_utils_strbuf_append (&buf, &len, " perturb %d", qdisc->sfq.perturb_period); + if (qdisc->sfq.limit) + nm_utils_strbuf_append (&buf, &len, " limit %u", (guint) qdisc->sfq.limit); + if (qdisc->sfq.divisor) + nm_utils_strbuf_append (&buf, &len, " divisor %u", qdisc->sfq.divisor); + if (qdisc->sfq.flows) + nm_utils_strbuf_append (&buf, &len, " flows %u", qdisc->sfq.flows); + if (qdisc->sfq.depth) + nm_utils_strbuf_append (&buf, &len, " depth %u", qdisc->sfq.depth); } return buf0; @@ -6512,6 +6525,14 @@ nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h) obj->fq_codel.memory_limit, NM_HASH_COMBINE_BOOLS (guint8, obj->fq_codel.ecn)); + } else if (nm_streq0 (obj->kind, "sfq")) { + nm_hash_update_vals (h, + obj->sfq.quantum, + obj->sfq.perturb_period, + obj->sfq.limit, + obj->sfq.divisor, + obj->sfq.flows, + obj->sfq.depth); } } @@ -6538,6 +6559,13 @@ nm_platform_qdisc_cmp_full (const NMPlatformQdisc *a, NM_CMP_FIELD (a, b, fq_codel.ce_threshold); NM_CMP_FIELD (a, b, fq_codel.memory_limit); NM_CMP_FIELD_UNSAFE (a, b, fq_codel.ecn); + } else if (nm_streq0 (a->kind, "sfq")) { + NM_CMP_FIELD (a, b, sfq.quantum); + NM_CMP_FIELD (a, b, sfq.perturb_period); + NM_CMP_FIELD (a, b, sfq.limit); + NM_CMP_FIELD (a, b, sfq.flows); + NM_CMP_FIELD (a, b, sfq.divisor); + NM_CMP_FIELD (a, b, sfq.depth); } return 0; diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index c4eda16cc4..8b0ec0eb4f 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -630,6 +630,15 @@ typedef struct { } NMPlatformQdiscFqCodel; typedef struct { + unsigned quantum; + int perturb_period; + guint32 limit; + unsigned divisor; + unsigned flows; + unsigned depth; +} NMPlatformQdiscSfq; + +typedef struct { __NMPlatformObjWithIfindex_COMMON; /* beware, kind is embedded in an NMPObject, hence you must @@ -642,6 +651,7 @@ typedef struct { guint32 info; union { NMPlatformQdiscFqCodel fq_codel; + NMPlatformQdiscSfq sfq; }; } NMPlatformQdisc; diff --git a/src/platform/tests/test-tc.c b/src/platform/tests/test-tc.c index dc2bf9f214..0fa4d8d96b 100644 --- a/src/platform/tests/test-tc.c +++ b/src/platform/tests/test-tc.c @@ -75,7 +75,7 @@ test_qdisc1 (void) } static void -test_qdisc2 (void) +test_qdisc_fq_codel (void) { int ifindex; gs_unref_ptrarray GPtrArray *known = NULL; @@ -113,6 +113,45 @@ test_qdisc2 (void) g_assert_cmpint (qdisc->fq_codel.quantum, ==, 1000); } +static void +test_qdisc_sfq (void) +{ + int ifindex; + gs_unref_ptrarray GPtrArray *known = NULL; + gs_unref_ptrarray GPtrArray *plat = NULL; + NMPObject *obj; + NMPlatformQdisc *qdisc; + + ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + g_assert_cmpint (ifindex, >, 0); + + nmtstp_run_command ("tc qdisc del dev %s root", DEVICE_NAME); + + nmtstp_wait_for_signal (NM_PLATFORM_GET, 0); + + known = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); + obj = qdisc_new (ifindex, "sfq", TC_H_ROOT); + obj->qdisc.handle = TC_H_MAKE (0x8143 << 16, 0); + obj->qdisc.sfq.perturb_period = 10; + obj->qdisc.sfq.quantum = 1540; + obj->qdisc.sfq.flows = 256; + g_ptr_array_add (known, obj); + + g_assert (nm_platform_qdisc_sync (NM_PLATFORM_GET, ifindex, known)); + plat = qdiscs_lookup (ifindex); + g_assert (plat); + g_assert_cmpint (plat->len, ==, 1); + + obj = plat->pdata[0]; + qdisc = NMP_OBJECT_CAST_QDISC (obj); + g_assert_cmpstr (qdisc->kind, ==, "sfq"); + g_assert_cmpint (qdisc->handle, ==, TC_H_MAKE (0x8143 << 16, 0)); + g_assert_cmpint (qdisc->parent, ==, TC_H_ROOT); + g_assert_cmpint (qdisc->sfq.perturb_period, ==, 10); + g_assert_cmpint (qdisc->sfq.quantum, ==, 1540); + g_assert_cmpint (qdisc->sfq.flows, ==, 256); +} + /*****************************************************************************/ NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; @@ -128,6 +167,7 @@ _nmtstp_setup_tests (void) { if (nmtstp_is_root_test ()) { nmtstp_env1_add_test_func ("/link/qdisc/1", test_qdisc1, TRUE); - nmtstp_env1_add_test_func ("/link/qdisc/2", test_qdisc2, TRUE); + nmtstp_env1_add_test_func ("/link/qdisc/fq_codel", test_qdisc_fq_codel, TRUE); + nmtstp_env1_add_test_func ("/link/qdisc/sfq", test_qdisc_sfq, TRUE); } } |