tc/qdisc: add support for fq_codel attributes
This commit is contained in:
@@ -2308,12 +2308,25 @@ static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const NMVariantAttributeSpec * const tc_qdisc_fq_codel_spec[] = {
|
||||||
|
TC_ATTR_SPEC_PTR ("limit", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ),
|
||||||
|
TC_ATTR_SPEC_PTR ("flows", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ),
|
||||||
|
TC_ATTR_SPEC_PTR ("target", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ),
|
||||||
|
TC_ATTR_SPEC_PTR ("interval", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ),
|
||||||
|
TC_ATTR_SPEC_PTR ("quantum", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ),
|
||||||
|
TC_ATTR_SPEC_PTR ("ce_threshold", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ),
|
||||||
|
TC_ATTR_SPEC_PTR ("memory", G_VARIANT_TYPE_UINT32, FALSE, FALSE, 0 ),
|
||||||
|
TC_ATTR_SPEC_PTR ("ecn", G_VARIANT_TYPE_BOOLEAN, TRUE, FALSE, 0 ),
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *kind;
|
const char *kind;
|
||||||
const NMVariantAttributeSpec * const *attrs;
|
const NMVariantAttributeSpec * const *attrs;
|
||||||
} NMQdiscAttributeSpec;
|
} NMQdiscAttributeSpec;
|
||||||
|
|
||||||
static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = {
|
static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = {
|
||||||
|
&(const NMQdiscAttributeSpec) { "fq_codel", tc_qdisc_fq_codel_spec },
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -6526,6 +6526,29 @@ tc_commit (NMDevice *self)
|
|||||||
qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc);
|
qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc);
|
||||||
qdisc->info = 0;
|
qdisc->info = 0;
|
||||||
|
|
||||||
|
#define GET_ATTR(name, dst, variant_type, type, dflt) G_STMT_START { \
|
||||||
|
GVariant *_variant = nm_tc_qdisc_get_attribute (s_qdisc, ""name""); \
|
||||||
|
\
|
||||||
|
if ( _variant \
|
||||||
|
&& g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \
|
||||||
|
(dst) = g_variant_get_ ## type (_variant); \
|
||||||
|
else \
|
||||||
|
(dst) = (dflt); \
|
||||||
|
} G_STMT_END
|
||||||
|
|
||||||
|
if (strcmp (qdisc->kind, "fq_codel") == 0) {
|
||||||
|
GET_ATTR("limit", qdisc->fq_codel.limit, UINT32, uint32, 0);
|
||||||
|
GET_ATTR("flows", qdisc->fq_codel.flows, UINT32, uint32, 0);
|
||||||
|
GET_ATTR("target", qdisc->fq_codel.target, UINT32, uint32, 0);
|
||||||
|
GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0);
|
||||||
|
GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0);
|
||||||
|
GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, -1);
|
||||||
|
GET_ATTR("memory", qdisc->fq_codel.memory, UINT32, uint32, -1);
|
||||||
|
GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef GET_ADDR
|
||||||
|
|
||||||
g_ptr_array_add (qdiscs, q);
|
g_ptr_array_add (qdiscs, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -84,6 +84,13 @@ enum {
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/* Compat with older kernels. */
|
||||||
|
|
||||||
|
#define TCA_FQ_CODEL_CE_THRESHOLD 7
|
||||||
|
#define TCA_FQ_CODEL_MEMORY_LIMIT 9
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
#define VLAN_FLAG_MVRP 0x8
|
#define VLAN_FLAG_MVRP 0x8
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -3481,6 +3488,7 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
|
|||||||
{
|
{
|
||||||
static const struct nla_policy policy[] = {
|
static const struct nla_policy policy[] = {
|
||||||
[TCA_KIND] = { .type = NLA_STRING },
|
[TCA_KIND] = { .type = NLA_STRING },
|
||||||
|
[TCA_OPTIONS] = { .type = NLA_NESTED },
|
||||||
};
|
};
|
||||||
struct nlattr *tb[G_N_ELEMENTS (policy)];
|
struct nlattr *tb[G_N_ELEMENTS (policy)];
|
||||||
const struct tcmsg *tcm;
|
const struct tcmsg *tcm;
|
||||||
@@ -3506,6 +3514,45 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
|
|||||||
obj->qdisc.parent = tcm->tcm_parent;
|
obj->qdisc.parent = tcm->tcm_parent;
|
||||||
obj->qdisc.info = tcm->tcm_info;
|
obj->qdisc.info = tcm->tcm_info;
|
||||||
|
|
||||||
|
if (tb[TCA_OPTIONS]) {
|
||||||
|
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 = nla_get_u32 (options_attr);
|
||||||
|
break;
|
||||||
|
case TCA_FQ_CODEL_ECN:
|
||||||
|
obj->qdisc.fq_codel.ecn = nla_get_u32 (options_attr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4161,6 +4208,7 @@ _nl_msg_new_qdisc (int nlmsg_type,
|
|||||||
const NMPlatformQdisc *qdisc)
|
const NMPlatformQdisc *qdisc)
|
||||||
{
|
{
|
||||||
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
nm_auto_nlmsg struct nl_msg *msg = NULL;
|
||||||
|
struct nlattr *tc_options;
|
||||||
const struct tcmsg tcm = {
|
const struct tcmsg tcm = {
|
||||||
.tcm_family = qdisc->addr_family,
|
.tcm_family = qdisc->addr_family,
|
||||||
.tcm_ifindex = qdisc->ifindex,
|
.tcm_ifindex = qdisc->ifindex,
|
||||||
@@ -4176,6 +4224,30 @@ _nl_msg_new_qdisc (int nlmsg_type,
|
|||||||
|
|
||||||
NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind);
|
NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind);
|
||||||
|
|
||||||
|
if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS)))
|
||||||
|
goto nla_put_failure;
|
||||||
|
|
||||||
|
if (strcmp (qdisc->kind, "fq_codel") == 0) {
|
||||||
|
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 != -1)
|
||||||
|
NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold);
|
||||||
|
if (qdisc->fq_codel.memory != -1)
|
||||||
|
NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory);
|
||||||
|
if (qdisc->fq_codel.ecn)
|
||||||
|
NLA_PUT_S32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
|
||||||
|
}
|
||||||
|
|
||||||
|
nla_nest_end (msg, tc_options);
|
||||||
|
|
||||||
return g_steal_pointer (&msg);
|
return g_steal_pointer (&msg);
|
||||||
|
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
|
@@ -6430,7 +6430,7 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
|
|||||||
if (!nm_utils_to_string_buffer_init_null (qdisc, &buf, &len))
|
if (!nm_utils_to_string_buffer_init_null (qdisc, &buf, &len))
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x",
|
nm_utils_strbuf_append (&buf, &len, "%s%s family %u handle %x parent %x info %x",
|
||||||
qdisc->kind,
|
qdisc->kind,
|
||||||
_to_string_dev (NULL, qdisc->ifindex, str_dev, sizeof (str_dev)),
|
_to_string_dev (NULL, qdisc->ifindex, str_dev, sizeof (str_dev)),
|
||||||
qdisc->addr_family,
|
qdisc->addr_family,
|
||||||
@@ -6438,6 +6438,25 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
|
|||||||
qdisc->parent,
|
qdisc->parent,
|
||||||
qdisc->info);
|
qdisc->info);
|
||||||
|
|
||||||
|
if (nm_streq0 (qdisc->kind, "fq_codel")) {
|
||||||
|
if (qdisc->fq_codel.limit)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " limit %u", qdisc->fq_codel.limit);
|
||||||
|
if (qdisc->fq_codel.flows)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " flows %u", qdisc->fq_codel.flows);
|
||||||
|
if (qdisc->fq_codel.target)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " target %u", qdisc->fq_codel.target);
|
||||||
|
if (qdisc->fq_codel.interval)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " interval %u", qdisc->fq_codel.interval);
|
||||||
|
if (qdisc->fq_codel.quantum)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " quantum %u", qdisc->fq_codel.quantum);
|
||||||
|
if (qdisc->fq_codel.ce_threshold != -1)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold);
|
||||||
|
if (qdisc->fq_codel.memory != -1)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " memory %u", qdisc->fq_codel.memory);
|
||||||
|
if (qdisc->fq_codel.ecn)
|
||||||
|
nm_utils_strbuf_append (&buf, &len, " ecn");
|
||||||
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6451,6 +6470,17 @@ nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h)
|
|||||||
obj->handle,
|
obj->handle,
|
||||||
obj->parent,
|
obj->parent,
|
||||||
obj->info);
|
obj->info);
|
||||||
|
if (nm_streq0 (obj->kind, "fq_codel")) {
|
||||||
|
nm_hash_update_vals (h,
|
||||||
|
obj->fq_codel.limit,
|
||||||
|
obj->fq_codel.flows,
|
||||||
|
obj->fq_codel.target,
|
||||||
|
obj->fq_codel.interval,
|
||||||
|
obj->fq_codel.quantum,
|
||||||
|
obj->fq_codel.ce_threshold,
|
||||||
|
obj->fq_codel.memory,
|
||||||
|
obj->fq_codel.ecn == TRUE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -6464,6 +6494,17 @@ nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
|
|||||||
NM_CMP_FIELD (a, b, handle);
|
NM_CMP_FIELD (a, b, handle);
|
||||||
NM_CMP_FIELD (a, b, info);
|
NM_CMP_FIELD (a, b, info);
|
||||||
|
|
||||||
|
if (nm_streq0 (a->kind, "fq_codel")) {
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.limit);
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.flows);
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.target);
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.interval);
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.quantum);
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.ce_threshold);
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.memory);
|
||||||
|
NM_CMP_FIELD (a, b, fq_codel.ecn == TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -596,6 +596,17 @@ typedef struct {
|
|||||||
bool uid_range_has:1; /* has(FRA_UID_RANGE) */
|
bool uid_range_has:1; /* has(FRA_UID_RANGE) */
|
||||||
} NMPlatformRoutingRule;
|
} NMPlatformRoutingRule;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
guint32 limit;
|
||||||
|
guint32 flows;
|
||||||
|
guint32 target;
|
||||||
|
guint32 interval;
|
||||||
|
guint32 quantum;
|
||||||
|
guint32 ce_threshold;
|
||||||
|
guint32 memory;
|
||||||
|
bool ecn:1;
|
||||||
|
} NMPlatformQdiscFqCodel;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
__NMPlatformObjWithIfindex_COMMON;
|
__NMPlatformObjWithIfindex_COMMON;
|
||||||
const char *kind;
|
const char *kind;
|
||||||
@@ -603,6 +614,9 @@ typedef struct {
|
|||||||
guint32 handle;
|
guint32 handle;
|
||||||
guint32 parent;
|
guint32 parent;
|
||||||
guint32 info;
|
guint32 info;
|
||||||
|
union {
|
||||||
|
NMPlatformQdiscFqCodel fq_codel;
|
||||||
|
};
|
||||||
} NMPlatformQdisc;
|
} NMPlatformQdisc;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
Reference in New Issue
Block a user