virnetdevbandwidth: Unbreak tc filter update on Linux-4.20+

Guests are allowed to change their MAC addresses. Subsequently,
we may respond to that with tweaking that part of host side
configuration that depends on it. In this particular case: QoS.

Some parts of QoS are in fact set on corresponding bridge, where
overall view on traffic can be seen. Here, TC filters are used to
place incoming packets into qdiscs. These filters match source
MAC address. Therefore, upon guest changing its MAC address, the
corresponding TC filter needs to be updated too. This is done by
simply removing the old one and instantiating a new one, with new
MAC address.

Now, u32 filters (which we use) use a hash table for matching,
internally. And when deleting the old filter, we used to remove
the hash table (ID = 800::) and let the new filter instantiate
new hash table. This used to work, until kernel release 4.20
(specifically commit v4.20-rc1~27^2~131^2~11 and its friends)
where this practice was turned into error.

But that's okay - we can delete the specific filter we are after
and not touch the hash table at all.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
Michal Privoznik 2022-11-24 12:34:56 +01:00
parent 0862cb3ce4
commit 3dce400c12
1 changed files with 4 additions and 2 deletions

View File

@ -114,8 +114,10 @@ virNetDevBandwidthManipulateFilter(const char *ifname,
goto cleanup;
}
/* u32 filters must have 800:: prefix. Don't ask. */
filter_id = g_strdup_printf("800::%u", id);
/* u32 filters must have 800:: prefix. Don't ask. Furthermore, handles
* start at 800. Therefore, we want the filter ID to look like this:
* 800::(800 + id) */
filter_id = g_strdup_printf("800::%u", 800 + id);
if (remove_old) {
g_autoptr(virCommand) cmd = virCommandNew(TC);