from dataclasses import dataclass
import ipaddress
import socket
import struct
from ubse.ffi.ubs_engine_types import UbsTopoLinkT, UbsTopoNodeT, UbsTopoIpAddressT, UBS_TOPO_SOCKET_NUM, \
UBS_TOPO_NUMA_NUM, UBS_TOPO_IPADDR_NUM
@dataclass
class UbsTopoNode:
slot_id: int
socket_ids: list
numa_ids: list
ips: list
host_name: str
def __str__(self):
ip_strings = []
for ip in self.ips:
ip_strings.append(f"IPv{ip.version}:{ip}")
ips_str = ", ".join(ip_strings)
return (
f"Node {self.slot_id} ('{self.host_name}'): "
f"{len(self.socket_ids)} sockets, "
f"IPs: [{ips_str}]"
)
@staticmethod
def from_c_struct(c_node) -> "UbsTopoNode":
socket_ids = [c_node.socket_id[i] for i in range(UBS_TOPO_SOCKET_NUM)]
numa_ids = []
for i in range(UBS_TOPO_SOCKET_NUM):
numa_row = [c_node.numa_ids[i][j] for j in range(UBS_TOPO_NUMA_NUM)]
numa_ids.append(numa_row)
ips = []
for i in range(UBS_TOPO_IPADDR_NUM):
if c_node.ips[i].af != 0:
ip_obj = UbsTopoNode._convert_ip_from_c_struct(c_node.ips[i])
if ip_obj is not None:
ips.append(ip_obj)
hostname = c_node.host_name.decode('utf-8', errors='ignore')
return UbsTopoNode(
slot_id=c_node.slot_id,
socket_ids=socket_ids,
numa_ids=numa_ids,
ips=ips,
host_name=hostname
)
@staticmethod
def _convert_ip_from_c_struct(c_ip):
"""将C结构体的IP地址转换为Python标准库的IP地址对象"""
try:
if c_ip.af == socket.AF_INET:
ipv4_int = c_ip.ipv4
ipv4_str = socket.inet_ntoa(struct.pack('<I', ipv4_int))
return ipaddress.IPv4Address(ipv4_str)
elif c_ip.af == socket.AF_INET6:
ipv6_bytes = bytes(c_ip.ipv6)
if any(ipv6_bytes):
ipv6_str = socket.inet_ntop(socket.AF_INET6, ipv6_bytes)
return ipaddress.IPv6Address(ipv6_str)
return None
except (ValueError, OSError, struct.error):
return None
@dataclass
class UbsTopoLink:
slot_id: int
socket_id: int
port_id: int
peer_slot_id: int
peer_socket_id: int
peer_port_id: int
def __str__(self):
return (f"Link : {self.slot_id}-{self.socket_id}-{self.port_id} <->"
f" {self.peer_slot_id}-{self.peer_socket_id}-{self.peer_port_id}")
@staticmethod
def from_c_struct(c_link: UbsTopoLinkT) -> "UbsTopoLink":
return UbsTopoLink(
slot_id=c_link.slot_id,
socket_id=c_link.socket_id,
port_id=c_link.port_id,
peer_slot_id=c_link.peer_slot_id,
peer_socket_id=c_link.peer_socket_id,
peer_port_id=c_link.peer_port_id
)