~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/python/xen/remus/netlink.py

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# netlink wrappers
 
2
 
 
3
import socket, struct
 
4
import xen.lowlevel.netlink
 
5
 
 
6
NETLINK_ROUTE          = 0
 
7
 
 
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
 
12
 
 
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
 
18
 
 
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
 
24
 
 
25
RTM_NEWLINK  = 16
 
26
RTM_GETLINK  = 18
 
27
RTM_NEWQDISC = 36
 
28
RTM_DELQDISC = 37
 
29
RTM_GETQDISC = 38
 
30
 
 
31
IFLA_UNSPEC    = 0
 
32
IFLA_ADDRESS   = 1
 
33
IFLA_BROADCAST = 2
 
34
IFLA_IFNAME    = 3
 
35
IFLA_MTU       = 4
 
36
IFLA_LINK      = 5
 
37
IFLA_QDISC     = 6
 
38
IFLA_STATS     = 7
 
39
IFLA_COST      = 8
 
40
IFLA_PRIORITY  = 9
 
41
IFLA_MASTER    = 10
 
42
IFLA_WIRELESS  = 11
 
43
IFLA_PROTINFO  = 12
 
44
IFLA_TXQLEN    = 13
 
45
IFLA_MAP       = 14
 
46
IFLA_WEIGHT    = 15
 
47
 
 
48
TCA_UNSPEC  = 0
 
49
TCA_KIND    = 1
 
50
TCA_OPTIONS = 2
 
51
TCA_STATS   = 3
 
52
TCA_XSTATS  = 4
 
53
TCA_RATE    = 5
 
54
TCA_FCNT    = 6
 
55
TCA_STATS2  = 7
 
56
 
 
57
class RTNLException(Exception): pass
 
58
 
 
59
def align(l, alignto=4):
 
60
    return (l + alignto - 1) & ~(alignto - 1)
 
61
 
 
62
class rtattr(object):
 
63
    "rtattribute"
 
64
    fmt = "HH"
 
65
    fmtlen = struct.calcsize(fmt)
 
66
 
 
67
    def __init__(self, msg=None):
 
68
        if msg:
 
69
            self.unpack(msg)
 
70
        else:
 
71
            self.rta_len = 0
 
72
            self.rta_type = 0
 
73
 
 
74
            self.body = ''
 
75
 
 
76
    def __len__(self):
 
77
        return align(self.rta_len)
 
78
 
 
79
    def pack(self):
 
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)
 
83
        if pad:
 
84
            s += '\0' * pad
 
85
        return s
 
86
 
 
87
    def unpack(self, msg):
 
88
        args = struct.unpack(self.fmt, msg[:self.fmtlen])
 
89
        self.rta_len, self.rta_type = args
 
90
 
 
91
        self.body = msg[align(self.fmtlen):self.rta_len]
 
92
 
 
93
class rtattrlist(object):
 
94
    def __init__(self, msg):
 
95
        self.start = msg
 
96
 
 
97
    def __iter__(self):
 
98
        body = self.start
 
99
        while len(body) > rtattr.fmtlen:
 
100
            rta = rtattr(body)
 
101
            yield rta
 
102
            body = body[len(rta):]
 
103
 
 
104
class nlmsg(object):
 
105
    "netlink message header"
 
106
    fmt = "IHHII"
 
107
    fmtlen = struct.calcsize(fmt)
 
108
 
 
109
    def __init__(self, msg=None):
 
110
        if msg:
 
111
            self.unpack(msg)
 
112
        else:
 
113
            self.nlmsg_len = 0
 
114
            self.nlmsg_type = 0
 
115
            self.nlmsg_flags = 0
 
116
            self.nlmsg_seq = 0
 
117
            self.nlmsg_pid = 0
 
118
 
 
119
            self.rta = ''
 
120
            self.body = ''
 
121
 
 
122
    def __len__(self):
 
123
        return align(self.fmtlen + len(self.body) + len(self.rta))
 
124
 
 
125
    def addattr(self, type, data):
 
126
        attr = rtattr()
 
127
        attr.rta_type = type
 
128
        attr.body = data
 
129
        self.rta += attr.pack()
 
130
 
 
131
    def settype(self, cmd):
 
132
        self.nlmsg_type = cmd
 
133
 
 
134
    def pack(self):
 
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
 
138
 
 
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:]
 
143
 
 
144
        self.body = msg[align(self.fmtlen):]
 
145
        self.rta = ''
 
146
 
 
147
    def __str__(self):
 
148
        return '<netlink message, len %d, type %d>' % \
 
149
            (self.nlmsg_len, self.nlmsg_type)
 
150
 
 
151
class ifinfomsg(object):
 
152
    "interface info message"
 
153
    fmt = "BxHiII"
 
154
    fmtlen = struct.calcsize(fmt)
 
155
 
 
156
    def __init__(self, msg=None):
 
157
        if msg:
 
158
            self.unpack(msg)
 
159
        else:
 
160
            self.ifi_family = 0
 
161
            self.ifi_type = 0
 
162
            self.ifi_index = 0
 
163
            self.ifi_flags = 0
 
164
            self.ifi_change = 0
 
165
 
 
166
            self.body = ''
 
167
 
 
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:]
 
172
 
 
173
        self.body = msg[align(self.fmtlen):]
 
174
 
 
175
    def __str__(self):
 
176
        return '<ifinfo message, family %d, type %d, index %d>' % \
 
177
            (self.ifi_family, self.ifi_type, self.ifi_index)
 
178
 
 
179
class tcmsg(object):
 
180
    "TC message"
 
181
    fmt = "BxxxiIII"
 
182
    fmtlen = struct.calcsize(fmt)
 
183
 
 
184
    def __init__(self, msg=None):
 
185
        if msg:
 
186
            self.unpack(msg)
 
187
        else:
 
188
            self.tcm_family = socket.AF_UNSPEC
 
189
            self.tcm_ifindex = 0
 
190
            self.tcm_handle = 0
 
191
            self.tcm_parent = 0
 
192
            self.tcm_info = 0
 
193
 
 
194
            self.rta = ''
 
195
 
 
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:]
 
200
 
 
201
        self.rta = msg[align(self.fmtlen):]
 
202
 
 
203
    def pack(self):
 
204
        return struct.pack(self.fmt, self.tcm_family, self.tcm_ifindex,
 
205
                           self.tcm_handle, self.tcm_parent, self.tcm_info)
 
206
 
 
207
    def __str__(self):
 
208
        return '<tc message, family %d, index %d>' % \
 
209
            (self.tcm_family, self.tcm_ifindex)
 
210
 
 
211
class newlinkmsg(object):
 
212
    def __init__(self, nlmsg):
 
213
        if nlmsg.nlmsg_type != RTM_NEWLINK:
 
214
            raise RTNLException("wrong message type")
 
215
        self.nlmsg = nlmsg
 
216
        self.ifi = ifinfomsg(self.nlmsg.body)
 
217
 
 
218
        self.rtattrs = {}
 
219
        for rta in rtattrlist(self.ifi.body):
 
220
            self.rtattrs[rta.rta_type] = rta.body
 
221
 
 
222
class newqdiscmsg(object):
 
223
    def __init__(self, nlmsg):
 
224
        if nlmsg.nlmsg_type != RTM_NEWQDISC:
 
225
            raise RTNLException("wrong message type")
 
226
        self.nlmsg = nlmsg
 
227
        self.t = tcmsg(self.nlmsg.body)
 
228
 
 
229
        self.rtattrs = {}
 
230
        for rta in rtattrlist(self.t.rta):
 
231
            self.rtattrs[rta.rta_type] = rta.body
 
232
 
 
233
class rtnl(object):
 
234
    def __init__(self):
 
235
        self._rth = xen.lowlevel.netlink.rtnl()
 
236
        self._linkcache = None
 
237
 
 
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."""
 
241
        if not cached:
 
242
            self._linkcache = None
 
243
        if self._linkcache is None:
 
244
            self._linkcache = self.getlinks()
 
245
 
 
246
        if isinstance(key, int):
 
247
            return self._linkcache.get(key)
 
248
 
 
249
        for k, v in self._linkcache.iteritems():
 
250
            if v['name'] == key:
 
251
                return v
 
252
 
 
253
        return None
 
254
 
 
255
    def getlinks(self):
 
256
        """returns a dictionary of interfaces keyed by kernel
 
257
        interface index"""
 
258
        links = {}
 
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)
 
264
 
 
265
            link = {'index': idx,
 
266
                    'type': msg.ifi.ifi_type,
 
267
                    'name': ifname,
 
268
                    'address': address}
 
269
            links[idx] = link
 
270
 
 
271
        self._rth.wilddump_request(socket.AF_UNSPEC, RTM_GETLINK)
 
272
        self._rth.dump_filter(dumpfilter)
 
273
 
 
274
        return links
 
275
 
 
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)
 
280
        if qdiscs:
 
281
            return qdiscs.values()[0]
 
282
        return None
 
283
 
 
284
    def getqdiscs(self, dev=None):
 
285
        """returns a dictionary of queueing disciplines keyed by kernel
 
286
        interface index"""
 
287
        qdiscs = {}
 
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)
 
294
 
 
295
            qdisc = {'index': idx,
 
296
                     'handle': handle,
 
297
                     'kind': kind,
 
298
                     'options': opts}
 
299
            qdiscs[idx] = qdisc
 
300
 
 
301
        tcm = tcmsg()
 
302
        if dev:
 
303
            link = self.getlink(dev)
 
304
            if not link:
 
305
                raise QdiscException('device %s not found' % dev)
 
306
            tcm.tcm_ifindex = link['index']
 
307
 
 
308
        msg = tcm.pack()
 
309
        self._rth.dump_request(RTM_GETQDISC, msg)
 
310
        self._rth.dump_filter(dumpfilter)
 
311
        return qdiscs
 
312
 
 
313
    def talk(self, req):
 
314
        self._rth.talk(req)