400 lines
14 KiB
Diff
400 lines
14 KiB
Diff
From d0552193364d160252d117c5bf2e298a31550e3c Mon Sep 17 00:00:00 2001
|
|
From: John Kacur <jkacur@redhat.com>
|
|
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 <jkacur@redhat.com>
|
|
- V2 Add SPDX license identifier
|
|
Signed-off-by: John Kacur <jkacur@redhat.com>
|
|
---
|
|
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 <davids@redhat.com>
|
|
-#
|
|
-# 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 <jkacur@redhat.com
|
|
+# SPDX-License-Identifier: GPL-2.0-or-later
|
|
+#
|
|
+
|
|
+import os
|
|
+import socket
|
|
+import ipaddress
|
|
+import sys
|
|
+import libxml2
|
|
+from rteval.Log import Log
|
|
+
|
|
+def get_active_devices():
|
|
+ ''' returns a list of active network devices, similar to ethtool '''
|
|
+ ret = []
|
|
+
|
|
+ for device in socket.if_nameindex():
|
|
+ ret.append(device[1])
|
|
+
|
|
+ return ret
|
|
+
|
|
+def compress_iv6(addr):
|
|
+ ''' inserts colons into an ipv6address and returns it in compressed form '''
|
|
+ retaddr = ''
|
|
+ # Insert colons into the number
|
|
+ for i in range(4,33,4):
|
|
+ if i == 32:
|
|
+ retaddr += addr[i-4:i]
|
|
+ else:
|
|
+ retaddr += addr[i-4:i] + ':'
|
|
+ addr = ipaddress.IPv6Network(retaddr)
|
|
+ retaddr = str(ipaddress.IPv6Address(retaddr))
|
|
+ return retaddr
|
|
+
|
|
+def get_defaultgw():
|
|
+ ''' return the ipv4address of the default gateway '''
|
|
+ defaultgw = None
|
|
+ with open('/proc/net/route') as f:
|
|
+ line = f.readline().strip()
|
|
+ while len(line) > 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
|
|
|