diff options
| author | Nataliia Solomko <natalirs1985@gmail.com> | 2025-09-24 11:56:19 +0300 |
|---|---|---|
| committer | Nataliia Solomko <natalirs1985@gmail.com> | 2025-10-31 18:20:41 +0200 |
| commit | 73b7431862d8da2e8063a6062f29fd0f65fdd210 (patch) | |
| tree | 74d4084b991e127ee03b1becf84b34379f6725a3 /python | |
| parent | 89e4e09ece8e54303f3d5e1f1ab4927e2351b24a (diff) | |
| download | vyos-1x-73b7431862d8da2e8063a6062f29fd0f65fdd210.tar.gz vyos-1x-73b7431862d8da2e8063a6062f29fd0f65fdd210.zip | |
T7789: T7661: VPP prevent failing to set XDP driver on clouds
Some cloud NICs (ena, gve) fail to load XDP if all RX queues are configured. To
avoid this, we limit the number of queues to half of the maximum supported by the driver.
Diffstat (limited to 'python')
| -rw-r--r-- | python/vyos/ethtool.py | 23 | ||||
| -rw-r--r-- | python/vyos/ifconfig/ethernet.py | 17 | ||||
| -rw-r--r-- | python/vyos/vpp/control_host.py | 38 | ||||
| -rw-r--r-- | python/vyos/vpp/control_vpp.py | 2 |
4 files changed, 79 insertions, 1 deletions
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py index 6c362163c..22e066def 100644 --- a/python/vyos/ethtool.py +++ b/python/vyos/ethtool.py @@ -59,6 +59,7 @@ class Ethtool: _ring_buffer = None _driver_name = None _flow_control = None + _channels = '' def __init__(self, ifname): # Get driver used for interface @@ -111,6 +112,11 @@ class Ethtool: if not bool(err): self._flow_control = loads(out)[0] + # Get information about NIC channels + out, err = popen(f'ethtool --show-channels {ifname}') + if not bool(err): + self._channels = out.lower() + def check_auto_negotiation_supported(self): """ Check if the NIC supports changing auto-negotiation """ return self._base_settings['supports-auto-negotiation'] @@ -199,3 +205,20 @@ class Ethtool: 'flow-control settings!') return 'on' if bool(self._flow_control['autonegotiate']) else 'off' + + def get_channels(self, rx_tx_comb): + """ + Get both the pre-set maximum and current value for a given channel type. + + Args: + rx_tx_comb (str): Channel type, one of "rx", "tx", or "combined". + + Returns: + list[int]: [maximum, current] values for the channel, + or an empty list if not supported. + """ + if rx_tx_comb not in ['rx', 'tx', 'combined']: + raise ValueError('Channel type must be either "rx", "tx" or "combined"') + matches = re.findall(rf'{rx_tx_comb}:\s+(\d+)', self._channels) + + return [int(value) for value in matches] diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py index 6c7b230ca..70da837b9 100644 --- a/python/vyos/ifconfig/ethernet.py +++ b/python/vyos/ifconfig/ethernet.py @@ -455,6 +455,23 @@ class EthernetIf(Interface): print(f'could not set "{rx_tx}" ring-buffer for {ifname}') return output + def set_channels(self, rx_tx_comb, queues): + """ + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_channels('rx', 2) + """ + ifname = self.config['ifname'] + cmd = f'ethtool --set-channels {ifname} {rx_tx_comb} {queues}' + output, code = self._popen(cmd) + # ethtool error codes: + # 80 - value already setted + # 81 - does not possible to set value + if code and code != 80: + print(f'could not set "{rx_tx_comb}" channel for {ifname}') + return output + def set_switchdev(self, enable): ifname = self.config['ifname'] addr, code = self._popen( diff --git a/python/vyos/vpp/control_host.py b/python/vyos/vpp/control_host.py index db1a492c9..2ebfd180b 100644 --- a/python/vyos/vpp/control_host.py +++ b/python/vyos/vpp/control_host.py @@ -24,6 +24,7 @@ from time import sleep from pyroute2 import IPRoute from vyos.ethtool import Ethtool +from vyos.ifconfig import EthernetIf from vyos.vpp.utils import EthtoolGDrvinfo @@ -376,3 +377,40 @@ def flush_ip(iface_name: str) -> None: """ iproute = IPRoute() iproute.flush_addr(label=iface_name) + + +def get_eth_channels(iface_name: str) -> dict: + """ + Get the current hardware queue counts for channels of an interface using ethtool. + + Args: + iface_name (str): name of an interface + + Returns: + dict: Mapping of channel types to their current values: + - 'rx' (int | None): RX channel count. + - 'tx' (int | None): TX channel count. + - 'combined' (int | None): Combined channel count. + Returns None if the channel type is not supported. + """ + ethtool = Ethtool(iface_name) + + channels = {} + for channel in ['rx', 'tx', 'combined']: + queues_list = ethtool.get_channels(channel) + channels[channel] = queues_list[-1] if (len(queues_list) == 2) else None + + return channels + + +def set_eth_channels(iface_name: str, channels: dict) -> None: + """Configure the number of RX, TX, or combined channels for an interface. + + Args: + iface_name (str): name of an interface + channels (dict): channels to set + """ + interface = EthernetIf(iface_name) + for channel, value in channels.items(): + if value: + interface.set_channels(channel, value) diff --git a/python/vyos/vpp/control_vpp.py b/python/vyos/vpp/control_vpp.py index cb8da50a6..2ee253b45 100644 --- a/python/vyos/vpp/control_vpp.py +++ b/python/vyos/vpp/control_vpp.py @@ -351,7 +351,7 @@ class VPPControl: self, host_if: str, name: str, - rxq_num: int = 0, + rxq_num: int = 65535, rxq_size: int = 0, txq_size: int = 0, mode: Literal['auto', 'copy', 'zero-copy'] = 'auto', |
