diff options
| author | Nataliia S. <81954790+natali-rs1985@users.noreply.github.com> | 2025-11-04 15:15:59 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-04 15:15:59 +0200 |
| commit | 4f9c241db48928f974a32bc6901b9ed4cf2ce20e (patch) | |
| tree | d781bbe53e9769cf669d8d792b5c0519e67a58c2 /src | |
| parent | e1b7b865a63454ae4b8f840c94ab599633faaf7f (diff) | |
| parent | 73b7431862d8da2e8063a6062f29fd0f65fdd210 (diff) | |
| download | vyos-1x-4f9c241db48928f974a32bc6901b9ed4cf2ce20e.tar.gz vyos-1x-4f9c241db48928f974a32bc6901b9ed4cf2ce20e.zip | |
Merge pull request #4747 from natali-rs1985/T7789
T7789: T7661: VPP prevent failing to load XDP in clouds (ena/gve drivers)
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/vpp.py | 85 |
1 files changed, 68 insertions, 17 deletions
diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py index 61b10406f..bd7ff173f 100755 --- a/src/conf_mode/vpp.py +++ b/src/conf_mode/vpp.py @@ -112,6 +112,9 @@ drivers_support_interrupt: dict[str, list] = { 'virtio_net': ['xdp'], } +# drivers that require changing channels (half the maximum number of RX/TX queues) +ethtool_channels_change_drv: list[str] = ['ena', 'gve'] + def _load_module(module_name: str): """ @@ -171,6 +174,25 @@ def _normalize_buffers(config: dict): config['settings']['buffers']['buffers_per_numa'] = str(buffers) +def _get_max_xdp_rx_queues(config: dict): + """ + Count max number of RX queues for XDP driver + - If the interface driver is in `ethtool_channels_change_drv` + only half of the available queues are used (to avoid NIC issues) + - For other interface drivers the full number of queues is returned. + - If neither `rx` nor `combined` is set, return 1. + """ + for key in ('rx', 'combined'): + value = config['channels'].get(key) + if value: + if config['original_driver'] in ethtool_channels_change_drv: + return max(1, int(value) // 2) + else: + return int(value) + + return 1 + + def get_config(config=None): # use persistent config to store interfaces data between executions # this is required because some interfaces after they are connected @@ -270,6 +292,20 @@ def get_config(config=None): _normalize_buffers(effective_config) config['effective'] = effective_config + # Save important info about all interfaces that cannot be retrieved later + # Add new interfaces (only if they are first time seen in a config) + for iface, iface_config in config.get('settings', {}).get('interface', {}).items(): + if iface not in effective_config.get('settings', {}).get('interface', {}): + eth_ifaces_persist[iface] = { + 'original_driver': EthtoolGDrvinfo(iface).driver, + } + eth_ifaces_persist[iface]['bus_id'] = control_host.get_bus_name(iface) + eth_ifaces_persist[iface]['dev_id'] = control_host.get_dev_id(iface) + eth_ifaces_persist[iface]['channels'] = control_host.get_eth_channels(iface) + + # Return to config dictionary + config['persist_config'] = eth_ifaces_persist + if 'settings' in config: if 'interface' in config['settings']: for iface, iface_config in config['settings']['interface'].items(): @@ -330,7 +366,8 @@ def get_config(config=None): 'txq_size': int(iface_config['xdp_options']['tx_queue_size']), } if iface_config['xdp_options']['num_rx_queues'] == 'all': - xdp_api_params['rxq_num'] = 0 + # 65535 is used as special value to request all available queues + xdp_api_params['rxq_num'] = 65535 else: xdp_api_params['rxq_num'] = int( iface_config['xdp_options']['num_rx_queues'] @@ -363,18 +400,6 @@ def get_config(config=None): iface_filter_eth(conf, iface) set_dependents(dependency, conf, iface) - # Save important info about all interfaces that cannot be retrieved later - # Add new interfaces (only if they are first time seen in a config) - for iface, iface_config in config.get('settings', {}).get('interface', {}).items(): - if iface not in effective_config.get('settings', {}).get('interface', {}): - eth_ifaces_persist[iface] = { - 'original_driver': config['settings']['interface'][iface][ - 'kernel_module' - ], - } - eth_ifaces_persist[iface]['bus_id'] = control_host.get_bus_name(iface) - eth_ifaces_persist[iface]['dev_id'] = control_host.get_dev_id(iface) - # kernel-interfaces dependency if effective_config.get('kernel_interfaces'): for iface in config.get('kernel_interfaces', {}): @@ -399,9 +424,6 @@ def get_config(config=None): config['pppoe_ifaces'] = pppoe_map_ifaces set_dependents('pppoe_server', conf) - # Return to config dictionary - config['persist_config'] = eth_ifaces_persist - return config @@ -493,6 +515,14 @@ def verify(config): ) if iface_config['driver'] == 'xdp' and 'xdp_options' in iface_config: if iface_config['xdp_options']['num_rx_queues'] != 'all': + rx_queues = iface_config['xdp_api_params']['rxq_num'] + max_rx_queues = _get_max_xdp_rx_queues(config['persist_config'][iface]) + if rx_queues > max_rx_queues: + raise ConfigError( + f'Maximum supported number of RX queues for interface {iface} is {max_rx_queues}. ' + f'Please set "xdp-options num-rx-queues" to {max_rx_queues} or fewer' + ) + Warning(f'Not all RX queues will be connected to VPP for {iface}!') if iface_config['driver'] == 'xdp' and 'dpdk_options' in iface_config: @@ -601,11 +631,13 @@ def initialize_interface(iface, driver, iface_config) -> None: iface_new_name: str = control_host.get_eth_name(iface_config['dev_id']) control_host.rename_iface(iface_new_name, iface) - # XDP - rename an interface, disable promisc and XDP + # XDP - rename an interface, disable promisc and XDP, set original channels if driver == 'xdp': control_host.set_promisc(f'defunct_{iface}', 'off') control_host.rename_iface(f'defunct_{iface}', iface) control_host.xdp_remove(iface) + if iface_config['original_driver'] in ethtool_channels_change_drv: + control_host.set_eth_channels(iface, iface_config['channels']) # Rename Mellanox NIC to a normal name try: @@ -720,6 +752,25 @@ def apply(config): # add XDP interfaces if iface_config['driver'] == 'xdp': control_host.rename_iface(iface, f'defunct_{iface}') + + # Some cloud NICs 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. + if ( + config['persist_config'][iface]['original_driver'] + in ethtool_channels_change_drv + ): + max_rx_queues = _get_max_xdp_rx_queues( + config['persist_config'][iface] + ) + channels_orig = config['persist_config'][iface]['channels'] + channels = {} + if channels_orig.get('rx'): + channels = {'rx': max_rx_queues, 'tx': max_rx_queues} + if channels_orig.get('combined'): + channels['combined'] = max_rx_queues + if channels: + control_host.set_eth_channels(f'defunct_{iface}', channels) + vpp_control.xdp_iface_create( host_if=f'defunct_{iface}', name=iface, |
