diff --git a/lisa/tools/ethtool.py b/lisa/tools/ethtool.py index 55ca86370e..b1e3c6c992 100644 --- a/lisa/tools/ethtool.py +++ b/lisa/tools/ethtool.py @@ -433,14 +433,26 @@ class DeviceStatistics: # tx_scattered: 0 # tx_no_memory: 0 _statistics_pattern = re.compile(r"^\s+(?P.*?)\: +?(?P\d*?)\r?$") + # FreeBSD NIC statistics: + # dev.hn.0.tx.0.packets: 0 + # dev.hn.0.rx.0.packets: 0 + # dev.mce.0.txstat0tc0.packets: 0 + # dev.mce.0.rxstat0.packets: 0 + _bsd_statistics_pattern = re.compile( + r"^dev\.\w+\.\d+.(?P.*?)\: +?(?P\d+?)\r?$" + ) - def __init__(self, interface: str, device_statistics_raw: str) -> None: - self._parse_statistics_info(interface, device_statistics_raw) + def __init__( + self, interface: str, device_statistics_raw: str, bsd: bool = False + ) -> None: + self._parse_statistics_info(interface, device_statistics_raw, bsd) - def _parse_statistics_info(self, interface: str, raw_str: str) -> None: + def _parse_statistics_info(self, interface: str, raw_str: str, bsd: bool) -> None: statistics: Dict[str, int] = {} - - items = find_groups_in_lines(raw_str, self._statistics_pattern) + if bsd: + items = find_groups_in_lines(raw_str, self._bsd_statistics_pattern) + else: + items = find_groups_in_lines(raw_str, self._statistics_pattern) statistics = {x["name"]: int(x["value"]) for x in items} self.interface = interface @@ -1120,3 +1132,41 @@ def get_device_enabled_features( device_features = DeviceFeatures(interface, features) return device_features + + def get_device_statistics( + self, interface: str, force_run: bool = False + ) -> DeviceStatistics: + device = self._get_or_create_device_setting(interface) + if not force_run and device.device_statistics: + return device.device_statistics + + # Example Matches + # hn0 + # mce0 + # da0 + match = re.match(r"^(\w+)(\d+)$", interface) + if not match: + raise LisaException(f"Invalid interface name: {interface}") + device_name = match.group(1) + number = match.group(2) + result = self.run( + f"sysctl dev.{device_name}.{number}", force_run=True, shell=True + ) + if (result.exit_code != 0) and ( + "Operation not supported" in result.stdout + or "no stats available" in result.stdout + ): + raise UnsupportedOperationException( + f"Stats retrieval for {interface} operation not supported." + ) + result.assert_exit_code(message=f"Couldn't get device {interface} statistics.") + + device.device_statistics = DeviceStatistics(interface, result.stdout, True) + return device.device_statistics + + def _get_or_create_device_setting(self, interface: str) -> DeviceSettings: + settings = self._device_settings_map.get(interface, None) + if settings is None: + settings = DeviceSettings(interface) + self._device_settings_map[interface] = settings + return settings diff --git a/microsoft/testsuites/network/networksettings.py b/microsoft/testsuites/network/networksettings.py index e45d11ffb1..f185459007 100644 --- a/microsoft/testsuites/network/networksettings.py +++ b/microsoft/testsuites/network/networksettings.py @@ -56,6 +56,11 @@ class NetworkSettings(TestSuite): _queue_stats_regex = re.compile(r"[tr]x_queue_(?P[\d]+)_packets") _vf_queue_stats_regex = re.compile(r"[tr]x[_]?(?P[\d]+)_packets") + # regex for filtering vf queue stats on FreeBSD + # dev.mce.0.rxstat3.packets: 2901 + # dev.mce.0.txstat3tc0.packets: 3287 + _bsd_vf_queue_stats_regex = re.compile(r"[tr]xstat(?P[\d]+)\S*\.packets") + # This will match different tx queues like - # {'name': 'tx_queue_0_packets', 'value': '0'} # {'name': 'tx_queue_1_packets', 'value': '0'} @@ -749,8 +754,8 @@ def _check_msg_level_change_supported(self, node: Node) -> None: "netvsc_set_msglevel" not in msg_level_symbols ): raise SkippedException( - f"Get/Set message level not supported on {kernel_version}," - " Skipping test." + f"Get/Set message level not supported on {kernel_version}, " + "Skipping test." ) def _verify_stats_exists( @@ -775,9 +780,14 @@ def _verify_stats_exists( raise SkippedException(identifier) for k in device_stats.counters.keys(): - if self._vf_queue_stats_regex.search(k): - # Both tx/rx queues will be counted with the regex. - per_vf_queue_stats += 1 + if isinstance(client_node.os, BSD): + if self._bsd_vf_queue_stats_regex.search(k): + # Both tx/rx queues will be counted with the regex. + per_vf_queue_stats += 1 + else: + if self._vf_queue_stats_regex.search(k): + # Both tx/rx queues will be counted with the regex. + per_vf_queue_stats += 1 assert_that( per_vf_queue_stats,