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