1import socket
2import struct
3from ctypes import c_int
4from ctypes import c_ubyte
5from ctypes import c_uint
6from ctypes import c_ushort
7from ctypes import sizeof
8from ctypes import Structure
9from enum import auto
10from enum import Enum
11
12from atf_python.sys.netlink.attrs import NlAttr
13from atf_python.sys.netlink.attrs import NlAttrIp
14from atf_python.sys.netlink.attrs import NlAttrNested
15from atf_python.sys.netlink.attrs import NlAttrStr
16from atf_python.sys.netlink.attrs import NlAttrU32
17from atf_python.sys.netlink.attrs import NlAttrU8
18from atf_python.sys.netlink.message import StdNetlinkMessage
19from atf_python.sys.netlink.message import NlMsgProps
20from atf_python.sys.netlink.message import NlMsgCategory
21from atf_python.sys.netlink.utils import AttrDescr
22from atf_python.sys.netlink.utils import get_bitmask_str
23from atf_python.sys.netlink.utils import prepare_attrs_map
24
25
26class RtattrType(Enum):
27    RTA_UNSPEC = 0
28    RTA_DST = 1
29    RTA_SRC = 2
30    RTA_IIF = 3
31    RTA_OIF = 4
32    RTA_GATEWAY = 5
33    RTA_PRIORITY = 6
34    RTA_PREFSRC = 7
35    RTA_METRICS = 8
36    RTA_MULTIPATH = 9
37    # RTA_PROTOINFO = 10
38    RTA_KNH_ID = 10
39    RTA_FLOW = 11
40    RTA_CACHEINFO = 12
41    RTA_SESSION = 13
42    # RTA_MP_ALGO = 14
43    RTA_RTFLAGS = 14
44    RTA_TABLE = 15
45    RTA_MARK = 16
46    RTA_MFC_STATS = 17
47    RTA_VIA = 18
48    RTA_NEWDST = 19
49    RTA_PREF = 20
50    RTA_ENCAP_TYPE = 21
51    RTA_ENCAP = 22
52    RTA_EXPIRES = 23
53    RTA_PAD = 24
54    RTA_UID = 25
55    RTA_TTL_PROPAGATE = 26
56    RTA_IP_PROTO = 27
57    RTA_SPORT = 28
58    RTA_DPORT = 29
59    RTA_NH_ID = 30
60
61
62class NlRtMsgType(Enum):
63    RTM_NEWLINK = 16
64    RTM_DELLINK = 17
65    RTM_GETLINK = 18
66    RTM_SETLINK = 19
67    RTM_NEWADDR = 20
68    RTM_DELADDR = 21
69    RTM_GETADDR = 22
70    RTM_NEWROUTE = 24
71    RTM_DELROUTE = 25
72    RTM_GETROUTE = 26
73    RTM_NEWNEIGH = 28
74    RTM_DELNEIGH = 29
75    RTM_GETNEIGH = 30
76    RTM_NEWRULE = 32
77    RTM_DELRULE = 33
78    RTM_GETRULE = 34
79    RTM_NEWQDISC = 36
80    RTM_DELQDISC = 37
81    RTM_GETQDISC = 38
82    RTM_NEWTCLASS = 40
83    RTM_DELTCLASS = 41
84    RTM_GETTCLASS = 42
85    RTM_NEWTFILTER = 44
86    RTM_DELTFILTER = 45
87    RTM_GETTFILTER = 46
88    RTM_NEWACTION = 48
89    RTM_DELACTION = 49
90    RTM_GETACTION = 50
91    RTM_NEWPREFIX = 52
92    RTM_GETMULTICAST = 58
93    RTM_GETANYCAST = 62
94    RTM_NEWNEIGHTBL = 64
95    RTM_GETNEIGHTBL = 66
96    RTM_SETNEIGHTBL = 67
97    RTM_NEWNDUSEROPT = 68
98    RTM_NEWADDRLABEL = 72
99    RTM_DELADDRLABEL = 73
100    RTM_GETADDRLABEL = 74
101    RTM_GETDCB = 78
102    RTM_SETDCB = 79
103    RTM_NEWNETCONF = 80
104    RTM_GETNETCONF = 82
105    RTM_NEWMDB = 84
106    RTM_DELMDB = 85
107    RTM_GETMDB = 86
108    RTM_NEWNSID = 88
109    RTM_DELNSID = 89
110    RTM_GETNSID = 90
111    RTM_NEWSTATS = 92
112    RTM_GETSTATS = 94
113
114
115class RtAttr(Structure):
116    _fields_ = [
117        ("rta_len", c_ushort),
118        ("rta_type", c_ushort),
119    ]
120
121
122class RtMsgHdr(Structure):
123    _fields_ = [
124        ("rtm_family", c_ubyte),
125        ("rtm_dst_len", c_ubyte),
126        ("rtm_src_len", c_ubyte),
127        ("rtm_tos", c_ubyte),
128        ("rtm_table", c_ubyte),
129        ("rtm_protocol", c_ubyte),
130        ("rtm_scope", c_ubyte),
131        ("rtm_type", c_ubyte),
132        ("rtm_flags", c_uint),
133    ]
134
135
136class RtMsgFlags(Enum):
137    RTM_F_NOTIFY = 0x100
138    RTM_F_CLONED = 0x200
139    RTM_F_EQUALIZE = 0x400
140    RTM_F_PREFIX = 0x800
141    RTM_F_LOOKUP_TABLE = 0x1000
142    RTM_F_FIB_MATCH = 0x2000
143    RTM_F_OFFLOAD = 0x4000
144    RTM_F_TRAP = 0x8000
145    RTM_F_OFFLOAD_FAILED = 0x20000000
146
147
148class RtScope(Enum):
149    RT_SCOPE_UNIVERSE = 0
150    RT_SCOPE_SITE = 200
151    RT_SCOPE_LINK = 253
152    RT_SCOPE_HOST = 254
153    RT_SCOPE_NOWHERE = 255
154
155
156class RtType(Enum):
157    RTN_UNSPEC = 0
158    RTN_UNICAST = auto()
159    RTN_LOCAL = auto()
160    RTN_BROADCAST = auto()
161    RTN_ANYCAST = auto()
162    RTN_MULTICAST = auto()
163    RTN_BLACKHOLE = auto()
164    RTN_UNREACHABLE = auto()
165    RTN_PROHIBIT = auto()
166    RTN_THROW = auto()
167    RTN_NAT = auto()
168    RTN_XRESOLVE = auto()
169
170
171class RtProto(Enum):
172    RTPROT_UNSPEC = 0
173    RTPROT_REDIRECT = 1
174    RTPROT_KERNEL = 2
175    RTPROT_BOOT = 3
176    RTPROT_STATIC = 4
177    RTPROT_GATED = 8
178    RTPROT_RA = 9
179    RTPROT_MRT = 10
180    RTPROT_ZEBRA = 11
181    RTPROT_BIRD = 12
182    RTPROT_DNROUTED = 13
183    RTPROT_XORP = 14
184    RTPROT_NTK = 15
185    RTPROT_DHCP = 16
186    RTPROT_MROUTED = 17
187    RTPROT_KEEPALIVED = 18
188    RTPROT_BABEL = 42
189    RTPROT_OPENR = 99
190    RTPROT_BGP = 186
191    RTPROT_ISIS = 187
192    RTPROT_OSPF = 188
193    RTPROT_RIP = 189
194    RTPROT_EIGRP = 192
195
196
197class NlRtaxType(Enum):
198    RTAX_UNSPEC = 0
199    RTAX_LOCK = auto()
200    RTAX_MTU = auto()
201    RTAX_WINDOW = auto()
202    RTAX_RTT = auto()
203    RTAX_RTTVAR = auto()
204    RTAX_SSTHRESH = auto()
205    RTAX_CWND = auto()
206    RTAX_ADVMSS = auto()
207    RTAX_REORDERING = auto()
208    RTAX_HOPLIMIT = auto()
209    RTAX_INITCWND = auto()
210    RTAX_FEATURES = auto()
211    RTAX_RTO_MIN = auto()
212    RTAX_INITRWND = auto()
213    RTAX_QUICKACK = auto()
214    RTAX_CC_ALGO = auto()
215    RTAX_FASTOPEN_NO_COOKIE = auto()
216
217
218class RtFlagsBSD(Enum):
219    RTF_UP = 0x1
220    RTF_GATEWAY = 0x2
221    RTF_HOST = 0x4
222    RTF_REJECT = 0x8
223    RTF_DYNAMIC = 0x10
224    RTF_MODIFIED = 0x20
225    RTF_DONE = 0x40
226    RTF_XRESOLVE = 0x200
227    RTF_LLINFO = 0x400
228    RTF_LLDATA = 0x400
229    RTF_STATIC = 0x800
230    RTF_BLACKHOLE = 0x1000
231    RTF_PROTO2 = 0x4000
232    RTF_PROTO1 = 0x8000
233    RTF_PROTO3 = 0x40000
234    RTF_FIXEDMTU = 0x80000
235    RTF_PINNED = 0x100000
236    RTF_LOCAL = 0x200000
237    RTF_BROADCAST = 0x400000
238    RTF_MULTICAST = 0x800000
239    RTF_STICKY = 0x10000000
240    RTF_RNH_LOCKED = 0x40000000
241    RTF_GWFLAG_COMPAT = 0x80000000
242
243
244class NlRtGroup(Enum):
245    RTNLGRP_NONE = 0
246    RTNLGRP_LINK = auto()
247    RTNLGRP_NOTIFY = auto()
248    RTNLGRP_NEIGH = auto()
249    RTNLGRP_TC = auto()
250    RTNLGRP_IPV4_IFADDR = auto()
251    RTNLGRP_IPV4_MROUTE = auto()
252    RTNLGRP_IPV4_ROUTE = auto()
253    RTNLGRP_IPV4_RULE = auto()
254    RTNLGRP_IPV6_IFADDR = auto()
255    RTNLGRP_IPV6_MROUTE = auto()
256    RTNLGRP_IPV6_ROUTE = auto()
257    RTNLGRP_IPV6_IFINFO = auto()
258    RTNLGRP_DECnet_IFADDR = auto()
259    RTNLGRP_NOP2 = auto()
260    RTNLGRP_DECnet_ROUTE = auto()
261    RTNLGRP_DECnet_RULE = auto()
262    RTNLGRP_NOP4 = auto()
263    RTNLGRP_IPV6_PREFIX = auto()
264    RTNLGRP_IPV6_RULE = auto()
265    RTNLGRP_ND_USEROPT = auto()
266    RTNLGRP_PHONET_IFADDR = auto()
267    RTNLGRP_PHONET_ROUTE = auto()
268    RTNLGRP_DCB = auto()
269    RTNLGRP_IPV4_NETCONF = auto()
270    RTNLGRP_IPV6_NETCONF = auto()
271    RTNLGRP_MDB = auto()
272    RTNLGRP_MPLS_ROUTE = auto()
273    RTNLGRP_NSID = auto()
274    RTNLGRP_MPLS_NETCONF = auto()
275    RTNLGRP_IPV4_MROUTE_R = auto()
276    RTNLGRP_IPV6_MROUTE_R = auto()
277    RTNLGRP_NEXTHOP = auto()
278    RTNLGRP_BRVLAN = auto()
279
280
281class IfinfoMsg(Structure):
282    _fields_ = [
283        ("ifi_family", c_ubyte),
284        ("__ifi_pad", c_ubyte),
285        ("ifi_type", c_ushort),
286        ("ifi_index", c_int),
287        ("ifi_flags", c_uint),
288        ("ifi_change", c_uint),
289    ]
290
291
292class IflattrType(Enum):
293    IFLA_UNSPEC = 0
294    IFLA_ADDRESS = auto()
295    IFLA_BROADCAST = auto()
296    IFLA_IFNAME = auto()
297    IFLA_MTU = auto()
298    IFLA_LINK = auto()
299    IFLA_QDISC = auto()
300    IFLA_STATS = auto()
301    IFLA_COST = auto()
302    IFLA_PRIORITY = auto()
303    IFLA_MASTER = auto()
304    IFLA_WIRELESS = auto()
305    IFLA_PROTINFO = auto()
306    IFLA_TXQLEN = auto()
307    IFLA_MAP = auto()
308    IFLA_WEIGHT = auto()
309    IFLA_OPERSTATE = auto()
310    IFLA_LINKMODE = auto()
311    IFLA_LINKINFO = auto()
312    IFLA_NET_NS_PID = auto()
313    IFLA_IFALIAS = auto()
314    IFLA_NUM_VF = auto()
315    IFLA_VFINFO_LIST = auto()
316    IFLA_STATS64 = auto()
317    IFLA_VF_PORTS = auto()
318    IFLA_PORT_SELF = auto()
319    IFLA_AF_SPEC = auto()
320    IFLA_GROUP = auto()
321    IFLA_NET_NS_FD = auto()
322    IFLA_EXT_MASK = auto()
323    IFLA_PROMISCUITY = auto()
324    IFLA_NUM_TX_QUEUES = auto()
325    IFLA_NUM_RX_QUEUES = auto()
326    IFLA_CARRIER = auto()
327    IFLA_PHYS_PORT_ID = auto()
328    IFLA_CARRIER_CHANGES = auto()
329    IFLA_PHYS_SWITCH_ID = auto()
330    IFLA_LINK_NETNSID = auto()
331    IFLA_PHYS_PORT_NAME = auto()
332    IFLA_PROTO_DOWN = auto()
333    IFLA_GSO_MAX_SEGS = auto()
334    IFLA_GSO_MAX_SIZE = auto()
335    IFLA_PAD = auto()
336    IFLA_XDP = auto()
337    IFLA_EVENT = auto()
338    IFLA_NEW_NETNSID = auto()
339    IFLA_IF_NETNSID = auto()
340    IFLA_CARRIER_UP_COUNT = auto()
341    IFLA_CARRIER_DOWN_COUNT = auto()
342    IFLA_NEW_IFINDEX = auto()
343    IFLA_MIN_MTU = auto()
344    IFLA_MAX_MTU = auto()
345    IFLA_PROP_LIST = auto()
346    IFLA_ALT_IFNAME = auto()
347    IFLA_PERM_ADDRESS = auto()
348    IFLA_PROTO_DOWN_REASON = auto()
349
350
351class IflinkInfo(Enum):
352    IFLA_INFO_UNSPEC = 0
353    IFLA_INFO_KIND = auto()
354    IFLA_INFO_DATA = auto()
355    IFLA_INFO_XSTATS = auto()
356    IFLA_INFO_SLAVE_KIND = auto()
357    IFLA_INFO_SLAVE_DATA = auto()
358
359
360class IfLinkInfoDataVlan(Enum):
361    IFLA_VLAN_UNSPEC = 0
362    IFLA_VLAN_ID = auto()
363    IFLA_VLAN_FLAGS = auto()
364    IFLA_VLAN_EGRESS_QOS = auto()
365    IFLA_VLAN_INGRESS_QOS = auto()
366    IFLA_VLAN_PROTOCOL = auto()
367
368
369class IfaddrMsg(Structure):
370    _fields_ = [
371        ("ifa_family", c_ubyte),
372        ("ifa_prefixlen", c_ubyte),
373        ("ifa_flags", c_ubyte),
374        ("ifa_scope", c_ubyte),
375        ("ifa_index", c_uint),
376    ]
377
378
379class IfattrType(Enum):
380    IFA_UNSPEC = 0
381    IFA_ADDRESS = auto()
382    IFA_LOCAL = auto()
383    IFA_LABEL = auto()
384    IFA_BROADCAST = auto()
385    IFA_ANYCAST = auto()
386    IFA_CACHEINFO = auto()
387    IFA_MULTICAST = auto()
388    IFA_FLAGS = auto()
389    IFA_RT_PRIORITY = auto()
390    IFA_TARGET_NETNSID = auto()
391
392
393class NdMsg(Structure):
394    _fields_ = [
395        ("ndm_family", c_ubyte),
396        ("ndm_pad1", c_ubyte),
397        ("ndm_pad2", c_ubyte),
398        ("ndm_ifindex", c_uint),
399        ("ndm_state", c_ushort),
400        ("ndm_flags", c_ubyte),
401        ("ndm_type", c_ubyte),
402    ]
403
404
405class NdAttrType(Enum):
406    NDA_UNSPEC = 0
407    NDA_DST = 1
408    NDA_LLADDR = 2
409    NDA_CACHEINFO = 3
410    NDA_PROBES = 4
411    NDA_VLAN = 5
412    NDA_PORT = 6
413    NDA_VNI = 7
414    NDA_IFINDEX = 8
415    NDA_MASTER = 9
416    NDA_LINK_NETNSID = 10
417    NDA_SRC_VNI = 11
418    NDA_PROTOCOL = 12
419    NDA_NH_ID = 13
420    NDA_FDB_EXT_ATTRS = 14
421    NDA_FLAGS_EXT = 15
422    NDA_NDM_STATE_MASK = 16
423    NDA_NDM_FLAGS_MASK = 17
424
425
426class NlAttrRtFlags(NlAttrU32):
427    def _print_attr_value(self):
428        s = get_bitmask_str(RtFlagsBSD, self.u32)
429        return " rtflags={}".format(s)
430
431
432class NlAttrIfindex(NlAttrU32):
433    def _print_attr_value(self):
434        try:
435            ifname = socket.if_indextoname(self.u32)
436            return " iface={}(#{})".format(ifname, self.u32)
437        except OSError:
438            pass
439        return " iface=if#{}".format(self.u32)
440
441
442class NlAttrTable(NlAttrU32):
443    def _print_attr_value(self):
444        return " rtable={}".format(self.u32)
445
446
447class NlAttrNhId(NlAttrU32):
448    def _print_attr_value(self):
449        return " nh_id={}".format(self.u32)
450
451
452class NlAttrKNhId(NlAttrU32):
453    def _print_attr_value(self):
454        return " knh_id={}".format(self.u32)
455
456
457class NlAttrMac(NlAttr):
458    def _print_attr_value(self):
459        return ' mac="' + ":".join(["{:02X}".format(b) for b in self._data]) + '"'
460
461
462class NlAttrIfStats(NlAttr):
463    def _print_attr_value(self):
464        return " stats={...}"
465
466
467class NlAttrVia(NlAttr):
468    def __init__(self, nla_type, family, addr: str):
469        super().__init__(nla_type, b"")
470        self.addr = addr
471        self.family = family
472
473    @staticmethod
474    def _validate(data):
475        nla_len, nla_type = struct.unpack("@HH", data[:4])
476        data_len = nla_len - 4
477        if data_len == 0:
478            raise ValueError(
479                "Error validating attr {}: empty data".format(nla_type)
480            )  # noqa: E501
481        family = int(data_len[0])
482        if family not in (socket.AF_INET, socket.AF_INET6):
483            raise ValueError(
484                "Error validating attr {}: unsupported AF {}".format(  # noqa: E501
485                    nla_type, family
486                )
487            )
488        if family == socket.AF_INET:
489            expected_len = 1 + 4
490        else:
491            expected_len = 1 + 16
492        if data_len != expected_len:
493            raise ValueError(
494                "Error validating attr {}: expected len {} got {}".format(  # noqa: E501
495                    nla_type, expected_len, data_len
496                )
497            )
498
499    @property
500    def nla_len(self):
501        if self.family == socket.AF_INET6:
502            return 21
503        else:
504            return 9
505
506    @classmethod
507    def _parse(cls, data):
508        nla_len, nla_type, family = struct.unpack("@HHB", data[:5])
509        off = 5
510        if family == socket.AF_INET:
511            addr = socket.inet_ntop(family, data[off:off + 4])
512        else:
513            addr = socket.inet_ntop(family, data[off:off + 16])
514        return cls(nla_type, family, addr)
515
516    def __bytes__(self):
517        addr = socket.inet_pton(self.family, self.addr)
518        return self._to_bytes(struct.pack("@B", self.family) + addr)
519
520    def _print_attr_value(self):
521        return " via={}".format(self.addr)
522
523
524rtnl_route_attrs = prepare_attrs_map(
525    [
526        AttrDescr(RtattrType.RTA_DST, NlAttrIp),
527        AttrDescr(RtattrType.RTA_SRC, NlAttrIp),
528        AttrDescr(RtattrType.RTA_IIF, NlAttrIfindex),
529        AttrDescr(RtattrType.RTA_OIF, NlAttrIfindex),
530        AttrDescr(RtattrType.RTA_GATEWAY, NlAttrIp),
531        AttrDescr(RtattrType.RTA_TABLE, NlAttrTable),
532        AttrDescr(RtattrType.RTA_PRIORITY, NlAttrU32),
533        AttrDescr(RtattrType.RTA_VIA, NlAttrVia),
534        AttrDescr(RtattrType.RTA_NH_ID, NlAttrNhId),
535        AttrDescr(RtattrType.RTA_KNH_ID, NlAttrKNhId),
536        AttrDescr(RtattrType.RTA_RTFLAGS, NlAttrRtFlags),
537        AttrDescr(
538            RtattrType.RTA_METRICS,
539            NlAttrNested,
540            [
541                AttrDescr(NlRtaxType.RTAX_MTU, NlAttrU32),
542            ],
543        ),
544    ]
545)
546
547rtnl_ifla_attrs = prepare_attrs_map(
548    [
549        AttrDescr(IflattrType.IFLA_ADDRESS, NlAttrMac),
550        AttrDescr(IflattrType.IFLA_BROADCAST, NlAttrMac),
551        AttrDescr(IflattrType.IFLA_IFNAME, NlAttrStr),
552        AttrDescr(IflattrType.IFLA_MTU, NlAttrU32),
553        AttrDescr(IflattrType.IFLA_LINK, NlAttrU32),
554        AttrDescr(IflattrType.IFLA_PROMISCUITY, NlAttrU32),
555        AttrDescr(IflattrType.IFLA_OPERSTATE, NlAttrU8),
556        AttrDescr(IflattrType.IFLA_CARRIER, NlAttrU8),
557        AttrDescr(IflattrType.IFLA_IFALIAS, NlAttrStr),
558        AttrDescr(IflattrType.IFLA_STATS64, NlAttrIfStats),
559        AttrDescr(IflattrType.IFLA_NEW_IFINDEX, NlAttrU32),
560        AttrDescr(
561            IflattrType.IFLA_LINKINFO,
562            NlAttrNested,
563            [
564                AttrDescr(IflinkInfo.IFLA_INFO_KIND, NlAttrStr),
565                AttrDescr(IflinkInfo.IFLA_INFO_DATA, NlAttr),
566            ],
567        ),
568    ]
569)
570
571rtnl_ifa_attrs = prepare_attrs_map(
572    [
573        AttrDescr(IfattrType.IFA_ADDRESS, NlAttrIp),
574        AttrDescr(IfattrType.IFA_LOCAL, NlAttrIp),
575        AttrDescr(IfattrType.IFA_LABEL, NlAttrStr),
576        AttrDescr(IfattrType.IFA_BROADCAST, NlAttrIp),
577        AttrDescr(IfattrType.IFA_ANYCAST, NlAttrIp),
578        AttrDescr(IfattrType.IFA_FLAGS, NlAttrU32),
579    ]
580)
581
582
583rtnl_nd_attrs = prepare_attrs_map(
584    [
585        AttrDescr(NdAttrType.NDA_DST, NlAttrIp),
586        AttrDescr(NdAttrType.NDA_IFINDEX, NlAttrIfindex),
587        AttrDescr(NdAttrType.NDA_FLAGS_EXT, NlAttrU32),
588        AttrDescr(NdAttrType.NDA_LLADDR, NlAttrMac),
589    ]
590)
591
592
593class BaseNetlinkRtMessage(StdNetlinkMessage):
594    pass
595
596
597class NetlinkRtMessage(BaseNetlinkRtMessage):
598    messages = [
599        NlMsgProps(NlRtMsgType.RTM_NEWROUTE, NlMsgCategory.NEW),
600        NlMsgProps(NlRtMsgType.RTM_DELROUTE, NlMsgCategory.DELETE),
601        NlMsgProps(NlRtMsgType.RTM_GETROUTE, NlMsgCategory.GET),
602    ]
603    nl_attrs_map = rtnl_route_attrs
604
605    def __init__(self, helper, nlm_type):
606        super().__init__(helper, nlm_type)
607        self.base_hdr = RtMsgHdr()
608
609    def parse_base_header(self, data):
610        if len(data) < sizeof(RtMsgHdr):
611            raise ValueError("length less than rtmsg header")
612        rtm_hdr = RtMsgHdr.from_buffer_copy(data)
613        return (rtm_hdr, sizeof(RtMsgHdr))
614
615    def print_base_header(self, hdr, prepend=""):
616        family = self.helper.get_af_name(hdr.rtm_family)
617        print(
618            "{}family={}, dst_len={}, src_len={}, tos={}, table={}, protocol={}({}), scope={}({}), type={}({}), flags={}({})".format(  # noqa: E501
619                prepend,
620                family,
621                hdr.rtm_dst_len,
622                hdr.rtm_src_len,
623                hdr.rtm_tos,
624                hdr.rtm_table,
625                self.helper.get_attr_byval(RtProto, hdr.rtm_protocol),
626                hdr.rtm_protocol,
627                self.helper.get_attr_byval(RtScope, hdr.rtm_scope),
628                hdr.rtm_scope,
629                self.helper.get_attr_byval(RtType, hdr.rtm_type),
630                hdr.rtm_type,
631                self.helper.get_bitmask_str(RtMsgFlags, hdr.rtm_flags),
632                hdr.rtm_flags,
633            )
634        )
635
636
637class NetlinkIflaMessage(BaseNetlinkRtMessage):
638    messages = [
639        NlMsgProps(NlRtMsgType.RTM_NEWLINK, NlMsgCategory.NEW),
640        NlMsgProps(NlRtMsgType.RTM_DELLINK, NlMsgCategory.DELETE),
641        NlMsgProps(NlRtMsgType.RTM_GETLINK, NlMsgCategory.GET),
642    ]
643    nl_attrs_map = rtnl_ifla_attrs
644
645    def __init__(self, helper, nlm_type):
646        super().__init__(helper, nlm_type)
647        self.base_hdr = IfinfoMsg()
648
649    def parse_base_header(self, data):
650        if len(data) < sizeof(IfinfoMsg):
651            raise ValueError("length less than IfinfoMsg header")
652        rtm_hdr = IfinfoMsg.from_buffer_copy(data)
653        return (rtm_hdr, sizeof(IfinfoMsg))
654
655    def print_base_header(self, hdr, prepend=""):
656        family = self.helper.get_af_name(hdr.ifi_family)
657        print(
658            "{}family={}, ifi_type={}, ifi_index={}, ifi_flags={}, ifi_change={}".format(  # noqa: E501
659                prepend,
660                family,
661                hdr.ifi_type,
662                hdr.ifi_index,
663                hdr.ifi_flags,
664                hdr.ifi_change,
665            )
666        )
667
668
669class NetlinkIfaMessage(BaseNetlinkRtMessage):
670    messages = [
671        NlMsgProps(NlRtMsgType.RTM_NEWADDR, NlMsgCategory.NEW),
672        NlMsgProps(NlRtMsgType.RTM_DELADDR, NlMsgCategory.DELETE),
673        NlMsgProps(NlRtMsgType.RTM_GETADDR, NlMsgCategory.GET),
674    ]
675    nl_attrs_map = rtnl_ifa_attrs
676
677    def __init__(self, helper, nlm_type):
678        super().__init__(helper, nlm_type)
679        self.base_hdr = IfaddrMsg()
680
681    def parse_base_header(self, data):
682        if len(data) < sizeof(IfaddrMsg):
683            raise ValueError("length less than IfaddrMsg header")
684        rtm_hdr = IfaddrMsg.from_buffer_copy(data)
685        return (rtm_hdr, sizeof(IfaddrMsg))
686
687    def print_base_header(self, hdr, prepend=""):
688        family = self.helper.get_af_name(hdr.ifa_family)
689        print(
690            "{}family={}, ifa_prefixlen={}, ifa_flags={}, ifa_scope={}, ifa_index={}".format(  # noqa: E501
691                prepend,
692                family,
693                hdr.ifa_prefixlen,
694                hdr.ifa_flags,
695                hdr.ifa_scope,
696                hdr.ifa_index,
697            )
698        )
699
700
701class NetlinkNdMessage(BaseNetlinkRtMessage):
702    messages = [
703        NlMsgProps(NlRtMsgType.RTM_NEWNEIGH, NlMsgCategory.NEW),
704        NlMsgProps(NlRtMsgType.RTM_DELNEIGH, NlMsgCategory.DELETE),
705        NlMsgProps(NlRtMsgType.RTM_GETNEIGH, NlMsgCategory.GET),
706    ]
707    nl_attrs_map = rtnl_nd_attrs
708
709    def __init__(self, helper, nlm_type):
710        super().__init__(helper, nlm_type)
711        self.base_hdr = NdMsg()
712
713    def parse_base_header(self, data):
714        if len(data) < sizeof(NdMsg):
715            raise ValueError("length less than NdMsg header")
716        nd_hdr = NdMsg.from_buffer_copy(data)
717        return (nd_hdr, sizeof(NdMsg))
718
719    def print_base_header(self, hdr, prepend=""):
720        family = self.helper.get_af_name(hdr.ndm_family)
721        print(
722            "{}family={}, ndm_ifindex={}, ndm_state={}, ndm_flags={}".format(  # noqa: E501
723                prepend,
724                family,
725                hdr.ndm_ifindex,
726                hdr.ndm_state,
727                hdr.ndm_flags,
728            )
729        )
730
731
732handler_classes = {
733    "netlink_route": [
734        NetlinkRtMessage,
735        NetlinkIflaMessage,
736        NetlinkIfaMessage,
737        NetlinkNdMessage,
738    ],
739}
740