4
import xen.lowlevel.netlink
8
NLM_F_REQUEST = 1 # It is request message.
9
NLM_F_MULTI = 2 # Multipart message, terminated by NLMSG_DONE
10
NLM_F_ACK = 4 # Reply with ack, with zero or error code
11
NLM_F_ECHO = 8 # Echo this request
13
# Modifiers to GET request
14
NLM_F_ROOT = 0x100 # specify tree root
15
NLM_F_MATCH = 0x200 # return all matching
16
NLM_F_ATOMIC = 0x400 # atomic GET
17
NLM_F_DUMP = NLM_F_ROOT|NLM_F_MATCH
19
# Modifiers to NEW request
20
NLM_F_REPLACE = 0x100 # Override existing
21
NLM_F_EXCL = 0x200 # Do not touch, if it exists
22
NLM_F_CREATE = 0x400 # Create, if it does not exist
23
NLM_F_APPEND = 0x800 # Add to end of list
57
class RTNLException(Exception): pass
59
def align(l, alignto=4):
60
return (l + alignto - 1) & ~(alignto - 1)
65
fmtlen = struct.calcsize(fmt)
67
def __init__(self, msg=None):
77
return align(self.rta_len)
80
self.rta_len = align(self.fmtlen + len(self.body))
81
s = struct.pack(self.fmt, self.rta_len, self.rta_type) + self.body
82
pad = self.rta_len - len(s)
87
def unpack(self, msg):
88
args = struct.unpack(self.fmt, msg[:self.fmtlen])
89
self.rta_len, self.rta_type = args
91
self.body = msg[align(self.fmtlen):self.rta_len]
93
class rtattrlist(object):
94
def __init__(self, msg):
99
while len(body) > rtattr.fmtlen:
102
body = body[len(rta):]
105
"netlink message header"
107
fmtlen = struct.calcsize(fmt)
109
def __init__(self, msg=None):
123
return align(self.fmtlen + len(self.body) + len(self.rta))
125
def addattr(self, type, data):
129
self.rta += attr.pack()
131
def settype(self, cmd):
132
self.nlmsg_type = cmd
135
return struct.pack(self.fmt, len(self), self.nlmsg_type,
136
self.nlmsg_flags, self.nlmsg_seq,
137
self.nlmsg_pid) + self.body + self.rta
139
def unpack(self, msg):
140
args = struct.unpack(self.fmt, msg[:self.fmtlen])
141
self.nlmsg_len, self.nlmsg_type, self.nlmsg_flags = args[:3]
142
self.nlmsg_seq, self.nlmsg_pid = args[3:]
144
self.body = msg[align(self.fmtlen):]
148
return '<netlink message, len %d, type %d>' % \
149
(self.nlmsg_len, self.nlmsg_type)
151
class ifinfomsg(object):
152
"interface info message"
154
fmtlen = struct.calcsize(fmt)
156
def __init__(self, msg=None):
168
def unpack(self, msg):
169
args = struct.unpack(self.fmt, msg[:self.fmtlen])
170
self.ifi_family, self.ifi_type, self.ifi_index= args[:3]
171
self.ifi_flags, self.ifi_change = args[3:]
173
self.body = msg[align(self.fmtlen):]
176
return '<ifinfo message, family %d, type %d, index %d>' % \
177
(self.ifi_family, self.ifi_type, self.ifi_index)
182
fmtlen = struct.calcsize(fmt)
184
def __init__(self, msg=None):
188
self.tcm_family = socket.AF_UNSPEC
196
def unpack(self, msg):
197
args = struct.unpack(self.fmt, msg[:self.fmtlen])
198
self.tcm_family, self.tcm_ifindex, self.tcm_handle = args[:3]
199
self.tcm_parent, self.tcm_info = args[3:]
201
self.rta = msg[align(self.fmtlen):]
204
return struct.pack(self.fmt, self.tcm_family, self.tcm_ifindex,
205
self.tcm_handle, self.tcm_parent, self.tcm_info)
208
return '<tc message, family %d, index %d>' % \
209
(self.tcm_family, self.tcm_ifindex)
211
class newlinkmsg(object):
212
def __init__(self, nlmsg):
213
if nlmsg.nlmsg_type != RTM_NEWLINK:
214
raise RTNLException("wrong message type")
216
self.ifi = ifinfomsg(self.nlmsg.body)
219
for rta in rtattrlist(self.ifi.body):
220
self.rtattrs[rta.rta_type] = rta.body
222
class newqdiscmsg(object):
223
def __init__(self, nlmsg):
224
if nlmsg.nlmsg_type != RTM_NEWQDISC:
225
raise RTNLException("wrong message type")
227
self.t = tcmsg(self.nlmsg.body)
230
for rta in rtattrlist(self.t.rta):
231
self.rtattrs[rta.rta_type] = rta.body
235
self._rth = xen.lowlevel.netlink.rtnl()
236
self._linkcache = None
238
def getlink(self, key, cached=False):
239
"""returns the interface object corresponding to the key, which
240
may be an index number or device name."""
242
self._linkcache = None
243
if self._linkcache is None:
244
self._linkcache = self.getlinks()
246
if isinstance(key, int):
247
return self._linkcache.get(key)
249
for k, v in self._linkcache.iteritems():
256
"""returns a dictionary of interfaces keyed by kernel
259
def dumpfilter(addr, msgstr):
260
msg = newlinkmsg(nlmsg(msgstr))
261
idx = msg.ifi.ifi_index
262
ifname = msg.rtattrs[IFLA_IFNAME].strip('\0')
263
address = msg.rtattrs.get(IFLA_ADDRESS)
265
link = {'index': idx,
266
'type': msg.ifi.ifi_type,
271
self._rth.wilddump_request(socket.AF_UNSPEC, RTM_GETLINK)
272
self._rth.dump_filter(dumpfilter)
276
def getqdisc(self, dev):
277
"""returns the queueing discipline on device dev, which may be
278
specified by kernel index or device name"""
279
qdiscs = self.getqdiscs(dev)
281
return qdiscs.values()[0]
284
def getqdiscs(self, dev=None):
285
"""returns a dictionary of queueing disciplines keyed by kernel
288
def dumpfilter(addr, msgstr):
289
msg = newqdiscmsg(nlmsg(msgstr))
290
idx = msg.t.tcm_ifindex
291
handle = msg.t.tcm_handle
292
kind = msg.rtattrs[TCA_KIND].strip('\0')
293
opts = msg.rtattrs.get(TCA_OPTIONS)
295
qdisc = {'index': idx,
303
link = self.getlink(dev)
305
raise QdiscException('device %s not found' % dev)
306
tcm.tcm_ifindex = link['index']
309
self._rth.dump_request(RTM_GETQDISC, msg)
310
self._rth.dump_filter(dumpfilter)