1fee65b7eSAlexander V. Chernikov#!/usr/local/bin/python3 2fee65b7eSAlexander V. Chernikovimport os 3fee65b7eSAlexander V. Chernikovimport socket 4fee65b7eSAlexander V. Chernikovimport sys 5fee65b7eSAlexander V. Chernikovfrom ctypes import c_int 6fee65b7eSAlexander V. Chernikovfrom ctypes import c_ubyte 7fee65b7eSAlexander V. Chernikovfrom ctypes import c_uint 8fee65b7eSAlexander V. Chernikovfrom ctypes import c_ushort 9fee65b7eSAlexander V. Chernikovfrom ctypes import sizeof 10fee65b7eSAlexander V. Chernikovfrom ctypes import Structure 11fee65b7eSAlexander V. Chernikovfrom enum import auto 12fee65b7eSAlexander V. Chernikovfrom enum import Enum 13fee65b7eSAlexander V. Chernikov 14fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.attrs import NlAttr 15fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.attrs import NlAttrStr 16fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.attrs import NlAttrU32 17fc2538cbSAlexander V. Chernikovfrom atf_python.sys.netlink.base_headers import GenlMsgHdr 18fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.base_headers import NlmBaseFlags 19fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.base_headers import Nlmsghdr 20fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.base_headers import NlMsgType 21fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.message import BaseNetlinkMessage 22fc2538cbSAlexander V. Chernikovfrom atf_python.sys.netlink.message import NlMsgCategory 23fc2538cbSAlexander V. Chernikovfrom atf_python.sys.netlink.message import NlMsgProps 24fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.message import StdNetlinkMessage 25fc2538cbSAlexander V. Chernikovfrom atf_python.sys.netlink.netlink_generic import GenlCtrlAttrType 263e5d0784SAlexander V. Chernikovfrom atf_python.sys.netlink.netlink_generic import GenlCtrlMsgType 27fc2538cbSAlexander V. Chernikovfrom atf_python.sys.netlink.netlink_generic import handler_classes as genl_classes 28fc2538cbSAlexander V. Chernikovfrom atf_python.sys.netlink.netlink_route import handler_classes as rt_classes 29fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.utils import align4 30fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.utils import AttrDescr 31fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.utils import build_propmap 32fc2538cbSAlexander V. Chernikovfrom atf_python.sys.netlink.utils import enum_or_int 33fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.utils import get_bitmask_map 34fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.utils import NlConst 35fee65b7eSAlexander V. Chernikovfrom atf_python.sys.netlink.utils import prepare_attrs_map 36fee65b7eSAlexander V. Chernikov 37fee65b7eSAlexander V. Chernikov 38fee65b7eSAlexander V. Chernikovclass SockaddrNl(Structure): 39fee65b7eSAlexander V. Chernikov _fields_ = [ 40fee65b7eSAlexander V. Chernikov ("nl_len", c_ubyte), 41fee65b7eSAlexander V. Chernikov ("nl_family", c_ubyte), 42fee65b7eSAlexander V. Chernikov ("nl_pad", c_ushort), 43fee65b7eSAlexander V. Chernikov ("nl_pid", c_uint), 44fee65b7eSAlexander V. Chernikov ("nl_groups", c_uint), 45fee65b7eSAlexander V. Chernikov ] 46fee65b7eSAlexander V. Chernikov 47fee65b7eSAlexander V. Chernikov 48fee65b7eSAlexander V. Chernikovclass Nlmsgdone(Structure): 49fee65b7eSAlexander V. Chernikov _fields_ = [ 50fee65b7eSAlexander V. Chernikov ("error", c_int), 51fee65b7eSAlexander V. Chernikov ] 52fee65b7eSAlexander V. Chernikov 53fee65b7eSAlexander V. Chernikov 54fee65b7eSAlexander V. Chernikovclass Nlmsgerr(Structure): 55fee65b7eSAlexander V. Chernikov _fields_ = [ 56fee65b7eSAlexander V. Chernikov ("error", c_int), 57fee65b7eSAlexander V. Chernikov ("msg", Nlmsghdr), 58fee65b7eSAlexander V. Chernikov ] 59fee65b7eSAlexander V. Chernikov 60fee65b7eSAlexander V. Chernikov 61fee65b7eSAlexander V. Chernikovclass NlErrattrType(Enum): 62fee65b7eSAlexander V. Chernikov NLMSGERR_ATTR_UNUSED = 0 63fee65b7eSAlexander V. Chernikov NLMSGERR_ATTR_MSG = auto() 64fee65b7eSAlexander V. Chernikov NLMSGERR_ATTR_OFFS = auto() 65fee65b7eSAlexander V. Chernikov NLMSGERR_ATTR_COOKIE = auto() 66fee65b7eSAlexander V. Chernikov NLMSGERR_ATTR_POLICY = auto() 67fee65b7eSAlexander V. Chernikov 68fee65b7eSAlexander V. Chernikov 69fee65b7eSAlexander V. Chernikovclass AddressFamilyLinux(Enum): 70fee65b7eSAlexander V. Chernikov AF_INET = socket.AF_INET 71fee65b7eSAlexander V. Chernikov AF_INET6 = socket.AF_INET6 72fee65b7eSAlexander V. Chernikov AF_NETLINK = 16 73fee65b7eSAlexander V. Chernikov 74fee65b7eSAlexander V. Chernikov 75fee65b7eSAlexander V. Chernikovclass AddressFamilyBsd(Enum): 76fee65b7eSAlexander V. Chernikov AF_INET = socket.AF_INET 77fee65b7eSAlexander V. Chernikov AF_INET6 = socket.AF_INET6 78fee65b7eSAlexander V. Chernikov AF_NETLINK = 38 79fee65b7eSAlexander V. Chernikov 80fee65b7eSAlexander V. Chernikov 81fee65b7eSAlexander V. Chernikovclass NlHelper: 82fee65b7eSAlexander V. Chernikov def __init__(self): 83fee65b7eSAlexander V. Chernikov self._pmap = {} 84fee65b7eSAlexander V. Chernikov self._af_cls = self.get_af_cls() 85fee65b7eSAlexander V. Chernikov self._seq_counter = 1 86fee65b7eSAlexander V. Chernikov self.pid = os.getpid() 87fee65b7eSAlexander V. Chernikov 88fee65b7eSAlexander V. Chernikov def get_seq(self): 89fee65b7eSAlexander V. Chernikov ret = self._seq_counter 90fee65b7eSAlexander V. Chernikov self._seq_counter += 1 91fee65b7eSAlexander V. Chernikov return ret 92fee65b7eSAlexander V. Chernikov 93fee65b7eSAlexander V. Chernikov def get_af_cls(self): 94fee65b7eSAlexander V. Chernikov if sys.platform.startswith("freebsd"): 95fee65b7eSAlexander V. Chernikov cls = AddressFamilyBsd 96fee65b7eSAlexander V. Chernikov else: 97fee65b7eSAlexander V. Chernikov cls = AddressFamilyLinux 98fee65b7eSAlexander V. Chernikov return cls 99fee65b7eSAlexander V. Chernikov 100fee65b7eSAlexander V. Chernikov def get_propmap(self, cls): 101fee65b7eSAlexander V. Chernikov if cls not in self._pmap: 102fee65b7eSAlexander V. Chernikov self._pmap[cls] = build_propmap(cls) 103fee65b7eSAlexander V. Chernikov return self._pmap[cls] 104fee65b7eSAlexander V. Chernikov 105fee65b7eSAlexander V. Chernikov def get_name_propmap(self, cls): 106fee65b7eSAlexander V. Chernikov ret = {} 107fee65b7eSAlexander V. Chernikov for prop in dir(cls): 108fee65b7eSAlexander V. Chernikov if not prop.startswith("_"): 109fee65b7eSAlexander V. Chernikov ret[prop] = getattr(cls, prop).value 110fee65b7eSAlexander V. Chernikov return ret 111fee65b7eSAlexander V. Chernikov 112fee65b7eSAlexander V. Chernikov def get_attr_byval(self, cls, attr_val): 113fee65b7eSAlexander V. Chernikov propmap = self.get_propmap(cls) 114fee65b7eSAlexander V. Chernikov return propmap.get(attr_val) 115fee65b7eSAlexander V. Chernikov 116fee65b7eSAlexander V. Chernikov def get_af_name(self, family): 117fee65b7eSAlexander V. Chernikov v = self.get_attr_byval(self._af_cls, family) 118fee65b7eSAlexander V. Chernikov if v is not None: 119fee65b7eSAlexander V. Chernikov return v 120fee65b7eSAlexander V. Chernikov return "af#{}".format(family) 121fee65b7eSAlexander V. Chernikov 122fee65b7eSAlexander V. Chernikov def get_af_value(self, family_str: str) -> int: 123fee65b7eSAlexander V. Chernikov propmap = self.get_name_propmap(self._af_cls) 124fee65b7eSAlexander V. Chernikov return propmap.get(family_str) 125fee65b7eSAlexander V. Chernikov 126fee65b7eSAlexander V. Chernikov def get_bitmask_str(self, cls, val): 127fee65b7eSAlexander V. Chernikov bmap = get_bitmask_map(self.get_propmap(cls), val) 128fee65b7eSAlexander V. Chernikov return ",".join([v for k, v in bmap.items()]) 129fee65b7eSAlexander V. Chernikov 130fee65b7eSAlexander V. Chernikov @staticmethod 131fee65b7eSAlexander V. Chernikov def get_bitmask_str_uncached(cls, val): 132fee65b7eSAlexander V. Chernikov pmap = NlHelper.build_propmap(cls) 133fee65b7eSAlexander V. Chernikov bmap = NlHelper.get_bitmask_map(pmap, val) 134fee65b7eSAlexander V. Chernikov return ",".join([v for k, v in bmap.items()]) 135fee65b7eSAlexander V. Chernikov 136fee65b7eSAlexander V. Chernikov 137fee65b7eSAlexander V. Chernikovnldone_attrs = prepare_attrs_map([]) 138fee65b7eSAlexander V. Chernikov 139fee65b7eSAlexander V. Chernikovnlerr_attrs = prepare_attrs_map( 140fee65b7eSAlexander V. Chernikov [ 141fee65b7eSAlexander V. Chernikov AttrDescr(NlErrattrType.NLMSGERR_ATTR_MSG, NlAttrStr), 142fee65b7eSAlexander V. Chernikov AttrDescr(NlErrattrType.NLMSGERR_ATTR_OFFS, NlAttrU32), 143fee65b7eSAlexander V. Chernikov AttrDescr(NlErrattrType.NLMSGERR_ATTR_COOKIE, NlAttr), 144fee65b7eSAlexander V. Chernikov ] 145fee65b7eSAlexander V. Chernikov) 146fee65b7eSAlexander V. Chernikov 147fee65b7eSAlexander V. Chernikov 148fee65b7eSAlexander V. Chernikovclass NetlinkDoneMessage(StdNetlinkMessage): 149fc2538cbSAlexander V. Chernikov messages = [NlMsgProps(NlMsgType.NLMSG_DONE, NlMsgCategory.ACK)] 150fee65b7eSAlexander V. Chernikov nl_attrs_map = nldone_attrs 151fee65b7eSAlexander V. Chernikov 152fee65b7eSAlexander V. Chernikov @property 153fee65b7eSAlexander V. Chernikov def error_code(self): 154fee65b7eSAlexander V. Chernikov return self.base_hdr.error 155fee65b7eSAlexander V. Chernikov 156fee65b7eSAlexander V. Chernikov def parse_base_header(self, data): 157fee65b7eSAlexander V. Chernikov if len(data) < sizeof(Nlmsgdone): 158fee65b7eSAlexander V. Chernikov raise ValueError("length less than nlmsgdone header") 159fee65b7eSAlexander V. Chernikov done_hdr = Nlmsgdone.from_buffer_copy(data) 160fee65b7eSAlexander V. Chernikov sz = sizeof(Nlmsgdone) 161fee65b7eSAlexander V. Chernikov return (done_hdr, sz) 162fee65b7eSAlexander V. Chernikov 163fee65b7eSAlexander V. Chernikov def print_base_header(self, hdr, prepend=""): 164fee65b7eSAlexander V. Chernikov print("{}error={}".format(prepend, hdr.error)) 165fee65b7eSAlexander V. Chernikov 166fee65b7eSAlexander V. Chernikov 167fee65b7eSAlexander V. Chernikovclass NetlinkErrorMessage(StdNetlinkMessage): 168fc2538cbSAlexander V. Chernikov messages = [NlMsgProps(NlMsgType.NLMSG_ERROR, NlMsgCategory.ACK)] 169fee65b7eSAlexander V. Chernikov nl_attrs_map = nlerr_attrs 170fee65b7eSAlexander V. Chernikov 171fee65b7eSAlexander V. Chernikov @property 172fee65b7eSAlexander V. Chernikov def error_code(self): 173fee65b7eSAlexander V. Chernikov return self.base_hdr.error 174fee65b7eSAlexander V. Chernikov 175fee65b7eSAlexander V. Chernikov @property 176fee65b7eSAlexander V. Chernikov def error_str(self): 177fee65b7eSAlexander V. Chernikov nla = self.get_nla(NlErrattrType.NLMSGERR_ATTR_MSG) 178fee65b7eSAlexander V. Chernikov if nla: 179fee65b7eSAlexander V. Chernikov return nla.text 180fee65b7eSAlexander V. Chernikov return None 181fee65b7eSAlexander V. Chernikov 182fee65b7eSAlexander V. Chernikov @property 183fee65b7eSAlexander V. Chernikov def error_offset(self): 184fee65b7eSAlexander V. Chernikov nla = self.get_nla(NlErrattrType.NLMSGERR_ATTR_OFFS) 185fee65b7eSAlexander V. Chernikov if nla: 186fee65b7eSAlexander V. Chernikov return nla.u32 187fee65b7eSAlexander V. Chernikov return None 188fee65b7eSAlexander V. Chernikov 189fee65b7eSAlexander V. Chernikov @property 190fee65b7eSAlexander V. Chernikov def cookie(self): 191fee65b7eSAlexander V. Chernikov return self.get_nla(NlErrattrType.NLMSGERR_ATTR_COOKIE) 192fee65b7eSAlexander V. Chernikov 193fee65b7eSAlexander V. Chernikov def parse_base_header(self, data): 194fee65b7eSAlexander V. Chernikov if len(data) < sizeof(Nlmsgerr): 195fee65b7eSAlexander V. Chernikov raise ValueError("length less than nlmsgerr header") 196fee65b7eSAlexander V. Chernikov err_hdr = Nlmsgerr.from_buffer_copy(data) 197fee65b7eSAlexander V. Chernikov sz = sizeof(Nlmsgerr) 198fee65b7eSAlexander V. Chernikov if (self.nl_hdr.nlmsg_flags & 0x100) == 0: 199fee65b7eSAlexander V. Chernikov sz += align4(err_hdr.msg.nlmsg_len - sizeof(Nlmsghdr)) 200fee65b7eSAlexander V. Chernikov return (err_hdr, sz) 201fee65b7eSAlexander V. Chernikov 202fee65b7eSAlexander V. Chernikov def print_base_header(self, errhdr, prepend=""): 203fee65b7eSAlexander V. Chernikov print("{}error={}, ".format(prepend, errhdr.error), end="") 204fc2538cbSAlexander V. Chernikov hdr = errhdr.msg 205fc2538cbSAlexander V. Chernikov print( 206fc2538cbSAlexander V. Chernikov "{}len={}, type={}, flags={}(0x{:X}), seq={}, pid={}".format( 207fc2538cbSAlexander V. Chernikov prepend, 208fc2538cbSAlexander V. Chernikov hdr.nlmsg_len, 209fc2538cbSAlexander V. Chernikov "msg#{}".format(hdr.nlmsg_type), 210fc2538cbSAlexander V. Chernikov self.helper.get_bitmask_str(NlmBaseFlags, hdr.nlmsg_flags), 211fc2538cbSAlexander V. Chernikov hdr.nlmsg_flags, 212fc2538cbSAlexander V. Chernikov hdr.nlmsg_seq, 213fc2538cbSAlexander V. Chernikov hdr.nlmsg_pid, 214fc2538cbSAlexander V. Chernikov ) 215fc2538cbSAlexander V. Chernikov ) 216fc2538cbSAlexander V. Chernikov 217fc2538cbSAlexander V. Chernikov 218fc2538cbSAlexander V. Chernikovcore_classes = { 219fc2538cbSAlexander V. Chernikov "netlink_core": [ 220fc2538cbSAlexander V. Chernikov NetlinkDoneMessage, 221fc2538cbSAlexander V. Chernikov NetlinkErrorMessage, 222fc2538cbSAlexander V. Chernikov ], 223fc2538cbSAlexander V. Chernikov} 224fee65b7eSAlexander V. Chernikov 225fee65b7eSAlexander V. Chernikov 226fee65b7eSAlexander V. Chernikovclass Nlsock: 227fc2538cbSAlexander V. Chernikov HANDLER_CLASSES = [core_classes, rt_classes, genl_classes] 228fc2538cbSAlexander V. Chernikov 229fee65b7eSAlexander V. Chernikov def __init__(self, family, helper): 230fee65b7eSAlexander V. Chernikov self.helper = helper 231fee65b7eSAlexander V. Chernikov self.sock_fd = self._setup_netlink(family) 232fc2538cbSAlexander V. Chernikov self._sock_family = family 233fee65b7eSAlexander V. Chernikov self._data = bytes() 234fee65b7eSAlexander V. Chernikov self.msgmap = self.build_msgmap() 235fc2538cbSAlexander V. Chernikov self._family_map = { 236fc2538cbSAlexander V. Chernikov NlConst.GENL_ID_CTRL: "nlctrl", 237fc2538cbSAlexander V. Chernikov } 238fee65b7eSAlexander V. Chernikov 239fee65b7eSAlexander V. Chernikov def build_msgmap(self): 240fc2538cbSAlexander V. Chernikov handler_classes = {} 241fc2538cbSAlexander V. Chernikov for d in self.HANDLER_CLASSES: 242fc2538cbSAlexander V. Chernikov handler_classes.update(d) 243fee65b7eSAlexander V. Chernikov xmap = {} 244fc2538cbSAlexander V. Chernikov # 'family_name': [class.messages[MsgProps.msg], ] 245fc2538cbSAlexander V. Chernikov for family_id, family_classes in handler_classes.items(): 246fc2538cbSAlexander V. Chernikov xmap[family_id] = {} 247fc2538cbSAlexander V. Chernikov for cls in family_classes: 248fc2538cbSAlexander V. Chernikov for msg_props in cls.messages: 249fc2538cbSAlexander V. Chernikov xmap[family_id][enum_or_int(msg_props.msg)] = cls 250fee65b7eSAlexander V. Chernikov return xmap 251fee65b7eSAlexander V. Chernikov 252fee65b7eSAlexander V. Chernikov def _setup_netlink(self, netlink_family) -> int: 253fee65b7eSAlexander V. Chernikov family = self.helper.get_af_value("AF_NETLINK") 254fee65b7eSAlexander V. Chernikov s = socket.socket(family, socket.SOCK_RAW, netlink_family) 255fee65b7eSAlexander V. Chernikov s.setsockopt(270, 10, 1) # NETLINK_CAP_ACK 256fee65b7eSAlexander V. Chernikov s.setsockopt(270, 11, 1) # NETLINK_EXT_ACK 257fee65b7eSAlexander V. Chernikov return s 258fee65b7eSAlexander V. Chernikov 259fee65b7eSAlexander V. Chernikov def set_groups(self, mask: int): 260fee65b7eSAlexander V. Chernikov self.sock_fd.setsockopt(socket.SOL_SOCKET, 1, mask) 261fee65b7eSAlexander V. Chernikov # snl = SockaddrNl(nl_len = sizeof(SockaddrNl), nl_family=38, 262fee65b7eSAlexander V. Chernikov # nl_pid=self.pid, nl_groups=mask) 263fee65b7eSAlexander V. Chernikov # xbuffer = create_string_buffer(sizeof(SockaddrNl)) 264fee65b7eSAlexander V. Chernikov # memmove(xbuffer, addressof(snl), sizeof(SockaddrNl)) 265fee65b7eSAlexander V. Chernikov # k = struct.pack("@BBHII", 12, 38, 0, self.pid, mask) 266fee65b7eSAlexander V. Chernikov # self.sock_fd.bind(k) 267fee65b7eSAlexander V. Chernikov 268*54b955f4SAlexander V. Chernikov def join_group(self, group_id: int): 269*54b955f4SAlexander V. Chernikov self.sock_fd.setsockopt(270, 1, group_id) 270*54b955f4SAlexander V. Chernikov 271fc2538cbSAlexander V. Chernikov def write_message(self, msg, verbose=True): 272fc2538cbSAlexander V. Chernikov if verbose: 273fee65b7eSAlexander V. Chernikov print("vvvvvvvv OUT vvvvvvvv") 274fee65b7eSAlexander V. Chernikov msg.print_message() 275fee65b7eSAlexander V. Chernikov msg_bytes = bytes(msg) 276fee65b7eSAlexander V. Chernikov try: 277fee65b7eSAlexander V. Chernikov ret = os.write(self.sock_fd.fileno(), msg_bytes) 278fee65b7eSAlexander V. Chernikov assert ret == len(msg_bytes) 279fee65b7eSAlexander V. Chernikov except Exception as e: 280fee65b7eSAlexander V. Chernikov print("write({}) -> {}".format(len(msg_bytes), e)) 281fee65b7eSAlexander V. Chernikov 282fee65b7eSAlexander V. Chernikov def parse_message(self, data: bytes): 283fee65b7eSAlexander V. Chernikov if len(data) < sizeof(Nlmsghdr): 284fee65b7eSAlexander V. Chernikov raise Exception("Short read from nl: {} bytes".format(len(data))) 285fee65b7eSAlexander V. Chernikov hdr = Nlmsghdr.from_buffer_copy(data) 286fc2538cbSAlexander V. Chernikov if hdr.nlmsg_type < 16: 287fc2538cbSAlexander V. Chernikov family_name = "netlink_core" 288fee65b7eSAlexander V. Chernikov nlmsg_type = hdr.nlmsg_type 289fc2538cbSAlexander V. Chernikov elif self._sock_family == NlConst.NETLINK_ROUTE: 290fc2538cbSAlexander V. Chernikov family_name = "netlink_route" 291fc2538cbSAlexander V. Chernikov nlmsg_type = hdr.nlmsg_type 292fc2538cbSAlexander V. Chernikov else: 293fc2538cbSAlexander V. Chernikov # Genetlink 294fc2538cbSAlexander V. Chernikov if len(data) < sizeof(Nlmsghdr) + sizeof(GenlMsgHdr): 295fc2538cbSAlexander V. Chernikov raise Exception("Short read from genl: {} bytes".format(len(data))) 296fc2538cbSAlexander V. Chernikov family_name = self._family_map.get(hdr.nlmsg_type, "") 297fc2538cbSAlexander V. Chernikov ghdr = GenlMsgHdr.from_buffer_copy(data[sizeof(Nlmsghdr):]) 298fc2538cbSAlexander V. Chernikov nlmsg_type = ghdr.cmd 299fc2538cbSAlexander V. Chernikov cls = self.msgmap.get(family_name, {}).get(nlmsg_type) 300fee65b7eSAlexander V. Chernikov if not cls: 301fee65b7eSAlexander V. Chernikov cls = BaseNetlinkMessage 302fee65b7eSAlexander V. Chernikov return cls.from_bytes(self.helper, data) 303fee65b7eSAlexander V. Chernikov 304fc2538cbSAlexander V. Chernikov def get_genl_family_id(self, family_name): 305fc2538cbSAlexander V. Chernikov hdr = Nlmsghdr( 306fc2538cbSAlexander V. Chernikov nlmsg_type=NlConst.GENL_ID_CTRL, 307fc2538cbSAlexander V. Chernikov nlmsg_flags=NlmBaseFlags.NLM_F_REQUEST.value, 308fc2538cbSAlexander V. Chernikov nlmsg_seq=self.helper.get_seq(), 309fc2538cbSAlexander V. Chernikov ) 310fc2538cbSAlexander V. Chernikov ghdr = GenlMsgHdr(cmd=GenlCtrlMsgType.CTRL_CMD_GETFAMILY.value) 311fc2538cbSAlexander V. Chernikov nla = NlAttrStr(GenlCtrlAttrType.CTRL_ATTR_FAMILY_NAME, family_name) 312fc2538cbSAlexander V. Chernikov hdr.nlmsg_len = sizeof(Nlmsghdr) + sizeof(GenlMsgHdr) + len(bytes(nla)) 313fc2538cbSAlexander V. Chernikov 314fc2538cbSAlexander V. Chernikov msg_bytes = bytes(hdr) + bytes(ghdr) + bytes(nla) 315fc2538cbSAlexander V. Chernikov self.write_data(msg_bytes) 316fc2538cbSAlexander V. Chernikov while True: 317fc2538cbSAlexander V. Chernikov rx_msg = self.read_message() 318fc2538cbSAlexander V. Chernikov if hdr.nlmsg_seq == rx_msg.nl_hdr.nlmsg_seq: 319fc2538cbSAlexander V. Chernikov if rx_msg.is_type(NlMsgType.NLMSG_ERROR): 320fc2538cbSAlexander V. Chernikov if rx_msg.error_code != 0: 321fc2538cbSAlexander V. Chernikov raise ValueError("unable to get family {}".format(family_name)) 322fc2538cbSAlexander V. Chernikov else: 323fc2538cbSAlexander V. Chernikov family_id = rx_msg.get_nla(GenlCtrlAttrType.CTRL_ATTR_FAMILY_ID).u16 324fc2538cbSAlexander V. Chernikov self._family_map[family_id] = family_name 325fc2538cbSAlexander V. Chernikov return family_id 326fc2538cbSAlexander V. Chernikov raise ValueError("unable to get family {}".format(family_name)) 327fc2538cbSAlexander V. Chernikov 328fee65b7eSAlexander V. Chernikov def write_data(self, data: bytes): 329fee65b7eSAlexander V. Chernikov self.sock_fd.send(data) 330fee65b7eSAlexander V. Chernikov 331fee65b7eSAlexander V. Chernikov def read_data(self): 332fee65b7eSAlexander V. Chernikov while True: 333fee65b7eSAlexander V. Chernikov data = self.sock_fd.recv(65535) 334fee65b7eSAlexander V. Chernikov self._data += data 335fee65b7eSAlexander V. Chernikov if len(self._data) >= sizeof(Nlmsghdr): 336fee65b7eSAlexander V. Chernikov break 337fee65b7eSAlexander V. Chernikov 338fee65b7eSAlexander V. Chernikov def read_message(self) -> bytes: 339fee65b7eSAlexander V. Chernikov if len(self._data) < sizeof(Nlmsghdr): 340fee65b7eSAlexander V. Chernikov self.read_data() 341fee65b7eSAlexander V. Chernikov hdr = Nlmsghdr.from_buffer_copy(self._data) 342fee65b7eSAlexander V. Chernikov while hdr.nlmsg_len > len(self._data): 343fee65b7eSAlexander V. Chernikov self.read_data() 344fee65b7eSAlexander V. Chernikov raw_msg = self._data[: hdr.nlmsg_len] 345fee65b7eSAlexander V. Chernikov self._data = self._data[hdr.nlmsg_len:] 346fee65b7eSAlexander V. Chernikov return self.parse_message(raw_msg) 347f3065e76SAlexander V. Chernikov 348f3065e76SAlexander V. Chernikov def get_reply(self, tx_msg): 349f3065e76SAlexander V. Chernikov self.write_message(tx_msg) 350f3065e76SAlexander V. Chernikov while True: 351f3065e76SAlexander V. Chernikov rx_msg = self.read_message() 352f3065e76SAlexander V. Chernikov if tx_msg.nl_hdr.nlmsg_seq == rx_msg.nl_hdr.nlmsg_seq: 353f3065e76SAlexander V. Chernikov return rx_msg 354fee65b7eSAlexander V. Chernikov 355fee65b7eSAlexander V. Chernikov 356fee65b7eSAlexander V. Chernikovclass NetlinkMultipartIterator(object): 357fee65b7eSAlexander V. Chernikov def __init__(self, obj, seq_number: int, msg_type): 358fee65b7eSAlexander V. Chernikov self._obj = obj 359fee65b7eSAlexander V. Chernikov self._seq = seq_number 360fee65b7eSAlexander V. Chernikov self._msg_type = msg_type 361fee65b7eSAlexander V. Chernikov 362fee65b7eSAlexander V. Chernikov def __iter__(self): 363fee65b7eSAlexander V. Chernikov return self 364fee65b7eSAlexander V. Chernikov 365fee65b7eSAlexander V. Chernikov def __next__(self): 366fee65b7eSAlexander V. Chernikov msg = self._obj.read_message() 367fee65b7eSAlexander V. Chernikov if self._seq != msg.nl_hdr.nlmsg_seq: 368fee65b7eSAlexander V. Chernikov raise ValueError("bad sequence number") 369fee65b7eSAlexander V. Chernikov if msg.is_type(NlMsgType.NLMSG_ERROR): 370fee65b7eSAlexander V. Chernikov raise ValueError( 371fee65b7eSAlexander V. Chernikov "error while handling multipart msg: {}".format(msg.error_code) 372fee65b7eSAlexander V. Chernikov ) 373fee65b7eSAlexander V. Chernikov elif msg.is_type(NlMsgType.NLMSG_DONE): 374fee65b7eSAlexander V. Chernikov if msg.error_code == 0: 375fee65b7eSAlexander V. Chernikov raise StopIteration 376fee65b7eSAlexander V. Chernikov raise ValueError( 377fee65b7eSAlexander V. Chernikov "error listing some parts of the multipart msg: {}".format( 378fee65b7eSAlexander V. Chernikov msg.error_code 379fee65b7eSAlexander V. Chernikov ) 380fee65b7eSAlexander V. Chernikov ) 381fee65b7eSAlexander V. Chernikov elif not msg.is_type(self._msg_type): 382fee65b7eSAlexander V. Chernikov raise ValueError("bad message type: {}".format(msg)) 383fee65b7eSAlexander V. Chernikov return msg 384fee65b7eSAlexander V. Chernikov 385fee65b7eSAlexander V. Chernikov 386fee65b7eSAlexander V. Chernikovclass NetlinkTestTemplate(object): 387fee65b7eSAlexander V. Chernikov REQUIRED_MODULES = ["netlink"] 388fee65b7eSAlexander V. Chernikov 389fee65b7eSAlexander V. Chernikov def setup_netlink(self, netlink_family: NlConst): 390fee65b7eSAlexander V. Chernikov self.helper = NlHelper() 391fee65b7eSAlexander V. Chernikov self.nlsock = Nlsock(netlink_family, self.helper) 392fee65b7eSAlexander V. Chernikov 393fee65b7eSAlexander V. Chernikov def write_message(self, msg, silent=False): 394fee65b7eSAlexander V. Chernikov if not silent: 395fee65b7eSAlexander V. Chernikov print("") 396fee65b7eSAlexander V. Chernikov print("============= >> TX MESSAGE =============") 397fee65b7eSAlexander V. Chernikov msg.print_message() 398fee65b7eSAlexander V. Chernikov msg.print_as_bytes(bytes(msg), "-- DATA --") 399fee65b7eSAlexander V. Chernikov self.nlsock.write_data(bytes(msg)) 400fee65b7eSAlexander V. Chernikov 401fee65b7eSAlexander V. Chernikov def read_message(self, silent=False): 402fee65b7eSAlexander V. Chernikov msg = self.nlsock.read_message() 403fee65b7eSAlexander V. Chernikov if not silent: 404fee65b7eSAlexander V. Chernikov print("") 405fee65b7eSAlexander V. Chernikov print("============= << RX MESSAGE =============") 406fee65b7eSAlexander V. Chernikov msg.print_message() 407fee65b7eSAlexander V. Chernikov return msg 408fee65b7eSAlexander V. Chernikov 409fee65b7eSAlexander V. Chernikov def get_reply(self, tx_msg): 410fee65b7eSAlexander V. Chernikov self.write_message(tx_msg) 411fee65b7eSAlexander V. Chernikov while True: 412fee65b7eSAlexander V. Chernikov rx_msg = self.read_message() 413fee65b7eSAlexander V. Chernikov if tx_msg.nl_hdr.nlmsg_seq == rx_msg.nl_hdr.nlmsg_seq: 414fee65b7eSAlexander V. Chernikov return rx_msg 415fee65b7eSAlexander V. Chernikov 416fee65b7eSAlexander V. Chernikov def read_msg_list(self, seq, msg_type): 417fee65b7eSAlexander V. Chernikov return list(NetlinkMultipartIterator(self, seq, msg_type)) 418