From 6a1006345e81e3622d94eb469df9e6afba7957a8 Mon Sep 17 00:00:00 2001 From: jkacur Date: Mon, 17 Oct 2022 20:02:00 +0000 Subject: [PATCH] rteval: Add patch to remove python3-ethtool Requires --- ...lace-python-ethtool-with-inline-code.patch | 399 ++++++++++++++++++ rteval.spec | 11 +- 2 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 rteval-Replace-python-ethtool-with-inline-code.patch diff --git a/rteval-Replace-python-ethtool-with-inline-code.patch b/rteval-Replace-python-ethtool-with-inline-code.patch new file mode 100644 index 0000000..59b4592 --- /dev/null +++ b/rteval-Replace-python-ethtool-with-inline-code.patch @@ -0,0 +1,399 @@ +From d0552193364d160252d117c5bf2e298a31550e3c Mon Sep 17 00:00:00 2001 +From: John Kacur +Date: Mon, 10 Oct 2022 09:49:47 -0400 +Subject: [PATCH] rteval: Replace python-ethtool with inline code + +This patch adds the file newnet.py to replace the use of python-ethtool +The information it generates will appear in the summary.xml +You can also test the functionality by running +python rteval/sysinfo/newnet.py + +Signed-off-by: John Kacur +- V2 Add SPDX license identifier +Signed-off-by: John Kacur +--- + rteval/sysinfo/__init__.py | 3 +- + rteval/sysinfo/network.py | 117 ------------------- + rteval/sysinfo/newnet.py | 225 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 227 insertions(+), 118 deletions(-) + delete mode 100644 rteval/sysinfo/network.py + create mode 100644 rteval/sysinfo/newnet.py + +diff --git a/rteval/sysinfo/__init__.py b/rteval/sysinfo/__init__.py +index a4359382f006..bb1d00810856 100644 +--- a/rteval/sysinfo/__init__.py ++++ b/rteval/sysinfo/__init__.py +@@ -32,7 +32,7 @@ from rteval.sysinfo.services import SystemServices + from rteval.sysinfo.cputopology import CPUtopology + from rteval.sysinfo.memory import MemoryInfo + from rteval.sysinfo.osinfo import OSInfo +-from rteval.sysinfo.network import NetworkInfo ++from rteval.sysinfo.newnet import NetworkInfo + from rteval.sysinfo.cmdline import cmdlineInfo + from rteval.sysinfo import dmi + +@@ -46,6 +46,7 @@ class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology, + CPUtopology.__init__(self) + OSInfo.__init__(self, logger=logger) + cmdlineInfo.__init__(self, logger=logger) ++ NetworkInfo.__init__(self, logger=logger) + + # Parse initial DMI decoding errors + dmi.ProcessWarnings() +diff --git a/rteval/sysinfo/network.py b/rteval/sysinfo/network.py +deleted file mode 100644 +index ce9989a1240b..000000000000 +--- a/rteval/sysinfo/network.py ++++ /dev/null +@@ -1,117 +0,0 @@ +-# -*- coding: utf-8 -*- +-# +-# Copyright 2009 - 2013 David Sommerseth +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of the GNU General Public License as published by +-# the Free Software Foundation; either version 2 of the License, or +-# (at your option) any later version. +-# +-# This program is distributed in the hope that it will be useful, +-# but WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-# GNU General Public License for more details. +-# +-# You should have received a copy of the GNU General Public License along +-# with this program; if not, write to the Free Software Foundation, Inc., +-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +-# +-# For the avoidance of doubt the "preferred form" of this code is one which +-# is in an open unpatent encumbered format. Where cryptographic key signing +-# forms part of the process of creating an executable the information +-# including keys needed to generate an equivalently functional executable +-# are deemed to be part of the source code. +-# +- +-import ethtool, libxml2 +- +-class NetworkInfo(object): +- def __init__(self): +- pass +- +- def net_GetDefaultGW(self): +- # Get the interface name for the IPv4 default gw +- route = open('/proc/net/route') +- defgw4 = None +- if route: +- rl = route.readline() +- while rl != '' : +- rl = route.readline() +- splt = rl.split("\t") +- # Only catch default route +- if len(splt) > 2 and splt[2] != '00000000' and splt[1] == '00000000': +- defgw4 = splt[0] +- break +- route.close() +- return (defgw4, None) # IPv6 gw not yet implemented +- +- def MakeReport(self): +- ncfg_n = libxml2.newNode("NetworkConfig") +- (defgw4, defgw6) = self.net_GetDefaultGW() +- +- # Make an interface tag for each device found +- if hasattr(ethtool, 'get_interfaces_info'): +- # Using the newer python-ethtool API (version >= 0.4) +- for dev in ethtool.get_interfaces_info(ethtool.get_devices()): +- if dev.device == 'lo': +- continue +- +- intf_n = libxml2.newNode('interface') +- intf_n.newProp('device', dev.device) +- intf_n.newProp('hwaddr', dev.mac_address) +- ncfg_n.addChild(intf_n) +- +- # Protcol configurations +- if dev.ipv4_address: +- ipv4_n = libxml2.newNode('IPv4') +- ipv4_n.newProp('ipaddr', dev.ipv4_address) +- ipv4_n.newProp('netmask', str(dev.ipv4_netmask)) +- ipv4_n.newProp('broadcast', dev.ipv4_broadcast) +- ipv4_n.newProp('defaultgw', (defgw4 == dev.device) and '1' or '0') +- intf_n.addChild(ipv4_n) +- +- for ip6 in dev.get_ipv6_addresses(): +- ipv6_n = libxml2.newNode('IPv6') +- ipv6_n.newProp('ipaddr', ip6.address) +- ipv6_n.newProp('netmask', str(ip6.netmask)) +- ipv6_n.newProp('scope', ip6.scope) +- intf_n.addChild(ipv6_n) +- +- else: # Fall back to older python-ethtool API (version < 0.4) +- ifdevs = ethtool.get_active_devices() +- ifdevs.remove('lo') +- ifdevs.sort() +- +- for dev in ifdevs: +- intf_n = libxml2.newNode('interface') +- intf_n.newProp('device', dev.device) +- intf_n.newProp('hwaddr', dev.mac_address) +- ncfg_n.addChild(intf_n) +- +- ipv4_n = libxml2.newNode('IPv4') +- ipv4_n.newProp('ipaddr', ethtool.get_ipaddr(dev)) +- ipv4_n.newProp('netmask', str(ethtool.get_netmask(dev))) +- ipv4_n.newProp('defaultgw', (defgw4 == dev) and '1' or '0') +- intf_n.addChild(ipv4_n) +- +- return ncfg_n +- +- +-def unit_test(rootdir): +- import sys +- try: +- net = NetworkInfo() +- doc = libxml2.newDoc('1.0') +- cfg = net.MakeReport() +- doc.setRootElement(cfg) +- doc.saveFormatFileEnc('-', 'UTF-8', 1) +- +- except Exception as e: +- import traceback +- traceback.print_exc(file=sys.stdout) +- print("** EXCEPTION %s", str(e)) +- return 1 +- +-if __name__ == '__main__': +- unit_test(None) +- +diff --git a/rteval/sysinfo/newnet.py b/rteval/sysinfo/newnet.py +new file mode 100644 +index 000000000000..63417d9e59f1 +--- /dev/null ++++ b/rteval/sysinfo/newnet.py +@@ -0,0 +1,225 @@ ++''' Module to obtain network information for the rteval report ''' ++# ++# Copyright 2022 John Kacur 0: ++ (iface, dest, gateway, _, _, _, _, _, _, _, _) = line.split() ++ if iface == 'Iface': ++ line = f.readline().strip() ++ continue ++ if dest == '00000000' and gateway != '00000000': ++ addr = int(gateway, base=16) ++ defaultgw = str(ipaddress.IPv4Address(socket.ntohl(addr))) ++ return defaultgw ++ line = f.readline().strip() ++ return defaultgw ++ ++class IPv6Addresses(): ++ ''' Obtains a list of IPv6 addresses from the proc file system ''' ++ ++ def __init__(self): ++ self.data = {} ++ IPv6Addresses.load(self) ++ ++ def __contains__(self, dev): ++ return dev in self.data ++ ++ def __getitem__(self, dev): ++ return self.data.get(dev, None) ++ ++ def __iter__(self): ++ return iter(self.data) ++ ++ def load(self): ++ ''' ++ Called by init to load the self.data dictionary with device keys ++ and a list of ipv6addresses ++ ''' ++ MYP = '/proc/net/if_inet6' ++ with open(MYP, 'r') as f: ++ mystr = f.readline().strip() ++ while len(mystr) > 0: ++ ipv6addr , _, _, _, _, intf = mystr.split() ++ ipv6addr = compress_iv6(ipv6addr) ++ if intf == 'lo': ++ mystr = f.readline().strip() ++ continue ++ if intf not in self.data: ++ self.data[intf] = [ipv6addr] ++ else: ++ self.data[intf].append(ipv6addr) ++ mystr = f.readline().strip() ++ ++class IPv4Addresses(): ++ ''' Obtains a list of IPv4 addresses from the proc file system ''' ++ ++ def __init__(self): ++ self.data = {} ++ IPv4Addresses.load(self) ++ ++ def __contains__(self, dev): ++ return dev in self.data ++ ++ def __getitem__(self, dev): ++ return self.data[dev] ++ ++ def __iter__(self): ++ return iter(self.data) ++ ++ def load(self): ++ ''' ++ Called by init to load the self.data dictionary with ++ device keys, and value consisting of a list of ++ ipv4address, netmask and broadcast address ++ ''' ++ MYP = '/proc/net/route' ++ with open(MYP, 'r') as f: ++ mystr = f.readline().strip() ++ while len(mystr) > 0: ++ intf, dest, _, _, _, _, _, mask, _, _, _ = mystr.split() ++ # Skip over the head of the table an the gateway line ++ if intf == "Iface" or dest == '00000000': ++ mystr = f.readline().strip() ++ continue ++ d1 = int(dest, base=16) ++ m1 = int(mask, base=16) ++ addr = str(ipaddress.IPv4Address(socket.ntohl(d1))) ++ netmask = str(ipaddress.IPv4Address(socket.ntohl(m1))) ++ addr_with_mask = ipaddress.ip_network(addr + '/' + netmask) ++ broadcast = str(addr_with_mask.broadcast_address) ++ if intf not in self.data: ++ self.data[intf] = [(addr, netmask, broadcast)] ++ else: ++ self.data[intf].append((addr, netmask, broadcast)) ++ mystr = f.readline().strip() ++ ++ ++class MacAddresses(): ++ ''' Obtains a list of hardware addresses of network devices ''' ++ ++ def __init__(self): ++ self.mac_address = {} ++ self.path = None ++ MacAddresses.load(self) ++ ++ def load(self): ++ ''' ++ called by init to load self.mac_address as a dictionary of ++ device keys, and mac or hardware addresses as values ++ ''' ++ nics = get_active_devices() ++ for nic in nics: ++ self.path = f'/sys/class/net/{nic}' ++ hwaddr = MacAddresses.set_val(self, 'address') ++ self.mac_address[nic] = hwaddr ++ ++ def set_val(self, val): ++ ''' Return the result of reading self.path/val ''' ++ val_path = f'{self.path}/{val}' ++ if os.path.exists(val_path): ++ with open(val_path, 'r') as f: ++ return f.readline().strip() ++ return None ++ ++ def __contains__(self, dev): ++ return dev in self.mac_address ++ ++ def __getitem__(self, dev): ++ return self.mac_address[dev] ++ ++ def __iter__(self): ++ return iter(self.mac_address) ++ ++class NetworkInfo(): ++ ''' Creates an xml report of the network for rteval ''' ++ ++ def __init__(self, logger): ++ self.defgw4 = get_defaultgw() ++ self.__logger = logger ++ ++ def MakeReport(self): ++ ''' Make an xml report for rteval ''' ++ ncfg_n = libxml2.newNode("NetworkConfig") ++ defgw4 = self.defgw4 ++ ++ mads = MacAddresses() ++ for device in mads: ++ if device == 'lo': ++ continue ++ intf_n = libxml2.newNode('interface') ++ intf_n.newProp('device', device) ++ intf_n.newProp('hwaddr', mads[device]) ++ ncfg_n.addChild(intf_n) ++ ++ ipv4ads = IPv4Addresses() ++ ipv6ads = IPv6Addresses() ++ for dev in ipv4ads: ++ if dev != device: ++ continue ++ for lelem in ipv4ads[dev]: ++ ipv4_n = libxml2.newNode('IPv4') ++ (ipaddr, netmask, broadcast) = lelem ++ ipv4_n.newProp('ipaddr', ipaddr) ++ ipv4_n.newProp('netmask', netmask) ++ ipv4_n.newProp('broadcast', broadcast) ++ ipv4_n.newProp('defaultgw', (defgw4 == ipaddr) and '1' or '0') ++ intf_n.addChild(ipv4_n) ++ if ipv6ads[dev]: ++ for lelem in ipv6ads[dev]: ++ ipv6_n = libxml2.newNode('IPv6') ++ ipaddr = lelem ++ ipv6_n.newProp('ipaddr', ipaddr) ++ intf_n.addChild(ipv6_n) ++ return ncfg_n ++ ++if __name__ == "__main__": ++ ++ try: ++ log = Log() ++ log.SetLogVerbosity(Log.DEBUG|Log.INFO) ++ net = NetworkInfo(logger=log) ++ doc = libxml2.newDoc('1.0') ++ cfg = net.MakeReport() ++ doc.setRootElement(cfg) ++ doc.saveFormatFileEnc('-', 'UTF-8', 1) ++ ++ except Exception as e: ++ import traceback ++ traceback.print_exc(file=sys.stdout) ++ print(f"** EXCEPTION {str(e)}") +-- +2.37.3 + diff --git a/rteval.spec b/rteval.spec index 6390f53..b19a664 100644 --- a/rteval.spec +++ b/rteval.spec @@ -1,6 +1,6 @@ Name: rteval Version: 3.5 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Utility to evaluate system suitability for RT Linux Group: Development/Tools @@ -10,8 +10,8 @@ Source0: https://www.kernel.org/pub/linux/utils/%{name}/%{name}-%{version}.tar.x BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: python3-devel -Requires: python3-ethtool Requires: python3-lxml +Requires: python3-libxml2 Requires: python3-dmidecode >= 3.10 Requires: python3-requests Requires: realtime-tests >= 2.1-1 @@ -30,6 +30,7 @@ Requires: libmpc, libmpc-devel BuildArch: noarch #Patches +Patch1: rteval-Replace-python-ethtool-with-inline-code.patch %description The rteval script is a utility for measuring various aspects of @@ -42,6 +43,7 @@ to the screen. %prep %setup -q +%patch1 -p1 %build %{__python3} setup.py build @@ -63,6 +65,11 @@ to the screen. %{_bindir}/rteval %changelog +* Mon Oct 17 2022 John Kacur - 3.5-2 +- Remove dependency on python-ethtool by using inline code +- Add Requires of python-libxml2 +Resolves: rhbz#2062388 + * Mon Sep 26 2022 John Kacur - 3.5-1 - Rebase to rteval-3.5 upstream Resolves: rhbz#2119171