diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2020-05-22 17:49:39 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2020-05-28 17:25:22 +0200 |
commit | 9064502834a650d8cb1a40f11b9833162679b109 (patch) | |
tree | 3a892dcd10ea7ca365f874b9843f7365961abdd1 | |
parent | 9a4578c8f9c8e098b6e9816c39841b60e1e62a26 (diff) | |
download | NetworkManager-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.c | 55 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 3 |
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); |