summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2020-05-22 17:49:39 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2020-05-28 17:25:22 +0200
commit9064502834a650d8cb1a40f11b9833162679b109 (patch)
tree3a892dcd10ea7ca365f874b9843f7365961abdd1
parent9a4578c8f9c8e098b6e9816c39841b60e1e62a26 (diff)
downloadNetworkManager-9064502834a650d8cb1a40f11b9833162679b109.tar.gz
platform: rework qdisc synchronization
Rework qdisc synchronization. The previous implementation added all known qdiscs and removed unneeded ones from platform; this had some problems: - kernel doesn't allow to add (with exclusive flag) a qdisc if one with the same parent already exists; - if we use the replace flag instead of add, then it becomes possible to add a new qdisc with the same parent of an existing one. However if the existing qdisc is of the same kind, kernel will try to to change() it, which fails for some qdiscs (e.g. sfq). - kernel doesn't allow to delete a qdisc with handle of zero because that is the default qdisc and can only be replaced; Fix that.
-rw-r--r--src/platform/nm-platform.c55
-rw-r--r--src/platform/nm-platform.h3
2 files changed, 48 insertions, 10 deletions
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 33aa8db69e..5ac788f73f 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -5064,12 +5064,15 @@ nm_platform_qdisc_sync (NMPlatform *self,
known_qdiscs_idx = g_hash_table_new ((GHashFunc) nmp_object_id_hash,
(GEqualFunc) nmp_object_id_equal);
-
if (known_qdiscs) {
for (i = 0; i < known_qdiscs->len; i++) {
const NMPObject *q = g_ptr_array_index (known_qdiscs, i);
- g_hash_table_insert (known_qdiscs_idx, (gpointer) q, (gpointer) q);
+ if (!g_hash_table_insert (known_qdiscs_idx, (gpointer) q, (gpointer) q)) {
+ _LOGW ("duplicate qdisc %s", nm_platform_qdisc_to_string (&q->qdisc, NULL, 0));
+ return FALSE;
+ }
+
}
}
@@ -5078,13 +5081,34 @@ nm_platform_qdisc_sync (NMPlatform *self,
NMP_OBJECT_TYPE_QDISC,
ifindex),
NULL, NULL);
-
if (plat_qdiscs) {
for (i = 0; i < plat_qdiscs->len; i++) {
- const NMPObject *q = g_ptr_array_index (plat_qdiscs, i);
+ const NMPObject *p = g_ptr_array_index (plat_qdiscs, i);
+ const NMPObject *k;
- if (!g_hash_table_lookup (known_qdiscs_idx, q))
- success &= nm_platform_object_delete (self, q);
+ /* look up known qdisc with same parent */
+ k = g_hash_table_lookup (known_qdiscs_idx, p);
+
+ if (k) {
+ const NMPlatformQdisc *qdisc_k = NMP_OBJECT_CAST_QDISC (k);
+ const NMPlatformQdisc *qdisc_p = NMP_OBJECT_CAST_QDISC (p);
+
+ /* check other fields */
+ if ( nm_platform_qdisc_cmp_full (qdisc_k, qdisc_p, FALSE) != 0
+ || ( qdisc_k->handle != qdisc_p->handle
+ && qdisc_k != 0)) {
+ k = NULL;
+ }
+ }
+
+ if (k) {
+ g_hash_table_remove (known_qdiscs_idx, k);
+ } else {
+ /* can't delete qdisc with zero handle */
+ if (TC_H_MAJ (p->qdisc.handle) != 0) {
+ success &= nm_platform_object_delete (self, p);
+ }
+ }
}
}
@@ -5092,8 +5116,10 @@ nm_platform_qdisc_sync (NMPlatform *self,
for (i = 0; i < known_qdiscs->len; i++) {
const NMPObject *q = g_ptr_array_index (known_qdiscs, i);
- success &= (nm_platform_qdisc_add (self, NMP_NLM_FLAG_ADD,
- NMP_OBJECT_CAST_QDISC (q)) >= 0);
+ if (g_hash_table_contains (known_qdiscs_idx, q)) {
+ success &= (nm_platform_qdisc_add (self, NMP_NLM_FLAG_ADD,
+ NMP_OBJECT_CAST_QDISC (q)) >= 0);
+ }
}
}
@@ -6518,14 +6544,17 @@ nm_platform_qdisc_hash_update (const NMPlatformQdisc *obj, NMHashState *h)
}
int
-nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
+nm_platform_qdisc_cmp_full (const NMPlatformQdisc *a,
+ const NMPlatformQdisc *b,
+ gboolean compare_handle)
{
NM_CMP_SELF (a, b);
NM_CMP_FIELD (a, b, ifindex);
NM_CMP_FIELD (a, b, parent);
NM_CMP_FIELD_STR_INTERNED (a, b, kind);
NM_CMP_FIELD (a, b, addr_family);
- NM_CMP_FIELD (a, b, handle);
+ if (compare_handle)
+ NM_CMP_FIELD (a, b, handle);
NM_CMP_FIELD (a, b, info);
if (nm_streq0 (a->kind, "fq_codel")) {
@@ -6542,6 +6571,12 @@ nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
return 0;
}
+int
+nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b)
+{
+ return nm_platform_qdisc_cmp_full (a, b, TRUE);
+}
+
const char *
nm_platform_tfilter_to_string (const NMPlatformTfilter *tfilter, char *buf, gsize len)
{
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 4bfbfea432..fb82262979 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -1909,6 +1909,9 @@ nm_platform_routing_rule_cmp_full (const NMPlatformRoutingRule *a, const NMPlatf
}
int nm_platform_qdisc_cmp (const NMPlatformQdisc *a, const NMPlatformQdisc *b);
+int nm_platform_qdisc_cmp_full (const NMPlatformQdisc *a,
+ const NMPlatformQdisc *b,
+ gboolean compare_handle);
int nm_platform_tfilter_cmp (const NMPlatformTfilter *a, const NMPlatformTfilter *b);
void nm_platform_link_hash_update (const NMPlatformLink *obj, NMHashState *h);