]> git.proxmox.com Git - mirror_ifupdown2.git/blame - nlmanager/nlpacket.py
Remove dependancy on tabulate
[mirror_ifupdown2.git] / nlmanager / nlpacket.py
CommitLineData
198ded6a
JF
1# Copyright (c) 2009-2013, Exa Networks Limited
2# Copyright (c) 2009-2013, Thomas Mangin
3# Copyright (c) 2015 Cumulus Networks, Inc.
4#
5# All rights reserved.
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9# Redistributions of source code must retain the above copyright notice, this
10# list of conditions and the following disclaimer.
11#
12# Redistributions in binary form must reproduce the above copyright notice,
13# this list of conditions and the following disclaimer in the documentation
14# and/or other materials provided with the distribution.
15#
16# The names of the Exa Networks Limited, Cumulus Networks, Inc. nor the names
17# of its contributors may be used to endorse or promote products derived from
18# this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31import logging
32import struct
33from ipaddr import IPv4Address, IPv6Address
34from binascii import hexlify
35from pprint import pformat
36from socket import AF_INET, AF_INET6, AF_BRIDGE
37from string import printable
38from struct import pack, unpack, calcsize
39
40log = logging.getLogger(__name__)
41
42# Netlink message types
43NLMSG_NOOP = 0x01
44NLMSG_ERROR = 0x02
45NLMSG_DONE = 0x03
46NLMSG_OVERRUN = 0x04
47
48RTM_NEWLINK = 0x10 # Create a new network interface
49RTM_DELLINK = 0x11 # Destroy a network interface
50RTM_GETLINK = 0x12 # Retrieve information about a network interface(ifinfomsg)
51RTM_SETLINK = 0x13 #
52
53RTM_NEWADDR = 0x14
54RTM_DELADDR = 0x15
55RTM_GETADDR = 0x16
56
57RTM_NEWNEIGH = 0x1C
58RTM_DELNEIGH = 0x1D
59RTM_GETNEIGH = 0x1E
60
61RTM_NEWROUTE = 0x18
62RTM_DELROUTE = 0x19
63RTM_GETROUTE = 0x1A
64
65RTM_NEWQDISC = 0x24
66RTM_DELQDISC = 0x25
67RTM_GETQDISC = 0x26
68
69# Netlink message flags
70NLM_F_REQUEST = 0x01 # It is query message.
71NLM_F_MULTI = 0x02 # Multipart message, terminated by NLMSG_DONE
72NLM_F_ACK = 0x04 # Reply with ack, with zero or error code
73NLM_F_ECHO = 0x08 # Echo this query
74
75# Modifiers to GET query
76NLM_F_ROOT = 0x100 # specify tree root
77NLM_F_MATCH = 0x200 # return all matching
78NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
79NLM_F_ATOMIC = 0x400 # atomic GET
80
81# Modifiers to NEW query
82NLM_F_REPLACE = 0x100 # Override existing
83NLM_F_EXCL = 0x200 # Do not touch, if it exists
84NLM_F_CREATE = 0x400 # Create, if it does not exist
85NLM_F_APPEND = 0x800 # Add to end of list
86
87NLA_F_NESTED = 0x8000
88NLA_F_NET_BYTEORDER = 0x4000
89NLA_TYPE_MASK = ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
90
91# Groups
92RTMGRP_LINK = 0x1
93RTMGRP_NOTIFY = 0x2
94RTMGRP_NEIGH = 0x4
95RTMGRP_TC = 0x8
96RTMGRP_IPV4_IFADDR = 0x10
97RTMGRP_IPV4_MROUTE = 0x20
98RTMGRP_IPV4_ROUTE = 0x40
99RTMGRP_IPV4_RULE = 0x80
100RTMGRP_IPV6_IFADDR = 0x100
101RTMGRP_IPV6_MROUTE = 0x200
102RTMGRP_IPV6_ROUTE = 0x400
103RTMGRP_IPV6_IFINFO = 0x800
104RTMGRP_DECnet_IFADDR = 0x1000
105RTMGRP_DECnet_ROUTE = 0x4000
106RTMGRP_IPV6_PREFIX = 0x20000
107
108RTMGRP_ALL = (RTMGRP_LINK | RTMGRP_NOTIFY | RTMGRP_NEIGH | RTMGRP_TC |
109 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_MROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE |
110 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO |
111 RTMGRP_DECnet_IFADDR | RTMGRP_DECnet_ROUTE |
112 RTMGRP_IPV6_PREFIX)
113
114# Colors for logging
115red = 91
116green = 92
117yellow = 93
118blue = 94
119
120
121def zfilled_hex(value, digits):
122 return '0x' + hex(value)[2:].zfill(digits)
123
124
125def remove_trailing_null(line):
126 """
127 Remove the last character if it is a NULL...having that NULL
128 causes python to print a garbage character
129 """
130
131 if ord(line[-1]) == 0:
132 line = line[:-1]
133
134 return line
135
136
137def mac_int_to_str(mac_int):
138 """
139 Return an integer in MAC string format
140 """
141
142 # [2:] to remove the leading 0x, then fill out to 12 zeroes, then uppercase
143 all_caps = hex(int(mac_int))[2:].zfill(12).upper()
144
145 if all_caps[-1] == 'L':
146 all_caps = all_caps[:-1]
147 all_caps = all_caps.zfill(12).upper()
148
149 return "%s.%s.%s" % (all_caps[0:4], all_caps[4:8], all_caps[8:12])
150
151
152def data_to_color_text(line_number, color, data, extra=''):
153 (c1, c2, c3, c4) = unpack('BBBB', data[0:4])
154 in_ascii = []
155
156 for c in (c1, c2, c3, c4):
157 char_c = chr(c)
158
159 if char_c in printable[:-5]:
160 in_ascii.append(char_c)
161 else:
162 in_ascii.append('.')
163
164 return ' %2d: \033[%dm0x%02x%02x%02x%02x\033[0m %s %s' % (line_number, color, c1, c2, c3, c4, ''.join(in_ascii), extra)
165
166
167def padded_length(length):
168 return int((length + 3) / 4) * 4
169
170
171class Attribute(object):
172
173 def __init__(self, atype, string, logger):
174 self.atype = atype
175 self.string = string
176 self.HEADER_PACK = '=HH'
177 self.HEADER_LEN = calcsize(self.HEADER_PACK)
178 self.PACK = None
179 self.LEN = None
180 self.value = None
181 self.nested = False
182 self.net_byteorder = False
183 self.log = logger
184
185 def __str__(self):
186 return self.string
187
188 def pad_bytes_needed(self, length):
189 """
190 Return the number of bytes that should be added to align on a 4-byte boundry
191 """
192 remainder = length % 4
193
194 if remainder:
195 return 4 - remainder
196
197 return 0
198
199 def pad(self, length, raw):
200 pad = self.pad_bytes_needed(length)
201
202 if pad:
203 raw += '\0' * pad
204
205 return raw
206
207 def encode(self):
208 length = self.HEADER_LEN + self.LEN
209 attr_type_with_flags = self.atype
210
211 if self.nested:
212 attr_type_with_flags = attr_type_with_flags | NLA_F_NESTED
213
214 if self.net_byteorder:
215 attr_type_with_flags = attr_type_with_flags | NLA_F_NET_BYTEORDER
216
217 raw = pack(self.HEADER_PACK, length, attr_type_with_flags) + pack(self.PACK, self.value)
218 raw = self.pad(length, raw)
219 return raw
220
221 def decode_length_type(self, data):
222 """
223 The first two bytes of an attribute are the length, the next two bytes are the type
224 """
225 self.data = data
226 prev_atype = self.atype
227 (data1, data2) = unpack(self.HEADER_PACK, data[:self.HEADER_LEN])
228 self.length = int(data1)
229 self.atype = int(data2)
230 self.attr_end = padded_length(self.length)
231
232 self.nested = True if self.atype & NLA_F_NESTED else False
233 self.net_byteorder = True if self.atype & NLA_F_NET_BYTEORDER else False
234 self.atype = self.atype & NLA_TYPE_MASK
235
236 # Should never happen
237 assert self.atype == prev_atype, "This object changes attribute type from %d to %d, this is bad" % (prev_atype, self.atype)
238
239 def dump_first_line(self, dump_buffer, line_number, color):
240 """
241 Add the "Length....Type..." line to the dump buffer
242 """
243 if self.attr_end == self.length:
244 padded_to = ', '
245 else:
246 padded_to = ' padded to %d, ' % self.attr_end
247
248 extra = 'Length %s (%d)%sType %s%s%s (%d) %s' % \
249 (zfilled_hex(self.length, 4), self.length,
250 padded_to,
251 zfilled_hex(self.atype, 4),
252 " (NLA_F_NESTED set)" if self.nested else "",
253 " (NLA_F_NET_BYTEORDER set)" if self.net_byteorder else "",
254 self.atype,
255 self)
256
257 dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], extra))
258 return line_number + 1
259
260 def dump_lines(self, dump_buffer, line_number, color):
261 line_number = self.dump_first_line(dump_buffer, line_number, color)
262
263 for x in xrange(1, self.attr_end/4):
264 start = x * 4
265 end = start + 4
266 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], ''))
267 line_number += 1
268
269 return line_number
270
271 def get_pretty_value(self):
272 return self.value
273
274
275class AttributeFourByteValue(Attribute):
276
277 def __init__(self, atype, string, logger):
278 Attribute.__init__(self, atype, string, logger)
279 self.PACK = '=L'
280 self.LEN = calcsize(self.PACK)
281
282 def decode(self, parent_msg, data):
283 self.decode_length_type(data)
284 assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
285
286 try:
287 self.value = int(unpack(self.PACK, self.data[4:])[0])
288 except struct.error:
289 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
290 raise
291
292 def dump_lines(self, dump_buffer, line_number, color):
293 line_number = self.dump_first_line(dump_buffer, line_number, color)
294 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
295 return line_number + 1
296
297
298class AttributeString(Attribute):
299
300 def __init__(self, atype, string, logger):
301 Attribute.__init__(self, atype, string, logger)
302 self.PACK = None
303 self.LEN = None
304
305 def encode(self):
306 # some interface names come from JSON unicode strings
307 # and cannot be packed as is so we must convert them to strings
308 if isinstance(self.value, unicode):
309 self.value = str(self.value)
310 self.PACK = '%ds' % len(self.value)
311 self.LEN = calcsize(self.PACK)
312
313 length = self.HEADER_LEN + self.LEN
314 raw = pack(self.HEADER_PACK, length, self.atype) + pack(self.PACK, self.value)
315 raw = self.pad(length, raw)
316 return raw
317
318 def decode(self, parent_msg, data):
319 self.decode_length_type(data)
320 self.PACK = '%ds' % (self.length - 4)
321 self.LEN = calcsize(self.PACK)
322
323 try:
324 self.value = remove_trailing_null(unpack(self.PACK, self.data[4:self.length])[0])
325 except struct.error:
326 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:self.length])))
327 raise
328
329
330class AttributeIPAddress(Attribute):
331
332 def __init__(self, atype, string, family, logger):
333 Attribute.__init__(self, atype, string, logger)
334 self.value_int = None
335 self.value_int_str = None
336 self.family = family
337
338 if self.family == AF_INET:
339 self.PACK = '>L'
340
341 elif self.family == AF_INET6:
342 self.PACK = '>QQ'
343
344 elif self.family == AF_BRIDGE:
345 self.PACK = '>L'
346
347 else:
348 raise Exception("%s is not a supported address family" % self.family)
349
350 self.LEN = calcsize(self.PACK)
351
352 def decode(self, parent_msg, data):
353 self.decode_length_type(data)
354
355 try:
356 if self.family == AF_INET:
357 self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0])
358
359 elif self.family == AF_INET6:
360 (data1, data2) = unpack(self.PACK, self.data[4:])
361 self.value = IPv6Address(data1 << 64 | data2)
362
363 elif self.family == AF_BRIDGE:
364 self.value = unpack(self.PACK, self.data[4:])[0]
365
366 self.value_int = int(self.value)
367 self.value_int_str = str(self.value_int)
368
369 except struct.error:
370 self.value = None
371 self.value_int = None
372 self.value_int_str = None
373 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
374 raise
375
376 def dump_lines(self, dump_buffer, line_number, color):
377 line_number = self.dump_first_line(dump_buffer, line_number, color)
378
379 if self.family == AF_INET:
380 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
381 line_number += 1
382
383 elif self.family == AF_INET6:
384
385 for x in xrange(1, self.attr_end/4):
386 start = x * 4
387 end = start + 4
388 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], self.value))
389 line_number += 1
390
391 elif self.family == AF_BRIDGE:
392 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
393 line_number += 1
394
395 return line_number
396
397
398class AttributeMACAddress(Attribute):
399
400 def __init__(self, atype, string, logger):
401 Attribute.__init__(self, atype, string, logger)
402 self.PACK = '>LHxx'
403 self.LEN = calcsize(self.PACK)
404
405 def decode(self, parent_msg, data):
406 self.decode_length_type(data)
407
408 try:
409 (data1, data2) = unpack(self.PACK, self.data[4:])
410 self.value = mac_int_to_str(data1 << 16 | data2)
411
412 except struct.error:
413 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
414 raise
415
416 def encode(self):
417 length = self.HEADER_LEN + self.LEN
418 mac_raw = int(self.value.replace('.', '').replace(':', ''), 16)
419 raw = pack(self.HEADER_PACK, length, self.atype) + pack(self.PACK, mac_raw >> 16, mac_raw & 0x0000FF)
420 raw = self.pad(length, raw)
421 return raw
422
423 def dump_lines(self, dump_buffer, line_number, color):
424 line_number = self.dump_first_line(dump_buffer, line_number, color)
425 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
426 dump_buffer.append(data_to_color_text(line_number, color, self.data[8:12], self.value))
427 return line_number + 1
428
429
430class AttributeGeneric(Attribute):
431
432 def __init__(self, atype, string, logger):
433 Attribute.__init__(self, atype, string, logger)
434 self.PACK = None
435 self.LEN = None
436
437 def decode(self, parent_msg, data):
438 self.decode_length_type(data)
439 wordcount = (self.attr_end - 4)/4
440 self.PACK = '=%dL' % wordcount
441 self.LEN = calcsize(self.PACK)
442
443 try:
444 self.value = ''.join(map(str, unpack(self.PACK, self.data[4:])))
445 except struct.error:
446 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
447 raise
448
449
450class AttributeIFLA_AF_SPEC(Attribute):
451 """
452 value will be a dictionary such as:
453 {
454 Link.IFLA_BRIDGE_FLAGS: flags,
455 Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid)
456 }
457 """
458
459 def encode(self):
460 pack_layout = [self.HEADER_PACK]
461 payload = [0, self.atype]
462 attr_length_index = 0
463
464 # For now this assumes that all data will be packed in the native endian
465 # order (=). If a field is added that needs to be packed via network
466 # order (>) then some smarts will need to be added to split the pack_layout
467 # string at the >, split the payload and make the needed pack() calls.
468 #
469 # Until we cross that bridge though we will keep things nice and simple and
470 # pack everything via a single pack() call.
471 for (sub_attr_type, sub_attr_value) in self.value.iteritems():
472 sub_attr_pack_layout = ['=', 'HH']
473 sub_attr_payload = [0, sub_attr_type]
474 sub_attr_length_index = 0
475
476 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
477 sub_attr_pack_layout.append('H')
478 sub_attr_payload.append(sub_attr_value)
479
480 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
481 sub_attr_pack_layout.append('HH')
482 sub_attr_payload.append(sub_attr_value[0])
483 sub_attr_payload.append(sub_attr_value[1])
484
485 else:
486 self.log.debug('Add support for encoding IFLA_AF_SPEC sub-attribute type %d' % sub_attr_type)
487 continue
488
489 sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
490 sub_attr_payload[sub_attr_length_index] = sub_attr_length
491
492 # add padding
493 for x in xrange(self.pad_bytes_needed(sub_attr_length)):
494 sub_attr_pack_layout.append('x')
495
496 # The [1:] is to remove the leading = so that when we do the ''.join() later
497 # we do not end up with an = in the middle of the pack layout string. There
498 # will be an = at the beginning via self.HEADER_PACK
499 sub_attr_pack_layout = sub_attr_pack_layout[1:]
500
501 # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
502 pack_layout.extend(sub_attr_pack_layout)
503 payload.extend(sub_attr_payload)
504
505 pack_layout = ''.join(pack_layout)
506
507 # Fill in the length field
508 length = calcsize(pack_layout)
509 payload[attr_length_index] = length
510
511 raw = pack(pack_layout, *payload)
512 raw = self.pad(length, raw)
513 return raw
514
515 def decode(self, parent_msg, data):
516 """
517 value is a dictionary such as:
518 {
519 Link.IFLA_BRIDGE_FLAGS: flags,
520 Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid)
521 }
522 """
523 self.decode_length_type(data)
524 self.value = {}
525
526 data = self.data[4:]
527
528 while data:
529 (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
530 sub_attr_end = padded_length(sub_attr_length)
531
532 if not sub_attr_length:
533 self.log.error('parsed a zero length sub-attr')
534 return
535
536 sub_attr_data = data[4:sub_attr_end]
537
538 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
539 self.value[Link.IFLA_BRIDGE_FLAGS] = unpack("=H", sub_attr_data[0:2])[0]
540
541 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
542 self.value[Link.IFLA_INFO_DATA] = tuple(unpack("=HH", sub_attr_data[0:4]))
543
544 else:
545 self.log.debug('Add support for decoding IFLA_AF_SPEC sub-attribute type %s (%d), length %d, padded to %d' %
546 (parent_msg.get_ifla_bridge_af_spec_to_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end))
547
548 data = data[sub_attr_end:]
549
550 def dump_lines(self, dump_buffer, line_number, color):
551 line_number = self.dump_first_line(dump_buffer, line_number, color)
552 extra = ''
553
554 next_sub_attr_line = 0
555 sub_attr_line = True
556
557 for x in xrange(1, self.attr_end/4):
558 start = x * 4
559 end = start + 4
560
561 if line_number == next_sub_attr_line:
562 sub_attr_line = True
563
564 if sub_attr_line:
565 sub_attr_line = False
566
567 (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4])
568 sub_attr_end = padded_length(sub_attr_length)
569
570 next_sub_attr_line = line_number + (sub_attr_end/4)
571
572 if sub_attr_end == sub_attr_length:
573 padded_to = ', '
574 else:
575 padded_to = ' padded to %d, ' % sub_attr_end
576
577 extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
578 (zfilled_hex(sub_attr_length, 4), sub_attr_length,
579 padded_to,
580 zfilled_hex(sub_attr_type, 4), sub_attr_type,
581 Link.ifla_bridge_af_spec_to_string.get(sub_attr_type))
582 else:
583 extra = ''
584
585 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra))
586 line_number += 1
587
588 return line_number
589
590 def get_pretty_value(self):
591 # We do this so we can print a more human readable dictionary
592 # with the names of the nested keys instead of their numbers
593 value_pretty = {}
594
595 for (sub_key, sub_value) in self.value.iteritems():
596 sub_key_pretty = "(%2d) % s" % (sub_key, Link.ifla_bridge_af_spec_to_string.get(sub_key))
597 value_pretty[sub_key_pretty] = sub_value
598
599 return value_pretty
600
601
602
603class AttributeRTA_MULTIPATH(Attribute):
604 """
605/* RTA_MULTIPATH --- array of struct rtnexthop.
606 *
607 * "struct rtnexthop" describes all necessary nexthop information,
608 * i.e. parameters of path to a destination via this nexthop.
609 *
610 * At the moment it is impossible to set different prefsrc, mtu, window
611 * and rtt for different paths from multipath.
612 */
613
614struct rtnexthop {
615 unsigned short rtnh_len;
616 unsigned char rtnh_flags;
617 unsigned char rtnh_hops;
618 int rtnh_ifindex;
619};
620 """
621
622 def __init__(self, atype, string, family, logger):
623 Attribute.__init__(self, atype, string, logger)
624 self.family = family
625 self.PACK = None
626 self.LEN = None
627 self.RTNH_PACK = '=HBBL' # rtnh_len, flags, hops, ifindex
628 self.RTNH_LEN = calcsize(self.RTNH_PACK)
629 self.IPV4_LEN = 4
630 self.IPV6_LEN = 16
631
632 def encode(self):
633
634 # Calculate the length
635 if self.family == AF_INET:
636 ip_len = self.IPV4_LEN
637 elif self.family == AF_INET6:
638 ip_len = self.IPV6_LEN
639
640 # Attribute header
641 length = self.HEADER_LEN + ((self.RTNH_LEN + self.HEADER_LEN + ip_len) * len(self.value))
642 raw = pack(self.HEADER_PACK, length, self.atype)
643
644 rtnh_flags = 0
645 rtnh_hops = 0
646 rtnh_len = self.RTNH_LEN + self.HEADER_LEN + ip_len
647
648 for (nexthop, rtnh_ifindex) in self.value:
649
650 # rtnh structure
651 raw += pack(self.RTNH_PACK, rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex)
652
653 # Gateway
654 raw += pack(self.HEADER_PACK, self.HEADER_LEN + ip_len, Route.RTA_GATEWAY)
655
656 if self.family == AF_INET:
657 raw += pack('>L', nexthop)
658 elif self.family == AF_INET6:
659 raw += pack('>QQ', nexthop >> 64, nexthop & 0x0000000000000000FFFFFFFFFFFFFFFF)
660
661 raw = self.pad(length, raw)
662 return raw
663
664 def decode(self, parent_msg, data):
665 self.decode_length_type(data)
666 self.value = []
667
668 data = self.data[4:]
669
670 while data:
671 (rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex) = unpack(self.RTNH_PACK, data[:self.RTNH_LEN])
672 data = data[self.RTNH_LEN:]
673
674 (attr_type, attr_length) = unpack(self.HEADER_PACK, self.data[:self.HEADER_LEN])
675 data = data[self.HEADER_LEN:]
676
677 if self.family == AF_INET:
678 nexthop = IPv4Address(unpack('>L', data[:self.IPV4_LEN])[0])
679 self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops))
680 data = data[self.IPV4_LEN:]
681
682 elif self.family == AF_INET6:
683 (data1, data2) = unpack('>QQ', data[:self.IPV6_LEN])
684 nexthop = IPv6Address(data1 << 64 | data2)
685 self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops))
686 data = data[self.IPV6_LEN:]
687
688 self.value = tuple(self.value)
689
690
691class AttributeIFLA_LINKINFO(Attribute):
692 """
693 value is a dictionary such as:
694
695 {
696 Link.IFLA_INFO_KIND : 'vlan',
697 Link.IFLA_INFO_DATA : {
698 Link.IFLA_VLAN_ID : vlanid,
699 }
700 }
701 """
702 def encode(self):
703 pack_layout = [self.HEADER_PACK]
704 payload = [0, self.atype]
705 attr_length_index = 0
706
707 kind = self.value[Link.IFLA_INFO_KIND]
708
709 if kind not in ('vlan', 'macvlan'):
710 raise Exception('Unsupported IFLA_INFO_KIND %s' % kind)
711
712 # For now this assumes that all data will be packed in the native endian
713 # order (=). If a field is added that needs to be packed via network
714 # order (>) then some smarts will need to be added to split the pack_layout
715 # string at the >, split the payload and make the needed pack() calls.
716 #
717 # Until we cross that bridge though we will keep things nice and simple and
718 # pack everything via a single pack() call.
719 for (sub_attr_type, sub_attr_value) in self.value.iteritems():
720 sub_attr_pack_layout = ['=', 'HH']
721 sub_attr_payload = [0, sub_attr_type]
722 sub_attr_length_index = 0
723
724 if sub_attr_type == Link.IFLA_INFO_KIND:
725 sub_attr_pack_layout.append('%ds' % len(sub_attr_value))
726 sub_attr_payload.append(sub_attr_value)
727
728 elif sub_attr_type == Link.IFLA_INFO_DATA:
729
730 for (info_data_type, info_data_value) in sub_attr_value.iteritems():
731
732 if kind == 'vlan':
733 if info_data_type == Link.IFLA_VLAN_ID:
734 sub_attr_pack_layout.append('HH')
735 sub_attr_payload.append(6) # length
736 sub_attr_payload.append(info_data_type)
737
738 # The vlan-id
739 sub_attr_pack_layout.append('H')
740 sub_attr_payload.append(info_data_value)
741
742 # pad 2 bytes
743 sub_attr_pack_layout.extend('xx')
744
745 else:
746 self.log.debug('Add support for encoding IFLA_INFO_DATA vlan sub-attribute type %d' % info_data_type)
747
748 elif kind == 'macvlan':
749 if info_data_type == Link.IFLA_MACVLAN_MODE:
750 sub_attr_pack_layout.append('HH')
751 sub_attr_payload.append(8) # length
752 sub_attr_payload.append(info_data_type)
753
754 # macvlan mode
755 sub_attr_pack_layout.append('L')
756 sub_attr_payload.append(info_data_value)
757
758 else:
759 self.log.debug('Add support for encoding IFLA_INFO_DATA macvlan sub-attribute type %d' % info_data_type)
760
761 else:
762 self.log.debug('Add support for encoding IFLA_LINKINFO sub-attribute type %d' % sub_attr_type)
763 continue
764
765 sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
766 sub_attr_payload[sub_attr_length_index] = sub_attr_length
767
768 # add padding
769 for x in xrange(self.pad_bytes_needed(sub_attr_length)):
770 sub_attr_pack_layout.append('x')
771
772 # The [1:] is to remove the leading = so that when we do the ''.join() later
773 # we do not end up with an = in the middle of the pack layout string. There
774 # will be an = at the beginning via self.HEADER_PACK
775 sub_attr_pack_layout = sub_attr_pack_layout[1:]
776
777 # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
778 pack_layout.extend(sub_attr_pack_layout)
779 payload.extend(sub_attr_payload)
780
781 pack_layout = ''.join(pack_layout)
782
783 # Fill in the length field
784 length = calcsize(pack_layout)
785 payload[attr_length_index] = length
786
787 raw = pack(pack_layout, *payload)
788 raw = self.pad(length, raw)
789 return raw
790
791 def decode(self, parent_msg, data):
792 """
793 value is a dictionary such as:
794
795 {
796 Link.IFLA_INFO_KIND : 'vlan',
797 Link.IFLA_INFO_DATA : {
798 Link.IFLA_VLAN_ID : vlanid,
799 }
800 }
801 """
802 self.decode_length_type(data)
803 self.value = {}
804
805 data = self.data[4:]
806
807 # IFLA_MACVLAN_MODE and IFLA_VLAN_ID both have a value of 1 and both are
808 # valid IFLA_INFO_DATA entries :( The sender must TX IFLA_INFO_KIND
809 # first in order for us to know if "1" is IFLA_MACVLAN_MODE vs IFLA_VLAN_ID.
810 while data:
811 (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
812 sub_attr_end = padded_length(sub_attr_length)
813
814 if not sub_attr_length:
815 self.log.error('parsed a zero length sub-attr')
816 return
817
818 if sub_attr_type == Link.IFLA_INFO_KIND:
819 self.value[Link.IFLA_INFO_KIND] = remove_trailing_null(unpack('%ds' % (sub_attr_length - 4), data[4:sub_attr_length])[0])
820
821 elif sub_attr_type == Link.IFLA_INFO_DATA:
822
823 sub_attr_data = data[4:sub_attr_end]
824 self.value[Link.IFLA_INFO_DATA] = {}
825
826 while sub_attr_data:
827 (info_data_length, info_data_type) = unpack('=HH', sub_attr_data[:4])
828 info_data_end = padded_length(info_data_length)
829 # self.log.info('sub attr length %d, end %d, type %d' % (info_data_length, info_data_end, info_data_type))
830
831 if not sub_attr_data:
832 self.log.error('RXed zero length sub-attribute')
833 break
834
835 if Link.IFLA_INFO_KIND not in self.value:
836 self.log.warning('IFLA_INFO_KIND is not known...we cannot parse IFLA_INFO_DATA')
837
838 elif self.value[Link.IFLA_INFO_KIND] == 'vlan':
839 if info_data_type == Link.IFLA_VLAN_ID:
840 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
841 else:
842 self.log.debug('Add support for decoding IFLA_INFO_KIND vlan type %s (%d), length %d, padded to %d' %
843 (parent_msg.get_ifla_vlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
844
845 elif self.value[Link.IFLA_INFO_KIND] == 'macvlan':
846 if info_data_type == Link.IFLA_MACVLAN_MODE:
847 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
848 else:
849 self.log.debug('Add support for decoding IFLA_INFO_KIND macvlan type %s (%d), length %d, padded to %d' %
850 (parent_msg.get_ifla_macvlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
851
852 elif self.value[Link.IFLA_INFO_KIND] == 'vxlan':
853
854 # IPv4Address
855 if info_data_type in (Link.IFLA_VXLAN_GROUP,
856 Link.IFLA_VXLAN_LOCAL):
857 self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack('>L', sub_attr_data[4:8])[0])
858
859 # 4-byte int
860 elif info_data_type in (Link.IFLA_VXLAN_ID,
861 Link.IFLA_VXLAN_LINK,
862 Link.IFLA_VXLAN_AGEING,
863 Link.IFLA_VXLAN_LIMIT,
864 Link.IFLA_VXLAN_PORT_RANGE):
865 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
866
867 # 2-byte int
868 elif info_data_type in (Link.IFLA_VXLAN_PORT, ):
869 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
870
871 # 1-byte int
872 elif info_data_type in (Link.IFLA_VXLAN_TTL,
873 Link.IFLA_VXLAN_TOS,
874 Link.IFLA_VXLAN_LEARNING,
875 Link.IFLA_VXLAN_PROXY,
876 Link.IFLA_VXLAN_RSC,
877 Link.IFLA_VXLAN_L2MISS,
878 Link.IFLA_VXLAN_L3MISS,
879 Link.IFLA_VXLAN_UDP_CSUM,
880 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
881 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
882 Link.IFLA_VXLAN_REMCSUM_TX,
883 Link.IFLA_VXLAN_REMCSUM_RX,
884 Link.IFLA_VXLAN_REPLICATION_TYPE):
885 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
886
887 else:
888 # sub_attr_end = padded_length(sub_attr_length)
889 self.log.debug('Add support for decoding IFLA_INFO_KIND vxlan type %s (%d), length %d, padded to %d' %
890 (parent_msg.get_ifla_vxlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
891
892 elif self.value[Link.IFLA_INFO_KIND] == 'bond':
893 self.log.debug('Add support for decoding IFLA_INFO_KIND bond type %s (%d), length %d, padded to %d' %
894 (parent_msg.get_ifla_bond_string(info_data_type), info_data_type, info_data_length, info_data_end))
895
896 elif self.value[Link.IFLA_INFO_KIND] == 'bridge':
897
898 if info_data_type in (Link.IFLA_BRPORT_STATE,
899 Link.IFLA_BRPORT_PRIORITY,
900 Link.IFLA_BRPORT_COST):
901 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
902
903 elif info_data_type in (Link.IFLA_BRPORT_FAST_LEAVE, ):
904 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
905
906 else:
907 self.log.debug('Add support for decoding IFLA_INFO_KIND bridge type %s (%d), length %d, padded to %d' %
908 (parent_msg.get_ifla_bridge_string(info_data_type), info_data_type, info_data_length, info_data_end))
909
910 else:
911 self.log.debug("Add support for decoding IFLA_INFO_KIND %s (%d), length %d, padded to %d" %
912 (self.value[Link.IFLA_INFO_KIND], info_data_type, info_data_length, info_data_end))
913
914 sub_attr_data = sub_attr_data[info_data_end:]
915
916 elif sub_attr_type == Link.IFLA_INFO_SLAVE_KIND:
917 self.value[Link.IFLA_INFO_SLAVE_KIND] = remove_trailing_null(unpack('%ds' % (sub_attr_length - 4), data[4:sub_attr_length])[0])
918
919 else:
920 self.log.debug('Add support for decoding IFLA_LINKINFO sub-attribute type %s (%d), length %d, padded to %d' %
921 (parent_msg.get_ifla_info_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end))
922
923 data = data[sub_attr_end:]
924
925 # self.log.info('IFLA_LINKINFO values %s' % pformat(self.value))
926
927 def dump_lines(self, dump_buffer, line_number, color):
928 line_number = self.dump_first_line(dump_buffer, line_number, color)
929 extra = ''
930
931 next_sub_attr_line = 0
932 sub_attr_line = True
933
934 for x in xrange(1, self.attr_end/4):
935 start = x * 4
936 end = start + 4
937
938 if line_number == next_sub_attr_line:
939 sub_attr_line = True
940
941 if sub_attr_line:
942 sub_attr_line = False
943
944 (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4])
945 sub_attr_end = padded_length(sub_attr_length)
946
947 next_sub_attr_line = line_number + (sub_attr_end/4)
948
949 if sub_attr_end == sub_attr_length:
950 padded_to = ', '
951 else:
952 padded_to = ' padded to %d, ' % sub_attr_end
953
954 extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
955 (zfilled_hex(sub_attr_length, 4), sub_attr_length,
956 padded_to,
957 zfilled_hex(sub_attr_type, 4), sub_attr_type,
958 Link.ifla_info_to_string.get(sub_attr_type))
959 else:
960 extra = ''
961
962 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra))
963 line_number += 1
964
965 return line_number
966
967 def get_pretty_value(self):
968 value_pretty = self.value
969 ifla_info_kind = self.value.get(Link.IFLA_INFO_KIND)
970
971 # We do this so we can print a more human readable dictionary
972 # with the names of the nested keys instead of their numbers
973
974 # Most of these are placeholders...we need to add support
975 # for more human readable dictionaries for bond, bridge, etc
976 if ifla_info_kind == 'bond':
977 pass
978
979 elif ifla_info_kind == 'bridge':
980 pass
981
982 elif ifla_info_kind == 'macvlan':
983 pass
984
985 elif ifla_info_kind == 'vlan':
986 pass
987
988 elif ifla_info_kind == 'vxlan':
989 value_pretty = {}
990
991 for (sub_key, sub_value) in self.value.iteritems():
992 sub_key_pretty = "(%2d) % s" % (sub_key, Link.ifla_info_to_string[sub_key])
993 sub_value_pretty = sub_value
994
995 if sub_key == Link.IFLA_INFO_DATA:
996 sub_value_pretty = {}
997
998 for (sub_sub_key, sub_sub_value) in sub_value.iteritems():
999 sub_sub_key_pretty = "(%2d) %s" % (sub_sub_key, Link.ifla_vxlan_to_string[sub_sub_key])
1000 sub_value_pretty[sub_sub_key_pretty] = sub_sub_value
1001
1002 value_pretty[sub_key_pretty] = sub_value_pretty
1003
1004 return value_pretty
1005
1006
1007class NetlinkPacket(object):
1008 """
1009 Netlink Header
1010
1011 0 1 2 3
1012 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1013 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1014 | Length |
1015 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1016 | Type | Flags |
1017 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1018 | Sequence Number |
1019 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1020 | Process ID (PID) |
1021 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1022 """
1023
1024 header_PACK = 'IHHII'
1025 header_LEN = calcsize(header_PACK)
1026
1027 # Netlink packet types
1028 # /usr/include/linux/rtnetlink.h
1029 type_to_string = {
1030 NLMSG_NOOP : 'NLMSG_NOOP',
1031 NLMSG_ERROR : 'NLMSG_ERROR',
1032 NLMSG_DONE : 'NLMSG_DONE',
1033 NLMSG_OVERRUN : 'NLMSG_OVERRUN',
1034 RTM_NEWLINK : 'RTM_NEWLINK',
1035 RTM_DELLINK : 'RTM_DELLINK',
1036 RTM_GETLINK : 'RTM_GETLINK',
1037 RTM_SETLINK : 'RTM_SETLINK',
1038 RTM_NEWADDR : 'RTM_NEWADDR',
1039 RTM_DELADDR : 'RTM_DELADDR',
1040 RTM_GETADDR : 'RTM_GETADDR',
1041 RTM_NEWNEIGH : 'RTM_NEWNEIGH',
1042 RTM_DELNEIGH : 'RTM_DELNEIGH',
1043 RTM_GETNEIGH : 'RTM_GETNEIGH',
1044 RTM_NEWROUTE : 'RTM_NEWROUTE',
1045 RTM_DELROUTE : 'RTM_DELROUTE',
1046 RTM_GETROUTE : 'RTM_GETROUTE',
1047 RTM_NEWQDISC : 'RTM_NEWQDISC',
1048 RTM_DELQDISC : 'RTM_DELQDISC',
1049 RTM_GETQDISC : 'RTM_GETQDISC'
1050 }
1051
1052 def __init__(self, msgtype, debug, owner_logger=None):
1053 self.msgtype = msgtype
1054 self.attributes = {}
1055 self.dump_buffer = ['']
1056 self.line_number = 1
1057 self.debug = debug
1058 self.message = None
1059
1060 if owner_logger:
1061 self.log = owner_logger
1062 else:
1063 self.log = log
1064
1065 def __str__(self):
1066 return self.get_type_string()
1067
1068 def get_string(self, to_string, index):
1069 """
1070 Used to do lookups in all of the various FOO_to_string dictionaries
1071 but returns 'UNKNOWN' if the key is bogus
1072 """
1073 if index in to_string:
1074 return to_string[index]
1075 return 'UNKNOWN'
1076
1077 def get_type_string(self, msgtype=None):
1078 if not msgtype:
1079 msgtype = self.msgtype
1080 return self.get_string(self.type_to_string, msgtype)
1081
1082 def get_flags_string(self):
1083 foo = []
1084
1085 for (flag, flag_string) in self.flag_to_string.iteritems():
1086 if self.flags & flag:
1087 foo.append(flag_string)
1088
1089 return ', '.join(foo)
1090
1091 def decode_packet(self, length, flags, seq, pid, data):
1092 self.length = length
1093 self.flags = flags
1094 self.seq = seq
1095 self.pid = pid
1096 self.header_data = data[0:self.header_LEN]
1097 self.msg_data = data[self.header_LEN:length]
1098
1099 self.decode_netlink_header()
1100 self.decode_service_header()
1101
1102 # NLMSG_ERROR is special case, it does not have attributes to decode
1103 if self.msgtype != NLMSG_ERROR:
1104 self.decode_attributes()
1105
1106 def get_netlink_header_flags_string(self, msg_type, flags):
1107 foo = []
1108
1109 if flags & NLM_F_REQUEST:
1110 foo.append('NLM_F_REQUEST')
1111
1112 if flags & NLM_F_MULTI:
1113 foo.append('NLM_F_MULTI')
1114
1115 if flags & NLM_F_ACK:
1116 foo.append('NLM_F_ACK')
1117
1118 if flags & NLM_F_ECHO:
1119 foo.append('NLM_F_ECHO')
1120
1121 # Modifiers to GET query
1122 if msg_type in (RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH, RTM_GETROUTE, RTM_GETQDISC):
1123 if flags & NLM_F_ROOT:
1124 foo.append('NLM_F_ROOT')
1125
1126 if flags & NLM_F_MATCH:
1127 foo.append('NLM_F_MATCH')
1128
1129 if flags & NLM_F_DUMP:
1130 foo.append('NLM_F_DUMP')
1131
1132 if flags & NLM_F_ATOMIC:
1133 foo.append('NLM_F_ATOMIC')
1134
1135 # Modifiers to NEW query
1136 elif msg_type in (RTM_NEWLINK, RTM_NEWADDR, RTM_NEWNEIGH, RTM_NEWROUTE, RTM_NEWQDISC):
1137 if flags & NLM_F_REPLACE:
1138 foo.append('NLM_F_REPLACE')
1139
1140 if flags & NLM_F_EXCL:
1141 foo.append('NLM_F_EXCL')
1142
1143 if flags & NLM_F_CREATE:
1144 foo.append('NLM_F_CREATE')
1145
1146 if flags & NLM_F_APPEND:
1147 foo.append('NLM_F_APPEND')
1148
1149 return ', '.join(foo)
1150
1151 # When we first RXed the netlink message we had to decode the header to
1152 # determine what type of netlink message we were dealing with. So the
1153 # header has actually already been decoded...what we do here is
1154 # populate the dump_buffer lines with the header content.
1155 def decode_netlink_header(self):
1156
1157 if not self.debug:
1158 return
1159
1160 header_data = self.header_data
1161
1162 # Print the netlink header in red
1163 color = red
1164 netlink_header_length = 16
1165 self.dump_buffer.append(" \033[%dmNetlink Header\033[0m" % color)
1166
1167 for x in range(0, netlink_header_length/4):
1168 start = x * 4
1169 end = start + 4
1170
1171 if self.line_number == 1:
1172 data = unpack('=L', header_data[start:end])[0]
1173 extra = "Length %s (%d)" % (zfilled_hex(data, 8), data)
1174
1175 elif self.line_number == 2:
1176 (data1, data2) = unpack('HH', header_data[start:end])
1177 extra = "Type %s (%d - %s), Flags %s (%s)" % \
1178 (zfilled_hex(data1, 4), data1, self.get_type_string(data1),
1179 zfilled_hex(data2, 4), self.get_netlink_header_flags_string(data1, data2))
1180
1181 elif self.line_number == 3:
1182 data = unpack('=L', header_data[start:end])[0]
1183 extra = "Sequence Number %s (%d)" % (zfilled_hex(data, 8), data)
1184
1185 elif self.line_number == 4:
1186 data = unpack('=L', header_data[start:end])[0]
1187 extra = "Process ID %s (%d)" % (zfilled_hex(data, 8), data)
1188 else:
1189 extra = "Unexpected line number %d" % self.line_number
1190
1191 self.dump_buffer.append(data_to_color_text(self.line_number, color, header_data[start:end], extra))
1192 self.line_number += 1
1193
1194 def decode_attributes(self):
1195 """
1196 Decode the attributes and populate the dump_buffer
1197 """
1198
1199 if self.debug:
1200 self.dump_buffer.append(" Attributes")
1201 color = green
1202
1203 data = self.msg_data[self.LEN:]
1204
1205 while data:
1206 (length, attr_type) = unpack('=HH', data[:4])
1207
1208 # If this is zero we will stay in this loop for forever
1209 if not length:
1210 self.log.error('Length is zero')
1211 return
1212
1213 if len(data) < length:
1214 self.log.error("Buffer underrun %d < %d" % (len(data), length))
1215 return
1216
1217 attr = self.add_attribute(attr_type, None)
1218
1219 # Find the end of 'data' for this attribute and decode our section
1220 # of 'data'. attributes are padded for alignment thus the attr_end.
1221 #
1222 # How the attribute is decoded/unpacked is specific per AttributeXXXX class.
1223 attr_end = padded_length(length)
1224 attr.decode(self, data[0:attr_end])
1225
1226 if self.debug:
1227 self.line_number = attr.dump_lines(self.dump_buffer, self.line_number, color)
1228
1229 # Alternate back and forth between green and blue
1230 if color == green:
1231 color = blue
1232 else:
1233 color = green
1234
1235 data = data[attr_end:]
1236
1237 def add_attribute(self, attr_type, value):
1238 nested = True if attr_type & NLA_F_NESTED else False
1239 net_byteorder = True if attr_type & NLA_F_NET_BYTEORDER else False
1240 attr_type = attr_type & NLA_TYPE_MASK
1241
1242 # Given an attr_type (say RTA_DST) find the type of AttributeXXXX class
1243 # that we will use to store this attribute...AttributeIPAddress in the
1244 # case of RTA_DST.
1245 if attr_type in self.attribute_to_class:
1246 (attr_string, attr_class) = self.attribute_to_class[attr_type]
1247 else:
1248 attr_string = "UNKNOWN_ATTRIBUTE_%d" % attr_type
1249 attr_class = AttributeGeneric
1250 self.log.debug("Attribute %d is not defined in %s.attribute_to_class, assuming AttributeGeneric" %
1251 (attr_type, self.__class__.__name__))
1252
1253 # A few attribute classes must know self.family (family was extracted from
1254 # the service header)
1255 if attr_class == AttributeIPAddress or attr_class == AttributeRTA_MULTIPATH:
1256 attr = attr_class(attr_type, attr_string, self.family, self.log)
1257 else:
1258 attr = attr_class(attr_type, attr_string, self.log)
1259
1260 attr.value = value
1261 attr.nested = nested
1262 attr.net_byteorder = net_byteorder
1263
1264 # self.attributes is a dictionary keyed by the attribute type where
1265 # the value is an instance of the corresponding AttributeXXXX class.
1266 self.attributes[attr_type] = attr
1267
1268 return attr
1269
1270 def get_attribute_value(self, attr_type):
1271 if attr_type not in self.attributes:
1272 return None
1273
1274 return self.attributes[attr_type].value
1275
1276 def get_attr_string(self, attr_type):
1277 """
1278 Example: If attr_type is Address.IFA_CACHEINFO return the string 'IFA_CACHEINFO'
1279 """
1280 if attr_type in self.attribute_to_class:
1281 (attr_string, attr_class) = self.attribute_to_class[attr_type]
1282 return attr_string
1283 return str(attr_type)
1284
1285 def build_message(self, seq, pid):
1286 self.seq = seq
1287 self.pid = pid
1288 attrs = ''
1289
1290 for attr in self.attributes.itervalues():
1291 attrs += attr.encode()
1292
1293 self.length = self.header_LEN + len(self.body) + len(attrs)
1294 self.header_data = pack(self.header_PACK, self.length, self.msgtype, self.flags, self.seq, self.pid)
1295 self.msg_data = self.body + attrs
1296 self.message = self.header_data + self.msg_data
1297
1298 if self.debug:
1299 self.decode_netlink_header()
1300 self.decode_service_header()
1301 self.decode_attributes()
1302 self.dump("TXed %s, length %d, seq %d, pid %d, flags 0x%x (%s)" %
1303 (self, self.length, self.seq, self.pid, self.flags,
1304 self.get_netlink_header_flags_string(self.msgtype, self.flags)))
1305
1306 # Print the netlink message in hex. This is only used for debugging.
1307 def dump(self, desc=None):
1308 attr_string = {}
1309
1310 if desc is None:
1311 desc = "RXed %s, length %d, seq %d, pid %d, flags 0x%x" % (self, self.length, self.seq, self.pid, self.flags)
1312
1313 for (attr_type, attr_obj) in self.attributes.iteritems():
1314 key_string = "(%2d) %s" % (attr_type, self.get_attr_string(attr_type))
1315 attr_string[key_string] = attr_obj.get_pretty_value()
1316
1317 self.log.debug("%s\n%s\n\nAttributes Summary\n%s\n" %
1318 (desc, '\n'.join(self.dump_buffer), pformat(attr_string)))
1319
1320
1321class Address(NetlinkPacket):
1322 """
1323 Service Header
1324 0 1 2 3
1325 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1326 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1327 | Family | Length | Flags | Scope |
1328 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1329 | Interface Index |
1330 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1331 """
1332
1333 # Address attributes
1334 # /usr/include/linux/if_addr.h
1335 IFA_UNSPEC = 0x00
1336 IFA_ADDRESS = 0x01
1337 IFA_LOCAL = 0x02
1338 IFA_LABEL = 0x03
1339 IFA_BROADCAST = 0x04
1340 IFA_ANYCAST = 0x05
1341 IFA_CACHEINFO = 0x06
1342 IFA_MULTICAST = 0x07
1343 IFA_FLAGS = 0x08
1344
1345 attribute_to_class = {
1346 IFA_UNSPEC : ('IFA_UNSPEC', AttributeGeneric),
1347 IFA_ADDRESS : ('IFA_ADDRESS', AttributeIPAddress),
1348 IFA_LOCAL : ('IFA_LOCAL', AttributeIPAddress),
1349 IFA_LABEL : ('IFA_LABEL', AttributeString),
1350 IFA_BROADCAST : ('IFA_BROADCAST', AttributeIPAddress),
1351 IFA_ANYCAST : ('IFA_ANYCAST', AttributeIPAddress),
1352 IFA_CACHEINFO : ('IFA_CACHEINFO', AttributeGeneric),
1353 IFA_MULTICAST : ('IFA_MULTICAST', AttributeIPAddress),
1354 IFA_FLAGS : ('IFA_FLAGS', AttributeGeneric)
1355 }
1356
1357 # Address flags
1358 # /usr/include/linux/if_addr.h
1359 IFA_F_SECONDARY = 0x01
1360 IFA_F_NODAD = 0x02
1361 IFA_F_OPTIMISTIC = 0x04
1362 IFA_F_DADFAILED = 0x08
1363 IFA_F_HOMEADDRESS = 0x10
1364 IFA_F_DEPRECATED = 0x20
1365 IFA_F_TENTATIVE = 0x40
1366 IFA_F_PERMANENT = 0x80
1367
1368 flag_to_string = {
1369 IFA_F_SECONDARY : 'IFA_F_SECONDARY',
1370 IFA_F_NODAD : 'IFA_F_NODAD',
1371 IFA_F_OPTIMISTIC : 'IFA_F_OPTIMISTIC',
1372 IFA_F_DADFAILED : 'IFA_F_DADFAILED',
1373 IFA_F_HOMEADDRESS : 'IFA_F_HOMEADDRESS',
1374 IFA_F_DEPRECATED : 'IFA_F_DEPRECATED',
1375 IFA_F_TENTATIVE : 'IFA_F_TENTATIVE',
1376 IFA_F_PERMANENT : 'IFA_F_PERMANENT'
1377 }
1378
1379 def __init__(self, msgtype, debug=False, logger=None):
1380 NetlinkPacket.__init__(self, msgtype, debug, logger)
1381 self.PACK = '4Bi'
1382 self.LEN = calcsize(self.PACK)
1383
1384 def decode_service_header(self):
1385
1386 # Nothing to do if the message did not contain a service header
1387 if self.length == self.header_LEN:
1388 return
1389
1390 (self.family, self.prefixlen, self.flags, self.scope,
1391 self.ifindex) = \
1392 unpack(self.PACK, self.msg_data[:self.LEN])
1393
1394 if self.debug:
1395 color = yellow
1396 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
1397
1398 for x in range(0, self.LEN/4):
1399 if self.line_number == 5:
1400 extra = "Family %s (%d), Length %s (%d), Flags %s, Scope %s (%d)" % \
1401 (zfilled_hex(self.family, 2), self.family,
1402 zfilled_hex(self.prefixlen, 2), self.prefixlen,
1403 zfilled_hex(self.flags, 2),
1404 zfilled_hex(self.scope, 2), self.scope)
1405 elif self.line_number == 6:
1406 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
1407 else:
1408 extra = "Unexpected line number %d" % self.line_number
1409
1410 start = x * 4
1411 end = start + 4
1412 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
1413 self.line_number += 1
1414
1415
1416class Error(NetlinkPacket):
1417
1418 # Error codes
1419 # /include/netlink/errno.h
1420 NLE_SUCCESS = 0x00
1421 NLE_FAILURE = 0x01
1422 NLE_INTR = 0x02
1423 NLE_BAD_SOCK = 0x03
1424 NLE_AGAIN = 0x04
1425 NLE_NOMEM = 0x05
1426 NLE_EXIST = 0x06
1427 NLE_INVAL = 0x07
1428 NLE_RANGE = 0x08
1429 NLE_MSGSIZE = 0x09
1430 NLE_OPNOTSUPP = 0x0A
1431 NLE_AF_NOSUPPORT = 0x0B
1432 NLE_OBJ_NOTFOUND = 0x0C
1433 NLE_NOATTR = 0x0D
1434 NLE_MISSING_ATTR = 0x0E
1435 NLE_AF_MISMATCH = 0x0F
1436 NLE_SEQ_MISMATCH = 0x10
1437 NLE_MSG_OVERFLOW = 0x11
1438 NLE_MSG_TRUNC = 0x12
1439 NLE_NOADDR = 0x13
1440 NLE_SRCRT_NOSUPPORT = 0x14
1441 NLE_MSG_TOOSHORT = 0x15
1442 NLE_MSGTYPE_NOSUPPORT = 0x16
1443 NLE_OBJ_MISMATCH = 0x17
1444 NLE_NOCACHE = 0x18
1445 NLE_BUSY = 0x19
1446 NLE_PROTO_MISMATCH = 0x1A
1447 NLE_NOACCESS = 0x1B
1448 NLE_PERM = 0x1C
1449 NLE_PKTLOC_FILE = 0x1D
1450 NLE_PARSE_ERR = 0x1E
1451 NLE_NODEV = 0x1F
1452 NLE_IMMUTABLE = 0x20
1453 NLE_DUMP_INTR = 0x21
1454
1455 error_to_string = {
1456 NLE_SUCCESS : 'NLE_SUCCESS',
1457 NLE_FAILURE : 'NLE_FAILURE',
1458 NLE_INTR : 'NLE_INTR',
1459 NLE_BAD_SOCK : 'NLE_BAD_SOCK',
1460 NLE_AGAIN : 'NLE_AGAIN',
1461 NLE_NOMEM : 'NLE_NOMEM',
1462 NLE_EXIST : 'NLE_EXIST',
1463 NLE_INVAL : 'NLE_INVAL',
1464 NLE_RANGE : 'NLE_RANGE',
1465 NLE_MSGSIZE : 'NLE_MSGSIZE',
1466 NLE_OPNOTSUPP : 'NLE_OPNOTSUPP',
1467 NLE_AF_NOSUPPORT : 'NLE_AF_NOSUPPORT',
1468 NLE_OBJ_NOTFOUND : 'NLE_OBJ_NOTFOUND',
1469 NLE_NOATTR : 'NLE_NOATTR',
1470 NLE_MISSING_ATTR : 'NLE_MISSING_ATTR',
1471 NLE_AF_MISMATCH : 'NLE_AF_MISMATCH',
1472 NLE_SEQ_MISMATCH : 'NLE_SEQ_MISMATCH',
1473 NLE_MSG_OVERFLOW : 'NLE_MSG_OVERFLOW',
1474 NLE_MSG_TRUNC : 'NLE_MSG_TRUNC',
1475 NLE_NOADDR : 'NLE_NOADDR',
1476 NLE_SRCRT_NOSUPPORT : 'NLE_SRCRT_NOSUPPORT',
1477 NLE_MSG_TOOSHORT : 'NLE_MSG_TOOSHORT',
1478 NLE_MSGTYPE_NOSUPPORT : 'NLE_MSGTYPE_NOSUPPORT',
1479 NLE_OBJ_MISMATCH : 'NLE_OBJ_MISMATCH',
1480 NLE_NOCACHE : 'NLE_NOCACHE',
1481 NLE_BUSY : 'NLE_BUSY',
1482 NLE_PROTO_MISMATCH : 'NLE_PROTO_MISMATCH',
1483 NLE_NOACCESS : 'NLE_NOACCESS',
1484 NLE_PERM : 'NLE_PERM',
1485 NLE_PKTLOC_FILE : 'NLE_PKTLOC_FILE',
1486 NLE_PARSE_ERR : 'NLE_PARSE_ERR',
1487 NLE_NODEV : 'NLE_NODEV',
1488 NLE_IMMUTABLE : 'NLE_IMMUTABLE',
1489 NLE_DUMP_INTR : 'NLE_DUMP_INTR'
1490 }
1491
1492 def __init__(self, msgtype, debug=False, logger=None):
1493 NetlinkPacket.__init__(self, msgtype, debug, logger)
1494 self.PACK = '=iLHHLL'
1495 self.LEN = calcsize(self.PACK)
1496
1497 def decode_service_header(self):
1498
1499 # Nothing to do if the message did not contain a service header
1500 if self.length == self.header_LEN:
1501 return
1502
1503 (self.negative_errno, self.bad_msg_len, self.bad_msg_type,
1504 self.bad_msg_flag, self.bad_msg_seq, self.bad_msg_pid) =\
1505 unpack(self.PACK, self.msg_data[:self.LEN])
1506
1507 if self.debug:
1508 color = yellow
1509 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
1510
1511 for x in range(0, self.LEN/4):
1512
1513 if self.line_number == 5:
1514 extra = "Error Number %s is %s" % (self.negative_errno, self.error_to_string.get(abs(self.negative_errno)))
1515 # zfilled_hex(self.negative_errno, 2)
1516
1517 elif self.line_number == 6:
1518 extra = "Length %s (%d)" % (zfilled_hex(self.bad_msg_len, 8), self.bad_msg_len)
1519
1520 elif self.line_number == 7:
1521 extra = "Type %s (%d - %s), Flags %s (%s)" % \
1522 (zfilled_hex(self.bad_msg_type, 4), self.bad_msg_type, self.get_type_string(self.bad_msg_type),
1523 zfilled_hex(self.bad_msg_flag, 4), self.get_netlink_header_flags_string(self.bad_msg_type, self.bad_msg_flag))
1524
1525 elif self.line_number == 8:
1526 extra = "Sequence Number %s (%d)" % (zfilled_hex(self.bad_msg_seq, 8), self.bad_msg_seq)
1527
1528 elif self.line_number == 9:
1529 extra = "Process ID %s (%d)" % (zfilled_hex(self.bad_msg_pid, 8), self.bad_msg_pid)
1530
1531 else:
1532 extra = "Unexpected line number %d" % self.line_number
1533
1534 start = x * 4
1535 end = start + 4
1536 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
1537 self.line_number += 1
1538
1539
1540class Link(NetlinkPacket):
1541 """
1542 Service Header
1543
1544 0 1 2 3
1545 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1546 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1547 | Family | Reserved | Device Type |
1548 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1549 | Interface Index |
1550 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1551 | Device Flags |
1552 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1553 | Change Mask |
1554 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1555 """
1556
1557 # Link attributes
1558 # /usr/include/linux/if_link.h
1559 IFLA_UNSPEC = 0
1560 IFLA_ADDRESS = 1
1561 IFLA_BROADCAST = 2
1562 IFLA_IFNAME = 3
1563 IFLA_MTU = 4
1564 IFLA_LINK = 5
1565 IFLA_QDISC = 6
1566 IFLA_STATS = 7
1567 IFLA_COST = 8
1568 IFLA_PRIORITY = 9
1569 IFLA_MASTER = 10
1570 IFLA_WIRELESS = 11
1571 IFLA_PROTINFO = 12
1572 IFLA_TXQLEN = 13
1573 IFLA_MAP = 14
1574 IFLA_WEIGHT = 15
1575 IFLA_OPERSTATE = 16
1576 IFLA_LINKMODE = 17
1577 IFLA_LINKINFO = 18
1578 IFLA_NET_NS_PID = 19
1579 IFLA_IFALIAS = 20
1580 IFLA_NUM_VF = 21
1581 IFLA_VFINFO_LIST = 22
1582 IFLA_STATS64 = 23
1583 IFLA_VF_PORTS = 24
1584 IFLA_PORT_SELF = 25
1585 IFLA_AF_SPEC = 26
1586 IFLA_GROUP = 27
1587 IFLA_NET_NS_FD = 28
1588 IFLA_EXT_MASK = 29
1589 IFLA_PROMISCUITY = 30
1590 IFLA_NUM_TX_QUEUES = 31
1591 IFLA_NUM_RX_QUEUES = 32
1592 IFLA_CARRIER = 33
1593 IFLA_PHYS_PORT_ID = 34
1594 IFLA_CARRIER_CHANGES = 35
1595 IFLA_PHYS_SWITCH_ID = 36
1596 IFLA_LINK_NETNSID = 37
1597 IFLA_PHYS_PORT_NAME = 38
1598 IFLA_PROTO_DOWN = 39
1599 IFLA_LINKPROTODOWN = 200
1600
1601 attribute_to_class = {
1602 IFLA_UNSPEC : ('IFLA_UNSPEC', AttributeGeneric),
1603 IFLA_ADDRESS : ('IFLA_ADDRESS', AttributeMACAddress),
1604 IFLA_BROADCAST : ('IFLA_BROADCAST', AttributeMACAddress),
1605 IFLA_IFNAME : ('IFLA_IFNAME', AttributeString),
1606 IFLA_MTU : ('IFLA_MTU', AttributeFourByteValue),
1607 IFLA_LINK : ('IFLA_LINK', AttributeFourByteValue),
1608 IFLA_QDISC : ('IFLA_QDISC', AttributeString),
1609 IFLA_STATS : ('IFLA_STATS', AttributeGeneric),
1610 IFLA_COST : ('IFLA_COST', AttributeGeneric),
1611 IFLA_PRIORITY : ('IFLA_PRIORITY', AttributeGeneric),
1612 IFLA_MASTER : ('IFLA_MASTER', AttributeFourByteValue),
1613 IFLA_WIRELESS : ('IFLA_WIRELESS', AttributeGeneric),
1614 IFLA_PROTINFO : ('IFLA_PROTINFO', AttributeGeneric),
1615 IFLA_TXQLEN : ('IFLA_TXQLEN', AttributeFourByteValue),
1616 IFLA_MAP : ('IFLA_MAP', AttributeGeneric),
1617 IFLA_WEIGHT : ('IFLA_WEIGHT', AttributeGeneric),
1618 IFLA_OPERSTATE : ('IFLA_OPERSTATE', AttributeFourByteValue),
1619 IFLA_LINKMODE : ('IFLA_LINKMODE', AttributeFourByteValue),
1620 IFLA_LINKINFO : ('IFLA_LINKINFO', AttributeIFLA_LINKINFO),
1621 IFLA_NET_NS_PID : ('IFLA_NET_NS_PID', AttributeGeneric),
1622 IFLA_IFALIAS : ('IFLA_IFALIAS', AttributeGeneric),
1623 IFLA_NUM_VF : ('IFLA_NUM_VF', AttributeGeneric),
1624 IFLA_VFINFO_LIST : ('IFLA_VFINFO_LIST', AttributeGeneric),
1625 IFLA_STATS64 : ('IFLA_STATS64', AttributeGeneric),
1626 IFLA_VF_PORTS : ('IFLA_VF_PORTS', AttributeGeneric),
1627 IFLA_PORT_SELF : ('IFLA_PORT_SELF', AttributeGeneric),
1628 IFLA_AF_SPEC : ('IFLA_AF_SPEC', AttributeIFLA_AF_SPEC),
1629 IFLA_GROUP : ('IFLA_GROUP', AttributeFourByteValue),
1630 IFLA_NET_NS_FD : ('IFLA_NET_NS_FD', AttributeGeneric),
1631 IFLA_EXT_MASK : ('IFLA_EXT_MASK', AttributeGeneric),
1632 IFLA_PROMISCUITY : ('IFLA_PROMISCUITY', AttributeGeneric),
1633 IFLA_NUM_TX_QUEUES : ('IFLA_NUM_TX_QUEUES', AttributeGeneric),
1634 IFLA_NUM_RX_QUEUES : ('IFLA_NUM_RX_QUEUES', AttributeGeneric),
1635 IFLA_CARRIER : ('IFLA_CARRIER', AttributeGeneric),
1636 IFLA_PHYS_PORT_ID : ('IFLA_PHYS_PORT_ID', AttributeGeneric),
1637 IFLA_CARRIER_CHANGES : ('IFLA_CARRIER_CHANGES', AttributeGeneric),
1638 IFLA_PHYS_SWITCH_ID : ('IFLA_PHYS_SWITCH_ID', AttributeGeneric),
1639 IFLA_LINK_NETNSID : ('IFLA_LINK_NETNSID', AttributeGeneric),
1640 IFLA_PHYS_PORT_NAME : ('IFLA_PHYS_PORT_NAME', AttributeGeneric),
1641 IFLA_PROTO_DOWN : ('IFLA_PROTO_DOWN', AttributeGeneric),
1642 IFLA_LINKPROTODOWN : ('IFLA_LINKPROTODOWN', AttributeGeneric)
1643 }
1644
1645 # Link flags
1646 # /usr/include/linux/if.h
1647 IFF_UP = 0x0001 # Interface is administratively up.
1648 IFF_BROADCAST = 0x0002 # Valid broadcast address set.
1649 IFF_DEBUG = 0x0004 # Internal debugging flag.
1650 IFF_LOOPBACK = 0x0008 # Interface is a loopback interface.
1651 IFF_POINTOPOINT = 0x0010 # Interface is a point-to-point link.
1652 IFF_NOTRAILERS = 0x0020 # Avoid use of trailers.
1653 IFF_RUNNING = 0x0040 # Interface is operationally up.
1654 IFF_NOARP = 0x0080 # No ARP protocol needed for this interface.
1655 IFF_PROMISC = 0x0100 # Interface is in promiscuous mode.
1656 IFF_ALLMULTI = 0x0200 # Receive all multicast packets.
1657 IFF_MASTER = 0x0400 # Master of a load balancing bundle.
1658 IFF_SLAVE = 0x0800 # Slave of a load balancing bundle.
1659 IFF_MULTICAST = 0x1000 # Supports multicast.
1660 IFF_PORTSEL = 0x2000 # Is able to select media type via ifmap.
1661 IFF_AUTOMEDIA = 0x4000 # Auto media selection active.
1662 IFF_DYNAMIC = 0x8000 # Interface was dynamically created.
1663 IFF_LOWER_UP = 0x10000 # driver signals L1 up
1664 IFF_DORMANT = 0x20000 # driver signals dormant
1665 IFF_ECHO = 0x40000 # echo sent packet
1666 IFF_PROTO_DOWN = 0x1000000 # protocol is down on the interface
1667
1668 flag_to_string = {
1669 IFF_UP : 'IFF_UP',
1670 IFF_BROADCAST : 'IFF_BROADCAST',
1671 IFF_DEBUG : 'IFF_DEBUG',
1672 IFF_LOOPBACK : 'IFF_LOOPBACK',
1673 IFF_POINTOPOINT : 'IFF_POINTOPOINT',
1674 IFF_NOTRAILERS : 'IFF_NOTRAILERS',
1675 IFF_RUNNING : 'IFF_RUNNING',
1676 IFF_NOARP : 'IFF_NOARP',
1677 IFF_PROMISC : 'IFF_PROMISC',
1678 IFF_ALLMULTI : 'IFF_ALLMULTI',
1679 IFF_MASTER : 'IFF_MASTER',
1680 IFF_SLAVE : 'IFF_SLAVE',
1681 IFF_MULTICAST : 'IFF_MULTICAST',
1682 IFF_PORTSEL : 'IFF_PORTSEL',
1683 IFF_AUTOMEDIA : 'IFF_AUTOMEDIA',
1684 IFF_DYNAMIC : 'IFF_DYNAMIC',
1685 IFF_LOWER_UP : 'IFF_LOWER_UP',
1686 IFF_DORMANT : 'IFF_DORMANT',
1687 IFF_ECHO : 'IFF_ECHO',
1688 IFF_PROTO_DOWN : 'IFF_PROTO_DOWN'
1689 }
1690
1691 # RFC 2863 operational status
1692 IF_OPER_UNKNOWN = 0
1693 IF_OPER_NOTPRESENT = 1
1694 IF_OPER_DOWN = 2
1695 IF_OPER_LOWERLAYERDOWN = 3
1696 IF_OPER_TESTING = 4
1697 IF_OPER_DORMANT = 5
1698 IF_OPER_UP = 6
1699
1700 oper_to_string = {
1701 IF_OPER_UNKNOWN : 'IF_OPER_UNKNOWN',
1702 IF_OPER_NOTPRESENT : 'IF_OPER_NOTPRESENT',
1703 IF_OPER_DOWN : 'IF_OPER_DOWN',
1704 IF_OPER_LOWERLAYERDOWN : 'IF_OPER_LOWERLAYERDOWN',
1705 IF_OPER_TESTING : 'IF_OPER_TESTING',
1706 IF_OPER_DORMANT : 'IF_OPER_DORMANT',
1707 IF_OPER_UP : 'IF_OPER_UP'
1708 }
1709
1710 # Link types
1711 # /usr/include/linux/if_arp.h
1712 # ARP protocol HARDWARE identifiers
1713 ARPHRD_NETROM = 0 # from KA9Q: NET/ROM pseudo
1714 ARPHRD_ETHER = 1 # Ethernet 10Mbps
1715 ARPHRD_EETHER = 2 # Experimental Ethernet
1716 ARPHRD_AX25 = 3 # AX.25 Level 2
1717 ARPHRD_PRONET = 4 # PROnet token ring
1718 ARPHRD_CHAOS = 5 # Chaosnet
1719 ARPHRD_IEEE802 = 6 # IEEE 802.2 Ethernet/TR/TB
1720 ARPHRD_ARCNET = 7 # ARCnet
1721 ARPHRD_APPLETLK = 8 # APPLEtalk
1722 ARPHRD_DLCI = 15 # Frame Relay DLCI
1723 ARPHRD_ATM = 19 # ATM
1724 ARPHRD_METRICOM = 23 # Metricom STRIP (new IANA id)
1725 ARPHRD_IEEE1394 = 24 # IEEE 1394 IPv4 - RFC 2734
1726 ARPHRD_EUI64 = 27 # EUI-64
1727 ARPHRD_INFINIBAND = 32 # InfiniBand
1728 # Dummy types for non ARP hardware
1729 ARPHRD_SLIP = 256
1730 ARPHRD_CSLIP = 257
1731 ARPHRD_SLIP6 = 258
1732 ARPHRD_CSLIP6 = 259
1733 ARPHRD_RSRVD = 260 # Notional KISS type
1734 ARPHRD_ADAPT = 264
1735 ARPHRD_ROSE = 270
1736 ARPHRD_X25 = 271 # CCITT X.25
1737 ARPHRD_HWX25 = 272 # Boards with X.25 in firmware
1738 ARPHRD_CAN = 280 # Controller Area Network
1739 ARPHRD_PPP = 512
1740 ARPHRD_CISCO = 513 # Cisco HDLC
1741 ARPHRD_HDLC = ARPHRD_CISCO
1742 ARPHRD_LAPB = 516 # LAPB
1743 ARPHRD_DDCMP = 517 # Digital's DDCMP protocol
1744 ARPHRD_RAWHDLC = 518 # Raw HDLC
1745 ARPHRD_TUNNEL = 768 # IPIP tunnel
1746 ARPHRD_TUNNEL6 = 769 # IP6IP6 tunnel
1747 ARPHRD_FRAD = 770 # Frame Relay Access Device
1748 ARPHRD_SKIP = 771 # SKIP vif
1749 ARPHRD_LOOPBACK = 772 # Loopback device
1750 ARPHRD_LOCALTLK = 773 # Localtalk device
1751 ARPHRD_FDDI = 774 # Fiber Distributed Data Interface
1752 ARPHRD_BIF = 775 # AP1000 BIF
1753 ARPHRD_SIT = 776 # sit0 device - IPv6-in-IPv4
1754 ARPHRD_IPDDP = 777 # IP over DDP tunneller
1755 ARPHRD_IPGRE = 778 # GRE over IP
1756 ARPHRD_PIMREG = 779 # PIMSM register interface
1757 ARPHRD_HIPPI = 780 # High Performance Parallel Interface
1758 ARPHRD_ASH = 781 # Nexus 64Mbps Ash
1759 ARPHRD_ECONET = 782 # Acorn Econet
1760 ARPHRD_IRDA = 783 # Linux-IrDA
1761 ARPHRD_FCPP = 784 # Point to point fibrechannel
1762 ARPHRD_FCAL = 785 # Fibrechannel arbitrated loop
1763 ARPHRD_FCPL = 786 # Fibrechannel public loop
1764 ARPHRD_FCFABRIC = 787 # Fibrechannel fabric
1765 # 787->799 reserved for fibrechannel media types
1766 ARPHRD_IEEE802_TR = 800 # Magic type ident for TR
1767 ARPHRD_IEEE80211 = 801 # IEEE 802.11
1768 ARPHRD_IEEE80211_PRISM = 802 # IEEE 802.11 + Prism2 header
1769 ARPHRD_IEEE80211_RADIOTAP = 803 # IEEE 802.11 + radiotap header
1770 ARPHRD_IEEE802154 = 804
1771 ARPHRD_PHONET = 820 # PhoNet media type
1772 ARPHRD_PHONET_PIPE = 821 # PhoNet pipe header
1773 ARPHRD_CAIF = 822 # CAIF media type
1774 ARPHRD_VOID = 0xFFFF # Void type, nothing is known
1775 ARPHRD_NONE = 0xFFFE # zero header length
1776
1777 link_type_to_string = {
1778 ARPHRD_NETROM : 'ARPHRD_NETROM',
1779 ARPHRD_ETHER : 'ARPHRD_ETHER',
1780 ARPHRD_EETHER : 'ARPHRD_EETHER',
1781 ARPHRD_AX25 : 'ARPHRD_AX25',
1782 ARPHRD_PRONET : 'ARPHRD_PRONET',
1783 ARPHRD_CHAOS : 'ARPHRD_CHAOS',
1784 ARPHRD_IEEE802 : 'ARPHRD_IEEE802',
1785 ARPHRD_ARCNET : 'ARPHRD_ARCNET',
1786 ARPHRD_APPLETLK : 'ARPHRD_APPLETLK',
1787 ARPHRD_DLCI : 'ARPHRD_DLCI',
1788 ARPHRD_ATM : 'ARPHRD_ATM',
1789 ARPHRD_METRICOM : 'ARPHRD_METRICOM',
1790 ARPHRD_IEEE1394 : 'ARPHRD_IEEE1394',
1791 ARPHRD_EUI64 : 'ARPHRD_EUI64',
1792 ARPHRD_INFINIBAND : 'ARPHRD_INFINIBAND',
1793 ARPHRD_SLIP : 'ARPHRD_SLIP',
1794 ARPHRD_CSLIP : 'ARPHRD_CSLIP',
1795 ARPHRD_SLIP6 : 'ARPHRD_SLIP6',
1796 ARPHRD_CSLIP6 : 'ARPHRD_CSLIP6',
1797 ARPHRD_RSRVD : 'ARPHRD_RSRVD',
1798 ARPHRD_ADAPT : 'ARPHRD_ADAPT',
1799 ARPHRD_ROSE : 'ARPHRD_ROSE',
1800 ARPHRD_X25 : 'ARPHRD_X25',
1801 ARPHRD_HWX25 : 'ARPHRD_HWX25',
1802 ARPHRD_CAN : 'ARPHRD_CAN',
1803 ARPHRD_PPP : 'ARPHRD_PPP',
1804 ARPHRD_CISCO : 'ARPHRD_CISCO',
1805 ARPHRD_HDLC : 'ARPHRD_HDLC',
1806 ARPHRD_LAPB : 'ARPHRD_LAPB',
1807 ARPHRD_DDCMP : 'ARPHRD_DDCMP',
1808 ARPHRD_RAWHDLC : 'ARPHRD_RAWHDLC',
1809 ARPHRD_TUNNEL : 'ARPHRD_TUNNEL',
1810 ARPHRD_TUNNEL6 : 'ARPHRD_TUNNEL6',
1811 ARPHRD_FRAD : 'ARPHRD_FRAD',
1812 ARPHRD_SKIP : 'ARPHRD_SKIP',
1813 ARPHRD_LOOPBACK : 'ARPHRD_LOOPBACK',
1814 ARPHRD_LOCALTLK : 'ARPHRD_LOCALTLK',
1815 ARPHRD_FDDI : 'ARPHRD_FDDI',
1816 ARPHRD_BIF : 'ARPHRD_BIF',
1817 ARPHRD_SIT : 'ARPHRD_SIT',
1818 ARPHRD_IPDDP : 'ARPHRD_IPDDP',
1819 ARPHRD_IPGRE : 'ARPHRD_IPGRE',
1820 ARPHRD_PIMREG : 'ARPHRD_PIMREG',
1821 ARPHRD_HIPPI : 'ARPHRD_HIPPI',
1822 ARPHRD_ASH : 'ARPHRD_ASH',
1823 ARPHRD_ECONET : 'ARPHRD_ECONET',
1824 ARPHRD_IRDA : 'ARPHRD_IRDA',
1825 ARPHRD_FCPP : 'ARPHRD_FCPP',
1826 ARPHRD_FCAL : 'ARPHRD_FCAL',
1827 ARPHRD_FCPL : 'ARPHRD_FCPL',
1828 ARPHRD_FCFABRIC : 'ARPHRD_FCFABRIC',
1829 ARPHRD_IEEE802_TR : 'ARPHRD_IEEE802_TR',
1830 ARPHRD_IEEE80211 : 'ARPHRD_IEEE80211',
1831 ARPHRD_IEEE80211_PRISM : 'ARPHRD_IEEE80211_PRISM',
1832 ARPHRD_IEEE80211_RADIOTAP : 'ARPHRD_IEEE80211_RADIOTAP',
1833 ARPHRD_IEEE802154 : 'ARPHRD_IEEE802154',
1834 ARPHRD_PHONET : 'ARPHRD_PHONET',
1835 ARPHRD_PHONET_PIPE : 'ARPHRD_PHONET_PIPE',
1836 ARPHRD_CAIF : 'ARPHRD_CAIF',
1837 ARPHRD_VOID : 'ARPHRD_VOID',
1838 ARPHRD_NONE : 'ARPHRD_NONE'
1839 }
1840
1841 # =========================================
1842 # IFLA_LINKINFO attributes
1843 # =========================================
1844 IFLA_INFO_UNSPEC = 0
1845 IFLA_INFO_KIND = 1
1846 IFLA_INFO_DATA = 2
1847 IFLA_INFO_XSTATS = 3
1848 IFLA_INFO_SLAVE_KIND = 4
1849 IFLA_INFO_SLAVE_DATA = 5
1850 IFLA_INFO_MAX = 6
1851
1852 ifla_info_to_string = {
1853 IFLA_INFO_UNSPEC : 'IFLA_INFO_UNSPEC',
1854 IFLA_INFO_KIND : 'IFLA_INFO_KIND',
1855 IFLA_INFO_DATA : 'IFLA_INFO_DATA',
1856 IFLA_INFO_XSTATS : 'IFLA_INFO_XSTATS',
1857 IFLA_INFO_SLAVE_KIND : 'IFLA_INFO_SLAVE_KIND',
1858 IFLA_INFO_SLAVE_DATA : 'IFLA_INFO_SLAVE_DATA',
1859 IFLA_INFO_MAX : 'IFLA_INFO_MAX'
1860 }
1861
1862 # =========================================
1863 # IFLA_INFO_DATA attributes for vlan
1864 # =========================================
1865 IFLA_VLAN_UNSPEC = 0
1866 IFLA_VLAN_ID = 1
1867 IFLA_VLAN_FLAGS = 2
1868 IFLA_VLAN_EGRESS_QOS = 3
1869 IFLA_VLAN_INGRESS_QOS = 4
1870 IFLA_VLAN_PROTOCOL = 5
1871
1872 ifla_vlan_to_string = {
1873 IFLA_VLAN_UNSPEC : 'IFLA_VLAN_UNSPEC',
1874 IFLA_VLAN_ID : 'IFLA_VLAN_ID',
1875 IFLA_VLAN_FLAGS : 'IFLA_VLAN_FLAGS',
1876 IFLA_VLAN_EGRESS_QOS : 'IFLA_VLAN_EGRESS_QOS',
1877 IFLA_VLAN_INGRESS_QOS : 'IFLA_VLAN_INGRESS_QOS',
1878 IFLA_VLAN_PROTOCOL : 'IFLA_VLAN_PROTOCOL'
1879 }
1880
1881 # =========================================
1882 # IFLA_INFO_DATA attributes for macvlan
1883 # =========================================
1884 IFLA_MACVLAN_UNSPEC = 0
1885 IFLA_MACVLAN_MODE = 1
1886
1887 ifla_macvlan_to_string = {
1888 IFLA_MACVLAN_UNSPEC : 'IFLA_MACVLAN_UNSPEC',
1889 IFLA_MACVLAN_MODE : 'IFLA_MACVLAN_MODE'
1890 }
1891
1892 # macvlan modes
1893 MACVLAN_MODE_PRIVATE = 1
1894 MACVLAN_MODE_VEPA = 2
1895 MACVLAN_MODE_BRIDGE = 3
1896 MACVLAN_MODE_PASSTHRU = 4
1897
1898 macvlan_mode_to_string = {
1899 MACVLAN_MODE_PRIVATE : 'MACVLAN_MODE_PRIVATE',
1900 MACVLAN_MODE_VEPA : 'MACVLAN_MODE_VEPA',
1901 MACVLAN_MODE_BRIDGE : 'MACVLAN_MODE_BRIDGE',
1902 MACVLAN_MODE_PASSTHRU : 'MACVLAN_MODE_PASSTHRU'
1903 }
1904
1905 # =========================================
1906 # IFLA_INFO_DATA attributes for vxlan
1907 # =========================================
1908 IFLA_VXLAN_UNSPEC = 0
1909 IFLA_VXLAN_ID = 1
1910 IFLA_VXLAN_GROUP = 2
1911 IFLA_VXLAN_LINK = 3
1912 IFLA_VXLAN_LOCAL = 4
1913 IFLA_VXLAN_TTL = 5
1914 IFLA_VXLAN_TOS = 6
1915 IFLA_VXLAN_LEARNING = 7
1916 IFLA_VXLAN_AGEING = 8
1917 IFLA_VXLAN_LIMIT = 9
1918 IFLA_VXLAN_PORT_RANGE = 10
1919 IFLA_VXLAN_PROXY = 11
1920 IFLA_VXLAN_RSC = 12
1921 IFLA_VXLAN_L2MISS = 13
1922 IFLA_VXLAN_L3MISS = 14
1923 IFLA_VXLAN_PORT = 15
1924 IFLA_VXLAN_GROUP6 = 16
1925 IFLA_VXLAN_LOCAL6 = 17
1926 IFLA_VXLAN_UDP_CSUM = 18
1927 IFLA_VXLAN_UDP_ZERO_CSUM6_TX = 19
1928 IFLA_VXLAN_UDP_ZERO_CSUM6_RX = 20
1929 IFLA_VXLAN_REMCSUM_TX = 21
1930 IFLA_VXLAN_REMCSUM_RX = 22
1931 IFLA_VXLAN_GBP = 23
1932 IFLA_VXLAN_REMCSUM_NOPARTIAL = 24
1933 IFLA_VXLAN_COLLECT_METADATA = 25
1934 IFLA_VXLAN_REPLICATION_NODE = 253
1935 IFLA_VXLAN_REPLICATION_TYPE = 254
1936
1937 ifla_vxlan_to_string = {
1938 IFLA_VXLAN_UNSPEC : 'IFLA_VXLAN_UNSPEC',
1939 IFLA_VXLAN_ID : 'IFLA_VXLAN_ID',
1940 IFLA_VXLAN_GROUP : 'IFLA_VXLAN_GROUP',
1941 IFLA_VXLAN_LINK : 'IFLA_VXLAN_LINK',
1942 IFLA_VXLAN_LOCAL : 'IFLA_VXLAN_LOCAL',
1943 IFLA_VXLAN_TTL : 'IFLA_VXLAN_TTL',
1944 IFLA_VXLAN_TOS : 'IFLA_VXLAN_TOS',
1945 IFLA_VXLAN_LEARNING : 'IFLA_VXLAN_LEARNING',
1946 IFLA_VXLAN_AGEING : 'IFLA_VXLAN_AGEING',
1947 IFLA_VXLAN_LIMIT : 'IFLA_VXLAN_LIMIT',
1948 IFLA_VXLAN_PORT_RANGE : 'IFLA_VXLAN_PORT_RANGE',
1949 IFLA_VXLAN_PROXY : 'IFLA_VXLAN_PROXY',
1950 IFLA_VXLAN_RSC : 'IFLA_VXLAN_RSC',
1951 IFLA_VXLAN_L2MISS : 'IFLA_VXLAN_L2MISS',
1952 IFLA_VXLAN_L3MISS : 'IFLA_VXLAN_L3MISS',
1953 IFLA_VXLAN_PORT : 'IFLA_VXLAN_PORT',
1954 IFLA_VXLAN_GROUP6 : 'IFLA_VXLAN_GROUP6',
1955 IFLA_VXLAN_LOCAL6 : 'IFLA_VXLAN_LOCAL6',
1956 IFLA_VXLAN_UDP_CSUM : 'IFLA_VXLAN_UDP_CSUM',
1957 IFLA_VXLAN_UDP_ZERO_CSUM6_TX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_TX',
1958 IFLA_VXLAN_UDP_ZERO_CSUM6_RX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_RX',
1959 IFLA_VXLAN_REMCSUM_TX : 'IFLA_VXLAN_REMCSUM_TX',
1960 IFLA_VXLAN_REMCSUM_RX : 'IFLA_VXLAN_REMCSUM_RX',
1961 IFLA_VXLAN_GBP : 'IFLA_VXLAN_GBP',
1962 IFLA_VXLAN_REMCSUM_NOPARTIAL : 'IFLA_VXLAN_REMCSUM_NOPARTIAL',
1963 IFLA_VXLAN_COLLECT_METADATA : 'IFLA_VXLAN_COLLECT_METADATA',
1964 IFLA_VXLAN_REPLICATION_NODE : 'IFLA_VXLAN_REPLICATION_NODE',
1965 IFLA_VXLAN_REPLICATION_TYPE : 'IFLA_VXLAN_REPLICATION_TYPE'
1966 }
1967
1968 # =========================================
1969 # IFLA_INFO_DATA attributes for bonds
1970 # =========================================
1971 IFLA_BOND_UNSPEC = 0
1972 IFLA_BOND_MODE = 1
1973 IFLA_BOND_ACTIVE_SLAVE = 2
1974 IFLA_BOND_MIIMON = 3
1975 IFLA_BOND_UPDELAY = 4
1976 IFLA_BOND_DOWNDELAY = 5
1977 IFLA_BOND_USE_CARRIER = 6
1978 IFLA_BOND_ARP_INTERVAL = 7
1979 IFLA_BOND_ARP_IP_TARGET = 8
1980 IFLA_BOND_ARP_VALIDATE = 9
1981 IFLA_BOND_ARP_ALL_TARGETS = 10
1982 IFLA_BOND_PRIMARY = 11
1983 IFLA_BOND_PRIMARY_RESELECT = 12
1984 IFLA_BOND_FAIL_OVER_MAC = 13
1985 IFLA_BOND_XMIT_HASH_POLICY = 14
1986 IFLA_BOND_RESEND_IGMP = 15
1987 IFLA_BOND_NUM_PEER_NOTIF = 16
1988 IFLA_BOND_ALL_SLAVES_ACTIVE = 17
1989 IFLA_BOND_MIN_LINKS = 18
1990 IFLA_BOND_LP_INTERVAL = 19
1991 IFLA_BOND_PACKETS_PER_SLAVE = 20
1992 IFLA_BOND_AD_LACP_RATE = 21
1993 IFLA_BOND_AD_SELECT = 22
1994 IFLA_BOND_AD_INFO = 23
1995 IFLA_BOND_AD_ACTOR_SYS_PRIO = 24
1996 IFLA_BOND_AD_USER_PORT_KEY = 25
1997 IFLA_BOND_AD_ACTOR_SYSTEM = 26
1998 IFLA_BOND_CL_LACP_BYPASS_ALLOW = 100
1999 IFLA_BOND_CL_LACP_BYPASS_ACTIVE = 101
2000 IFLA_BOND_CL_LACP_BYPASS_PERIOD = 102
2001 IFLA_BOND_CL_CLAG_ENABLE = 103
2002 IFLA_BOND_CL_LACP_BYPASS_ALL_ACTIVE = 104
2003
2004 ifla_bond_to_string = {
2005 IFLA_BOND_UNSPEC : 'IFLA_BOND_UNSPEC',
2006 IFLA_BOND_MODE : 'IFLA_BOND_MODE',
2007 IFLA_BOND_ACTIVE_SLAVE : 'IFLA_BOND_ACTIVE_SLAVE',
2008 IFLA_BOND_MIIMON : 'IFLA_BOND_MIIMON',
2009 IFLA_BOND_UPDELAY : 'IFLA_BOND_UPDELAY',
2010 IFLA_BOND_DOWNDELAY : 'IFLA_BOND_DOWNDELAY',
2011 IFLA_BOND_USE_CARRIER : 'IFLA_BOND_USE_CARRIER',
2012 IFLA_BOND_ARP_INTERVAL : 'IFLA_BOND_ARP_INTERVAL',
2013 IFLA_BOND_ARP_IP_TARGET : 'IFLA_BOND_ARP_IP_TARGET',
2014 IFLA_BOND_ARP_VALIDATE : 'IFLA_BOND_ARP_VALIDATE',
2015 IFLA_BOND_ARP_ALL_TARGETS : 'IFLA_BOND_ARP_ALL_TARGETS',
2016 IFLA_BOND_PRIMARY : 'IFLA_BOND_PRIMARY',
2017 IFLA_BOND_PRIMARY_RESELECT : 'IFLA_BOND_PRIMARY_RESELECT',
2018 IFLA_BOND_FAIL_OVER_MAC : 'IFLA_BOND_FAIL_OVER_MAC',
2019 IFLA_BOND_XMIT_HASH_POLICY : 'IFLA_BOND_XMIT_HASH_POLICY',
2020 IFLA_BOND_RESEND_IGMP : 'IFLA_BOND_RESEND_IGMP',
2021 IFLA_BOND_NUM_PEER_NOTIF : 'IFLA_BOND_NUM_PEER_NOTIF',
2022 IFLA_BOND_ALL_SLAVES_ACTIVE : 'IFLA_BOND_ALL_SLAVES_ACTIVE',
2023 IFLA_BOND_MIN_LINKS : 'IFLA_BOND_MIN_LINKS',
2024 IFLA_BOND_LP_INTERVAL : 'IFLA_BOND_LP_INTERVAL',
2025 IFLA_BOND_PACKETS_PER_SLAVE : 'IFLA_BOND_PACKETS_PER_SLAVE',
2026 IFLA_BOND_AD_LACP_RATE : 'IFLA_BOND_AD_LACP_RATE',
2027 IFLA_BOND_AD_SELECT : 'IFLA_BOND_AD_SELECT',
2028 IFLA_BOND_AD_INFO : 'IFLA_BOND_AD_INFO',
2029 IFLA_BOND_AD_ACTOR_SYS_PRIO : 'IFLA_BOND_AD_ACTOR_SYS_PRIO',
2030 IFLA_BOND_AD_USER_PORT_KEY : 'IFLA_BOND_AD_USER_PORT_KEY',
2031 IFLA_BOND_AD_ACTOR_SYSTEM : 'IFLA_BOND_AD_ACTOR_SYSTEM',
2032 IFLA_BOND_CL_LACP_BYPASS_ALLOW : 'IFLA_BOND_CL_LACP_BYPASS_ALLOW',
2033 IFLA_BOND_CL_LACP_BYPASS_ACTIVE : 'IFLA_BOND_CL_LACP_BYPASS_ACTIVE',
2034 IFLA_BOND_CL_LACP_BYPASS_PERIOD : 'IFLA_BOND_CL_LACP_BYPASS_PERIOD',
2035 IFLA_BOND_CL_CLAG_ENABLE : 'IFLA_BOND_CL_CLAG_ENABLE',
2036 IFLA_BOND_CL_LACP_BYPASS_ALL_ACTIVE : 'IFLA_BOND_CL_LACP_BYPASS_ALL_ACTIVE'
2037 }
2038
2039 # =========================================
2040 # IFLA_INFO_DATA attributes for bridges
2041 # =========================================
2042 IFLA_BRPORT_UNSPEC = 0
2043 IFLA_BRPORT_STATE = 1
2044 IFLA_BRPORT_PRIORITY = 2
2045 IFLA_BRPORT_COST = 3
2046 IFLA_BRPORT_MODE = 4
2047 IFLA_BRPORT_GUARD = 5
2048 IFLA_BRPORT_PROTECT = 6
2049 IFLA_BRPORT_FAST_LEAVE = 7
2050 IFLA_BRPORT_LEARNING = 8
2051 IFLA_BRPORT_UNICAST_FLOOD = 9
2052 IFLA_BRPORT_PROXYARP = 10
2053 IFLA_BRPORT_LEARNING_SYNC = 11
2054 IFLA_BRPORT_PROXYARP_WIFI = 12
2055 IFLA_BRPORT_ROOT_ID = 13
2056 IFLA_BRPORT_BRIDGE_ID = 14
2057 IFLA_BRPORT_DESIGNATED_PORT = 15
2058 IFLA_BRPORT_DESIGNATED_COST = 16
2059 IFLA_BRPORT_ID = 17
2060 IFLA_BRPORT_NO = 18
2061 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19
2062 IFLA_BRPORT_CONFIG_PENDING = 20
2063 IFLA_BRPORT_MESSAGE_AGE_TIMER = 21
2064 IFLA_BRPORT_FORWARD_DELAY_TIMER = 22
2065 IFLA_BRPORT_HOLD_TIMER = 23
2066 IFLA_BRPORT_FLUSH = 24
2067 IFLA_BRPORT_MULTICAST_ROUTER = 25
2068 IFLA_BRPORT_PEER_LINK = 150
2069 IFLA_BRPORT_DUAL_LINK = 151
2070
2071 ifla_bridge_to_string = {
2072 IFLA_BRPORT_UNSPEC : 'IFLA_BRPORT_UNSPEC',
2073 IFLA_BRPORT_STATE : 'IFLA_BRPORT_STATE',
2074 IFLA_BRPORT_PRIORITY : 'IFLA_BRPORT_PRIORITY',
2075 IFLA_BRPORT_COST : 'IFLA_BRPORT_COST',
2076 IFLA_BRPORT_MODE : 'IFLA_BRPORT_MODE',
2077 IFLA_BRPORT_GUARD : 'IFLA_BRPORT_GUARD',
2078 IFLA_BRPORT_PROTECT : 'IFLA_BRPORT_PROTECT',
2079 IFLA_BRPORT_FAST_LEAVE : 'IFLA_BRPORT_FAST_LEAVE',
2080 IFLA_BRPORT_LEARNING : 'IFLA_BRPORT_LEARNING',
2081 IFLA_BRPORT_UNICAST_FLOOD : 'IFLA_BRPORT_UNICAST_FLOOD',
2082 IFLA_BRPORT_PROXYARP : 'IFLA_BRPORT_PROXYARP',
2083 IFLA_BRPORT_LEARNING_SYNC : 'IFLA_BRPORT_LEARNING_SYNC',
2084 IFLA_BRPORT_PROXYARP_WIFI : 'IFLA_BRPORT_PROXYARP_WIFI',
2085 IFLA_BRPORT_ROOT_ID : 'IFLA_BRPORT_ROOT_ID',
2086 IFLA_BRPORT_BRIDGE_ID : 'IFLA_BRPORT_BRIDGE_ID',
2087 IFLA_BRPORT_DESIGNATED_PORT : 'IFLA_BRPORT_DESIGNATED_PORT',
2088 IFLA_BRPORT_DESIGNATED_COST : 'IFLA_BRPORT_DESIGNATED_COST',
2089 IFLA_BRPORT_ID : 'IFLA_BRPORT_ID',
2090 IFLA_BRPORT_NO : 'IFLA_BRPORT_NO',
2091 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK : 'IFLA_BRPORT_TOPOLOGY_CHANGE_ACK',
2092 IFLA_BRPORT_CONFIG_PENDING : 'IFLA_BRPORT_CONFIG_PENDING',
2093 IFLA_BRPORT_MESSAGE_AGE_TIMER : 'IFLA_BRPORT_MESSAGE_AGE_TIMER',
2094 IFLA_BRPORT_FORWARD_DELAY_TIMER : 'IFLA_BRPORT_FORWARD_DELAY_TIMER',
2095 IFLA_BRPORT_HOLD_TIMER : 'IFLA_BRPORT_HOLD_TIMER',
2096 IFLA_BRPORT_FLUSH : 'IFLA_BRPORT_FLUSH',
2097 IFLA_BRPORT_MULTICAST_ROUTER : 'IFLA_BRPORT_MULTICAST_ROUTER',
2098 IFLA_BRPORT_PEER_LINK : 'IFLA_BRPORT_PEER_LINK',
2099 IFLA_BRPORT_DUAL_LINK : 'IFLA_BRPORT_DUAL_LINK'
2100 }
2101
2102 # BRIDGE IFLA_AF_SPEC attributes
2103 IFLA_BRIDGE_FLAGS = 0
2104 IFLA_BRIDGE_MODE = 1
2105 IFLA_BRIDGE_VLAN_INFO = 2
2106
2107 ifla_bridge_af_spec_to_string = {
2108 IFLA_BRIDGE_FLAGS : 'IFLA_BRIDGE_FLAGS',
2109 IFLA_BRIDGE_MODE : 'IFLA_BRIDGE_MODE',
2110 IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO'
2111 }
2112
2113 # BRIDGE_VLAN_INFO flags
2114 BRIDGE_VLAN_INFO_MASTER = 1
2115 BRIDGE_VLAN_INFO_PVID = 2
2116 BRIDGE_VLAN_INFO_UNTAGGED = 4
2117
2118 bridge_vlan_to_string = {
2119 BRIDGE_VLAN_INFO_MASTER : 'BRIDGE_VLAN_INFO_MASTER',
2120 BRIDGE_VLAN_INFO_PVID : 'BRIDGE_VLAN_INFO_PVID',
2121 BRIDGE_VLAN_INFO_UNTAGGED : 'BRIDGE_VLAN_INFO_UNTAGGED'
2122 }
2123
2124 # Bridge flags
2125 BRIDGE_FLAGS_MASTER = 1
2126 BRIDGE_FLAGS_SELF = 2
2127
2128 bridge_flags_to_string = {
2129 BRIDGE_FLAGS_MASTER : 'BRIDGE_FLAGS_MASTER',
2130 BRIDGE_FLAGS_SELF : 'BRIDGE_FLAGS_SELF'
2131 }
2132
2133 def __init__(self, msgtype, debug=False, logger=None):
2134 NetlinkPacket.__init__(self, msgtype, debug, logger)
2135 self.PACK = 'BxHiII'
2136 self.LEN = calcsize(self.PACK)
2137
2138 def get_link_type_string(self, index):
2139 return self.get_string(self.link_type_to_string, index)
2140
2141 def get_ifla_bridge_af_spec_to_string(self, index):
2142 return self.get_string(self.ifla_bridge_af_spec_to_string, index)
2143
2144 def get_ifla_info_string(self, index):
2145 return self.get_string(self.ifla_info_to_string, index)
2146
2147 def get_ifla_vlan_string(self, index):
2148 return self.get_string(self.ifla_vlan_to_string, index)
2149
2150 def get_ifla_vxlan_string(self, index):
2151 return self.get_string(self.ifla_vxlan_to_string, index)
2152
2153 def get_ifla_macvlan_string(self, index):
2154 return self.get_string(self.ifla_macvlan_to_string, index)
2155
2156 def get_macvlan_mode_string(self, index):
2157 return self.get_string(self.macvlan_mode_to_string, index)
2158
2159 def get_ifla_bond_string(self, index):
2160 return self.get_string(self.ifla_bond_to_string, index)
2161
2162 def get_ifla_bridge_string(self, index):
2163 return self.get_string(self.ifla_bridge_to_string, index)
2164
2165 def get_bridge_vlan_string(self, index):
2166 return self.get_string(self.bridge_vlan_to_string, index)
2167
2168 def get_bridge_flags_string(self, index):
2169 return self.get_string(self.bridge_flags_to_string, index)
2170
2171 def decode_service_header(self):
2172
2173 # Nothing to do if the message did not contain a service header
2174 if self.length == self.header_LEN:
2175 return
2176
2177 (self.family, self.device_type,
2178 self.ifindex,
2179 self.flags,
2180 self.change_mask) = \
2181 unpack(self.PACK, self.msg_data[:self.LEN])
2182
2183 if self.debug:
2184 color = yellow
2185 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
2186 for x in range(0, self.LEN/4):
2187 if self.line_number == 5:
2188 extra = "Family %s (%d), Device Type %s (%d - %s)" % \
2189 (zfilled_hex(self.family, 2), self.family,
2190 zfilled_hex(self.device_type, 4), self.device_type, self.get_link_type_string(self.device_type))
2191 elif self.line_number == 6:
2192 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
2193 elif self.line_number == 7:
2194 extra = "Device Flags %s (%s)" % (zfilled_hex(self.flags, 8), self.get_flags_string())
2195 elif self.line_number == 8:
2196 extra = "Change Mask %s" % zfilled_hex(self.change_mask, 8)
2197 else:
2198 extra = "Unexpected line number %d" % self.line_number
2199
2200 start = x * 4
2201 end = start + 4
2202 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2203 self.line_number += 1
2204
2205 def is_up(self):
2206 if self.flags & Link.IFF_UP:
2207 return True
2208 return False
2209
2210
2211class Neighbor(NetlinkPacket):
2212 """
2213 Service Header
2214
2215 0 1 2 3
2216 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2217 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2218 | Family | Reserved1 | Reserved2 |
2219 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2220 | Interface Index |
2221 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2222 | State | Flags | Type |
2223 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2224 """
2225
2226 # Neighbor attributes
2227 # /usr/include/linux/neighbour.h
2228 NDA_UNSPEC = 0x00 # Unknown type
2229 NDA_DST = 0x01 # A neighbour cache network. layer destination address
2230 NDA_LLADDR = 0x02 # A neighbor cache link layer address.
2231 NDA_CACHEINFO = 0x03 # Cache statistics
2232 NDA_PROBES = 0x04
2233 NDA_VLAN = 0x05
2234 NDA_PORT = 0x06
2235 NDA_VNI = 0x07
2236 NDA_IFINDEX = 0x08
2237 NDA_MASTER = 0x09
2238 NDA_LINK_NETNSID = 0x0A
2239
2240 attribute_to_class = {
2241 NDA_UNSPEC : ('NDA_UNSPEC', AttributeGeneric),
2242 NDA_DST : ('NDA_DST', AttributeIPAddress),
2243 NDA_LLADDR : ('NDA_LLADDR', AttributeMACAddress),
2244 NDA_CACHEINFO : ('NDA_CACHEINFO', AttributeGeneric),
2245 NDA_PROBES : ('NDA_PROBES', AttributeFourByteValue),
2246 NDA_VLAN : ('NDA_VLAN', AttributeGeneric),
2247 NDA_PORT : ('NDA_PORT', AttributeGeneric),
2248 NDA_VNI : ('NDA_VNI', AttributeGeneric),
2249 NDA_IFINDEX : ('NDA_IFINDEX', AttributeGeneric),
2250 NDA_MASTER : ('NDA_MASTER', AttributeGeneric),
2251 NDA_LINK_NETNSID : ('NDA_LINK_NETNSID', AttributeGeneric)
2252 }
2253
2254 # Neighbor flags
2255 # /usr/include/linux/neighbour.h
2256 NTF_USE = 0x01
2257 NTF_PROXY = 0x08 # A proxy ARP entry
2258 NTF_ROUTER = 0x80 # An IPv6 router
2259
2260 flag_to_string = {
2261 NTF_USE : 'NTF_USE',
2262 NTF_PROXY : 'NTF_PROXY',
2263 NTF_ROUTER : 'NTF_ROUTER'
2264 }
2265
2266 # Neighbor states
2267 # /usr/include/linux/neighbour.h
2268 NUD_NONE = 0x00
2269 NUD_INCOMPLETE = 0x01 # Still attempting to resolve
2270 NUD_REACHABLE = 0x02 # A confirmed working cache entry
2271 NUD_STALE = 0x04 # an expired cache entry
2272 NUD_DELAY = 0x08 # Neighbor no longer reachable. Traffic sent, waiting for confirmatio.
2273 NUD_PROBE = 0x10 # A cache entry that is currently being re-solicited
2274 NUD_FAILED = 0x20 # An invalid cache entry
2275 NUD_NOARP = 0x40 # A device which does not do neighbor discovery(ARP)
2276 NUD_PERMANENT = 0x80 # A static entry
2277
2278 state_to_string = {
2279 NUD_NONE : 'NUD_NONE',
2280 NUD_INCOMPLETE : 'NUD_INCOMPLETE',
2281 NUD_REACHABLE : 'NUD_REACHABLE',
2282 NUD_STALE : 'NUD_STALE',
2283 NUD_DELAY : 'NUD_DELAY',
2284 NUD_PROBE : 'NUD_PROBE',
2285 NUD_FAILED : 'NUD_FAILED',
2286 NUD_NOARP : 'NUD_NOARP',
2287 NUD_PERMANENT : 'NUD_PERMANENT'
2288 }
2289
2290 def __init__(self, msgtype, debug=False, logger=None):
2291 NetlinkPacket.__init__(self, msgtype, debug, logger)
2292 self.PACK = 'BxxxiHBB'
2293 self.LEN = calcsize(self.PACK)
2294
2295 def get_state_string(self, index):
2296 return self.get_string(self.state_to_string, index)
2297
2298 def decode_service_header(self):
2299
2300 # Nothing to do if the message did not contain a service header
2301 if self.length == self.header_LEN:
2302 return
2303
2304 (self.family,
2305 self.ifindex,
2306 self.state, self.flags, self.neighbor_type) = \
2307 unpack(self.PACK, self.msg_data[:self.LEN])
2308
2309 if self.debug:
2310 color = yellow
2311 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
2312
2313 for x in range(0, self.LEN/4):
2314 if self.line_number == 5:
2315 extra = "Family %s (%d)" % (zfilled_hex(self.family, 2), self.family)
2316 elif self.line_number == 6:
2317 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
2318 elif self.line_number == 7:
2319 extra = "State %s (%d), Flags %s, Type %s (%d)" % \
2320 (zfilled_hex(self.state, 4), self.state,
2321 zfilled_hex(self.flags, 2),
2322 zfilled_hex(self.neighbor_type, 4), self.neighbor_type)
2323 else:
2324 extra = "Unexpected line number %d" % self.line_number
2325
2326 start = x * 4
2327 end = start + 4
2328 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2329 self.line_number += 1
2330
2331
2332class Route(NetlinkPacket):
2333 """
2334 Service Header
2335
2336 0 1 2 3
2337 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
2338 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2339 | Family | Dest length | Src length | TOS |
2340 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2341 | Table ID | Protocol | Scope | Type |
2342 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2343 | Flags |
2344 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2345 """
2346
2347 # Route attributes
2348 # /usr/include/linux/rtnetlink.h
2349 RTA_UNSPEC = 0x00 # Ignored.
2350 RTA_DST = 0x01 # Protocol address for route destination address.
2351 RTA_SRC = 0x02 # Protocol address for route source address.
2352 RTA_IIF = 0x03 # Input interface index.
2353 RTA_OIF = 0x04 # Output interface index.
2354 RTA_GATEWAY = 0x05 # Protocol address for the gateway of the route
2355 RTA_PRIORITY = 0x06 # Priority of broker.
2356 RTA_PREFSRC = 0x07 # Preferred source address in cases where more than one source address could be used.
2357 RTA_METRICS = 0x08 # Route metrics attributed to route and associated protocols(e.g., RTT, initial TCP window, etc.).
2358 RTA_MULTIPATH = 0x09 # Multipath route next hop's attributes.
2359 RTA_PROTOINFO = 0x0A # Firewall based policy routing attribute.
2360 RTA_FLOW = 0x0B # Route realm.
2361 RTA_CACHEINFO = 0x0C # Cached route information.
2362 RTA_SESSION = 0x0D
2363 RTA_MP_ALGO = 0x0E
2364 RTA_TABLE = 0x0F
2365 RTA_MARK = 0x10
2366
2367 attribute_to_class = {
2368 RTA_UNSPEC : ('RTA_UNSPEC', AttributeGeneric),
2369 RTA_DST : ('RTA_DST', AttributeIPAddress),
2370 RTA_SRC : ('RTA_SRC', AttributeIPAddress),
2371 RTA_IIF : ('RTA_IIF', AttributeFourByteValue),
2372 RTA_OIF : ('RTA_OIF', AttributeFourByteValue),
2373 RTA_GATEWAY : ('RTA_GATEWAY', AttributeIPAddress),
2374 RTA_PRIORITY : ('RTA_PRIORITY', AttributeFourByteValue),
2375 RTA_PREFSRC : ('RTA_PREFSRC', AttributeIPAddress),
2376 RTA_METRICS : ('RTA_METRICS', AttributeGeneric),
2377 RTA_MULTIPATH : ('RTA_MULTIPATH', AttributeRTA_MULTIPATH),
2378 RTA_PROTOINFO : ('RTA_PROTOINFO', AttributeGeneric),
2379 RTA_FLOW : ('RTA_FLOW', AttributeGeneric),
2380 RTA_CACHEINFO : ('RTA_CACHEINFO', AttributeGeneric),
2381 RTA_SESSION : ('RTA_SESSION', AttributeGeneric),
2382 RTA_MP_ALGO : ('RTA_MP_ALGO', AttributeGeneric),
2383 RTA_TABLE : ('RTA_TABLE', AttributeFourByteValue),
2384 RTA_MARK : ('RTA_MARK', AttributeGeneric)
2385 }
2386
2387 # Route tables
2388 # /usr/include/linux/rtnetlink.h
2389 RT_TABLE_UNSPEC = 0x00 # An unspecified routing table
2390 RT_TABLE_COMPAT = 0xFC
2391 RT_TABLE_DEFAULT = 0xFD # The default table
2392 RT_TABLE_MAIN = 0xFE # The main table
2393 RT_TABLE_LOCAL = 0xFF # The local table
2394
2395 table_to_string = {
2396 RT_TABLE_UNSPEC : 'RT_TABLE_UNSPEC',
2397 RT_TABLE_COMPAT : 'RT_TABLE_COMPAT',
2398 RT_TABLE_DEFAULT : 'RT_TABLE_DEFAULT',
2399 RT_TABLE_MAIN : 'RT_TABLE_MAIN',
2400 RT_TABLE_LOCAL : 'RT_TABLE_LOCAL'
2401 }
2402
2403 # Route scope
2404 # /usr/include/linux/rtnetlink.h
2405 RT_SCOPE_UNIVERSE = 0x00 # Global route
2406 RT_SCOPE_SITE = 0xC8 # Interior route in the local autonomous system
2407 RT_SCOPE_LINK = 0xFD # Route on this link
2408 RT_SCOPE_HOST = 0xFE # Route on the local host
2409 RT_SCOPE_NOWHERE = 0xFF # Destination does not exist
2410
2411 scope_to_string = {
2412 RT_SCOPE_UNIVERSE : 'RT_SCOPE_UNIVERSE',
2413 RT_SCOPE_SITE : 'RT_SCOPE_SITE',
2414 RT_SCOPE_LINK : 'RT_SCOPE_LINK',
2415 RT_SCOPE_HOST : 'RT_SCOPE_HOST',
2416 RT_SCOPE_NOWHERE : 'RT_SCOPE_NOWHERE'
2417 }
2418
2419 # Routing stack
2420 # /usr/include/linux/rtnetlink.h
2421 RT_PROT_UNSPEC = 0x00 # Identifies what/who added the route
2422 RT_PROT_REDIRECT = 0x01 # By an ICMP redirect
2423 RT_PROT_KERNEL = 0x02 # By the kernel
2424 RT_PROT_BOOT = 0x03 # During bootup
2425 RT_PROT_STATIC = 0x04 # By the administrator
2426 RT_PROT_GATED = 0x08 # GateD
2427 RT_PROT_RA = 0x09 # RDISC/ND router advertissements
2428 RT_PROT_MRT = 0x0A # Merit MRT
2429 RT_PROT_ZEBRA = 0x0B # ZEBRA
2430 RT_PROT_BIRD = 0x0C # BIRD
2431 RT_PROT_DNROUTED = 0x0D # DECnet routing daemon
2432 RT_PROT_XORP = 0x0E # XORP
2433 RT_PROT_NTK = 0x0F # Netsukuku
2434 RT_PROT_DHCP = 0x10 # DHCP client
2435 RT_PROT_EXABGP = 0x11 # Exa Networks ExaBGP
2436
2437 prot_to_string = {
2438 RT_PROT_UNSPEC : 'RT_PROT_UNSPEC',
2439 RT_PROT_REDIRECT : 'RT_PROT_REDIRECT',
2440 RT_PROT_KERNEL : 'RT_PROT_KERNEL',
2441 RT_PROT_BOOT : 'RT_PROT_BOOT',
2442 RT_PROT_STATIC : 'RT_PROT_STATIC',
2443 RT_PROT_GATED : 'RT_PROT_GATED',
2444 RT_PROT_RA : 'RT_PROT_RA',
2445 RT_PROT_MRT : 'RT_PROT_MRT',
2446 RT_PROT_ZEBRA : 'RT_PROT_ZEBRA',
2447 RT_PROT_BIRD : 'RT_PROT_BIRD',
2448 RT_PROT_DNROUTED : 'RT_PROT_DNROUTED',
2449 RT_PROT_XORP : 'RT_PROT_XORP',
2450 RT_PROT_NTK : 'RT_PROT_NTK',
2451 RT_PROT_DHCP : 'RT_PROT_DHCP',
2452 RT_PROT_EXABGP : 'RT_PROT_EXABGP'
2453 }
2454
2455 # Route types
2456 # /usr/include/linux/rtnetlink.h
2457 RTN_UNSPEC = 0x00 # Unknown broker.
2458 RTN_UNICAST = 0x01 # A gateway or direct broker.
2459 RTN_LOCAL = 0x02 # A local interface broker.
2460 RTN_BROADCAST = 0x03 # A local broadcast route(sent as a broadcast).
2461 RTN_ANYCAST = 0x04 # An anycast broker.
2462 RTN_MULTICAST = 0x05 # A multicast broker.
2463 RTN_BLACKHOLE = 0x06 # A silent packet dropping broker.
2464 RTN_UNREACHABLE = 0x07 # An unreachable destination. Packets dropped and
2465 # host unreachable ICMPs are sent to the originator.
2466 RTN_PROHIBIT = 0x08 # A packet rejection broker. Packets are dropped and
2467 # communication prohibited ICMPs are sent to the originator.
2468 RTN_THROW = 0x09 # When used with policy routing, continue routing lookup
2469 # in another table. Under normal routing, packets are
2470 # dropped and net unreachable ICMPs are sent to the originator.
2471 RTN_NAT = 0x0A # A network address translation rule.
2472 RTN_XRESOLVE = 0x0B # Refer to an external resolver(not implemented).
2473
2474 rt_type_to_string = {
2475 RTN_UNSPEC : 'RTN_UNSPEC',
2476 RTN_UNICAST : 'RTN_UNICAST',
2477 RTN_LOCAL : 'RTN_LOCAL',
2478 RTN_BROADCAST : 'RTN_BROADCAST',
2479 RTN_ANYCAST : 'RTN_ANYCAST',
2480 RTN_MULTICAST : 'RTN_MULTICAST',
2481 RTN_BLACKHOLE : 'RTN_BLACKHOLE',
2482 RTN_UNREACHABLE : 'RTN_UNREACHABLE',
2483 RTN_PROHIBIT : 'RTN_PROHIBIT',
2484 RTN_THROW : 'RTN_THROW',
2485 RTN_NAT : 'RTN_NAT',
2486 RTN_XRESOLVE : 'RTN_XRESOLVE'
2487 }
2488
2489 # Route flags
2490 # /usr/include/linux/rtnetlink.h
2491 RTM_F_NOTIFY = 0x100 # If the route changes, notify the user
2492 RTM_F_CLONED = 0x200 # Route is cloned from another route
2493 RTM_F_EQUALIZE = 0x400 # Allow randomization of next hop path in multi-path routing(currently not implemented)
2494 RTM_F_PREFIX = 0x800 # Prefix Address
2495
2496 flag_to_string = {
2497 RTM_F_NOTIFY : 'RTM_F_NOTIFY',
2498 RTM_F_CLONED : 'RTM_F_CLONED',
2499 RTM_F_EQUALIZE : 'RTM_F_EQUALIZE',
2500 RTM_F_PREFIX : 'RTM_F_PREFIX'
2501 }
2502
2503 def __init__(self, msgtype, debug=False, logger=None):
2504 NetlinkPacket.__init__(self, msgtype, debug, logger)
2505 self.PACK = '=8BI' # or is it 8Bi ?
2506 self.LEN = calcsize(self.PACK)
2507 self.family = None
2508
2509 def get_prefix_string(self):
2510 dst = self.get_attribute_value(self.RTA_DST)
2511
2512 if dst:
2513 return "%s/%d" % (dst, self.src_len)
2514 else:
2515 if self.family == AF_INET:
2516 return "0.0.0.0/0"
2517 elif self.family == AF_INET6:
2518 return "::/0"
2519
2520 def get_protocol_string(self, index=None):
2521 if index is None:
2522 index = self.protocol
2523 return self.get_string(self.prot_to_string, index)
2524
2525 def get_rt_type_string(self, index=None):
2526 if index is None:
2527 index = self.route_type
2528 return self.get_string(self.rt_type_to_string, index)
2529
2530 def get_scope_string(self, index=None):
2531 if index is None:
2532 index = self.scope
2533 return self.get_string(self.scope_to_string, index)
2534
2535 def get_table_id_string(self, index=None):
2536 if index is None:
2537 index = self.table_id
2538 return self.get_string(self.table_to_string, index)
2539
2540 def _get_ifname_from_index(self, ifindex, ifname_by_index):
2541 if ifindex:
2542 ifname = ifname_by_index.get(ifindex)
2543
2544 if ifname is None:
2545 ifname = str(ifindex)
2546 else:
2547 ifname = None
2548
2549 return ifname
2550
2551 def get_nexthops(self, ifname_by_index={}):
2552 nexthop = self.get_attribute_value(self.RTA_GATEWAY)
2553 multipath = self.get_attribute_value(self.RTA_MULTIPATH)
2554 nexthops = []
2555
2556 if nexthop:
2557 rta_oif = self.get_attribute_value(self.RTA_OIF)
2558 ifname = self._get_ifname_from_index(rta_oif, ifname_by_index)
2559 nexthops.append((nexthop, ifname))
2560
2561 elif multipath:
2562 for (nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops) in multipath:
2563 ifname = self._get_ifname_from_index(rtnh_ifindex, ifname_by_index)
2564 nexthops.append((nexthop, ifname))
2565
2566 return nexthops
2567
2568 def get_nexthops_string(self, ifname_by_index={}):
2569 output = []
2570
2571 for (nexthop, ifname) in self.get_nexthops(ifname_by_index):
2572 output.append(" via %s on %s" % (nexthop, ifname))
2573
2574 return ",".join(output)
2575
2576 def decode_service_header(self):
2577
2578 # Nothing to do if the message did not contain a service header
2579 if self.length == self.header_LEN:
2580 return
2581
2582 (self.family, self.src_len, self.dst_len, self.tos,
2583 self.table_id, self.protocol, self.scope, self.route_type,
2584 self.flags) = \
2585 unpack(self.PACK, self.msg_data[:self.LEN])
2586
2587 if self.debug:
2588 color = yellow
2589 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
2590
2591 for x in range(0, self.LEN/4):
2592 if self.line_number == 5:
2593 extra = "Family %s (%d), Source Length %s (%d), Destination Length %s (%d), TOS %s (%d)" % \
2594 (zfilled_hex(self.family, 2), self.family,
2595 zfilled_hex(self.src_len, 2), self.src_len,
2596 zfilled_hex(self.dst_len, 2), self.dst_len,
2597 zfilled_hex(self.tos, 2), self.tos)
2598 elif self.line_number == 6:
2599 extra = "Table ID %s (%d - %s), Protocol %s (%d - %s), Scope %s (%d - %s), Type %s (%d - %s)" % \
2600 (zfilled_hex(self.table_id, 2), self.table_id, self.get_table_id_string(),
2601 zfilled_hex(self.protocol, 2), self.protocol, self.get_protocol_string(),
2602 zfilled_hex(self.scope, 2), self.scope, self.get_scope_string(),
2603 zfilled_hex(self.route_type, 2), self.route_type, self.get_rt_type_string())
2604 elif self.line_number == 7:
2605 extra = "Flags %s" % zfilled_hex(self.flags, 8)
2606 else:
2607 extra = "Unexpected line number %d" % self.line_number
2608
2609 start = x * 4
2610 end = start + 4
2611 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2612 self.line_number += 1