Blame SOURCES/1007-tc-update-rh1546802.patch

7b922c
From 67047a444d45dd6e74d381cfe06a418c13693539 Mon Sep 17 00:00:00 2001
7b922c
From: Lubomir Rintel <lkundrak@v3.sk>
7b922c
Date: Tue, 9 Apr 2019 13:42:52 +0200
7b922c
Subject: [PATCH 01/20] tc/qdisc: add support for fq_codel attributes
7b922c
7b922c
(cherry picked from commit 1efe982e39be7e8b7852a19957c7b49cab46e67c)
7b922c
---
7b922c
 libnm-core/nm-utils.c            | 13 ++++++
7b922c
 src/devices/nm-device.c          | 23 ++++++++++
7b922c
 src/platform/nm-linux-platform.c | 72 ++++++++++++++++++++++++++++++++
7b922c
 src/platform/nm-platform.c       | 55 ++++++++++++++++++++----
7b922c
 src/platform/nm-platform.h       | 14 +++++++
7b922c
 5 files changed, 170 insertions(+), 7 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index 04d5b1b558..b82c580345 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2309,12 +2309,25 @@ static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = {
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
+static const NMVariantAttributeSpec * const tc_qdisc_fq_codel_spec[] = {
7b922c
+	TC_ATTR_SPEC_PTR ("limit",        G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("flows",        G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("target",       G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("interval",     G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("quantum",      G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("ce_threshold", G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("memory",       G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("ecn",          G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
+	NULL,
7b922c
+};
7b922c
+
7b922c
 typedef struct {
7b922c
 	const char *kind;
7b922c
 	const NMVariantAttributeSpec * const *attrs;
7b922c
 } NMQdiscAttributeSpec;
7b922c
 
7b922c
 static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = {
7b922c
+	&(const NMQdiscAttributeSpec) { "fq_codel", tc_qdisc_fq_codel_spec },
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index 60709c50d5..195686707b 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6522,6 +6522,29 @@ tc_commit (NMDevice *self)
7b922c
 			qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc);
7b922c
 			qdisc->info = 0;
7b922c
 
7b922c
+#define GET_ATTR(name, dst, variant_type, type, dflt) G_STMT_START { \
7b922c
+	GVariant *_variant = nm_tc_qdisc_get_attribute (s_qdisc, ""name""); \
7b922c
+	\
7b922c
+	if (   _variant \
7b922c
+	    && g_variant_is_of_type (_variant, G_VARIANT_TYPE_ ## variant_type)) \
7b922c
+		(dst) = g_variant_get_ ## type (_variant); \
7b922c
+	else \
7b922c
+		(dst) = (dflt); \
7b922c
+} G_STMT_END
7b922c
+
7b922c
+			if (strcmp (qdisc->kind, "fq_codel") == 0) {
7b922c
+				GET_ATTR("limit", qdisc->fq_codel.limit, UINT32, uint32, 0);
7b922c
+				GET_ATTR("flows", qdisc->fq_codel.flows, UINT32, uint32, 0);
7b922c
+				GET_ATTR("target", qdisc->fq_codel.target, UINT32, uint32, 0);
7b922c
+				GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0);
7b922c
+				GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0);
7b922c
+				GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, -1);
7b922c
+				GET_ATTR("memory", qdisc->fq_codel.memory, UINT32, uint32, -1);
7b922c
+				GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE);
7b922c
+			}
7b922c
+
7b922c
+#undef GET_ADDR
7b922c
+
7b922c
 			g_ptr_array_add (qdiscs, q);
7b922c
 		}
7b922c
 
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index d4b0115252..a346d6618c 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -84,6 +84,13 @@ enum {
7b922c
 
7b922c
 /*****************************************************************************/
7b922c
 
7b922c
+/* Compat with older kernels. */
7b922c
+
7b922c
+#define TCA_FQ_CODEL_CE_THRESHOLD 7
7b922c
+#define TCA_FQ_CODEL_MEMORY_LIMIT 9
7b922c
+
7b922c
+/*****************************************************************************/
7b922c
+
7b922c
 #define VLAN_FLAG_MVRP 0x8
7b922c
 
7b922c
 /*****************************************************************************/
7b922c
@@ -3481,6 +3488,7 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
7b922c
 {
7b922c
 	static const struct nla_policy policy[] = {
7b922c
 		[TCA_KIND] = { .type = NLA_STRING },
7b922c
+		[TCA_OPTIONS] = { .type = NLA_NESTED },
7b922c
 	};
7b922c
 	struct nlattr *tb[G_N_ELEMENTS (policy)];
7b922c
 	const struct tcmsg *tcm;
7b922c
@@ -3506,6 +3514,45 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
7b922c
 	obj->qdisc.parent = tcm->tcm_parent;
7b922c
 	obj->qdisc.info = tcm->tcm_info;
7b922c
 
7b922c
+	if (tb[TCA_OPTIONS]) {
7b922c
+		struct nlattr *options_attr;
7b922c
+		int remaining;
7b922c
+
7b922c
+		nla_for_each_nested (options_attr, tb[TCA_OPTIONS], remaining) {
7b922c
+			if (nla_len (options_attr) < sizeof (uint32_t))
7b922c
+				continue;
7b922c
+
7b922c
+			if (nm_streq0 (obj->qdisc.kind, "fq_codel")) {
7b922c
+				switch (nla_type (options_attr)) {
7b922c
+				case TCA_FQ_CODEL_LIMIT:
7b922c
+					obj->qdisc.fq_codel.limit = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				case TCA_FQ_CODEL_FLOWS:
7b922c
+					obj->qdisc.fq_codel.flows = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				case TCA_FQ_CODEL_TARGET:
7b922c
+					obj->qdisc.fq_codel.target = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				case TCA_FQ_CODEL_INTERVAL:
7b922c
+					obj->qdisc.fq_codel.interval = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				case TCA_FQ_CODEL_QUANTUM:
7b922c
+					obj->qdisc.fq_codel.quantum = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				case TCA_FQ_CODEL_CE_THRESHOLD:
7b922c
+					obj->qdisc.fq_codel.ce_threshold = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				case TCA_FQ_CODEL_MEMORY_LIMIT:
7b922c
+					obj->qdisc.fq_codel.memory = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				case TCA_FQ_CODEL_ECN:
7b922c
+					obj->qdisc.fq_codel.ecn = nla_get_u32 (options_attr);
7b922c
+					break;
7b922c
+				}
7b922c
+			}
7b922c
+		}
7b922c
+	}
7b922c
+
7b922c
 	return obj;
7b922c
 }
7b922c
 
7b922c
@@ -4161,6 +4208,7 @@ _nl_msg_new_qdisc (int nlmsg_type,
7b922c
                    const NMPlatformQdisc *qdisc)
7b922c
 {
7b922c
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
7b922c
+	struct nlattr *tc_options;
7b922c
 	const struct tcmsg tcm = {
7b922c
 		.tcm_family = qdisc->addr_family,
7b922c
 		.tcm_ifindex = qdisc->ifindex,
7b922c
@@ -4176,6 +4224,30 @@ _nl_msg_new_qdisc (int nlmsg_type,
7b922c
 
7b922c
 	NLA_PUT_STRING (msg, TCA_KIND, qdisc->kind);
7b922c
 
7b922c
+	if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS)))
7b922c
+		goto nla_put_failure;
7b922c
+
7b922c
+	if (strcmp (qdisc->kind, "fq_codel") == 0) {
7b922c
+		if (qdisc->fq_codel.limit)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_LIMIT, qdisc->fq_codel.limit);
7b922c
+		if (qdisc->fq_codel.flows)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_FLOWS, qdisc->fq_codel.flows);
7b922c
+		if (qdisc->fq_codel.target)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_TARGET, qdisc->fq_codel.target);
7b922c
+		if (qdisc->fq_codel.interval)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_INTERVAL, qdisc->fq_codel.interval);
7b922c
+		if (qdisc->fq_codel.quantum)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum);
7b922c
+		if (qdisc->fq_codel.ce_threshold != -1)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold);
7b922c
+		if (qdisc->fq_codel.memory != -1)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory);
7b922c
+		if (qdisc->fq_codel.ecn)
7b922c
+			NLA_PUT_S32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
7b922c
+	}
7b922c
+
7b922c
+	nla_nest_end (msg, tc_options);
7b922c
+
7b922c
 	return g_steal_pointer (&msg;;
7b922c
 
7b922c
 nla_put_failure:
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index 1fc0ccb750..3d78902860 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -6430,13 +6430,32 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
7b922c
 	if (!nm_utils_to_string_buffer_init_null (qdisc, &buf, &len))
7b922c
 		return buf;
7b922c
 
7b922c
-	g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x",
7b922c
-	            qdisc->kind,
7b922c
-	            _to_string_dev (NULL, qdisc->ifindex, str_dev, sizeof (str_dev)),
7b922c
-	            qdisc->addr_family,
7b922c
-	            qdisc->handle,
7b922c
-	            qdisc->parent,
7b922c
-	            qdisc->info);
7b922c
+	nm_utils_strbuf_append (&buf, &len, "%s%s family %u handle %x parent %x info %x",
7b922c
+	                        qdisc->kind,
7b922c
+	                        _to_string_dev (NULL, qdisc->ifindex, str_dev, sizeof (str_dev)),
7b922c
+	                        qdisc->addr_family,
7b922c
+	                        qdisc->handle,
7b922c
+	                        qdisc->parent,
7b922c
+	                        qdisc->info);
7b922c
+
7b922c
+	if (nm_streq0 (qdisc->kind, "fq_codel")) {
7b922c
+		if (qdisc->fq_codel.limit)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " limit %u", qdisc->fq_codel.limit);
7b922c
+		if (qdisc->fq_codel.flows)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " flows %u", qdisc->fq_codel.flows);
7b922c
+		if (qdisc->fq_codel.target)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " target %u", qdisc->fq_codel.target);
7b922c
+		if (qdisc->fq_codel.interval)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " interval %u", qdisc->fq_codel.interval);
7b922c
+		if (qdisc->fq_codel.quantum)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " quantum %u", qdisc->fq_codel.quantum);
7b922c
+		if (qdisc->fq_codel.ce_threshold != -1)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold);
7b922c
+		if (qdisc->fq_codel.memory != -1)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " memory %u", qdisc->fq_codel.memory);
7b922c
+		if (qdisc->fq_codel.ecn)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " ecn");
7b922c
+	}
7b922c
 
7b922c
 	return buf;
7b922c
 }
7b922c
@@ -6451,6 +6470,17 @@ nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h)
7b922c
 	                     obj->handle,
7b922c
 	                     obj->parent,
7b922c
 	                     obj->info);
7b922c
+	if (nm_streq0 (obj->kind, "fq_codel")) {
7b922c
+		nm_hash_update_vals (h,
7b922c
+		                     obj->fq_codel.limit,
7b922c
+		                     obj->fq_codel.flows,
7b922c
+		                     obj->fq_codel.target,
7b922c
+		                     obj->fq_codel.interval,
7b922c
+		                     obj->fq_codel.quantum,
7b922c
+		                     obj->fq_codel.ce_threshold,
7b922c
+		                     obj->fq_codel.memory,
7b922c
+		                     obj->fq_codel.ecn == TRUE);
7b922c
+	}
7b922c
 }
7b922c
 
7b922c
 int
7b922c
@@ -6464,6 +6494,17 @@ nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
7b922c
 	NM_CMP_FIELD (a, b, handle);
7b922c
 	NM_CMP_FIELD (a, b, info);
7b922c
 
7b922c
+	if (nm_streq0 (a->kind, "fq_codel")) {
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.limit);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.flows);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.target);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.interval);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.quantum);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.ce_threshold);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.memory);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.ecn == TRUE);
7b922c
+	}
7b922c
+
7b922c
 	return 0;
7b922c
 }
7b922c
 
7b922c
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
7b922c
index 97be88324e..8742b90555 100644
7b922c
--- a/src/platform/nm-platform.h
7b922c
+++ b/src/platform/nm-platform.h
7b922c
@@ -596,6 +596,17 @@ typedef struct {
7b922c
 	bool     uid_range_has:1;            /* has(FRA_UID_RANGE) */
7b922c
 } NMPlatformRoutingRule;
7b922c
 
7b922c
+typedef struct {
7b922c
+	guint32 limit;
7b922c
+	guint32 flows;
7b922c
+	guint32 target;
7b922c
+	guint32 interval;
7b922c
+	guint32 quantum;
7b922c
+	guint32 ce_threshold;
7b922c
+	guint32 memory;
7b922c
+	bool ecn:1;
7b922c
+} NMPlatformQdiscFqCodel;
7b922c
+
7b922c
 typedef struct {
7b922c
 	__NMPlatformObjWithIfindex_COMMON;
7b922c
 	const char *kind;
7b922c
@@ -603,6 +614,9 @@ typedef struct {
7b922c
 	guint32 handle;
7b922c
 	guint32 parent;
7b922c
 	guint32 info;
7b922c
+	union {
7b922c
+		NMPlatformQdiscFqCodel fq_codel;
7b922c
+	};
7b922c
 } NMPlatformQdisc;
7b922c
 
7b922c
 typedef struct {
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 4be7cf71e06da4801d8bb066b977c733e7e7097c Mon Sep 17 00:00:00 2001
7b922c
From: Lubomir Rintel <lkundrak@v3.sk>
7b922c
Date: Tue, 9 Apr 2019 16:23:39 +0200
7b922c
Subject: [PATCH 02/20] tc/tfilter: add mirred action
7b922c
7b922c
(cherry picked from commit 900292147d8fd584479a7af0881984c2d77a60bf)
7b922c
---
7b922c
 libnm-core/nm-utils.c            | 11 +++++++++++
7b922c
 src/devices/nm-device.c          | 29 +++++++++++++++++++++++-----
7b922c
 src/platform/nm-linux-platform.c | 33 ++++++++++++++++++++++++++++++++
7b922c
 src/platform/nm-platform.c       | 29 +++++++++++++++++++++++++---
7b922c
 src/platform/nm-platform.h       | 10 ++++++++++
7b922c
 5 files changed, 104 insertions(+), 8 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index b82c580345..3af3e04ed9 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2542,6 +2542,15 @@ static const NMVariantAttributeSpec * const tc_action_simple_attribute_spec[] =
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
+static const NMVariantAttributeSpec * const tc_action_mirred_attribute_spec[] = {
7b922c
+	TC_ATTR_SPEC_PTR ("egress",   G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("ingress",  G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("mirror",   G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("redirect", G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
+	TC_ATTR_SPEC_PTR ("dev",      G_VARIANT_TYPE_STRING,  TRUE,  FALSE, 'a' ),
7b922c
+	NULL,
7b922c
+};
7b922c
+
7b922c
 static const NMVariantAttributeSpec * const tc_action_attribute_spec[] = {
7b922c
 	TC_ATTR_SPEC_PTR ("kind",    G_VARIANT_TYPE_STRING,      TRUE,  FALSE, 'a' ),
7b922c
 	TC_ATTR_SPEC_PTR ("",        G_VARIANT_TYPE_STRING,      TRUE,  TRUE,  'a' ),
7b922c
@@ -2636,6 +2645,8 @@ nm_utils_tc_action_from_str (const char *str, GError **error)
7b922c
 	kind = g_variant_get_string (variant, NULL);
7b922c
 	if (strcmp (kind, "simple") == 0)
7b922c
 		attrs = tc_action_simple_attribute_spec;
7b922c
+	else if (strcmp (kind, "mirred") == 0)
7b922c
+		attrs = tc_action_mirred_attribute_spec;
7b922c
 	else
7b922c
 		attrs = NULL;
7b922c
 
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index 195686707b..ea6ad7e2ad 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6566,16 +6566,35 @@ tc_commit (NMDevice *self)
7b922c
 
7b922c
 			action = nm_tc_tfilter_get_action (s_tfilter);
7b922c
 			if (action) {
7b922c
+				GVariant *var;
7b922c
+
7b922c
 				tfilter->action.kind = nm_tc_action_get_kind (action);
7b922c
 				if (strcmp (tfilter->action.kind, "simple") == 0) {
7b922c
-					GVariant *sdata;
7b922c
-
7b922c
-					sdata = nm_tc_action_get_attribute (action, "sdata");
7b922c
-					if (sdata && g_variant_is_of_type (sdata, G_VARIANT_TYPE_BYTESTRING)) {
7b922c
+					var = nm_tc_action_get_attribute (action, "sdata");
7b922c
+					if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_BYTESTRING)) {
7b922c
 						g_strlcpy (tfilter->action.simple.sdata,
7b922c
-						           g_variant_get_bytestring (sdata),
7b922c
+						           g_variant_get_bytestring (var),
7b922c
 						           sizeof (tfilter->action.simple.sdata));
7b922c
 					}
7b922c
+				} else if (strcmp (tfilter->action.kind, "mirred") == 0) {
7b922c
+					if (nm_tc_action_get_attribute (action, "egress"))
7b922c
+						tfilter->action.mirred.egress = TRUE;
7b922c
+
7b922c
+					if (nm_tc_action_get_attribute (action, "ingress"))
7b922c
+						tfilter->action.mirred.ingress = TRUE;
7b922c
+
7b922c
+					if (nm_tc_action_get_attribute (action, "mirror"))
7b922c
+						tfilter->action.mirred.mirror = TRUE;
7b922c
+
7b922c
+					if (nm_tc_action_get_attribute (action, "redirect"))
7b922c
+						tfilter->action.mirred.redirect = TRUE;
7b922c
+
7b922c
+					var = nm_tc_action_get_attribute (action, "dev");
7b922c
+					if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_STRING)) {
7b922c
+						int ifindex = nm_platform_link_get_ifindex (nm_device_get_platform (self),
7b922c
+						                                            g_variant_get_string (var, NULL));
7b922c
+						tfilter->action.mirred.ifindex = ifindex;
7b922c
+					}
7b922c
 				}
7b922c
 			}
7b922c
 
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index a346d6618c..6064d89eb6 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -34,6 +34,7 @@
7b922c
 #include <linux/if_tun.h>
7b922c
 #include <linux/if_tunnel.h>
7b922c
 #include <linux/ip6_tunnel.h>
7b922c
+#include <linux/tc_act/tc_mirred.h>
7b922c
 #include <netinet/icmp6.h>
7b922c
 #include <netinet/in.h>
7b922c
 #include <poll.h>
7b922c
@@ -4275,6 +4276,36 @@ nla_put_failure:
7b922c
 	return FALSE;
7b922c
 }
7b922c
 
7b922c
+static gboolean
7b922c
+_add_action_mirred (struct nl_msg *msg,
7b922c
+                    const NMPlatformActionMirred *mirred)
7b922c
+{
7b922c
+	struct nlattr *act_options;
7b922c
+	struct tc_mirred sel = { 0, };
7b922c
+
7b922c
+	if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS)))
7b922c
+		goto nla_put_failure;
7b922c
+
7b922c
+	if (mirred->egress && mirred->redirect)
7b922c
+		sel.eaction = TCA_EGRESS_REDIR;
7b922c
+	else if (mirred->egress && mirred->mirror)
7b922c
+		sel.eaction = TCA_EGRESS_MIRROR;
7b922c
+	else if (mirred->ingress && mirred->redirect)
7b922c
+		sel.eaction = TCA_INGRESS_REDIR;
7b922c
+	else if (mirred->ingress && mirred->mirror)
7b922c
+		sel.eaction = TCA_INGRESS_MIRROR;
7b922c
+	sel.ifindex = mirred->ifindex;
7b922c
+
7b922c
+	NLA_PUT (msg, TCA_MIRRED_PARMS, sizeof (sel), &sel;;
7b922c
+
7b922c
+	nla_nest_end (msg, act_options);
7b922c
+
7b922c
+	return TRUE;
7b922c
+
7b922c
+nla_put_failure:
7b922c
+	return FALSE;
7b922c
+}
7b922c
+
7b922c
 static gboolean
7b922c
 _add_action (struct nl_msg *msg,
7b922c
              const NMPlatformAction *action)
7b922c
@@ -4290,6 +4321,8 @@ _add_action (struct nl_msg *msg,
7b922c
 
7b922c
 	if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE))
7b922c
 		_add_action_simple (msg, &action->simple);
7b922c
+	else if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_MIRRED))
7b922c
+		_add_action_mirred (msg, &action->mirred);
7b922c
 
7b922c
 	nla_nest_end (msg, prio);
7b922c
 
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index 3d78902860..6f23ddb589 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -34,6 +34,7 @@
7b922c
 #include <linux/if_tun.h>
7b922c
 #include <linux/if_tunnel.h>
7b922c
 #include <linux/rtnetlink.h>
7b922c
+#include <linux/tc_act/tc_mirred.h>
7b922c
 #include <libudev.h>
7b922c
 
7b922c
 #include "nm-utils.h"
7b922c
@@ -6533,11 +6534,18 @@ nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsiz
7b922c
 			                                                        NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL
7b922c
 			                                                      | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII,
7b922c
 			                                                      &t);;
7b922c
+		} else if (nm_streq (tfilter->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
7b922c
+			nm_utils_strbuf_append (&p, &l, "%s%s%s%s dev %d",
7b922c
+			                        tfilter->action.mirred.ingress ? " ingress" : "",
7b922c
+			                        tfilter->action.mirred.egress ? " egress" : "",
7b922c
+			                        tfilter->action.mirred.mirror ? " mirror" : "",
7b922c
+			                        tfilter->action.mirred.redirect ? " redirect" : "",
7b922c
+			                        tfilter->action.mirred.ifindex);
7b922c
 		}
7b922c
 	} else
7b922c
 		act_buf[0] = '\0';
7b922c
 
7b922c
-	g_snprintf (buf, len, "%s%s family %d handle %x parent %x info %x%s",
7b922c
+	g_snprintf (buf, len, "%s%s family %u handle %x parent %x info %x%s",
7b922c
 	            tfilter->kind,
7b922c
 	            _to_string_dev (NULL, tfilter->ifindex, str_dev, sizeof (str_dev)),
7b922c
 	            tfilter->addr_family,
7b922c
@@ -6561,8 +6569,16 @@ nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h)
7b922c
 	                     obj->info);
7b922c
 	if (obj->action.kind) {
7b922c
 		nm_hash_update_str (h, obj->action.kind);
7b922c
-		if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE))
7b922c
+		if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
7b922c
 			nm_hash_update_strarr (h, obj->action.simple.sdata);
7b922c
+		} else if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
7b922c
+			nm_hash_update_vals (h,
7b922c
+			                     obj->action.mirred.ingress,
7b922c
+			                     obj->action.mirred.egress,
7b922c
+			                     obj->action.mirred.mirror,
7b922c
+			                     obj->action.mirred.redirect,
7b922c
+			                     obj->action.mirred.ifindex);
7b922c
+		}
7b922c
 	}
7b922c
 }
7b922c
 
7b922c
@@ -6579,8 +6595,15 @@ nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b)
7b922c
 
7b922c
 	NM_CMP_FIELD_STR_INTERNED (a, b, action.kind);
7b922c
 	if (a->action.kind) {
7b922c
-		if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE))
7b922c
+		if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
7b922c
 			NM_CMP_FIELD_STR (a, b, action.simple.sdata);
7b922c
+		} else if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
7b922c
+			NM_CMP_FIELD (a, b, action.mirred.ingress);
7b922c
+			NM_CMP_FIELD (a, b, action.mirred.egress);
7b922c
+			NM_CMP_FIELD (a, b, action.mirred.mirror);
7b922c
+			NM_CMP_FIELD (a, b, action.mirred.redirect);
7b922c
+			NM_CMP_FIELD (a, b, action.mirred.ifindex);
7b922c
+		}
7b922c
 	}
7b922c
 
7b922c
 	return 0;
7b922c
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
7b922c
index 8742b90555..16747f093b 100644
7b922c
--- a/src/platform/nm-platform.h
7b922c
+++ b/src/platform/nm-platform.h
7b922c
@@ -623,14 +623,24 @@ typedef struct {
7b922c
 	char sdata[32];
7b922c
 } NMPlatformActionSimple;
7b922c
 
7b922c
+typedef struct {
7b922c
+	gboolean egress;
7b922c
+	gboolean ingress;
7b922c
+	gboolean mirror;
7b922c
+	gboolean redirect;
7b922c
+	int ifindex;
7b922c
+} NMPlatformActionMirred;
7b922c
+
7b922c
 typedef struct {
7b922c
 	const char *kind;
7b922c
 	union {
7b922c
 		NMPlatformActionSimple simple;
7b922c
+		NMPlatformActionMirred mirred;
7b922c
 	};
7b922c
 } NMPlatformAction;
7b922c
 
7b922c
 #define NM_PLATFORM_ACTION_KIND_SIMPLE "simple"
7b922c
+#define NM_PLATFORM_ACTION_KIND_MIRRED "mirred"
7b922c
 
7b922c
 typedef struct {
7b922c
 	__NMPlatformObjWithIfindex_COMMON;
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 84bd35e4fadf0aa8244b2c683c60fdfc4b87cf6f Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 11:36:02 +0200
7b922c
Subject: [PATCH 03/20] shared: use nm_str_skip_leading_spaces() in
7b922c
 _nm_utils_ascii_str_to_int64()
7b922c
7b922c
(cherry picked from commit 9d2623cceb8550fbe6becf5dde2e0cef152e1086)
7b922c
---
7b922c
 shared/nm-glib-aux/nm-shared-utils.c | 9 +++------
7b922c
 1 file changed, 3 insertions(+), 6 deletions(-)
7b922c
7b922c
diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c
7b922c
index cf08a77fde..fb945ef9fb 100644
7b922c
--- a/shared/nm-glib-aux/nm-shared-utils.c
7b922c
+++ b/shared/nm-glib-aux/nm-shared-utils.c
7b922c
@@ -734,10 +734,7 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
7b922c
 	gint64 v;
7b922c
 	const char *s = NULL;
7b922c
 
7b922c
-	if (str) {
7b922c
-		while (g_ascii_isspace (str[0]))
7b922c
-			str++;
7b922c
-	}
7b922c
+	str = nm_str_skip_leading_spaces (str);
7b922c
 	if (!str || !str[0]) {
7b922c
 		errno = EINVAL;
7b922c
 		return fallback;
7b922c
@@ -748,9 +745,9 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
7b922c
 
7b922c
 	if (errno != 0)
7b922c
 		return fallback;
7b922c
+
7b922c
 	if (s[0] != '\0') {
7b922c
-		while (g_ascii_isspace (s[0]))
7b922c
-			s++;
7b922c
+		s = nm_str_skip_leading_spaces (s);
7b922c
 		if (s[0] != '\0') {
7b922c
 			errno = EINVAL;
7b922c
 			return fallback;
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 13e3bd4161d11c81cd4188a733c6d370d41452c3 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 10:49:16 +0200
7b922c
Subject: [PATCH 04/20] libnm/tests: add test for _nm_utils_parse_tc_handle()
7b922c
7b922c
(cherry picked from commit fac95d0062d9bbe256b8e479ba7cb452cbac340e)
7b922c
---
7b922c
 libnm-core/tests/test-setting.c | 56 +++++++++++++++++++++++++++++++++
7b922c
 1 file changed, 56 insertions(+)
7b922c
7b922c
diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c
7b922c
index 03100a039b..7587b65ba7 100644
7b922c
--- a/libnm-core/tests/test-setting.c
7b922c
+++ b/libnm-core/tests/test-setting.c
7b922c
@@ -2979,6 +2979,60 @@ test_routing_rule (gconstpointer test_data)
7b922c
 
7b922c
 /*****************************************************************************/
7b922c
 
7b922c
+static void
7b922c
+test_parse_tc_handle (void)
7b922c
+{
7b922c
+#define _parse_tc_handle(str, exp) \
7b922c
+	G_STMT_START { \
7b922c
+		gs_free_error GError *_error = NULL; \
7b922c
+		GError **_perror = nmtst_get_rand_bool () ? &_error : NULL; \
7b922c
+		guint32 _v; \
7b922c
+		const guint32 _v_exp = (exp); \
7b922c
+		\
7b922c
+		_v = _nm_utils_parse_tc_handle (""str"", _perror); \
7b922c
+		\
7b922c
+		if (_v != _v_exp) \
7b922c
+			g_error ("%s:%d: \"%s\" gave %08x but %08x expected.", __FILE__, __LINE__, ""str"", _v, _v_exp); \
7b922c
+		\
7b922c
+		if (_v == TC_H_UNSPEC) \
7b922c
+			g_assert (!_perror || *_perror); \
7b922c
+		else \
7b922c
+			g_assert (!_perror || !*_perror); \
7b922c
+		\
7b922c
+	} G_STMT_END
7b922c
+
7b922c
+#define _parse_tc_handle_inval(str)           _parse_tc_handle (str, TC_H_UNSPEC)
7b922c
+#define _parse_tc_handle_valid(str, maj, min) _parse_tc_handle (str, TC_H_MAKE (((guint32) (maj)) << 16, ((guint16) (min))))
7b922c
+
7b922c
+	_parse_tc_handle_inval ("");
7b922c
+	_parse_tc_handle_inval (" ");
7b922c
+	_parse_tc_handle_inval (" \n");
7b922c
+	_parse_tc_handle_valid ("1", 1, 0);
7b922c
+	_parse_tc_handle_inval(" 1 ");
7b922c
+	_parse_tc_handle_valid ("1:", 1, 0);
7b922c
+	_parse_tc_handle_inval ("1:  ");
7b922c
+	_parse_tc_handle_valid ("1:0", 1, 0);
7b922c
+	_parse_tc_handle_inval ("1   :0");
7b922c
+	_parse_tc_handle_inval ("1   \t\n\f\r:0");
7b922c
+	_parse_tc_handle_inval ("1   \t\n\f\r\v:0");
7b922c
+	_parse_tc_handle_inval (" 1 : 0  ");
7b922c
+	_parse_tc_handle_valid (" \t\v\n1: 0", 1, 0);
7b922c
+	_parse_tc_handle_valid ("1:2", 1, 2);
7b922c
+	_parse_tc_handle_valid ("01:02", 1, 2);
7b922c
+	_parse_tc_handle_valid ("0x01:0x02", 1, 2);
7b922c
+	_parse_tc_handle_valid ("  01:   02", 1, 2);
7b922c
+	_parse_tc_handle_valid ("019:   020", 0x19, 0x20);
7b922c
+	_parse_tc_handle_valid ("FFFF:   020", 0xFFFF, 0x20);
7b922c
+	_parse_tc_handle_valid ("FfFF:   ffff", 0xFFFF, 0xFFFF);
7b922c
+	_parse_tc_handle_valid ("FFFF", 0xFFFF, 0);
7b922c
+	_parse_tc_handle_valid ("0xFFFF", 0xFFFF, 0);
7b922c
+	_parse_tc_handle_inval ("10000");
7b922c
+	_parse_tc_handle_valid ("\t\n\f\r FFFF", 0xFFFF, 0);
7b922c
+	_parse_tc_handle_valid ("\t\n\f\r \vFFFF", 0xFFFF, 0);
7b922c
+}
7b922c
+
7b922c
+/*****************************************************************************/
7b922c
+
7b922c
 NMTST_DEFINE ();
7b922c
 
7b922c
 int
7b922c
@@ -3064,5 +3118,7 @@ main (int argc, char **argv)
7b922c
 
7b922c
 	g_test_add_data_func ("/libnm/settings/routing-rule/1", GINT_TO_POINTER (0), test_routing_rule);
7b922c
 
7b922c
+	g_test_add_func ("/libnm/parse-tc-handle", test_parse_tc_handle);
7b922c
+
7b922c
 	return g_test_run ();
7b922c
 }
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From b954ddc2752285b28885398441879edb922c68fc Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 10:27:32 +0200
7b922c
Subject: [PATCH 05/20] libnm: cleanup _nm_utils_parse_tc_handle()
7b922c
7b922c
- g_ascii_strtoll() accepts leading spaces, but it leaves
7b922c
  the end pointer at the first space after the digit. That means,
7b922c
  we accepted "1: 0" but not "1 :0". We should either consistently
7b922c
  accept spaces around the digits/colon or reject it.
7b922c
7b922c
- g_ascii_strtoll() accepts "\v" as a space (just like `man 3 isspace`
7b922c
  comments that "\v" is a space in C and POSIX locale.
7b922c
  For some reasons (unknown to me) g_ascii_isspace() does not treat
7b922c
  "\v" as space. And neither does NM_ASCII_SPACES and
7b922c
  nm_str_skip_leading_spaces().
7b922c
  We should be consistent about what we consider spaces and what not.
7b922c
  It's already odd to accept '\n' as spaces here, but well, lets do
7b922c
  it for the sake of consistency (so that it matches with our
7b922c
  understanding of ASCII spaces, albeit not POSIX's).
7b922c
7b922c
- don't use bogus error domains in "g_set_error (error, 1, 0, ..."
7b922c
  That is a bug and we have NM_UTILS_ERROR exactly for error instances
7b922c
  with unspecified domain and code.
7b922c
7b922c
- as before, accept a trailing ":" with omitted minor number.
7b922c
7b922c
- reject all unexpected characters. strtoll() accepts '+' / '-'
7b922c
  and a "0x" prefix of the numbers (and leading POSIX spaces). Be
7b922c
  strict here and only accepts NM_ASCII_SPACES, ':', and hexdigits.
7b922c
  In particular, don't accept the "0x" prefix.
7b922c
7b922c
This parsing would be significantly simpler to implement, if we could
7b922c
just strdup() the string, split the string at the colon delimiter and
7b922c
use _nm_utils_ascii_str_to_int64() which gets leading/trailing spaces
7b922c
right. But let's save the "overhead" of an additional alloc.
7b922c
7b922c
(cherry picked from commit cc9f07167607124bcb0df735034858aadfdb8541)
7b922c
---
7b922c
 libnm-core/nm-utils.c           | 43 ++++++++++++++++++++++++---------
7b922c
 libnm-core/tests/test-setting.c | 18 +++++++-------
7b922c
 2 files changed, 41 insertions(+), 20 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index 3af3e04ed9..7a7c6de114 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2280,21 +2280,42 @@ _nm_utils_string_append_tc_parent (GString *string, const char *prefix, guint32
7b922c
 guint32
7b922c
 _nm_utils_parse_tc_handle (const char *str, GError **error)
7b922c
 {
7b922c
-	gint64 maj, min;
7b922c
-	char *sep;
7b922c
+	gint64 maj;
7b922c
+	gint64 min = 0;
7b922c
+	const char *sep;
7b922c
 
7b922c
-	maj = g_ascii_strtoll (str, &sep, 0x10);
7b922c
-	if (*sep == ':')
7b922c
-		min = g_ascii_strtoll (&sep[1], &sep, 0x10);
7b922c
-	else
7b922c
-		min = 0;
7b922c
+	nm_assert (str);
7b922c
 
7b922c
-	if (*sep != '\0' || maj <= 0 || maj > 0xffff || min < 0 || min > 0xffff) {
7b922c
-		g_set_error (error, 1, 0, _("'%s' is not a valid handle."), str);
7b922c
-		return TC_H_UNSPEC;
7b922c
+	maj = g_ascii_strtoll (str, (char **) &sep, 0x10);
7b922c
+	if (sep == str)
7b922c
+		goto fail;
7b922c
+
7b922c
+	sep = nm_str_skip_leading_spaces (sep);
7b922c
+
7b922c
+	if (sep[0] == ':') {
7b922c
+		const char *str2 = &sep[1];
7b922c
+
7b922c
+		min = g_ascii_strtoll (str2, (char **) &sep, 0x10);
7b922c
+		sep = nm_str_skip_leading_spaces (sep);
7b922c
+		if (sep[0] != '\0')
7b922c
+			goto fail;
7b922c
+	} else if (sep[0] != '\0')
7b922c
+		goto fail;
7b922c
+
7b922c
+	if (   maj <= 0
7b922c
+	    || maj > 0xffff
7b922c
+	    || min < 0
7b922c
+	    || min > 0xffff
7b922c
+	    || !NM_STRCHAR_ALL (str, ch, (   g_ascii_isxdigit (ch)
7b922c
+	                                  || ch == ':'
7b922c
+	                                  || g_ascii_isspace (ch)))) {
7b922c
+		goto fail;
7b922c
 	}
7b922c
 
7b922c
-	return TC_H_MAKE (maj << 16, min);
7b922c
+	return TC_H_MAKE (((guint32) maj) << 16, (guint32) min);
7b922c
+fail:
7b922c
+	nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, _("'%s' is not a valid handle."), str);
7b922c
+	return TC_H_UNSPEC;
7b922c
 }
7b922c
 
7b922c
 #define TC_ATTR_SPEC_PTR(name, type, no_value, consumes_rest, str_type) \
7b922c
diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c
7b922c
index 7587b65ba7..5c9c614fb5 100644
7b922c
--- a/libnm-core/tests/test-setting.c
7b922c
+++ b/libnm-core/tests/test-setting.c
7b922c
@@ -3008,27 +3008,27 @@ test_parse_tc_handle (void)
7b922c
 	_parse_tc_handle_inval (" ");
7b922c
 	_parse_tc_handle_inval (" \n");
7b922c
 	_parse_tc_handle_valid ("1", 1, 0);
7b922c
-	_parse_tc_handle_inval(" 1 ");
7b922c
+	_parse_tc_handle_valid(" 1 ", 1, 0);
7b922c
 	_parse_tc_handle_valid ("1:", 1, 0);
7b922c
-	_parse_tc_handle_inval ("1:  ");
7b922c
+	_parse_tc_handle_valid ("1:  ", 1, 0);
7b922c
 	_parse_tc_handle_valid ("1:0", 1, 0);
7b922c
-	_parse_tc_handle_inval ("1   :0");
7b922c
-	_parse_tc_handle_inval ("1   \t\n\f\r:0");
7b922c
+	_parse_tc_handle_valid ("1   :0", 1, 0);
7b922c
+	_parse_tc_handle_valid ("1   \t\n\f\r:0", 1, 0);
7b922c
 	_parse_tc_handle_inval ("1   \t\n\f\r\v:0");
7b922c
-	_parse_tc_handle_inval (" 1 : 0  ");
7b922c
-	_parse_tc_handle_valid (" \t\v\n1: 0", 1, 0);
7b922c
+	_parse_tc_handle_valid (" 1 : 0  ", 1, 0);
7b922c
+	_parse_tc_handle_inval (" \t\v\n1: 0");
7b922c
 	_parse_tc_handle_valid ("1:2", 1, 2);
7b922c
 	_parse_tc_handle_valid ("01:02", 1, 2);
7b922c
-	_parse_tc_handle_valid ("0x01:0x02", 1, 2);
7b922c
+	_parse_tc_handle_inval ("0x01:0x02");
7b922c
 	_parse_tc_handle_valid ("  01:   02", 1, 2);
7b922c
 	_parse_tc_handle_valid ("019:   020", 0x19, 0x20);
7b922c
 	_parse_tc_handle_valid ("FFFF:   020", 0xFFFF, 0x20);
7b922c
 	_parse_tc_handle_valid ("FfFF:   ffff", 0xFFFF, 0xFFFF);
7b922c
 	_parse_tc_handle_valid ("FFFF", 0xFFFF, 0);
7b922c
-	_parse_tc_handle_valid ("0xFFFF", 0xFFFF, 0);
7b922c
+	_parse_tc_handle_inval ("0xFFFF");
7b922c
 	_parse_tc_handle_inval ("10000");
7b922c
 	_parse_tc_handle_valid ("\t\n\f\r FFFF", 0xFFFF, 0);
7b922c
-	_parse_tc_handle_valid ("\t\n\f\r \vFFFF", 0xFFFF, 0);
7b922c
+	_parse_tc_handle_inval ("\t\n\f\r \vFFFF");
7b922c
 }
7b922c
 
7b922c
 /*****************************************************************************/
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From fde9250cdc664b557a80a517f57929a36597094a Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 11:53:13 +0200
7b922c
Subject: [PATCH 06/20] libnm: mark NMVariantAttributeSpec pointers as const
7b922c
7b922c
This actually allows the compiler/linker to mark the memory as read-only and any
7b922c
modification will cause a segmentation fault.
7b922c
7b922c
I would also think that it allows the compiler to put the structure directly
7b922c
beside the outer constant array (in which this pointer is embedded). That is good
7b922c
locality-wise.
7b922c
7b922c
(cherry picked from commit 4e3955e6ddf02d5ea32012bd563aa02fece5c0ef)
7b922c
---
7b922c
 libnm-core/nm-setting-ip-config.c | 2 +-
7b922c
 libnm-core/nm-setting-sriov.c     | 2 +-
7b922c
 libnm-core/nm-utils.c             | 2 +-
7b922c
 3 files changed, 3 insertions(+), 3 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
7b922c
index f362945f41..26fbc8849f 100644
7b922c
--- a/libnm-core/nm-setting-ip-config.c
7b922c
+++ b/libnm-core/nm-setting-ip-config.c
7b922c
@@ -1213,7 +1213,7 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
7b922c
 }
7b922c
 
7b922c
 #define ATTR_SPEC_PTR(name, type, v4, v6, str_type) \
7b922c
-	&(NMVariantAttributeSpec) { name, type, v4, v6, FALSE, FALSE, str_type }
7b922c
+	&((const NMVariantAttributeSpec) { name, type, v4, v6, FALSE, FALSE, str_type })
7b922c
 
7b922c
 static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = {
7b922c
 	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TABLE,           G_VARIANT_TYPE_UINT32,   TRUE,  TRUE,  0 ),
7b922c
diff --git a/libnm-core/nm-setting-sriov.c b/libnm-core/nm-setting-sriov.c
7b922c
index b662ca2cf6..9a47d141d2 100644
7b922c
--- a/libnm-core/nm-setting-sriov.c
7b922c
+++ b/libnm-core/nm-setting-sriov.c
7b922c
@@ -366,7 +366,7 @@ nm_sriov_vf_get_attribute (const NMSriovVF *vf, const char *name)
7b922c
 }
7b922c
 
7b922c
 #define SRIOV_ATTR_SPEC_PTR(name, type, str_type) \
7b922c
-	&(NMVariantAttributeSpec) { name, type, FALSE, FALSE, FALSE, FALSE, str_type }
7b922c
+	&((const NMVariantAttributeSpec) { name, type, FALSE, FALSE, FALSE, FALSE, str_type })
7b922c
 
7b922c
 const NMVariantAttributeSpec * const _nm_sriov_vf_attribute_spec[] = {
7b922c
 	SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_MAC,          G_VARIANT_TYPE_STRING,  'm'),
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index 7a7c6de114..7df63b83bb 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2319,7 +2319,7 @@ fail:
7b922c
 }
7b922c
 
7b922c
 #define TC_ATTR_SPEC_PTR(name, type, no_value, consumes_rest, str_type) \
7b922c
-	&(NMVariantAttributeSpec) { name, type, FALSE, FALSE, no_value, consumes_rest, str_type }
7b922c
+	&((const NMVariantAttributeSpec) { name, type, FALSE, FALSE, no_value, consumes_rest, str_type })
7b922c
 
7b922c
 static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = {
7b922c
 	TC_ATTR_SPEC_PTR ("root",    G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 38cf36022ef0bb678daf4d2e70da82c96185b310 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 11:56:29 +0200
7b922c
Subject: [PATCH 07/20] libnm: use macro and designated initializers for
7b922c
 NMVariantAttributeSpec
7b922c
7b922c
I think initializing structs should (almost) be always done with designated
7b922c
initializers, because otherwise it's easy to get the order wrong. The
7b922c
problem is that otherwise the order of fields gets additional meaning
7b922c
not only for the memory layout, but also for the code that initialize
7b922c
the structs.
7b922c
7b922c
Add a macro NM_VARIANT_ATTRIBUTE_SPEC_DEFINE() that replaces the other
7b922c
(duplicate) macros. This macro also gets it right to mark the struct as
7b922c
const.
7b922c
7b922c
(cherry picked from commit 86dc50d4760b77f30f3d29c5fa46ea32b06d73f8)
7b922c
---
7b922c
 libnm-core/nm-setting-ip-config.c | 35 ++++++++--------
7b922c
 libnm-core/nm-setting-sriov.c     | 17 ++++----
7b922c
 libnm-core/nm-utils-private.h     |  7 ++++
7b922c
 libnm-core/nm-utils.c             | 67 +++++++++++++++----------------
7b922c
 4 files changed, 62 insertions(+), 64 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
7b922c
index 26fbc8849f..375c309dd6 100644
7b922c
--- a/libnm-core/nm-setting-ip-config.c
7b922c
+++ b/libnm-core/nm-setting-ip-config.c
7b922c
@@ -1212,25 +1212,22 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value)
7b922c
 		g_hash_table_remove (route->attributes, name);
7b922c
 }
7b922c
 
7b922c
-#define ATTR_SPEC_PTR(name, type, v4, v6, str_type) \
7b922c
-	&((const NMVariantAttributeSpec) { name, type, v4, v6, FALSE, FALSE, str_type })
7b922c
-
7b922c
-static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = {
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TABLE,           G_VARIANT_TYPE_UINT32,   TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_SRC,             G_VARIANT_TYPE_STRING,   TRUE,  TRUE, 'a'),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_FROM,            G_VARIANT_TYPE_STRING,   FALSE, TRUE, 'p'),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TOS,             G_VARIANT_TYPE_BYTE,     TRUE,  FALSE, 0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_ONLINK,          G_VARIANT_TYPE_BOOLEAN,  TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW,          G_VARIANT_TYPE_UINT32,   TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_CWND,            G_VARIANT_TYPE_UINT32,   TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND,        G_VARIANT_TYPE_UINT32,   TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND,        G_VARIANT_TYPE_UINT32,   TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_MTU,             G_VARIANT_TYPE_UINT32,   TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW,     G_VARIANT_TYPE_BOOLEAN,  TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND,       G_VARIANT_TYPE_BOOLEAN,  TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND,   G_VARIANT_TYPE_BOOLEAN,  TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND,   G_VARIANT_TYPE_BOOLEAN,  TRUE,  TRUE,  0 ),
7b922c
-	ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU,        G_VARIANT_TYPE_BOOLEAN,  TRUE,  TRUE,  0 ),
7b922c
+static const NMVariantAttributeSpec *const ip_route_attribute_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TABLE,         G_VARIANT_TYPE_UINT32,  .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_SRC,           G_VARIANT_TYPE_STRING,  .v4 = TRUE, .v6 = TRUE, .str_type = 'a', ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_FROM,          G_VARIANT_TYPE_STRING,              .v6 = TRUE, .str_type = 'p', ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_TOS,           G_VARIANT_TYPE_BYTE,    .v4 = TRUE,                              ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_ONLINK,        G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_WINDOW,        G_VARIANT_TYPE_UINT32,  .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_CWND,          G_VARIANT_TYPE_UINT32,  .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_INITCWND,      G_VARIANT_TYPE_UINT32,  .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_INITRWND,      G_VARIANT_TYPE_UINT32,  .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_MTU,           G_VARIANT_TYPE_UINT32,  .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW,   G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND,     G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU,      G_VARIANT_TYPE_BOOLEAN, .v4 = TRUE, .v6 = TRUE,                  ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
diff --git a/libnm-core/nm-setting-sriov.c b/libnm-core/nm-setting-sriov.c
7b922c
index 9a47d141d2..0625331e3f 100644
7b922c
--- a/libnm-core/nm-setting-sriov.c
7b922c
+++ b/libnm-core/nm-setting-sriov.c
7b922c
@@ -365,17 +365,14 @@ nm_sriov_vf_get_attribute (const NMSriovVF *vf, const char *name)
7b922c
 	return g_hash_table_lookup (vf->attributes, name);
7b922c
 }
7b922c
 
7b922c
-#define SRIOV_ATTR_SPEC_PTR(name, type, str_type) \
7b922c
-	&((const NMVariantAttributeSpec) { name, type, FALSE, FALSE, FALSE, FALSE, str_type })
7b922c
-
7b922c
-const NMVariantAttributeSpec * const _nm_sriov_vf_attribute_spec[] = {
7b922c
-	SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_MAC,          G_VARIANT_TYPE_STRING,  'm'),
7b922c
-	SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK,  G_VARIANT_TYPE_BOOLEAN,  0),
7b922c
-	SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_TRUST,        G_VARIANT_TYPE_BOOLEAN,  0),
7b922c
-	SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE,  G_VARIANT_TYPE_UINT32,   0),
7b922c
-	SRIOV_ATTR_SPEC_PTR (NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE,  G_VARIANT_TYPE_UINT32,   0),
7b922c
+const NMVariantAttributeSpec *const _nm_sriov_vf_attribute_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_MAC,         G_VARIANT_TYPE_STRING,  .str_type = 'm', ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK, G_VARIANT_TYPE_BOOLEAN,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_TRUST,       G_VARIANT_TYPE_BOOLEAN,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE, G_VARIANT_TYPE_UINT32,                   ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE (NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE, G_VARIANT_TYPE_UINT32,                   ),
7b922c
 	/* D-Bus only, synthetic attributes */
7b922c
-	SRIOV_ATTR_SPEC_PTR ("vlans",                            G_VARIANT_TYPE_STRING,  'd'),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("vlans",                           G_VARIANT_TYPE_STRING,  .str_type = 'd', ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h
7b922c
index a1a1369a39..1b9b888773 100644
7b922c
--- a/libnm-core/nm-utils-private.h
7b922c
+++ b/libnm-core/nm-utils-private.h
7b922c
@@ -38,6 +38,13 @@ struct _NMVariantAttributeSpec {
7b922c
 	char str_type;
7b922c
 };
7b922c
 
7b922c
+#define NM_VARIANT_ATTRIBUTE_SPEC_DEFINE(_name, _type, ...) \
7b922c
+	(&((const NMVariantAttributeSpec) { \
7b922c
+		.name          = _name, \
7b922c
+		.type          = _type, \
7b922c
+		__VA_ARGS__ \
7b922c
+	}))
7b922c
+
7b922c
 gboolean    _nm_utils_string_slist_validate (GSList *list,
7b922c
                                              const char **valid_values);
7b922c
 
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index 7df63b83bb..7cf482d3de 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2318,33 +2318,30 @@ fail:
7b922c
 	return TC_H_UNSPEC;
7b922c
 }
7b922c
 
7b922c
-#define TC_ATTR_SPEC_PTR(name, type, no_value, consumes_rest, str_type) \
7b922c
-	&((const NMVariantAttributeSpec) { name, type, FALSE, FALSE, no_value, consumes_rest, str_type })
7b922c
-
7b922c
-static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = {
7b922c
-	TC_ATTR_SPEC_PTR ("root",    G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("parent",  G_VARIANT_TYPE_STRING,  FALSE, FALSE, 'a' ),
7b922c
-	TC_ATTR_SPEC_PTR ("handle",  G_VARIANT_TYPE_STRING,  FALSE, FALSE, 'a' ),
7b922c
-	TC_ATTR_SPEC_PTR ("kind",    G_VARIANT_TYPE_STRING,  TRUE,  FALSE, 'a' ),
7b922c
-	TC_ATTR_SPEC_PTR ("",        G_VARIANT_TYPE_STRING,  TRUE,  TRUE,  'a' ),
7b922c
+static const NMVariantAttributeSpec *const tc_object_attribute_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("root",   G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE,                                         ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("parent", G_VARIANT_TYPE_STRING,                                           .str_type = 'a', ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("handle", G_VARIANT_TYPE_STRING,                                           .str_type = 'a', ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("kind",   G_VARIANT_TYPE_STRING,  .no_value = TRUE,                        .str_type = 'a', ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("",       G_VARIANT_TYPE_STRING,  .no_value = TRUE, .consumes_rest = TRUE, .str_type = 'a', ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
-static const NMVariantAttributeSpec * const tc_qdisc_fq_codel_spec[] = {
7b922c
-	TC_ATTR_SPEC_PTR ("limit",        G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("flows",        G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("target",       G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("interval",     G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("quantum",      G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("ce_threshold", G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("memory",       G_VARIANT_TYPE_UINT32,  FALSE, FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("ecn",          G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
+static const NMVariantAttributeSpec *const tc_qdisc_fq_codel_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("limit",        G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("flows",        G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("target",       G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("interval",     G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("quantum",      G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ce_threshold", G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("memory",       G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ecn",          G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
 typedef struct {
7b922c
 	const char *kind;
7b922c
-	const NMVariantAttributeSpec * const *attrs;
7b922c
+	const NMVariantAttributeSpec *const *attrs;
7b922c
 } NMQdiscAttributeSpec;
7b922c
 
7b922c
 static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = {
7b922c
@@ -2558,23 +2555,23 @@ nm_utils_tc_qdisc_from_str (const char *str, GError **error)
7b922c
 
7b922c
 /*****************************************************************************/
7b922c
 
7b922c
-static const NMVariantAttributeSpec * const tc_action_simple_attribute_spec[] = {
7b922c
-	TC_ATTR_SPEC_PTR ("sdata",   G_VARIANT_TYPE_BYTESTRING,  FALSE, FALSE, 0   ),
7b922c
+static const NMVariantAttributeSpec *const tc_action_simple_attribute_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("sdata", G_VARIANT_TYPE_BYTESTRING, ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
-static const NMVariantAttributeSpec * const tc_action_mirred_attribute_spec[] = {
7b922c
-	TC_ATTR_SPEC_PTR ("egress",   G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("ingress",  G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("mirror",   G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("redirect", G_VARIANT_TYPE_BOOLEAN, TRUE,  FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("dev",      G_VARIANT_TYPE_STRING,  TRUE,  FALSE, 'a' ),
7b922c
+static const NMVariantAttributeSpec *const tc_action_mirred_attribute_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("egress",   G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ingress",  G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("mirror",   G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("redirect", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE,                  ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("dev",      G_VARIANT_TYPE_STRING,  .no_value = TRUE, .str_type = 'a', ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
-static const NMVariantAttributeSpec * const tc_action_attribute_spec[] = {
7b922c
-	TC_ATTR_SPEC_PTR ("kind",    G_VARIANT_TYPE_STRING,      TRUE,  FALSE, 'a' ),
7b922c
-	TC_ATTR_SPEC_PTR ("",        G_VARIANT_TYPE_STRING,      TRUE,  TRUE,  'a' ),
7b922c
+static const NMVariantAttributeSpec *const tc_action_attribute_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("kind",    G_VARIANT_TYPE_STRING, .no_value = TRUE,                        .str_type = 'a', ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("",        G_VARIANT_TYPE_STRING, .no_value = TRUE, .consumes_rest = TRUE, .str_type = 'a', ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
@@ -2643,7 +2640,7 @@ nm_utils_tc_action_from_str (const char *str, GError **error)
7b922c
 	gs_unref_hashtable GHashTable *ht = NULL;
7b922c
 	gs_unref_hashtable GHashTable *options = NULL;
7b922c
 	GVariant *variant;
7b922c
-	const NMVariantAttributeSpec * const *attrs;
7b922c
+	const NMVariantAttributeSpec *const *attrs;
7b922c
 
7b922c
 	nm_assert (str);
7b922c
 	nm_assert (!error || !*error);
7b922c
@@ -2771,9 +2768,9 @@ nm_utils_tc_tfilter_to_str (NMTCTfilter *tfilter, GError **error)
7b922c
 	return g_string_free (string, FALSE);
7b922c
 }
7b922c
 
7b922c
-static const NMVariantAttributeSpec * const tc_tfilter_attribute_spec[] = {
7b922c
-	TC_ATTR_SPEC_PTR ("action",  G_VARIANT_TYPE_BOOLEAN,     TRUE,  FALSE, 0   ),
7b922c
-	TC_ATTR_SPEC_PTR ("",        G_VARIANT_TYPE_STRING,      TRUE,  TRUE,  'a' ),
7b922c
+static const NMVariantAttributeSpec *const tc_tfilter_attribute_spec[] = {
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("action", G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE,                                         ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("",       G_VARIANT_TYPE_STRING,  .no_value = TRUE, .consumes_rest = TRUE, .str_type = 'a', ),
7b922c
 	NULL,
7b922c
 };
7b922c
 
7b922c
@@ -6460,7 +6457,7 @@ nm_utils_parse_variant_attributes (const char *string,
7b922c
 	gs_unref_hashtable GHashTable *ht = NULL;
7b922c
 	const char *ptr = string, *start = NULL, *sep;
7b922c
 	GVariant *variant;
7b922c
-	const NMVariantAttributeSpec * const *s;
7b922c
+	const NMVariantAttributeSpec *const *s;
7b922c
 
7b922c
 	g_return_val_if_fail (string, NULL);
7b922c
 	g_return_val_if_fail (attr_separator, NULL);
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 73fdcd38f16eb759de395de8680c994a742fbe1c Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 08:52:54 +0200
7b922c
Subject: [PATCH 08/20] device: fix type of loop variable in tc_commit()
7b922c
7b922c
nqdiscs and ntfilters are unsigned integers. The loop variable must agree in
7b922c
range and signedness.
7b922c
7b922c
(cherry picked from commit 438855e915c328867b7802b14ebef47d7f946ca8)
7b922c
---
7b922c
 src/devices/nm-device.c | 2 +-
7b922c
 1 file changed, 1 insertion(+), 1 deletion(-)
7b922c
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index ea6ad7e2ad..e07798094f 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6496,7 +6496,7 @@ tc_commit (NMDevice *self)
7b922c
 	NMSettingTCConfig *s_tc = NULL;
7b922c
 	int ip_ifindex;
7b922c
 	guint nqdiscs, ntfilters;
7b922c
-	int i;
7b922c
+	guint i;
7b922c
 
7b922c
 	connection = nm_device_get_applied_connection (self);
7b922c
 	if (connection)
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 366d3af00960803c973a307a6bd7ffeedd9c1520 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 08:10:47 +0200
7b922c
Subject: [PATCH 09/20] platform: use NM_CMP_FIELD_UNSAFE() for comparing
7b922c
 bitfield in nm_platform_qdisc_cmp()
7b922c
7b922c
"NM_CMP_FIELD (a, b, fq_codel.ecn == TRUE)" is quite a hack as it relies on
7b922c
the implementation of the macro in a particular way. The problem is, that
7b922c
NM_CMP_FIELD() uses typeof() which cannot be used with bitfields. So, the
7b922c
nicer solution is to use NM_CMP_FIELD_UNSAFE() which exists exactly for bitfields
7b922c
(it's "unsafe", because it evaluates arguments more than once as it avoids
7b922c
the temporary variable with typeof()).
7b922c
7b922c
Same with nm_hash_update_vals() which uses typeof() to avoid evaluating
7b922c
arguments more than once. But that again does not work with bitfields.
7b922c
The "proper" way is to use NM_HASH_COMBINE_BOOLS().
7b922c
7b922c
(cherry picked from commit 47d8bee1130c619a41fe64753d88d88012f9fb98)
7b922c
---
7b922c
 src/platform/nm-platform.c | 5 +++--
7b922c
 1 file changed, 3 insertions(+), 2 deletions(-)
7b922c
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index 6f23ddb589..f8cf0b8999 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -6480,7 +6480,8 @@ nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h)
7b922c
 		                     obj->fq_codel.quantum,
7b922c
 		                     obj->fq_codel.ce_threshold,
7b922c
 		                     obj->fq_codel.memory,
7b922c
-		                     obj->fq_codel.ecn == TRUE);
7b922c
+		                     NM_HASH_COMBINE_BOOLS (guint8,
7b922c
+		                                            obj->fq_codel.ecn));
7b922c
 	}
7b922c
 }
7b922c
 
7b922c
@@ -6503,7 +6504,7 @@ nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
7b922c
 		NM_CMP_FIELD (a, b, fq_codel.quantum);
7b922c
 		NM_CMP_FIELD (a, b, fq_codel.ce_threshold);
7b922c
 		NM_CMP_FIELD (a, b, fq_codel.memory);
7b922c
-		NM_CMP_FIELD (a, b, fq_codel.ecn == TRUE);
7b922c
+		NM_CMP_FIELD_UNSAFE (a, b, fq_codel.ecn);
7b922c
 	}
7b922c
 
7b922c
 	return 0;
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From ef2b660bb8cb2c30faf55c51a411e8a757707076 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 08:20:42 +0200
7b922c
Subject: [PATCH 10/20] platform: use u32 netlink type for TCA_FQ_CODEL_ECN
7b922c
7b922c
In practice, there is no difference when representing 0 or 1 as signed/unsigned 32
7b922c
bit integer. But still use the correct type that also kernel uses.
7b922c
7b922c
Also, the implicit conversation from uint32 to bool was correct already.
7b922c
Still, explicitly convert the uint32 value to boolean in _new_from_nl_qdisc().
7b922c
It's no change in behavior.
7b922c
7b922c
(cherry picked from commit a1099a1fab661a430fa8e8015369b536c806433e)
7b922c
---
7b922c
 src/platform/nm-linux-platform.c | 4 ++--
7b922c
 1 file changed, 2 insertions(+), 2 deletions(-)
7b922c
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index 6064d89eb6..1428778e03 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -3547,7 +3547,7 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
7b922c
 					obj->qdisc.fq_codel.memory = nla_get_u32 (options_attr);
7b922c
 					break;
7b922c
 				case TCA_FQ_CODEL_ECN:
7b922c
-					obj->qdisc.fq_codel.ecn = nla_get_u32 (options_attr);
7b922c
+					obj->qdisc.fq_codel.ecn = !!nla_get_u32 (options_attr);
7b922c
 					break;
7b922c
 				}
7b922c
 			}
7b922c
@@ -4244,7 +4244,7 @@ _nl_msg_new_qdisc (int nlmsg_type,
7b922c
 		if (qdisc->fq_codel.memory != -1)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory);
7b922c
 		if (qdisc->fq_codel.ecn)
7b922c
-			NLA_PUT_S32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
7b922c
 	}
7b922c
 
7b922c
 	nla_nest_end (msg, tc_options);
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From dd3ca10284f9f7f95b1f313a3aa678f2aef01b3f Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 08:23:00 +0200
7b922c
Subject: [PATCH 11/20] platform: fix nm_platform_qdisc_to_string()
7b922c
7b922c
When using nm_utils_strbuf_*() API, the buffer gets always moved to the current
7b922c
end. We must thus remember and return the original start of the buffer.
7b922c
7b922c
(cherry picked from commit b658e3da0825cf6e62e0850d3508dde1dd5c1914)
7b922c
---
7b922c
 src/platform/nm-platform.c | 5 ++++-
7b922c
 1 file changed, 4 insertions(+), 1 deletion(-)
7b922c
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index f8cf0b8999..4d3b61405d 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -6427,10 +6427,13 @@ const char *
7b922c
 nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
7b922c
 {
7b922c
 	char str_dev[TO_STRING_DEV_BUF_SIZE];
7b922c
+	const char *buf0;
7b922c
 
7b922c
 	if (!nm_utils_to_string_buffer_init_null (qdisc, &buf, &len))
7b922c
 		return buf;
7b922c
 
7b922c
+	buf0 = buf;
7b922c
+
7b922c
 	nm_utils_strbuf_append (&buf, &len, "%s%s family %u handle %x parent %x info %x",
7b922c
 	                        qdisc->kind,
7b922c
 	                        _to_string_dev (NULL, qdisc->ifindex, str_dev, sizeof (str_dev)),
7b922c
@@ -6458,7 +6461,7 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " ecn");
7b922c
 	}
7b922c
 
7b922c
-	return buf;
7b922c
+	return buf0;
7b922c
 }
7b922c
 
7b922c
 void
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 509a1bc5f2e52f6d639b75a0467b584c08a90463 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 08:43:31 +0200
7b922c
Subject: [PATCH 12/20] platform: fix handling of fq_codel's memory limit
7b922c
 default value
7b922c
7b922c
The memory-limit is an unsigned integer. It is ugly (if not wrong) to compare unsigned
7b922c
values with "-1". When comparing with the default value we must also use an u32 type.
7b922c
Instead add a define NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET.
7b922c
7b922c
Note that like iproute2 we treat NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET
7b922c
to indicate to not set TCA_FQ_CODEL_MEMORY_LIMIT in RTM_NEWQDISC. This
7b922c
special value is entirely internal to NetworkManager (or iproute2) and
7b922c
kernel will then choose a default memory limit (of 32MB). So setting
7b922c
NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET means to leave it to kernel to
7b922c
choose a value (which then chooses 32MB).
7b922c
7b922c
See kernel's net/sched/sch_fq_codel.c:
7b922c
7b922c
    static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt,
7b922c
                             struct netlink_ext_ack *extack)
7b922c
    {
7b922c
    ...
7b922c
            q->memory_limit = 32 << 20; /* 32 MBytes */
7b922c
7b922c
    static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
7b922c
                               struct netlink_ext_ack *extack)
7b922c
    ...
7b922c
            if (tb[TCA_FQ_CODEL_MEMORY_LIMIT])
7b922c
                    q->memory_limit = min(1U << 31, nla_get_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]));
7b922c
7b922c
Note that not having zero as default value is problematic. In fields like
7b922c
"NMPlatformIP4Route.table_coerced" and "NMPlatformRoutingRule.suppress_prefixlen_inverse"
7b922c
we avoid this problem by storing a coerced value in the structure so that zero is still
7b922c
the default. We don't do that here for memory-limit, so the caller must always explicitly
7b922c
set the value.
7b922c
7b922c
(cherry picked from commit 46a904389bf13a2cfd40888ab2a843827fda7469)
7b922c
---
7b922c
 libnm-core/nm-utils.c            | 5 +++++
7b922c
 src/devices/nm-device.c          | 2 +-
7b922c
 src/platform/nm-linux-platform.c | 5 ++++-
7b922c
 src/platform/nm-platform.c       | 2 +-
7b922c
 src/platform/nm-platform.h       | 9 ++++++++-
7b922c
 5 files changed, 19 insertions(+), 4 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index 7cf482d3de..2e66e6ae2d 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2334,7 +2334,12 @@ static const NMVariantAttributeSpec *const tc_qdisc_fq_codel_spec[] = {
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("interval",     G_VARIANT_TYPE_UINT32,                    ),
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("quantum",      G_VARIANT_TYPE_UINT32,                    ),
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ce_threshold", G_VARIANT_TYPE_UINT32,                    ),
7b922c
+
7b922c
+	/* kernel clamps the value at 2^31. Possibly such values should be rejected from configuration
7b922c
+	 * as they cannot be configured. Leaving the attribute unspecified causes kernel to choose
7b922c
+	 * a default (currently 32MB). */
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("memory",       G_VARIANT_TYPE_UINT32,                    ),
7b922c
+
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ecn",          G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
7b922c
 	NULL,
7b922c
 };
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index e07798094f..ce50d5b73d 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6539,7 +6539,7 @@ tc_commit (NMDevice *self)
7b922c
 				GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0);
7b922c
 				GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0);
7b922c
 				GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, -1);
7b922c
-				GET_ATTR("memory", qdisc->fq_codel.memory, UINT32, uint32, -1);
7b922c
+				GET_ATTR("memory", qdisc->fq_codel.memory, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET);
7b922c
 				GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE);
7b922c
 			}
7b922c
 
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index 1428778e03..cec5fb9431 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -3515,6 +3515,9 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
7b922c
 	obj->qdisc.parent = tcm->tcm_parent;
7b922c
 	obj->qdisc.info = tcm->tcm_info;
7b922c
 
7b922c
+	if (nm_streq0 (obj->qdisc.kind, "fq_codel"))
7b922c
+		obj->qdisc.fq_codel.memory = NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET;
7b922c
+
7b922c
 	if (tb[TCA_OPTIONS]) {
7b922c
 		struct nlattr *options_attr;
7b922c
 		int remaining;
7b922c
@@ -4241,7 +4244,7 @@ _nl_msg_new_qdisc (int nlmsg_type,
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum);
7b922c
 		if (qdisc->fq_codel.ce_threshold != -1)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold);
7b922c
-		if (qdisc->fq_codel.memory != -1)
7b922c
+		if (qdisc->fq_codel.memory != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory);
7b922c
 		if (qdisc->fq_codel.ecn)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index 4d3b61405d..fc49db19a1 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -6455,7 +6455,7 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " quantum %u", qdisc->fq_codel.quantum);
7b922c
 		if (qdisc->fq_codel.ce_threshold != -1)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold);
7b922c
-		if (qdisc->fq_codel.memory != -1)
7b922c
+		if (qdisc->fq_codel.memory != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " memory %u", qdisc->fq_codel.memory);
7b922c
 		if (qdisc->fq_codel.ecn)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " ecn");
7b922c
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
7b922c
index 16747f093b..9f9fcf5c31 100644
7b922c
--- a/src/platform/nm-platform.h
7b922c
+++ b/src/platform/nm-platform.h
7b922c
@@ -596,6 +596,8 @@ typedef struct {
7b922c
 	bool     uid_range_has:1;            /* has(FRA_UID_RANGE) */
7b922c
 } NMPlatformRoutingRule;
7b922c
 
7b922c
+#define NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET   (~((guint32) 0))
7b922c
+
7b922c
 typedef struct {
7b922c
 	guint32 limit;
7b922c
 	guint32 flows;
7b922c
@@ -603,7 +605,12 @@ typedef struct {
7b922c
 	guint32 interval;
7b922c
 	guint32 quantum;
7b922c
 	guint32 ce_threshold;
7b922c
-	guint32 memory;
7b922c
+	guint32 memory;       /* TCA_FQ_CODEL_MEMORY_LIMIT: note that only values <= 2^31 are accepted by kernel
7b922c
+	                       *   and kernel defaults to 32MB.
7b922c
+	                       *   Note that we use the special value NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET
7b922c
+	                       *   to indicate that no explicit limit is set (when we send a RTM_NEWQDISC request).
7b922c
+	                       *   This will cause kernel to choose the default (32MB).
7b922c
+	                       *   Beware: zero is not the default you must always explicitly set this value. */
7b922c
 	bool ecn:1;
7b922c
 } NMPlatformQdiscFqCodel;
7b922c
 
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 859f8479d453c9270987245b9d6e537af0e42077 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 09:19:59 +0200
7b922c
Subject: [PATCH 13/20] platform: fix handling of default value for
7b922c
 TCA_FQ_CODEL_CE_THRESHOLD
7b922c
7b922c
iproute2 uses the special value ~0u to indicate not to set
7b922c
TCA_FQ_CODEL_CE_THRESHOLD in RTM_NEWQDISC. When not explicitly
7b922c
setting the value, kernel treats the threshold as disabled.
7b922c
7b922c
However note that 0xFFFFFFFFu is not an invalid threshold (as far as
7b922c
kernel is concerned). Thus, we should not use that as value to indicate
7b922c
that the value is unset. Note that iproute2 uses the special value ~0u
7b922c
only internally thereby making it impossible to set the threshold to
7b922c
0xFFFFFFFFu). But kernel does not have this limitation.
7b922c
7b922c
Maybe the cleanest way would be to add another field to NMPlatformQDisc:
7b922c
7b922c
    guint32 ce_threshold;
7b922c
    bool ce_threshold_set:1;
7b922c
7b922c
that indicates whether the threshold is enable or not.
7b922c
But note that kernel does:
7b922c
7b922c
    static void codel_params_init(struct codel_params *params)
7b922c
    {
7b922c
    ...
7b922c
            params->ce_threshold = CODEL_DISABLED_THRESHOLD;
7b922c
7b922c
    static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt,
7b922c
                               struct netlink_ext_ack *extack)
7b922c
    {
7b922c
    ...
7b922c
            if (tb[TCA_FQ_CODEL_CE_THRESHOLD]) {
7b922c
                    u64 val = nla_get_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]);
7b922c
7b922c
                    q->cparams.ce_threshold = (val * NSEC_PER_USEC) >> CODEL_SHIFT;
7b922c
            }
7b922c
7b922c
    static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb)
7b922c
    {
7b922c
    ...
7b922c
            if (q->cparams.ce_threshold != CODEL_DISABLED_THRESHOLD &&
7b922c
                nla_put_u32(skb, TCA_FQ_CODEL_CE_THRESHOLD,
7b922c
                            codel_time_to_us(q->cparams.ce_threshold)))
7b922c
                    goto nla_put_failure;
7b922c
7b922c
This means, kernel internally uses the special value 0x83126E97u to indicate
7b922c
that the threshold is disabled (WTF). That is because
7b922c
7b922c
  (((guint64) 0x83126E97u) * NSEC_PER_USEC) >> CODEL_SHIFT == CODEL_DISABLED_THRESHOLD
7b922c
7b922c
So in kernel API this value is reserved (and has a special meaning
7b922c
to indicate that the threshold is disabled). So, instead of adding a
7b922c
ce_threshold_set flag, use the same value that kernel anyway uses.
7b922c
7b922c
(cherry picked from commit 973db2d41b957c4ee9d4ee9863f4b35c6890ac30)
7b922c
---
7b922c
 libnm-core/nm-utils.c            |  3 +++
7b922c
 src/devices/nm-device.c          |  2 +-
7b922c
 src/platform/nm-linux-platform.c |  6 ++++--
7b922c
 src/platform/nm-platform.c       |  2 +-
7b922c
 src/platform/nm-platform.h       | 12 +++++++++++-
7b922c
 5 files changed, 20 insertions(+), 5 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index 2e66e6ae2d..9e2eb63594 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2333,6 +2333,9 @@ static const NMVariantAttributeSpec *const tc_qdisc_fq_codel_spec[] = {
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("target",       G_VARIANT_TYPE_UINT32,                    ),
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("interval",     G_VARIANT_TYPE_UINT32,                    ),
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("quantum",      G_VARIANT_TYPE_UINT32,                    ),
7b922c
+
7b922c
+	/* 0x83126E97u is not a valid value (it means "disabled"). We should reject that
7b922c
+	 * value. Or alternatively, reject all values >= MAX_INT(32). */
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ce_threshold", G_VARIANT_TYPE_UINT32,                    ),
7b922c
 
7b922c
 	/* kernel clamps the value at 2^31. Possibly such values should be rejected from configuration
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index ce50d5b73d..22ccabb26e 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6538,7 +6538,7 @@ tc_commit (NMDevice *self)
7b922c
 				GET_ATTR("target", qdisc->fq_codel.target, UINT32, uint32, 0);
7b922c
 				GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0);
7b922c
 				GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0);
7b922c
-				GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, -1);
7b922c
+				GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED);
7b922c
 				GET_ATTR("memory", qdisc->fq_codel.memory, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET);
7b922c
 				GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE);
7b922c
 			}
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index cec5fb9431..2e11052e1a 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -3515,8 +3515,10 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
7b922c
 	obj->qdisc.parent = tcm->tcm_parent;
7b922c
 	obj->qdisc.info = tcm->tcm_info;
7b922c
 
7b922c
-	if (nm_streq0 (obj->qdisc.kind, "fq_codel"))
7b922c
+	if (nm_streq0 (obj->qdisc.kind, "fq_codel")) {
7b922c
 		obj->qdisc.fq_codel.memory = NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET;
7b922c
+		obj->qdisc.fq_codel.ce_threshold = NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED;
7b922c
+	}
7b922c
 
7b922c
 	if (tb[TCA_OPTIONS]) {
7b922c
 		struct nlattr *options_attr;
7b922c
@@ -4242,7 +4244,7 @@ _nl_msg_new_qdisc (int nlmsg_type,
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_INTERVAL, qdisc->fq_codel.interval);
7b922c
 		if (qdisc->fq_codel.quantum)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum);
7b922c
-		if (qdisc->fq_codel.ce_threshold != -1)
7b922c
+		if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold);
7b922c
 		if (qdisc->fq_codel.memory != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory);
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index fc49db19a1..cbf9eed5c1 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -6453,7 +6453,7 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " interval %u", qdisc->fq_codel.interval);
7b922c
 		if (qdisc->fq_codel.quantum)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " quantum %u", qdisc->fq_codel.quantum);
7b922c
-		if (qdisc->fq_codel.ce_threshold != -1)
7b922c
+		if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold);
7b922c
 		if (qdisc->fq_codel.memory != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " memory %u", qdisc->fq_codel.memory);
7b922c
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
7b922c
index 9f9fcf5c31..d7c388b1b8 100644
7b922c
--- a/src/platform/nm-platform.h
7b922c
+++ b/src/platform/nm-platform.h
7b922c
@@ -598,13 +598,23 @@ typedef struct {
7b922c
 
7b922c
 #define NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET   (~((guint32) 0))
7b922c
 
7b922c
+#define NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED ((guint32) 0x83126E97u)
7b922c
+
7b922c
+G_STATIC_ASSERT (((((guint64) NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) * 1000u) >> 10) == (guint64) INT_MAX);
7b922c
+
7b922c
 typedef struct {
7b922c
 	guint32 limit;
7b922c
 	guint32 flows;
7b922c
 	guint32 target;
7b922c
 	guint32 interval;
7b922c
 	guint32 quantum;
7b922c
-	guint32 ce_threshold;
7b922c
+	guint32 ce_threshold; /* TCA_FQ_CODEL_CE_THRESHOLD: kernel internally stores this value as
7b922c
+	                       *   ((val64 * NSEC_PER_USEC) >> CODEL_SHIFT). The default value (in
7b922c
+	                       *   the domain with this coersion) is CODEL_DISABLED_THRESHOLD (INT_MAX).
7b922c
+	                       *   That means, "disabled" is expressed on RTM_NEWQDISC netlink API by absence of the
7b922c
+	                       *   netlink attribute but also as the special value 0x83126E97u
7b922c
+	                       *   (NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED).
7b922c
+	                       *   Beware: zero is not the default you must always explicitly set this value. */
7b922c
 	guint32 memory;       /* TCA_FQ_CODEL_MEMORY_LIMIT: note that only values <= 2^31 are accepted by kernel
7b922c
 	                       *   and kernel defaults to 32MB.
7b922c
 	                       *   Note that we use the special value NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From c17fa82b314d6b3c027240ee3506706e26ef9e5d Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 12:56:46 +0200
7b922c
Subject: [PATCH 14/20] libnm: rename "memory" parameter of fq_codel QDisc to
7b922c
 "memory_limit"
7b922c
7b922c
Kernel calls the netlink attribute TCA_FQ_CODEL_MEMORY_LIMIT. Likewise,
7b922c
iproute2 calls this "memory_limit".
7b922c
7b922c
Rename because TC parameters are inherrently tied to the kernel
7b922c
implementation and we should use the familiar name.
7b922c
7b922c
(cherry picked from commit 666d58802b6f9072825d97498ab74e5d37652e93)
7b922c
---
7b922c
 libnm-core/nm-utils.c            | 2 +-
7b922c
 src/devices/nm-device.c          | 2 +-
7b922c
 src/platform/nm-linux-platform.c | 8 ++++----
7b922c
 src/platform/nm-platform.c       | 8 ++++----
7b922c
 src/platform/nm-platform.h       | 2 +-
7b922c
 5 files changed, 11 insertions(+), 11 deletions(-)
7b922c
7b922c
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
7b922c
index 9e2eb63594..394ca7c3a7 100644
7b922c
--- a/libnm-core/nm-utils.c
7b922c
+++ b/libnm-core/nm-utils.c
7b922c
@@ -2341,7 +2341,7 @@ static const NMVariantAttributeSpec *const tc_qdisc_fq_codel_spec[] = {
7b922c
 	/* kernel clamps the value at 2^31. Possibly such values should be rejected from configuration
7b922c
 	 * as they cannot be configured. Leaving the attribute unspecified causes kernel to choose
7b922c
 	 * a default (currently 32MB). */
7b922c
-	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("memory",       G_VARIANT_TYPE_UINT32,                    ),
7b922c
+	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("memory_limit", G_VARIANT_TYPE_UINT32,                    ),
7b922c
 
7b922c
 	NM_VARIANT_ATTRIBUTE_SPEC_DEFINE ("ecn",          G_VARIANT_TYPE_BOOLEAN, .no_value = TRUE, ),
7b922c
 	NULL,
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index 22ccabb26e..e2a5fd4bf2 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6539,7 +6539,7 @@ tc_commit (NMDevice *self)
7b922c
 				GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0);
7b922c
 				GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0);
7b922c
 				GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED);
7b922c
-				GET_ATTR("memory", qdisc->fq_codel.memory, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET);
7b922c
+				GET_ATTR("memory_limit", qdisc->fq_codel.memory_limit, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET);
7b922c
 				GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE);
7b922c
 			}
7b922c
 
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index 2e11052e1a..9721ff9403 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -3516,7 +3516,7 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
7b922c
 	obj->qdisc.info = tcm->tcm_info;
7b922c
 
7b922c
 	if (nm_streq0 (obj->qdisc.kind, "fq_codel")) {
7b922c
-		obj->qdisc.fq_codel.memory = NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET;
7b922c
+		obj->qdisc.fq_codel.memory_limit = NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET;
7b922c
 		obj->qdisc.fq_codel.ce_threshold = NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED;
7b922c
 	}
7b922c
 
7b922c
@@ -3549,7 +3549,7 @@ _new_from_nl_qdisc (struct nlmsghdr *nlh, gboolean id_only)
7b922c
 					obj->qdisc.fq_codel.ce_threshold = nla_get_u32 (options_attr);
7b922c
 					break;
7b922c
 				case TCA_FQ_CODEL_MEMORY_LIMIT:
7b922c
-					obj->qdisc.fq_codel.memory = nla_get_u32 (options_attr);
7b922c
+					obj->qdisc.fq_codel.memory_limit = nla_get_u32 (options_attr);
7b922c
 					break;
7b922c
 				case TCA_FQ_CODEL_ECN:
7b922c
 					obj->qdisc.fq_codel.ecn = !!nla_get_u32 (options_attr);
7b922c
@@ -4246,8 +4246,8 @@ _nl_msg_new_qdisc (int nlmsg_type,
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum);
7b922c
 		if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold);
7b922c
-		if (qdisc->fq_codel.memory != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
-			NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory);
7b922c
+		if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
+			NLA_PUT_U32 (msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory_limit);
7b922c
 		if (qdisc->fq_codel.ecn)
7b922c
 			NLA_PUT_U32 (msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn);
7b922c
 	}
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index cbf9eed5c1..ea73f21019 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -6455,8 +6455,8 @@ nm_platform_qdisc_to_string (const NMPlatformQdisc *qdisc, char *buf, gsize len)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " quantum %u", qdisc->fq_codel.quantum);
7b922c
 		if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold);
7b922c
-		if (qdisc->fq_codel.memory != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
-			nm_utils_strbuf_append (&buf, &len, " memory %u", qdisc->fq_codel.memory);
7b922c
+		if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET)
7b922c
+			nm_utils_strbuf_append (&buf, &len, " memory_limit %u", qdisc->fq_codel.memory_limit);
7b922c
 		if (qdisc->fq_codel.ecn)
7b922c
 			nm_utils_strbuf_append (&buf, &len, " ecn");
7b922c
 	}
7b922c
@@ -6482,7 +6482,7 @@ nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h)
7b922c
 		                     obj->fq_codel.interval,
7b922c
 		                     obj->fq_codel.quantum,
7b922c
 		                     obj->fq_codel.ce_threshold,
7b922c
-		                     obj->fq_codel.memory,
7b922c
+		                     obj->fq_codel.memory_limit,
7b922c
 		                     NM_HASH_COMBINE_BOOLS (guint8,
7b922c
 		                                            obj->fq_codel.ecn));
7b922c
 	}
7b922c
@@ -6506,7 +6506,7 @@ nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
7b922c
 		NM_CMP_FIELD (a, b, fq_codel.interval);
7b922c
 		NM_CMP_FIELD (a, b, fq_codel.quantum);
7b922c
 		NM_CMP_FIELD (a, b, fq_codel.ce_threshold);
7b922c
-		NM_CMP_FIELD (a, b, fq_codel.memory);
7b922c
+		NM_CMP_FIELD (a, b, fq_codel.memory_limit);
7b922c
 		NM_CMP_FIELD_UNSAFE (a, b, fq_codel.ecn);
7b922c
 	}
7b922c
 
7b922c
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
7b922c
index d7c388b1b8..5a0efceca7 100644
7b922c
--- a/src/platform/nm-platform.h
7b922c
+++ b/src/platform/nm-platform.h
7b922c
@@ -615,7 +615,7 @@ typedef struct {
7b922c
 	                       *   netlink attribute but also as the special value 0x83126E97u
7b922c
 	                       *   (NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED).
7b922c
 	                       *   Beware: zero is not the default you must always explicitly set this value. */
7b922c
-	guint32 memory;       /* TCA_FQ_CODEL_MEMORY_LIMIT: note that only values <= 2^31 are accepted by kernel
7b922c
+	guint32 memory_limit; /* TCA_FQ_CODEL_MEMORY_LIMIT: note that only values <= 2^31 are accepted by kernel
7b922c
 	                       *   and kernel defaults to 32MB.
7b922c
 	                       *   Note that we use the special value NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET
7b922c
 	                       *   to indicate that no explicit limit is set (when we send a RTM_NEWQDISC request).
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 79e3b2a838b1ae7e6174de8ff000509e918d5c90 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 12:58:37 +0200
7b922c
Subject: [PATCH 15/20] platform: use bool bitfields in NMPlatformActionMirred
7b922c
 structure
7b922c
7b922c
Arguably, the structure is used inside a union with another (larger)
7b922c
struct, hence no memory is saved.
7b922c
7b922c
In fact, it may well be slower performance wise to access a boolean bitfield
7b922c
than a gboolean (int).
7b922c
7b922c
Still, boolean fields in structures should be bool:1 bitfields for
7b922c
consistency.
7b922c
7b922c
(cherry picked from commit 36d6aa3bcd97f2144e8f435249ed8f3cb709ae43)
7b922c
---
7b922c
 src/platform/nm-platform.c | 19 ++++++++++---------
7b922c
 src/platform/nm-platform.h |  8 ++++----
7b922c
 2 files changed, 14 insertions(+), 13 deletions(-)
7b922c
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index ea73f21019..ee71319dd6 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -6577,11 +6577,12 @@ nm_platform_tfilter_hash_update (const NMPlatformTfilter *obj, NMHashState *h)
7b922c
 			nm_hash_update_strarr (h, obj->action.simple.sdata);
7b922c
 		} else if (nm_streq (obj->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
7b922c
 			nm_hash_update_vals (h,
7b922c
-			                     obj->action.mirred.ingress,
7b922c
-			                     obj->action.mirred.egress,
7b922c
-			                     obj->action.mirred.mirror,
7b922c
-			                     obj->action.mirred.redirect,
7b922c
-			                     obj->action.mirred.ifindex);
7b922c
+			                     obj->action.mirred.ifindex,
7b922c
+			                     NM_HASH_COMBINE_BOOLS (guint8,
7b922c
+			                                            obj->action.mirred.ingress,
7b922c
+			                                            obj->action.mirred.egress,
7b922c
+			                                            obj->action.mirred.mirror,
7b922c
+			                                            obj->action.mirred.redirect));
7b922c
 		}
7b922c
 	}
7b922c
 }
7b922c
@@ -6602,11 +6603,11 @@ nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b)
7b922c
 		if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
7b922c
 			NM_CMP_FIELD_STR (a, b, action.simple.sdata);
7b922c
 		} else if (nm_streq (a->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
7b922c
-			NM_CMP_FIELD (a, b, action.mirred.ingress);
7b922c
-			NM_CMP_FIELD (a, b, action.mirred.egress);
7b922c
-			NM_CMP_FIELD (a, b, action.mirred.mirror);
7b922c
-			NM_CMP_FIELD (a, b, action.mirred.redirect);
7b922c
 			NM_CMP_FIELD (a, b, action.mirred.ifindex);
7b922c
+			NM_CMP_FIELD_UNSAFE (a, b, action.mirred.ingress);
7b922c
+			NM_CMP_FIELD_UNSAFE (a, b, action.mirred.egress);
7b922c
+			NM_CMP_FIELD_UNSAFE (a, b, action.mirred.mirror);
7b922c
+			NM_CMP_FIELD_UNSAFE (a, b, action.mirred.redirect);
7b922c
 		}
7b922c
 	}
7b922c
 
7b922c
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
7b922c
index 5a0efceca7..9b6848d977 100644
7b922c
--- a/src/platform/nm-platform.h
7b922c
+++ b/src/platform/nm-platform.h
7b922c
@@ -641,11 +641,11 @@ typedef struct {
7b922c
 } NMPlatformActionSimple;
7b922c
 
7b922c
 typedef struct {
7b922c
-	gboolean egress;
7b922c
-	gboolean ingress;
7b922c
-	gboolean mirror;
7b922c
-	gboolean redirect;
7b922c
 	int ifindex;
7b922c
+	bool egress:1;
7b922c
+	bool ingress:1;
7b922c
+	bool mirror:1;
7b922c
+	bool redirect:1;
7b922c
 } NMPlatformActionMirred;
7b922c
 
7b922c
 typedef struct {
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 8b1b398c0545f31121c52d323276e013705ddf80 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 13:07:43 +0200
7b922c
Subject: [PATCH 16/20] platform: assert for out-of-memory in netlink code
7b922c
7b922c
These lines can be reached if the allocated buffer is too
7b922c
small to hold the netlink message. That is actually a bug
7b922c
that we need to fix. Assert.
7b922c
7b922c
(cherry picked from commit 3784a2a2ec6f8c6307f45bae12c17630b7d70b0a)
7b922c
---
7b922c
 src/platform/nm-linux-platform.c          | 10 +++++-----
7b922c
 src/platform/wifi/nm-wifi-utils-nl80211.c | 12 ++++++------
7b922c
 src/platform/wpan/nm-wpan-utils.c         |  8 ++++----
7b922c
 3 files changed, 15 insertions(+), 15 deletions(-)
7b922c
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index 9721ff9403..6dd5b4ab3e 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -3681,7 +3681,7 @@ _nl_msg_new_link_set_afspec (struct nl_msg *msg,
7b922c
 
7b922c
 	return TRUE;
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 static gboolean
7b922c
@@ -3832,7 +3832,7 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg,
7b922c
 
7b922c
 	return TRUE;
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 static struct nl_msg *
7b922c
@@ -4278,7 +4278,7 @@ _add_action_simple (struct nl_msg *msg,
7b922c
 	return TRUE;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 static gboolean
7b922c
@@ -4308,7 +4308,7 @@ _add_action_mirred (struct nl_msg *msg,
7b922c
 	return TRUE;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 static gboolean
7b922c
@@ -4334,7 +4334,7 @@ _add_action (struct nl_msg *msg,
7b922c
 	return TRUE;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 static struct nl_msg *
7b922c
diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c
7b922c
index 4f7ede9757..6a8525ed4b 100644
7b922c
--- a/src/platform/wifi/nm-wifi-utils-nl80211.c
7b922c
+++ b/src/platform/wifi/nm-wifi-utils-nl80211.c
7b922c
@@ -103,7 +103,7 @@ _nl80211_alloc_msg (int id, int ifindex, int phy, guint32 cmd, guint32 flags)
7b922c
 	return g_steal_pointer (&msg;;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return NULL;
7b922c
+	g_return_val_if_reached (NULL);
7b922c
 }
7b922c
 
7b922c
 static struct nl_msg *
7b922c
@@ -250,7 +250,7 @@ wifi_nl80211_set_mode (NMWifiUtils *data, const NM80211Mode mode)
7b922c
 	return err >= 0;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 static gboolean
7b922c
@@ -267,7 +267,7 @@ wifi_nl80211_set_powersave (NMWifiUtils *data, guint32 powersave)
7b922c
 	return err >= 0;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 static int
7b922c
@@ -365,7 +365,7 @@ wifi_nl80211_set_wake_on_wlan (NMWifiUtils *data, NMSettingWirelessWakeOnWLan wo
7b922c
 	return err >= 0;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 /* @divisor: pass what value @xbm should be divided by to get dBm */
7b922c
@@ -642,7 +642,7 @@ nl80211_get_ap_info (NMWifiUtilsNl80211 *self,
7b922c
 	return;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return;
7b922c
+	g_return_if_reached ();
7b922c
 }
7b922c
 
7b922c
 static guint32
7b922c
@@ -695,7 +695,7 @@ wifi_nl80211_indicate_addressing_running (NMWifiUtils *data, gboolean running)
7b922c
 	return err >= 0;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 struct nl80211_device_info {
7b922c
diff --git a/src/platform/wpan/nm-wpan-utils.c b/src/platform/wpan/nm-wpan-utils.c
7b922c
index b7a51e9bf2..0afc2a4d0c 100644
7b922c
--- a/src/platform/wpan/nm-wpan-utils.c
7b922c
+++ b/src/platform/wpan/nm-wpan-utils.c
7b922c
@@ -92,7 +92,7 @@ _nl802154_alloc_msg (int id, int ifindex, guint32 cmd, guint32 flags)
7b922c
 	return g_steal_pointer (&msg;;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return NULL;
7b922c
+	g_return_val_if_reached (NULL);
7b922c
 }
7b922c
 
7b922c
 static struct nl_msg *
7b922c
@@ -217,7 +217,7 @@ nm_wpan_utils_set_pan_id (NMWpanUtils *self, guint16 pan_id)
7b922c
 	return err >= 0;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 guint16
7b922c
@@ -244,7 +244,7 @@ nm_wpan_utils_set_short_addr (NMWpanUtils *self, guint16 short_addr)
7b922c
 	return err >= 0;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 gboolean
7b922c
@@ -262,7 +262,7 @@ nm_wpan_utils_set_channel (NMWpanUtils *self, guint8 page, guint8 channel)
7b922c
 	return err >= 0;
7b922c
 
7b922c
 nla_put_failure:
7b922c
-	return FALSE;
7b922c
+	g_return_val_if_reached (FALSE);
7b922c
 }
7b922c
 
7b922c
 /*****************************************************************************/
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 27341d042487afabcd48fbc08054069f89b9c424 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 13:15:57 +0200
7b922c
Subject: [PATCH 17/20] platform: merge _add_action(), _add_action_simple() and
7b922c
 _add_action_mirred() into _nl_msg_new_tfilter()
7b922c
7b922c
There is only one caller, hence it's simpler to see it all in one place.
7b922c
I prefer this, because then I can read the code top to bottom and
7b922c
see what's happening, without following helper functions.
7b922c
7b922c
Also, this way we can "reuse" the nla_put_failure label and assertion. Previously,
7b922c
if the assertion was hit we would not rewind the buffer but continue
7b922c
constructing the message (which is already borked). Not that it matters
7b922c
too much, because this was on an "failed-assertion" code path.
7b922c
7b922c
(cherry picked from commit 04bd404dffc8bc1ec5c3fed91e75fad1a1b1a4d3)
7b922c
---
7b922c
 src/platform/nm-linux-platform.c | 125 ++++++++++++-------------------
7b922c
 1 file changed, 46 insertions(+), 79 deletions(-)
7b922c
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index 6dd5b4ab3e..4a62a76485 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -4260,83 +4260,6 @@ nla_put_failure:
7b922c
 	g_return_val_if_reached (NULL);
7b922c
 }
7b922c
 
7b922c
-static gboolean
7b922c
-_add_action_simple (struct nl_msg *msg,
7b922c
-                    const NMPlatformActionSimple *simple)
7b922c
-{
7b922c
-	struct nlattr *act_options;
7b922c
-	struct tc_defact sel = { 0, };
7b922c
-
7b922c
-	if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS)))
7b922c
-		goto nla_put_failure;
7b922c
-
7b922c
-	NLA_PUT (msg, TCA_DEF_PARMS, sizeof (sel), &sel;;
7b922c
-	NLA_PUT (msg, TCA_DEF_DATA, sizeof (simple->sdata), simple->sdata);
7b922c
-
7b922c
-	nla_nest_end (msg, act_options);
7b922c
-
7b922c
-	return TRUE;
7b922c
-
7b922c
-nla_put_failure:
7b922c
-	g_return_val_if_reached (FALSE);
7b922c
-}
7b922c
-
7b922c
-static gboolean
7b922c
-_add_action_mirred (struct nl_msg *msg,
7b922c
-                    const NMPlatformActionMirred *mirred)
7b922c
-{
7b922c
-	struct nlattr *act_options;
7b922c
-	struct tc_mirred sel = { 0, };
7b922c
-
7b922c
-	if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS)))
7b922c
-		goto nla_put_failure;
7b922c
-
7b922c
-	if (mirred->egress && mirred->redirect)
7b922c
-		sel.eaction = TCA_EGRESS_REDIR;
7b922c
-	else if (mirred->egress && mirred->mirror)
7b922c
-		sel.eaction = TCA_EGRESS_MIRROR;
7b922c
-	else if (mirred->ingress && mirred->redirect)
7b922c
-		sel.eaction = TCA_INGRESS_REDIR;
7b922c
-	else if (mirred->ingress && mirred->mirror)
7b922c
-		sel.eaction = TCA_INGRESS_MIRROR;
7b922c
-	sel.ifindex = mirred->ifindex;
7b922c
-
7b922c
-	NLA_PUT (msg, TCA_MIRRED_PARMS, sizeof (sel), &sel;;
7b922c
-
7b922c
-	nla_nest_end (msg, act_options);
7b922c
-
7b922c
-	return TRUE;
7b922c
-
7b922c
-nla_put_failure:
7b922c
-	g_return_val_if_reached (FALSE);
7b922c
-}
7b922c
-
7b922c
-static gboolean
7b922c
-_add_action (struct nl_msg *msg,
7b922c
-             const NMPlatformAction *action)
7b922c
-{
7b922c
-	struct nlattr *prio;
7b922c
-
7b922c
-	nm_assert (action || action->kind);
7b922c
-
7b922c
-	if (!(prio = nla_nest_start (msg, 1 /* priority */)))
7b922c
-		goto nla_put_failure;
7b922c
-
7b922c
-	NLA_PUT_STRING (msg, TCA_ACT_KIND, action->kind);
7b922c
-
7b922c
-	if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE))
7b922c
-		_add_action_simple (msg, &action->simple);
7b922c
-	else if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_MIRRED))
7b922c
-		_add_action_mirred (msg, &action->mirred);
7b922c
-
7b922c
-	nla_nest_end (msg, prio);
7b922c
-
7b922c
-	return TRUE;
7b922c
-
7b922c
-nla_put_failure:
7b922c
-	g_return_val_if_reached (FALSE);
7b922c
-}
7b922c
-
7b922c
 static struct nl_msg *
7b922c
 _nl_msg_new_tfilter (int nlmsg_type,
7b922c
                      int nlmsg_flags,
7b922c
@@ -4366,8 +4289,52 @@ _nl_msg_new_tfilter (int nlmsg_type,
7b922c
 	if (!(act_tab = nla_nest_start (msg, TCA_OPTIONS))) // 3 TCA_ACT_KIND TCA_ACT_KIND
7b922c
 		goto nla_put_failure;
7b922c
 
7b922c
-	if (tfilter->action.kind)
7b922c
-		_add_action (msg, &tfilter->action);
7b922c
+	if (tfilter->action.kind) {
7b922c
+		const NMPlatformAction *action = &tfilter->action;
7b922c
+		struct nlattr *prio;
7b922c
+		struct nlattr *act_options;
7b922c
+
7b922c
+		if (!(prio = nla_nest_start (msg, 1 /* priority */)))
7b922c
+			goto nla_put_failure;
7b922c
+
7b922c
+		NLA_PUT_STRING (msg, TCA_ACT_KIND, action->kind);
7b922c
+
7b922c
+		if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) {
7b922c
+			const NMPlatformActionSimple *simple = &action->simple;
7b922c
+			struct tc_defact sel = { 0, };
7b922c
+
7b922c
+			if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS)))
7b922c
+				goto nla_put_failure;
7b922c
+
7b922c
+			NLA_PUT (msg, TCA_DEF_PARMS, sizeof (sel), &sel;;
7b922c
+			NLA_PUT (msg, TCA_DEF_DATA, sizeof (simple->sdata), simple->sdata);
7b922c
+
7b922c
+			nla_nest_end (msg, act_options);
7b922c
+
7b922c
+		} else if (nm_streq (action->kind, NM_PLATFORM_ACTION_KIND_MIRRED)) {
7b922c
+			const NMPlatformActionMirred *mirred = &action->mirred;
7b922c
+			struct tc_mirred sel = { 0, };
7b922c
+
7b922c
+			if (!(act_options = nla_nest_start (msg, TCA_ACT_OPTIONS)))
7b922c
+				goto nla_put_failure;
7b922c
+
7b922c
+			if (mirred->egress && mirred->redirect)
7b922c
+				sel.eaction = TCA_EGRESS_REDIR;
7b922c
+			else if (mirred->egress && mirred->mirror)
7b922c
+				sel.eaction = TCA_EGRESS_MIRROR;
7b922c
+			else if (mirred->ingress && mirred->redirect)
7b922c
+				sel.eaction = TCA_INGRESS_REDIR;
7b922c
+			else if (mirred->ingress && mirred->mirror)
7b922c
+				sel.eaction = TCA_INGRESS_MIRROR;
7b922c
+			sel.ifindex = mirred->ifindex;
7b922c
+
7b922c
+			NLA_PUT (msg, TCA_MIRRED_PARMS, sizeof (sel), &sel;;
7b922c
+
7b922c
+			nla_nest_end (msg, act_options);
7b922c
+		}
7b922c
+
7b922c
+		nla_nest_end (msg, prio);
7b922c
+	}
7b922c
 
7b922c
 	nla_nest_end (msg, tc_options);
7b922c
 
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From a0161aa9772af8d7a35812dfdf86864bb941f751 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 13:27:28 +0200
7b922c
Subject: [PATCH 18/20] device/trivial: add space between macro name and
7b922c
 arguments and vertically align lines
7b922c
7b922c
Also calling macros we commonly put a space between the macro name and
7b922c
the parenthesis.
7b922c
7b922c
Also align the parameters. Otherwise it's hard to read for me.
7b922c
7b922c
(cherry picked from commit 9399297a82cbb5e8fc218fdefde7005353cb44d6)
7b922c
---
7b922c
 src/devices/nm-device.c | 16 ++++++++--------
7b922c
 1 file changed, 8 insertions(+), 8 deletions(-)
7b922c
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index e2a5fd4bf2..1241a098d1 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6533,14 +6533,14 @@ tc_commit (NMDevice *self)
7b922c
 } G_STMT_END
7b922c
 
7b922c
 			if (strcmp (qdisc->kind, "fq_codel") == 0) {
7b922c
-				GET_ATTR("limit", qdisc->fq_codel.limit, UINT32, uint32, 0);
7b922c
-				GET_ATTR("flows", qdisc->fq_codel.flows, UINT32, uint32, 0);
7b922c
-				GET_ATTR("target", qdisc->fq_codel.target, UINT32, uint32, 0);
7b922c
-				GET_ATTR("interval", qdisc->fq_codel.interval, UINT32, uint32, 0);
7b922c
-				GET_ATTR("quantum", qdisc->fq_codel.quantum, UINT32, uint32, 0);
7b922c
-				GET_ATTR("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32, uint32, NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED);
7b922c
-				GET_ATTR("memory_limit", qdisc->fq_codel.memory_limit, UINT32, uint32, NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET);
7b922c
-				GET_ATTR("ecn", qdisc->fq_codel.ecn, BOOLEAN, boolean, FALSE);
7b922c
+				GET_ATTR ("limit",        qdisc->fq_codel.limit,        UINT32,  uint32,  0);
7b922c
+				GET_ATTR ("flows",        qdisc->fq_codel.flows,        UINT32,  uint32,  0);
7b922c
+				GET_ATTR ("target",       qdisc->fq_codel.target,       UINT32,  uint32,  0);
7b922c
+				GET_ATTR ("interval",     qdisc->fq_codel.interval,     UINT32,  uint32,  0);
7b922c
+				GET_ATTR ("quantum",      qdisc->fq_codel.quantum,      UINT32,  uint32,  0);
7b922c
+				GET_ATTR ("ce_threshold", qdisc->fq_codel.ce_threshold, UINT32,  uint32,  NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED);
7b922c
+				GET_ATTR ("memory_limit", qdisc->fq_codel.memory_limit, UINT32,  uint32,  NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET);
7b922c
+				GET_ATTR ("ecn",          qdisc->fq_codel.ecn,          BOOLEAN, boolean, FALSE);
7b922c
 			}
7b922c
 
7b922c
 #undef GET_ADDR
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From ea7de52d774f3aa3a099f6fce1cb9313b6456cef Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 16:34:27 +0200
7b922c
Subject: [PATCH 19/20] device: don't rely on nm_platform_link_get_ifindex()
7b922c
 returning 0
7b922c
7b922c
While nm_platform_link_get_ifindex() is documented to return 0 if the device
7b922c
is not found, don't rely on it. Instead, check that a valid(!) ifindex was
7b922c
returned, and only then set the ifindex. Otherwise leave it at zero. There
7b922c
is of course no difference in practice, but we generally treat invalid ifindexes
7b922c
as <= 0, so it's not immediately clear what nm_platform_link_get_ifindex()
7b922c
returns to signal no device.
7b922c
7b922c
(cherry picked from commit 9eefe27a1c7879e6f94bbb7dec5c9efe722888fa)
7b922c
---
7b922c
 src/devices/nm-device.c | 11 +++++++----
7b922c
 1 file changed, 7 insertions(+), 4 deletions(-)
7b922c
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index 1241a098d1..5195eb667f 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6504,7 +6504,7 @@ tc_commit (NMDevice *self)
7b922c
 
7b922c
 	ip_ifindex = nm_device_get_ip_ifindex (self);
7b922c
 	if (!ip_ifindex)
7b922c
-	       return s_tc == NULL;
7b922c
+		return s_tc == NULL;
7b922c
 
7b922c
 	if (s_tc) {
7b922c
 		nqdiscs = nm_setting_tc_config_get_num_qdiscs (s_tc);
7b922c
@@ -6591,9 +6591,12 @@ tc_commit (NMDevice *self)
7b922c
 
7b922c
 					var = nm_tc_action_get_attribute (action, "dev");
7b922c
 					if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_STRING)) {
7b922c
-						int ifindex = nm_platform_link_get_ifindex (nm_device_get_platform (self),
7b922c
-						                                            g_variant_get_string (var, NULL));
7b922c
-						tfilter->action.mirred.ifindex = ifindex;
7b922c
+						int ifindex;
7b922c
+
7b922c
+						ifindex = nm_platform_link_get_ifindex (nm_device_get_platform (self),
7b922c
+						                                        g_variant_get_string (var, NULL));
7b922c
+						if (ifindex > 0)
7b922c
+							tfilter->action.mirred.ifindex = ifindex;
7b922c
 					}
7b922c
 				}
7b922c
 			}
7b922c
-- 
7b922c
2.21.0
7b922c
7b922c
From 6d9030acb60c2f9a89224847f0a5e68f8b55b0f0 Mon Sep 17 00:00:00 2001
7b922c
From: Thomas Haller <thaller@redhat.com>
7b922c
Date: Wed, 1 May 2019 16:35:29 +0200
7b922c
Subject: [PATCH 20/20] device/trivial: add comment about lifetime of "kind" in
7b922c
 tc_commit()
7b922c
7b922c
In general, all fields of public NMPlatform* structs must be
7b922c
plain/simple. Meaning: copying the struct must be possible without
7b922c
caring about cloning/duplicating memory.
7b922c
In other words, if there are fields which lifetime is limited,
7b922c
then these fields cannot be inside the public part NMPlatform*.
7b922c
7b922c
That is why
7b922c
7b922c
  - "NMPlatformLink.kind", "NMPlatformQdisc.kind", "NMPlatformTfilter.kind"
7b922c
    are set by platform code to an interned string (g_intern_string())
7b922c
    that has a static lifetime.
7b922c
7b922c
  - the "ingress_qos_map" field is inside the ref-counted struct NMPObjectLnkVlan
7b922c
    and not NMPlatformLnkVlan. This field requires managing the lifetime
7b922c
    of the array and NMPlatformLnkVlan cannot provide that.
7b922c
7b922c
See also for example NMPClass.cmd_obj_copy() which can deep-copy an object.
7b922c
But this is only suitable for fields in NMPObject*. The purpose of this
7b922c
rule is that you always can safely copy a NMPlatform* struct without
7b922c
worrying about the ownership and lifetime of the fields (the field's
7b922c
lifetime is unlimited).
7b922c
7b922c
This rule and managing of resource lifetime is the main reason for the
7b922c
NMPlatform*/NMPObject* split. NMPlatform* structs simply have no mechanism
7b922c
for copying/releasing fields, that is why the NMPObject* counterpart exists
7b922c
(which is ref-counted and has a copy and destructor function).
7b922c
7b922c
This is violated in tc_commit() for the "kind" strings. The lifetime
7b922c
of these strings is tied to the setting instance.
7b922c
7b922c
We cannot intern the strings (because these are arbitrary strings
7b922c
and interned strings are leaked indefinitely). We also cannot g_strdup()
7b922c
the strings, because NMPlatform* is not supposed to own strings.
7b922c
7b922c
So, just add comments that warn about this ugliness.
7b922c
7b922c
The more correct solution would be to move the "kind" fields inside
7b922c
NMPObjectQdisc and NMPObjectTfilter, but that is a lot of extra effort.
7b922c
7b922c
(cherry picked from commit f2ae994b2359aa690183a268c5b4cc8fb1a6012e)
7b922c
---
7b922c
 src/devices/nm-device.c          | 14 +++++++++++++
7b922c
 src/platform/nm-linux-platform.c |  6 ++++++
7b922c
 src/platform/nm-platform.c       | 34 ++++++++++++++++++++++++++++++++
7b922c
 src/platform/nm-platform.h       | 12 +++++++++++
7b922c
 4 files changed, 66 insertions(+)
7b922c
7b922c
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
7b922c
index 5195eb667f..09ba9c5d57 100644
7b922c
--- a/src/devices/nm-device.c
7b922c
+++ b/src/devices/nm-device.c
7b922c
@@ -6516,7 +6516,12 @@ tc_commit (NMDevice *self)
7b922c
 			NMPlatformQdisc *qdisc = NMP_OBJECT_CAST_QDISC (q);
7b922c
 
7b922c
 			qdisc->ifindex = ip_ifindex;
7b922c
+
7b922c
+			/* Note: kind string is still owned by NMTCTfilter.
7b922c
+			 * This qdisc instance must not be kept alive beyond this function.
7b922c
+			 * nm_platform_qdisc_sync() promises to do that. */
7b922c
 			qdisc->kind = nm_tc_qdisc_get_kind (s_qdisc);
7b922c
+
7b922c
 			qdisc->addr_family = AF_UNSPEC;
7b922c
 			qdisc->handle = nm_tc_qdisc_get_handle (s_qdisc);
7b922c
 			qdisc->parent = nm_tc_qdisc_get_parent (s_qdisc);
7b922c
@@ -6558,7 +6563,12 @@ tc_commit (NMDevice *self)
7b922c
 			NMPlatformTfilter *tfilter = NMP_OBJECT_CAST_TFILTER (q);
7b922c
 
7b922c
 			tfilter->ifindex = ip_ifindex;
7b922c
+
7b922c
+			/* Note: kind string is still owned by NMTCTfilter.
7b922c
+			 * This tfilter instance must not be kept alive beyond this function.
7b922c
+			 * nm_platform_tfilter_sync() promises to do that. */
7b922c
 			tfilter->kind = nm_tc_tfilter_get_kind (s_tfilter);
7b922c
+
7b922c
 			tfilter->addr_family = AF_UNSPEC;
7b922c
 			tfilter->handle = nm_tc_tfilter_get_handle (s_tfilter);
7b922c
 			tfilter->parent = nm_tc_tfilter_get_parent (s_tfilter);
7b922c
@@ -6568,7 +6578,11 @@ tc_commit (NMDevice *self)
7b922c
 			if (action) {
7b922c
 				GVariant *var;
7b922c
 
7b922c
+				/* Note: kind string is still owned by NMTCAction.
7b922c
+				 * This tfilter instance must not be kept alive beyond this function.
7b922c
+				 * nm_platform_tfilter_sync() promises to do that. */
7b922c
 				tfilter->action.kind = nm_tc_action_get_kind (action);
7b922c
+
7b922c
 				if (strcmp (tfilter->action.kind, "simple") == 0) {
7b922c
 					var = nm_tc_action_get_attribute (action, "sdata");
7b922c
 					if (var && g_variant_is_of_type (var, G_VARIANT_TYPE_BYTESTRING)) {
7b922c
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
7b922c
index 4a62a76485..7d66a88fa7 100644
7b922c
--- a/src/platform/nm-linux-platform.c
7b922c
+++ b/src/platform/nm-linux-platform.c
7b922c
@@ -8244,6 +8244,9 @@ qdisc_add (NMPlatform *platform,
7b922c
 	char s_buf[256];
7b922c
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
7b922c
 
7b922c
+	/* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind
7b922c
+	 * is undefined. */
7b922c
+
7b922c
 	msg = _nl_msg_new_qdisc (RTM_NEWQDISC, flags, qdisc);
7b922c
 
7b922c
 	event_handler_read_netlink (platform, FALSE);
7b922c
@@ -8285,6 +8288,9 @@ tfilter_add (NMPlatform *platform,
7b922c
 	char s_buf[256];
7b922c
 	nm_auto_nlmsg struct nl_msg *msg = NULL;
7b922c
 
7b922c
+	/* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind
7b922c
+	 * and tfilter.action.kind is undefined. */
7b922c
+
7b922c
 	msg = _nl_msg_new_tfilter (RTM_NEWTFILTER, flags, tfilter);
7b922c
 
7b922c
 	event_handler_read_netlink (platform, FALSE);
7b922c
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
7b922c
index ee71319dd6..7add7dcdbe 100644
7b922c
--- a/src/platform/nm-platform.c
7b922c
+++ b/src/platform/nm-platform.c
7b922c
@@ -5077,10 +5077,27 @@ nm_platform_qdisc_add (NMPlatform *self,
7b922c
 	int ifindex = qdisc->ifindex;
7b922c
 	_CHECK_SELF (self, klass, -NME_BUG);
7b922c
 
7b922c
+	/* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind
7b922c
+	 * is undefined. */
7b922c
+
7b922c
 	_LOG3D ("adding or updating a qdisc: %s", nm_platform_qdisc_to_string (qdisc, NULL, 0));
7b922c
 	return klass->qdisc_add (self, flags, qdisc);
7b922c
 }
7b922c
 
7b922c
+/**
7b922c
+ * nm_platform_qdisc_sync:
7b922c
+ * @self: the #NMPlatform instance
7b922c
+ * @ifindex: the ifindex where to configure the qdiscs.
7b922c
+ * @known_qdiscs: the list of qdiscs (#NMPObject).
7b922c
+ *
7b922c
+ * The function promises not to take any reference to the qdisc
7b922c
+ * instances from @known_qdiscs, nor to keep them around after
7b922c
+ * the function returns. This is important, because it allows the
7b922c
+ * caller to pass NMPlatformQdisc instances which "kind" string
7b922c
+ * have a limited lifetime.
7b922c
+ *
7b922c
+ * Returns: %TRUE on success.
7b922c
+ */
7b922c
 gboolean
7b922c
 nm_platform_qdisc_sync (NMPlatform *self,
7b922c
                         int ifindex,
7b922c
@@ -5143,10 +5160,27 @@ nm_platform_tfilter_add (NMPlatform *self,
7b922c
 	int ifindex = tfilter->ifindex;
7b922c
 	_CHECK_SELF (self, klass, -NME_BUG);
7b922c
 
7b922c
+	/* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind
7b922c
+	 * and tfilter.action.kind is undefined. */
7b922c
+
7b922c
 	_LOG3D ("adding or updating a tfilter: %s", nm_platform_tfilter_to_string (tfilter, NULL, 0));
7b922c
 	return klass->tfilter_add (self, flags, tfilter);
7b922c
 }
7b922c
 
7b922c
+/**
7b922c
+ * nm_platform_qdisc_sync:
7b922c
+ * @self: the #NMPlatform instance
7b922c
+ * @ifindex: the ifindex where to configure the qdiscs.
7b922c
+ * @known_tfilters: the list of tfilters (#NMPObject).
7b922c
+ *
7b922c
+ * The function promises not to take any reference to the tfilter
7b922c
+ * instances from @known_tfilters, nor to keep them around after
7b922c
+ * the function returns. This is important, because it allows the
7b922c
+ * caller to pass NMPlatformTfilter instances which "kind" string
7b922c
+ * have a limited lifetime.
7b922c
+ *
7b922c
+ * Returns: %TRUE on success.
7b922c
+ */
7b922c
 gboolean
7b922c
 nm_platform_tfilter_sync (NMPlatform *self,
7b922c
                           int ifindex,
7b922c
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
7b922c
index 9b6848d977..a2d8e57ff6 100644
7b922c
--- a/src/platform/nm-platform.h
7b922c
+++ b/src/platform/nm-platform.h
7b922c
@@ -626,7 +626,11 @@ typedef struct {
7b922c
 
7b922c
 typedef struct {
7b922c
 	__NMPlatformObjWithIfindex_COMMON;
7b922c
+
7b922c
+	/* beware, kind is embedded in an NMPObject, hence you must
7b922c
+	 * take care of the lifetime of the string. */
7b922c
 	const char *kind;
7b922c
+
7b922c
 	int addr_family;
7b922c
 	guint32 handle;
7b922c
 	guint32 parent;
7b922c
@@ -649,7 +653,11 @@ typedef struct {
7b922c
 } NMPlatformActionMirred;
7b922c
 
7b922c
 typedef struct {
7b922c
+
7b922c
+	/* beware, kind is embedded in an NMPObject, hence you must
7b922c
+	 * take care of the lifetime of the string. */
7b922c
 	const char *kind;
7b922c
+
7b922c
 	union {
7b922c
 		NMPlatformActionSimple simple;
7b922c
 		NMPlatformActionMirred mirred;
7b922c
@@ -661,7 +669,11 @@ typedef struct {
7b922c
 
7b922c
 typedef struct {
7b922c
 	__NMPlatformObjWithIfindex_COMMON;
7b922c
+
7b922c
+	/* beware, kind is embedded in an NMPObject, hence you must
7b922c
+	 * take care of the lifetime of the string. */
7b922c
 	const char *kind;
7b922c
+
7b922c
 	int addr_family;
7b922c
 	guint32 handle;
7b922c
 	guint32 parent;
7b922c
-- 
7b922c
2.21.0
7b922c