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.
This commit is contained in:
Beniamino Galvani 2020-05-22 17:49:39 +02:00
parent 9a4578c8f9
commit 9064502834
2 changed files with 48 additions and 10 deletions

View file

@ -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)
{

View file

@ -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);