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

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