Instead of copy/pasting pynl80211 in iotop.py, keep it in separate files
[iotop.git] / netlink.py
blobdabada4122ddaf3b09f69d998c15d4d56dbc350d
1 '''
2 Netlink message generation/parsing
4 Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
6 GPLv2
7 '''
9 import struct, socket
11 try:
12 # try to use python 2.5's netlink support
13 _dummysock = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, 0)
14 _dummysock.bind((0, 0))
15 del _dummysock
16 def _nl_bind(descriptor, addr):
17 descriptor.bind(addr)
18 def _nl_getsockname(descriptor):
19 return descriptor.getsockname()
20 def _nl_send(descriptor, msg):
21 descriptor.send(msg)
22 def _nl_recv(descriptor, bufs=16384):
23 return descriptor.recvfrom(bufs)
24 except socket.error:
25 # or fall back to the _netlink C module
26 try:
27 import _netlink
28 except ImportError:
29 raise ImportError("This is neither python 2.5 nor is "
30 "the _netlink C module available!")
31 def _nl_bind(descriptor, addr):
32 _netlink.bind(descriptor.fileno(), addr[1])
33 def _nl_getsockname(descriptor):
34 return _netlink.getsockname(descriptor.fileno())
35 def _nl_send(descriptor, msg):
36 _netlink.send(descriptor.fileno(), msg)
37 def _nl_recv(descriptor, bufs=16384):
38 return _netlink.recvfrom(descriptor.fileno(), bufs)
40 # flags
41 NLM_F_REQUEST = 1
42 NLM_F_MULTI = 2
43 NLM_F_ACK = 4
44 NLM_F_ECHO = 8
46 # types
47 NLMSG_NOOP = 1
48 NLMSG_ERROR = 2
49 NLMSG_DONE = 3
50 NLMSG_OVERRUN = 4
51 NLMSG_MIN_TYPE = 0x10
53 class Attr:
54 def __init__(self, attr_type, data, *values):
55 self.type = attr_type
56 if len(values):
57 self.data = struct.pack(data, *values)
58 else:
59 self.data = data
61 def _dump(self):
62 hdr = struct.pack("HH", len(self.data)+4, self.type)
63 length = len(self.data)
64 pad = ((length + 4 - 1) & ~3 ) - length
65 return hdr + self.data + '\0' * pad
67 def __repr__(self):
68 return '<Attr type %d, data "%s">' % (self.type, repr(self.data))
70 def u16(self):
71 return struct.unpack('H', self.data)[0]
72 def s16(self):
73 return struct.unpack('h', self.data)[0]
74 def u32(self):
75 return struct.unpack('I', self.data)[0]
76 def s32(self):
77 return struct.unpack('i', self.data)[0]
78 def str(self):
79 return self.data
80 def nulstr(self):
81 return self.data.split('\0')[0]
82 def nested(self):
83 return parse_attributes(self.data)
85 class StrAttr(Attr):
86 def __init__(self, attr_type, data):
87 Attr.__init__(self, attr_type, "%ds" % len(data), data)
89 class NulStrAttr(Attr):
90 def __init__(self, attr_type, data):
91 Attr.__init__(self, attr_type, "%dsB" % len(data), data, 0)
93 class U32Attr(Attr):
94 def __init__(self, attr_type, val):
95 Attr.__init__(self, attr_type, "L", val)
97 class U8Attr(Attr):
98 def __init__(self, attr_type, val):
99 Attr.__init__(self, attr_type, "B", val)
101 class Nested(Attr):
102 def __init__(self, attr_type, attrs):
103 self.attrs = attrs
104 self.type = attr_type
106 def _dump(self):
107 contents = []
108 for attr in self.attrs:
109 contents.append(attr._dump())
110 contents = ''.join(contents)
111 length = len(contents)
112 hdr = struct.pack("HH", length+4, self.type)
113 return hdr + contents
115 NETLINK_ROUTE = 0
116 NETLINK_UNUSED = 1
117 NETLINK_USERSOCK = 2
118 NETLINK_FIREWALL = 3
119 NETLINK_INET_DIAG = 4
120 NETLINK_NFLOG = 5
121 NETLINK_XFRM = 6
122 NETLINK_SELINUX = 7
123 NETLINK_ISCSI = 8
124 NETLINK_AUDIT = 9
125 NETLINK_FIB_LOOKUP = 10
126 NETLINK_CONNECTOR = 11
127 NETLINK_NETFILTER = 12
128 NETLINK_IP6_FW = 13
129 NETLINK_DNRTMSG = 14
130 NETLINK_KOBJECT_UEVENT = 15
131 NETLINK_GENERIC = 16
133 class Message:
134 def __init__(self, msg_type, flags=0, seq=-1, payload=None):
135 self.type = msg_type
136 self.flags = flags
137 self.seq = seq
138 self.pid = -1
139 payload = payload or []
140 if isinstance(payload, list):
141 contents = []
142 for attr in payload:
143 contents.append(attr._dump())
144 self.payload = ''.join(contents)
145 else:
146 self.payload = payload
148 def send(self, conn):
149 if self.seq == -1:
150 self.seq = conn.seq()
152 self.pid = conn.pid
153 length = len(self.payload)
155 hdr = struct.pack("IHHII", length + 4*4, self.type,
156 self.flags, self.seq, self.pid)
157 conn.send(hdr + self.payload)
159 def __repr__(self):
160 return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
161 self.type, self.pid, self.seq, self.flags, repr(self.payload))
163 class Connection:
164 def __init__(self, nltype, groups=0, unexpected_msg_handler=None):
165 self.descriptor = socket.socket(socket.AF_NETLINK,
166 socket.SOCK_RAW, nltype)
167 self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
168 self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
169 _nl_bind(self.descriptor, (0, groups))
170 self.pid, self.groups = _nl_getsockname(self.descriptor)
171 self._seq = 0
172 self.unexpected = unexpected_msg_handler
173 def send(self, msg):
174 _nl_send(self.descriptor, msg)
175 def recv(self):
176 contents, (nlpid, nlgrps) = _nl_recv(self.descriptor)
177 # XXX: python doesn't give us message flags, check
178 # len(contents) vs. msglen for TRUNC
179 msglen, msg_type, flags, seq, pid = struct.unpack("IHHII",
180 contents[:16])
181 msg = Message(msg_type, flags, seq, contents[16:])
182 msg.pid = pid
183 if msg.type == NLMSG_ERROR:
184 import os
185 errno = -struct.unpack("i", msg.payload[:4])[0]
186 if errno != 0:
187 err = OSError("Netlink error: %s (%d)" % (
188 os.strerror(errno), errno))
189 err.errno = errno
190 raise err
191 return msg
192 def seq(self):
193 self._seq += 1
194 return self._seq
196 def parse_attributes(data):
197 attrs = {}
198 while len(data):
199 attr_len, attr_type = struct.unpack("HH", data[:4])
200 attrs[attr_type] = Attr(attr_type, data[4:attr_len])
201 attr_len = ((attr_len + 4 - 1) & ~3 )
202 data = data[attr_len:]
203 return attrs