diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-06-20 10:37:32 +0000 |
|---|---|---|
| committer | Christian Breunig <christian@breunig.cc> | 2026-06-22 21:33:50 +0200 |
| commit | 50ffc690fdeaaa30a9f353bc76fe87d748cc2e58 (patch) | |
| tree | afebfe34d5924d11b5015cb956008d2d3e259c32 /src/conf_mode | |
| parent | 2c6c98060ec2af764d4802ec58969399854eb140 (diff) | |
| download | vyos-1x-50ffc690fdeaaa30a9f353bc76fe87d748cc2e58.tar.gz vyos-1x-50ffc690fdeaaa30a9f353bc76fe87d748cc2e58.zip | |
vyos-netlink: T7965: only re-apply QoS configuration to individual interface
The previous vyos-netlinkd implementation for QoS policy re-apply was very heavy.
It conducted a full CLI validation and re-apply on every interface. Instead we
do not only re-apply the QoS configuration to the interface which has had an
address change detected by vyos-netlinkd.
This can be tested by checking "tc qdisc show" before disconnecting a PPPoE
interface and during/after reconnect. There will be no qdisc until the dynamic
interface has received an IP address - then the qdisc will be re-applied.
Diffstat (limited to 'src/conf_mode')
| -rwxr-xr-x | src/conf_mode/qos.py | 43 |
1 files changed, 28 insertions, 15 deletions
diff --git a/src/conf_mode/qos.py b/src/conf_mode/qos.py index e31c6b931..1e6797c60 100755 --- a/src/conf_mode/qos.py +++ b/src/conf_mode/qos.py @@ -349,6 +349,32 @@ def generate(qos): return None +def apply_interface(qos, ifname): + """ Clear and re-apply QoS for a single interface only. """ + run(f'tc qdisc del dev {ifname} parent ffff:') + run(f'tc qdisc del dev {ifname} root') + + if not qos or 'interface' not in qos or ifname not in qos['interface']: + return None + + interface_config = qos['interface'][ifname] + if not verify_interface_exists(qos, ifname, state_required=True, warning_only=True): + # When shaper is bound to a dialup (e.g. PPPoE) interface it is + # possible that it is yet not available when the QoS code runs. + # Skip the configuration and inform the user via warning_only=True + return None + + for direction in ['egress', 'ingress']: + # bail out early if shaper for given direction is not used at all + if direction not in interface_config: + continue + + shaper_type, shaper_config = get_shaper(qos, interface_config, direction) + shaper_type(ifname).update(shaper_config, direction) + + return None + + def apply(qos): # Always delete "old" shapers first for interface in interfaces(): @@ -361,21 +387,8 @@ def apply(qos): if not qos or 'interface' not in qos: return None - for interface, interface_config in qos['interface'].items(): - if not verify_interface_exists(qos, interface, state_required=True, warning_only=True): - # When shaper is bound to a dialup (e.g. PPPoE) interface it is - # possible that it is yet not available when to QoS code runs. - # Skip the configuration and inform the user via warning_only=True - continue - - for direction in ['egress', 'ingress']: - # bail out early if shaper for given direction is not used at all - if direction not in interface_config: - continue - - shaper_type, shaper_config = get_shaper(qos, interface_config, direction) - tmp = shaper_type(interface) - tmp.update(shaper_config, direction) + for ifname in qos['interface']: + apply_interface(qos, ifname) return None |
