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 = 1
295    IFLA_BROADCAST = 2
296    IFLA_IFNAME = 3
297    IFLA_MTU = 4
298    IFLA_LINK = 5
299    IFLA_QDISC = 6
300    IFLA_STATS = 7
301    IFLA_COST = 8
302    IFLA_PRIORITY = 9
303    IFLA_MASTER = 10
304    IFLA_WIRELESS = 11
305    IFLA_PROTINFO = 12
306    IFLA_TXQLEN = 13
307    IFLA_MAP = 14
308    IFLA_WEIGHT = 15
309    IFLA_OPERSTATE = 16
310    IFLA_LINKMODE = 17
311    IFLA_LINKINFO = 18
312    IFLA_NET_NS_PID = 19
313    IFLA_IFALIAS = 20
314    IFLA_NUM_VF = 21
315    IFLA_VFINFO_LIST = 22
316    IFLA_STATS64 = 23
317    IFLA_VF_PORTS = 24
318    IFLA_PORT_SELF = 25
319    IFLA_AF_SPEC = 26
320    IFLA_GROUP = 27
321    IFLA_NET_NS_FD = 28
322    IFLA_EXT_MASK = 29
323    IFLA_PROMISCUITY = 30
324    IFLA_NUM_TX_QUEUES = 31
325    IFLA_NUM_RX_QUEUES = 32
326    IFLA_CARRIER = 33
327    IFLA_PHYS_PORT_ID = 34
328    IFLA_CARRIER_CHANGES = 35
329    IFLA_PHYS_SWITCH_ID = 36
330    IFLA_LINK_NETNSID = 37
331    IFLA_PHYS_PORT_NAME = 38
332    IFLA_PROTO_DOWN = 39
333    IFLA_GSO_MAX_SEGS = 40
334    IFLA_GSO_MAX_SIZE = 41
335    IFLA_PAD = 42
336    IFLA_XDP = 43
337    IFLA_EVENT = 44
338    IFLA_NEW_NETNSID = 45
339    IFLA_IF_NETNSID = 46
340    IFLA_CARRIER_UP_COUNT = 47
341    IFLA_CARRIER_DOWN_COUNT = 48
342    IFLA_NEW_IFINDEX = 49
343    IFLA_MIN_MTU = 50
344    IFLA_MAX_MTU = 51
345    IFLA_PROP_LIST = 52
346    IFLA_ALT_IFNAME = 53
347    IFLA_PERM_ADDRESS = 54
348    IFLA_PROTO_DOWN_REASON = 55
349    IFLA_PARENT_DEV_NAME = 56
350    IFLA_PARENT_DEV_BUS_NAME = 57
351    IFLA_GRO_MAX_SIZE = 58
352    IFLA_TSO_MAX_SEGS = 59
353    IFLA_ALLMULTI = 60
354    IFLA_DEVLINK_PORT = 61
355    IFLA_GSO_IPV4_MAX_SIZE = 62
356    IFLA_GRO_IPV4_MAX_SIZE = 63
357    IFLA_FREEBSD = 64
358
359
360class IflafAttrType(Enum):
361    IFLAF_UNSPEC = 0
362    IFLAF_ORIG_IFNAME = 1
363    IFLAF_ORIG_HWADDR = 2
364
365
366class IflinkInfo(Enum):
367    IFLA_INFO_UNSPEC = 0
368    IFLA_INFO_KIND = auto()
369    IFLA_INFO_DATA = auto()
370    IFLA_INFO_XSTATS = auto()
371    IFLA_INFO_SLAVE_KIND = auto()
372    IFLA_INFO_SLAVE_DATA = auto()
373
374
375class IfLinkInfoDataVlan(Enum):
376    IFLA_VLAN_UNSPEC = 0
377    IFLA_VLAN_ID = auto()
378    IFLA_VLAN_FLAGS = auto()
379    IFLA_VLAN_EGRESS_QOS = auto()
380    IFLA_VLAN_INGRESS_QOS = auto()
381    IFLA_VLAN_PROTOCOL = auto()
382
383
384class IfaddrMsg(Structure):
385    _fields_ = [
386        ("ifa_family", c_ubyte),
387        ("ifa_prefixlen", c_ubyte),
388        ("ifa_flags", c_ubyte),
389        ("ifa_scope", c_ubyte),
390        ("ifa_index", c_uint),
391    ]
392
393
394class IfaAttrType(Enum):
395    IFA_UNSPEC = 0
396    IFA_ADDRESS = 1
397    IFA_LOCAL = 2
398    IFA_LABEL = 3
399    IFA_BROADCAST = 4
400    IFA_ANYCAST = 5
401    IFA_CACHEINFO = 6
402    IFA_MULTICAST = 7
403    IFA_FLAGS = 8
404    IFA_RT_PRIORITY = 9
405    IFA_TARGET_NETNSID = 10
406    IFA_FREEBSD = 11
407
408
409class IfafAttrType(Enum):
410    IFAF_UNSPEC = 0
411    IFAF_VHID = 1
412    IFAF_FLAGS = 2
413
414
415class IfaCacheInfo(Structure):
416    _fields_ = [
417        ("ifa_prefered", c_uint),   # seconds till the end of the prefix considered preferred
418        ("ifa_valid", c_uint),      # seconds till the end of the prefix considered valid
419        ("cstamp", c_uint),         # creation time in 1ms intervals from the boot time
420        ("tstamp", c_uint),         # update time in 1ms intervals from the boot time
421    ]
422
423
424class IfaFlags(Enum):
425    IFA_F_TEMPORARY = 0x01
426    IFA_F_NODAD = 0x02
427    IFA_F_OPTIMISTIC = 0x04
428    IFA_F_DADFAILED = 0x08
429    IFA_F_HOMEADDRESS = 0x10
430    IFA_F_DEPRECATED = 0x20
431    IFA_F_TENTATIVE = 0x40
432    IFA_F_PERMANENT = 0x80
433    IFA_F_MANAGETEMPADDR = 0x100
434    IFA_F_NOPREFIXROUTE = 0x200
435    IFA_F_MCAUTOJOIN = 0x400
436    IFA_F_STABLE_PRIVACY = 0x800
437
438
439class IfafFlags6(Enum):
440    IN6_IFF_ANYCAST = 0x01
441    IN6_IFF_TENTATIVE = 0x02
442    IN6_IFF_DUPLICATED = 0x04
443    IN6_IFF_DETACHED = 0x08
444    IN6_IFF_DEPRECATED = 0x10
445    IN6_IFF_NODAD = 0x20
446    IN6_IFF_AUTOCONF = 0x40
447    IN6_IFF_TEMPORARY = 0x80
448    IN6_IFF_PREFER_SOURCE = 0x100
449
450
451class NdMsg(Structure):
452    _fields_ = [
453        ("ndm_family", c_ubyte),
454        ("ndm_pad1", c_ubyte),
455        ("ndm_pad2", c_ubyte),
456        ("ndm_ifindex", c_uint),
457        ("ndm_state", c_ushort),
458        ("ndm_flags", c_ubyte),
459        ("ndm_type", c_ubyte),
460    ]
461
462
463class NdAttrType(Enum):
464    NDA_UNSPEC = 0
465    NDA_DST = 1
466    NDA_LLADDR = 2
467    NDA_CACHEINFO = 3
468    NDA_PROBES = 4
469    NDA_VLAN = 5
470    NDA_PORT = 6
471    NDA_VNI = 7
472    NDA_IFINDEX = 8
473    NDA_MASTER = 9
474    NDA_LINK_NETNSID = 10
475    NDA_SRC_VNI = 11
476    NDA_PROTOCOL = 12
477    NDA_NH_ID = 13
478    NDA_FDB_EXT_ATTRS = 14
479    NDA_FLAGS_EXT = 15
480    NDA_NDM_STATE_MASK = 16
481    NDA_NDM_FLAGS_MASK = 17
482
483
484class NlAttrRtFlags(NlAttrU32):
485    def _print_attr_value(self):
486        s = get_bitmask_str(RtFlagsBSD, self.u32)
487        return " rtflags={}".format(s)
488
489
490class NlAttrIfindex(NlAttrU32):
491    def _print_attr_value(self):
492        try:
493            ifname = socket.if_indextoname(self.u32)
494            return " iface={}(#{})".format(ifname, self.u32)
495        except OSError:
496            pass
497        return " iface=if#{}".format(self.u32)
498
499
500class NlAttrTable(NlAttrU32):
501    def _print_attr_value(self):
502        return " rtable={}".format(self.u32)
503
504
505class NlAttrNhId(NlAttrU32):
506    def _print_attr_value(self):
507        return " nh_id={}".format(self.u32)
508
509
510class NlAttrKNhId(NlAttrU32):
511    def _print_attr_value(self):
512        return " knh_id={}".format(self.u32)
513
514
515class NlAttrMac(NlAttr):
516    def _print_attr_value(self):
517        return ' mac="' + ":".join(["{:02X}".format(b) for b in self._data]) + '"'
518
519
520class NlAttrIfStats(NlAttr):
521    def _print_attr_value(self):
522        return " stats={...}"
523
524
525class NlAttrCacheInfo(NlAttr):
526    def __init__(self, nla_type, data):
527        super().__init__(nla_type, data)
528        self.ci = IfaCacheInfo.from_buffer_copy(data)
529
530    @staticmethod
531    def _validate(data):
532        nla_len, nla_type = struct.unpack("@HH", data[:4])
533        data_len = nla_len - 4
534        if data_len != sizeof(IfaCacheInfo):
535            raise ValueError(
536                "Error validating attr {}: wrong size".format(nla_type)
537            )  # noqa: E501
538
539    def _print_attr_value(self):
540        return " ifa_prefered={} ifa_valid={} cstamp={} tstamp={}".format(
541                self.ci.ifa_prefered, self.ci.ifa_valid, self.ci.cstamp, self.ci.tstamp)
542
543
544class NlAttrVia(NlAttr):
545    def __init__(self, nla_type, family, addr: str):
546        super().__init__(nla_type, b"")
547        self.addr = addr
548        self.family = family
549
550    @staticmethod
551    def _validate(data):
552        nla_len, nla_type = struct.unpack("@HH", data[:4])
553        data_len = nla_len - 4
554        if data_len == 0:
555            raise ValueError(
556                "Error validating attr {}: empty data".format(nla_type)
557            )  # noqa: E501
558        family = int(data_len[0])
559        if family not in (socket.AF_INET, socket.AF_INET6):
560            raise ValueError(
561                "Error validating attr {}: unsupported AF {}".format(  # noqa: E501
562                    nla_type, family
563                )
564            )
565        if family == socket.AF_INET:
566            expected_len = 1 + 4
567        else:
568            expected_len = 1 + 16
569        if data_len != expected_len:
570            raise ValueError(
571                "Error validating attr {}: expected len {} got {}".format(  # noqa: E501
572                    nla_type, expected_len, data_len
573                )
574            )
575
576    @property
577    def nla_len(self):
578        if self.family == socket.AF_INET6:
579            return 21
580        else:
581            return 9
582
583    @classmethod
584    def _parse(cls, data):
585        nla_len, nla_type, family = struct.unpack("@HHB", data[:5])
586        off = 5
587        if family == socket.AF_INET:
588            addr = socket.inet_ntop(family, data[off:off + 4])
589        else:
590            addr = socket.inet_ntop(family, data[off:off + 16])
591        return cls(nla_type, family, addr)
592
593    def __bytes__(self):
594        addr = socket.inet_pton(self.family, self.addr)
595        return self._to_bytes(struct.pack("@B", self.family) + addr)
596
597    def _print_attr_value(self):
598        return " via={}".format(self.addr)
599
600
601rtnl_route_attrs = prepare_attrs_map(
602    [
603        AttrDescr(RtattrType.RTA_DST, NlAttrIp),
604        AttrDescr(RtattrType.RTA_SRC, NlAttrIp),
605        AttrDescr(RtattrType.RTA_IIF, NlAttrIfindex),
606        AttrDescr(RtattrType.RTA_OIF, NlAttrIfindex),
607        AttrDescr(RtattrType.RTA_GATEWAY, NlAttrIp),
608        AttrDescr(RtattrType.RTA_TABLE, NlAttrTable),
609        AttrDescr(RtattrType.RTA_PRIORITY, NlAttrU32),
610        AttrDescr(RtattrType.RTA_VIA, NlAttrVia),
611        AttrDescr(RtattrType.RTA_NH_ID, NlAttrNhId),
612        AttrDescr(RtattrType.RTA_KNH_ID, NlAttrKNhId),
613        AttrDescr(RtattrType.RTA_RTFLAGS, NlAttrRtFlags),
614        AttrDescr(
615            RtattrType.RTA_METRICS,
616            NlAttrNested,
617            [
618                AttrDescr(NlRtaxType.RTAX_MTU, NlAttrU32),
619            ],
620        ),
621    ]
622)
623
624rtnl_ifla_attrs = prepare_attrs_map(
625    [
626        AttrDescr(IflattrType.IFLA_ADDRESS, NlAttrMac),
627        AttrDescr(IflattrType.IFLA_BROADCAST, NlAttrMac),
628        AttrDescr(IflattrType.IFLA_IFNAME, NlAttrStr),
629        AttrDescr(IflattrType.IFLA_MTU, NlAttrU32),
630        AttrDescr(IflattrType.IFLA_LINK, NlAttrU32),
631        AttrDescr(IflattrType.IFLA_PROMISCUITY, NlAttrU32),
632        AttrDescr(IflattrType.IFLA_OPERSTATE, NlAttrU8),
633        AttrDescr(IflattrType.IFLA_CARRIER, NlAttrU8),
634        AttrDescr(IflattrType.IFLA_IFALIAS, NlAttrStr),
635        AttrDescr(IflattrType.IFLA_STATS64, NlAttrIfStats),
636        AttrDescr(IflattrType.IFLA_NEW_IFINDEX, NlAttrU32),
637        AttrDescr(
638            IflattrType.IFLA_LINKINFO,
639            NlAttrNested,
640            [
641                AttrDescr(IflinkInfo.IFLA_INFO_KIND, NlAttrStr),
642                AttrDescr(IflinkInfo.IFLA_INFO_DATA, NlAttr),
643            ],
644        ),
645        AttrDescr(
646            IflattrType.IFLA_FREEBSD,
647            NlAttrNested,
648            [
649                AttrDescr(IflafAttrType.IFLAF_ORIG_HWADDR, NlAttrMac),
650            ],
651        ),
652    ]
653)
654
655rtnl_ifa_attrs = prepare_attrs_map(
656    [
657        AttrDescr(IfaAttrType.IFA_ADDRESS, NlAttrIp),
658        AttrDescr(IfaAttrType.IFA_LOCAL, NlAttrIp),
659        AttrDescr(IfaAttrType.IFA_LABEL, NlAttrStr),
660        AttrDescr(IfaAttrType.IFA_BROADCAST, NlAttrIp),
661        AttrDescr(IfaAttrType.IFA_ANYCAST, NlAttrIp),
662        AttrDescr(IfaAttrType.IFA_FLAGS, NlAttrU32),
663        AttrDescr(IfaAttrType.IFA_CACHEINFO, NlAttrCacheInfo),
664        AttrDescr(
665            IfaAttrType.IFA_FREEBSD,
666            NlAttrNested,
667            [
668                AttrDescr(IfafAttrType.IFAF_VHID, NlAttrU32),
669                AttrDescr(IfafAttrType.IFAF_FLAGS, NlAttrU32),
670            ],
671        ),
672    ]
673)
674
675
676rtnl_nd_attrs = prepare_attrs_map(
677    [
678        AttrDescr(NdAttrType.NDA_DST, NlAttrIp),
679        AttrDescr(NdAttrType.NDA_IFINDEX, NlAttrIfindex),
680        AttrDescr(NdAttrType.NDA_FLAGS_EXT, NlAttrU32),
681        AttrDescr(NdAttrType.NDA_LLADDR, NlAttrMac),
682    ]
683)
684
685
686class BaseNetlinkRtMessage(StdNetlinkMessage):
687    pass
688
689
690class NetlinkRtMessage(BaseNetlinkRtMessage):
691    messages = [
692        NlMsgProps(NlRtMsgType.RTM_NEWROUTE, NlMsgCategory.NEW),
693        NlMsgProps(NlRtMsgType.RTM_DELROUTE, NlMsgCategory.DELETE),
694        NlMsgProps(NlRtMsgType.RTM_GETROUTE, NlMsgCategory.GET),
695    ]
696    nl_attrs_map = rtnl_route_attrs
697
698    def __init__(self, helper, nlm_type):
699        super().__init__(helper, nlm_type)
700        self.base_hdr = RtMsgHdr()
701
702    def parse_base_header(self, data):
703        if len(data) < sizeof(RtMsgHdr):
704            raise ValueError("length less than rtmsg header")
705        rtm_hdr = RtMsgHdr.from_buffer_copy(data)
706        return (rtm_hdr, sizeof(RtMsgHdr))
707
708    def print_base_header(self, hdr, prepend=""):
709        family = self.helper.get_af_name(hdr.rtm_family)
710        print(
711            "{}family={}, dst_len={}, src_len={}, tos={}, table={}, protocol={}({}), scope={}({}), type={}({}), flags={}({})".format(  # noqa: E501
712                prepend,
713                family,
714                hdr.rtm_dst_len,
715                hdr.rtm_src_len,
716                hdr.rtm_tos,
717                hdr.rtm_table,
718                self.helper.get_attr_byval(RtProto, hdr.rtm_protocol),
719                hdr.rtm_protocol,
720                self.helper.get_attr_byval(RtScope, hdr.rtm_scope),
721                hdr.rtm_scope,
722                self.helper.get_attr_byval(RtType, hdr.rtm_type),
723                hdr.rtm_type,
724                self.helper.get_bitmask_str(RtMsgFlags, hdr.rtm_flags),
725                hdr.rtm_flags,
726            )
727        )
728
729
730class NetlinkIflaMessage(BaseNetlinkRtMessage):
731    messages = [
732        NlMsgProps(NlRtMsgType.RTM_NEWLINK, NlMsgCategory.NEW),
733        NlMsgProps(NlRtMsgType.RTM_DELLINK, NlMsgCategory.DELETE),
734        NlMsgProps(NlRtMsgType.RTM_GETLINK, NlMsgCategory.GET),
735    ]
736    nl_attrs_map = rtnl_ifla_attrs
737
738    def __init__(self, helper, nlm_type):
739        super().__init__(helper, nlm_type)
740        self.base_hdr = IfinfoMsg()
741
742    def parse_base_header(self, data):
743        if len(data) < sizeof(IfinfoMsg):
744            raise ValueError("length less than IfinfoMsg header")
745        rtm_hdr = IfinfoMsg.from_buffer_copy(data)
746        return (rtm_hdr, sizeof(IfinfoMsg))
747
748    def print_base_header(self, hdr, prepend=""):
749        family = self.helper.get_af_name(hdr.ifi_family)
750        print(
751            "{}family={}, ifi_type={}, ifi_index={}, ifi_flags={}, ifi_change={}".format(  # noqa: E501
752                prepend,
753                family,
754                hdr.ifi_type,
755                hdr.ifi_index,
756                hdr.ifi_flags,
757                hdr.ifi_change,
758            )
759        )
760
761
762class NetlinkIfaMessage(BaseNetlinkRtMessage):
763    messages = [
764        NlMsgProps(NlRtMsgType.RTM_NEWADDR, NlMsgCategory.NEW),
765        NlMsgProps(NlRtMsgType.RTM_DELADDR, NlMsgCategory.DELETE),
766        NlMsgProps(NlRtMsgType.RTM_GETADDR, NlMsgCategory.GET),
767    ]
768    nl_attrs_map = rtnl_ifa_attrs
769
770    def __init__(self, helper, nlm_type):
771        super().__init__(helper, nlm_type)
772        self.base_hdr = IfaddrMsg()
773
774    def parse_base_header(self, data):
775        if len(data) < sizeof(IfaddrMsg):
776            raise ValueError("length less than IfaddrMsg header")
777        rtm_hdr = IfaddrMsg.from_buffer_copy(data)
778        return (rtm_hdr, sizeof(IfaddrMsg))
779
780    def print_base_header(self, hdr, prepend=""):
781        family = self.helper.get_af_name(hdr.ifa_family)
782        print(
783            "{}family={}, ifa_prefixlen={}, ifa_flags={}, ifa_scope={}, ifa_index={}".format(  # noqa: E501
784                prepend,
785                family,
786                hdr.ifa_prefixlen,
787                hdr.ifa_flags,
788                hdr.ifa_scope,
789                hdr.ifa_index,
790            )
791        )
792
793
794class NetlinkNdMessage(BaseNetlinkRtMessage):
795    messages = [
796        NlMsgProps(NlRtMsgType.RTM_NEWNEIGH, NlMsgCategory.NEW),
797        NlMsgProps(NlRtMsgType.RTM_DELNEIGH, NlMsgCategory.DELETE),
798        NlMsgProps(NlRtMsgType.RTM_GETNEIGH, NlMsgCategory.GET),
799    ]
800    nl_attrs_map = rtnl_nd_attrs
801
802    def __init__(self, helper, nlm_type):
803        super().__init__(helper, nlm_type)
804        self.base_hdr = NdMsg()
805
806    def parse_base_header(self, data):
807        if len(data) < sizeof(NdMsg):
808            raise ValueError("length less than NdMsg header")
809        nd_hdr = NdMsg.from_buffer_copy(data)
810        return (nd_hdr, sizeof(NdMsg))
811
812    def print_base_header(self, hdr, prepend=""):
813        family = self.helper.get_af_name(hdr.ndm_family)
814        print(
815            "{}family={}, ndm_ifindex={}, ndm_state={}, ndm_flags={}".format(  # noqa: E501
816                prepend,
817                family,
818                hdr.ndm_ifindex,
819                hdr.ndm_state,
820                hdr.ndm_flags,
821            )
822        )
823
824
825handler_classes = {
826    "netlink_route": [
827        NetlinkRtMessage,
828        NetlinkIflaMessage,
829        NetlinkIfaMessage,
830        NetlinkNdMessage,
831    ],
832}
833