]> git.proxmox.com Git - mirror_ifupdown2.git/blame - ifupdown2/nlmanager/nlpacket.py
config: local addons modules should be loaded first
[mirror_ifupdown2.git] / ifupdown2 / nlmanager / nlpacket.py
CommitLineData
198ded6a
JF
1# Copyright (c) 2009-2013, Exa Networks Limited
2# Copyright (c) 2009-2013, Thomas Mangin
d486dd0d 3# Copyright (c) 2015-2017 Cumulus Networks, Inc.
198ded6a
JF
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
c4fd4972 33from ipaddr import IPv4Address, IPv6Address, IPAddress
198ded6a
JF
34from binascii import hexlify
35from pprint import pformat
d486dd0d 36from socket import AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE, htons
198ded6a
JF
37from string import printable
38from struct import pack, unpack, calcsize
39
40log = logging.getLogger(__name__)
d486dd0d
JF
41SYSLOG_EXTRA_DEBUG = 5
42
198ded6a 43
4e979b1b
JF
44# Interface name buffer size #define IFNAMSIZ 16 (kernel source)
45IF_NAME_SIZE = 15 # 15 because python doesn't have \0
46
198ded6a
JF
47# Netlink message types
48NLMSG_NOOP = 0x01
49NLMSG_ERROR = 0x02
50NLMSG_DONE = 0x03
51NLMSG_OVERRUN = 0x04
52
53RTM_NEWLINK = 0x10 # Create a new network interface
54RTM_DELLINK = 0x11 # Destroy a network interface
55RTM_GETLINK = 0x12 # Retrieve information about a network interface(ifinfomsg)
56RTM_SETLINK = 0x13 #
57
58RTM_NEWADDR = 0x14
59RTM_DELADDR = 0x15
60RTM_GETADDR = 0x16
61
62RTM_NEWNEIGH = 0x1C
63RTM_DELNEIGH = 0x1D
64RTM_GETNEIGH = 0x1E
65
66RTM_NEWROUTE = 0x18
67RTM_DELROUTE = 0x19
68RTM_GETROUTE = 0x1A
69
70RTM_NEWQDISC = 0x24
71RTM_DELQDISC = 0x25
72RTM_GETQDISC = 0x26
73
3479a0c3
JF
74RTM_NEWNETCONF = 80
75RTM_GETNETCONF = 82
76
198ded6a
JF
77# Netlink message flags
78NLM_F_REQUEST = 0x01 # It is query message.
79NLM_F_MULTI = 0x02 # Multipart message, terminated by NLMSG_DONE
80NLM_F_ACK = 0x04 # Reply with ack, with zero or error code
81NLM_F_ECHO = 0x08 # Echo this query
82
83# Modifiers to GET query
84NLM_F_ROOT = 0x100 # specify tree root
85NLM_F_MATCH = 0x200 # return all matching
86NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
87NLM_F_ATOMIC = 0x400 # atomic GET
88
89# Modifiers to NEW query
90NLM_F_REPLACE = 0x100 # Override existing
91NLM_F_EXCL = 0x200 # Do not touch, if it exists
92NLM_F_CREATE = 0x400 # Create, if it does not exist
93NLM_F_APPEND = 0x800 # Add to end of list
94
95NLA_F_NESTED = 0x8000
96NLA_F_NET_BYTEORDER = 0x4000
97NLA_TYPE_MASK = ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
98
99# Groups
100RTMGRP_LINK = 0x1
101RTMGRP_NOTIFY = 0x2
102RTMGRP_NEIGH = 0x4
103RTMGRP_TC = 0x8
104RTMGRP_IPV4_IFADDR = 0x10
105RTMGRP_IPV4_MROUTE = 0x20
106RTMGRP_IPV4_ROUTE = 0x40
107RTMGRP_IPV4_RULE = 0x80
108RTMGRP_IPV6_IFADDR = 0x100
109RTMGRP_IPV6_MROUTE = 0x200
110RTMGRP_IPV6_ROUTE = 0x400
111RTMGRP_IPV6_IFINFO = 0x800
112RTMGRP_DECnet_IFADDR = 0x1000
113RTMGRP_DECnet_ROUTE = 0x4000
114RTMGRP_IPV6_PREFIX = 0x20000
115
116RTMGRP_ALL = (RTMGRP_LINK | RTMGRP_NOTIFY | RTMGRP_NEIGH | RTMGRP_TC |
117 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_MROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE |
118 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO |
119 RTMGRP_DECnet_IFADDR | RTMGRP_DECnet_ROUTE |
120 RTMGRP_IPV6_PREFIX)
121
d486dd0d
JF
122AF_MPLS = 28
123
4d4aac88
JF
124
125AF_FAMILY = dict()
126
127import socket
128
129for family in [attr for attr in dir(socket) if attr.startswith('AF_')]:
130 AF_FAMILY[getattr(socket, family)] = family
131
132AF_FAMILY[AF_MPLS] = 'AF_MPLS'
133
134
135def get_family_str(family):
136 return AF_FAMILY.get(family, 'UNKNOWN')
137
198ded6a
JF
138# Colors for logging
139red = 91
140green = 92
141yellow = 93
142blue = 94
143
d486dd0d
JF
144value_to_bool_dict = {
145 False: False,
146 None: False,
147 0: False,
148 '0': False,
149 'no': False,
150 'off': False,
151 'slow': False,
152 'None': False,
153 True: True,
154 1: True,
155 '1': True,
156 'on': True,
157 'yes': True,
158 'fast': True
159}
711d7575 160
d486dd0d
JF
161
162def set_log_level(level):
163 log.setLevel(level)
711d7575 164
198ded6a
JF
165
166def zfilled_hex(value, digits):
167 return '0x' + hex(value)[2:].zfill(digits)
168
169
170def remove_trailing_null(line):
171 """
172 Remove the last character if it is a NULL...having that NULL
173 causes python to print a garbage character
174 """
175
176 if ord(line[-1]) == 0:
177 line = line[:-1]
178
179 return line
180
181
182def mac_int_to_str(mac_int):
183 """
184 Return an integer in MAC string format
185 """
186
187 # [2:] to remove the leading 0x, then fill out to 12 zeroes, then uppercase
188 all_caps = hex(int(mac_int))[2:].zfill(12).upper()
189
190 if all_caps[-1] == 'L':
191 all_caps = all_caps[:-1]
192 all_caps = all_caps.zfill(12).upper()
193
194 return "%s.%s.%s" % (all_caps[0:4], all_caps[4:8], all_caps[8:12])
195
196
197def data_to_color_text(line_number, color, data, extra=''):
198 (c1, c2, c3, c4) = unpack('BBBB', data[0:4])
199 in_ascii = []
200
201 for c in (c1, c2, c3, c4):
202 char_c = chr(c)
203
204 if char_c in printable[:-5]:
205 in_ascii.append(char_c)
206 else:
207 in_ascii.append('.')
208
a61d1777
SE
209 if color:
210 return ' %2d: \033[%dm0x%02x%02x%02x%02x\033[0m %s %s' % (line_number, color, c1, c2, c3, c4, ''.join(in_ascii), extra)
211
212 return ' %2d: 0x%02x%02x%02x%02x %s %s' % (line_number, c1, c2, c3, c4, ''.join(in_ascii), extra)
198ded6a
JF
213
214
215def padded_length(length):
216 return int((length + 3) / 4) * 4
217
218
219class Attribute(object):
220
221 def __init__(self, atype, string, logger):
222 self.atype = atype
223 self.string = string
224 self.HEADER_PACK = '=HH'
225 self.HEADER_LEN = calcsize(self.HEADER_PACK)
226 self.PACK = None
227 self.LEN = None
228 self.value = None
229 self.nested = False
230 self.net_byteorder = False
231 self.log = logger
232
233 def __str__(self):
234 return self.string
235
4e979b1b
JF
236 def set_value(self, value):
237 self.value = value
238
239 def set_nested(self, nested):
240 self.nested = nested
241
242 def set_net_byteorder(self, net_byteorder):
243 self.net_byteorder = net_byteorder
244
198ded6a
JF
245 def pad_bytes_needed(self, length):
246 """
247 Return the number of bytes that should be added to align on a 4-byte boundry
248 """
249 remainder = length % 4
250
251 if remainder:
252 return 4 - remainder
253
254 return 0
255
256 def pad(self, length, raw):
257 pad = self.pad_bytes_needed(length)
258
259 if pad:
260 raw += '\0' * pad
261
262 return raw
263
264 def encode(self):
26e7207b
JF
265
266 if not self.LEN:
267 raise Exception('Please define an encode() method in your child attribute class, or do not use AttributeGeneric')
268
198ded6a
JF
269 length = self.HEADER_LEN + self.LEN
270 attr_type_with_flags = self.atype
271
272 if self.nested:
273 attr_type_with_flags = attr_type_with_flags | NLA_F_NESTED
274
275 if self.net_byteorder:
276 attr_type_with_flags = attr_type_with_flags | NLA_F_NET_BYTEORDER
277
278 raw = pack(self.HEADER_PACK, length, attr_type_with_flags) + pack(self.PACK, self.value)
279 raw = self.pad(length, raw)
280 return raw
281
282 def decode_length_type(self, data):
283 """
284 The first two bytes of an attribute are the length, the next two bytes are the type
285 """
286 self.data = data
287 prev_atype = self.atype
288 (data1, data2) = unpack(self.HEADER_PACK, data[:self.HEADER_LEN])
289 self.length = int(data1)
290 self.atype = int(data2)
291 self.attr_end = padded_length(self.length)
292
293 self.nested = True if self.atype & NLA_F_NESTED else False
294 self.net_byteorder = True if self.atype & NLA_F_NET_BYTEORDER else False
295 self.atype = self.atype & NLA_TYPE_MASK
296
297 # Should never happen
298 assert self.atype == prev_atype, "This object changes attribute type from %d to %d, this is bad" % (prev_atype, self.atype)
299
300 def dump_first_line(self, dump_buffer, line_number, color):
301 """
302 Add the "Length....Type..." line to the dump buffer
303 """
304 if self.attr_end == self.length:
305 padded_to = ', '
306 else:
307 padded_to = ' padded to %d, ' % self.attr_end
308
309 extra = 'Length %s (%d)%sType %s%s%s (%d) %s' % \
310 (zfilled_hex(self.length, 4), self.length,
311 padded_to,
312 zfilled_hex(self.atype, 4),
313 " (NLA_F_NESTED set)" if self.nested else "",
314 " (NLA_F_NET_BYTEORDER set)" if self.net_byteorder else "",
315 self.atype,
316 self)
317
318 dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], extra))
319 return line_number + 1
320
321 def dump_lines(self, dump_buffer, line_number, color):
322 line_number = self.dump_first_line(dump_buffer, line_number, color)
323
324 for x in xrange(1, self.attr_end/4):
325 start = x * 4
326 end = start + 4
327 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], ''))
328 line_number += 1
329
330 return line_number
331
d486dd0d
JF
332 def get_pretty_value(self, obj=None):
333 if obj and callable(obj):
334 return obj(self.value)
198ded6a
JF
335 return self.value
336
337
9f25ff0d
SE
338class AttributeFourByteList(Attribute):
339
340 def __init__(self, atype, string, family, logger):
341 Attribute.__init__(self, atype, string, logger)
342
343 def decode(self, parent_msg, data):
344 self.decode_length_type(data)
345 wordcount = (self.attr_end - 4)/4
346 self.PACK = '=%dL' % wordcount
347 self.LEN = calcsize(self.PACK)
348
349 try:
350 self.value = unpack(self.PACK, self.data[4:])
351 except struct.error:
352 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
353 raise
354
355 def dump_lines(self, dump_buffer, line_number, color):
356 line_number = self.dump_first_line(dump_buffer, line_number, color)
357 idx = 1
358 for val in self.value:
359 dump_buffer.append(data_to_color_text(line_number, color, self.data[4*idx:4*(idx+1)], val))
360 line_number += 1
361 idx += 1
362 return line_number
363
364
198ded6a
JF
365class AttributeFourByteValue(Attribute):
366
9f25ff0d 367 def __init__(self, atype, string, family, logger):
198ded6a
JF
368 Attribute.__init__(self, atype, string, logger)
369 self.PACK = '=L'
370 self.LEN = calcsize(self.PACK)
371
372 def decode(self, parent_msg, data):
373 self.decode_length_type(data)
374 assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
375
376 try:
377 self.value = int(unpack(self.PACK, self.data[4:])[0])
378 except struct.error:
379 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
380 raise
381
382 def dump_lines(self, dump_buffer, line_number, color):
383 line_number = self.dump_first_line(dump_buffer, line_number, color)
384 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
385 return line_number + 1
386
387
9f25ff0d
SE
388class AttributeTwoByteValue(Attribute):
389
390 def __init__(self, atype, string, family, logger):
391 Attribute.__init__(self, atype, string, logger)
392 self.PACK = '=Hxx'
393 self.LEN = calcsize(self.PACK)
394
395 def decode(self, parent_msg, data):
396 self.decode_length_type(data)
397 assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
398
399 try:
400 self.value = int(unpack(self.PACK, self.data[4:8])[0])
401 except struct.error:
402 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:6])))
403 raise
404
405 def encode(self):
406 length = self.HEADER_LEN + self.LEN
407 raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, self.value)
408 raw = self.pad(length, raw)
409 return raw
410
411 def dump_lines(self, dump_buffer, line_number, color):
412 line_number = self.dump_first_line(dump_buffer, line_number, color)
413 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
414 return line_number + 1
415
416
198ded6a
JF
417class AttributeString(Attribute):
418
9f25ff0d 419 def __init__(self, atype, string, family, logger):
198ded6a
JF
420 Attribute.__init__(self, atype, string, logger)
421 self.PACK = None
422 self.LEN = None
423
424 def encode(self):
26d1e82b 425 # some interface names come from JSON as unicode strings
198ded6a
JF
426 # and cannot be packed as is so we must convert them to strings
427 if isinstance(self.value, unicode):
428 self.value = str(self.value)
429 self.PACK = '%ds' % len(self.value)
430 self.LEN = calcsize(self.PACK)
431
432 length = self.HEADER_LEN + self.LEN
433 raw = pack(self.HEADER_PACK, length, self.atype) + pack(self.PACK, self.value)
434 raw = self.pad(length, raw)
435 return raw
436
437 def decode(self, parent_msg, data):
438 self.decode_length_type(data)
439 self.PACK = '%ds' % (self.length - 4)
440 self.LEN = calcsize(self.PACK)
441
442 try:
443 self.value = remove_trailing_null(unpack(self.PACK, self.data[4:self.length])[0])
444 except struct.error:
445 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:self.length])))
446 raise
447
448
4e979b1b
JF
449class AttributeStringInterfaceName(AttributeString):
450
9f25ff0d
SE
451 def __init__(self, atype, string, family, logger):
452 AttributeString.__init__(self, atype, string, family, logger)
4e979b1b
JF
453
454 def set_value(self, value):
455 if value and len(value) > IF_NAME_SIZE:
456 raise Exception('interface name exceeds max length of %d' % IF_NAME_SIZE)
457 self.value = value
458
459
198ded6a
JF
460class AttributeIPAddress(Attribute):
461
462 def __init__(self, atype, string, family, logger):
463 Attribute.__init__(self, atype, string, logger)
464 self.value_int = None
465 self.value_int_str = None
466 self.family = family
467
468 if self.family == AF_INET:
469 self.PACK = '>L'
470
471 elif self.family == AF_INET6:
472 self.PACK = '>QQ'
473
474 elif self.family == AF_BRIDGE:
475 self.PACK = '>L'
476
477 else:
478 raise Exception("%s is not a supported address family" % self.family)
479
480 self.LEN = calcsize(self.PACK)
481
c4fd4972
JF
482 def set_value(self, value):
483 if value is None:
484 self.value = None
485 else:
486 self.value = IPAddress(value)
487
198ded6a
JF
488 def decode(self, parent_msg, data):
489 self.decode_length_type(data)
490
491 try:
492 if self.family == AF_INET:
493 self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0])
494
495 elif self.family == AF_INET6:
496 (data1, data2) = unpack(self.PACK, self.data[4:])
497 self.value = IPv6Address(data1 << 64 | data2)
498
499 elif self.family == AF_BRIDGE:
9f25ff0d 500 self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0])
198ded6a
JF
501
502 self.value_int = int(self.value)
503 self.value_int_str = str(self.value_int)
504
505 except struct.error:
506 self.value = None
507 self.value_int = None
508 self.value_int_str = None
509 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
510 raise
511
9f25ff0d
SE
512 def encode(self):
513 length = self.HEADER_LEN + self.LEN
514
515 if self.family not in [AF_INET, AF_INET6, AF_BRIDGE]:
516 raise Exception("%s is not a supported address family" % self.family)
517
518 raw = pack(self.HEADER_PACK, length, self.atype) + self.value.packed
519 raw = self.pad(length, raw)
520 return raw
521
198ded6a
JF
522 def dump_lines(self, dump_buffer, line_number, color):
523 line_number = self.dump_first_line(dump_buffer, line_number, color)
524
525 if self.family == AF_INET:
526 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
527 line_number += 1
528
529 elif self.family == AF_INET6:
530
531 for x in xrange(1, self.attr_end/4):
532 start = x * 4
533 end = start + 4
534 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], self.value))
535 line_number += 1
536
537 elif self.family == AF_BRIDGE:
538 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
539 line_number += 1
540
541 return line_number
542
543
544class AttributeMACAddress(Attribute):
545
9f25ff0d 546 def __init__(self, atype, string, family, logger):
198ded6a
JF
547 Attribute.__init__(self, atype, string, logger)
548 self.PACK = '>LHxx'
549 self.LEN = calcsize(self.PACK)
550
551 def decode(self, parent_msg, data):
552 self.decode_length_type(data)
53747c55
JF
553
554 # IFLA_ADDRESS and IFLA_BROADCAST attributes for all interfaces has been a
555 # 6-byte MAC address. But the GRE interface uses a 4-byte IP address and
556 # GREv6 uses a 16-byte IPv6 address for this attribute.
198ded6a 557 try:
53747c55 558 # GRE interface uses a 4-byte IP address for this attribute
08862a99
SA
559 if self.length == 8:
560 self.value = IPv4Address(unpack('>L', self.data[4:])[0])
561 self.value_int = int(self.value)
562 self.value_int_str = str(self.value_int)
53747c55 563 # MAC Address
08862a99 564 elif self.length == 10:
abd9194b
SE
565 (data1, data2) = unpack(self.PACK, self.data[4:])
566 self.value = mac_int_to_str(data1 << 16 | data2)
08862a99
SA
567 # GREv6 interface uses a 16-byte IP address for this attribute
568 elif self.length == 20:
569 self.value = IPv6Address(unpack('>L', self.data[16:])[0])
abd9194b
SE
570 self.value_int = int(self.value)
571 self.value_int_str = str(self.value_int)
572 else:
573 raise Exception("Length of MACAddress attribute not supported: %d" % self.length)
198ded6a
JF
574
575 except struct.error:
576 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
577 raise
578
579 def encode(self):
580 length = self.HEADER_LEN + self.LEN
581 mac_raw = int(self.value.replace('.', '').replace(':', ''), 16)
9f25ff0d 582 raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, mac_raw >> 16, mac_raw & 0x0000FFFF)
198ded6a
JF
583 raw = self.pad(length, raw)
584 return raw
585
586 def dump_lines(self, dump_buffer, line_number, color):
587 line_number = self.dump_first_line(dump_buffer, line_number, color)
588 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
abd9194b
SE
589 line_number += 1
590 if len(self.data) >= 12:
591 dump_buffer.append(data_to_color_text(line_number, color, self.data[8:12]))
592 line_number += 1
593 return line_number
198ded6a
JF
594
595
d486dd0d
JF
596class AttributeMplsLabel(Attribute):
597
598 def __init__(self, atype, string, family, logger):
599 Attribute.__init__(self, atype, string, logger)
600 self.value_int = None
601 self.value_int_str = None
602 self.family = family
603 self.PACK = '>HBB'
604
605 def decode(self, parent_msg, data):
606 self.decode_length_type(data)
607
608 try:
609 (label_high, label_low_tc_s, self.ttl) = unpack(self.PACK, self.data[4:])
610 self.s_bit = label_low_tc_s & 0x1
611 self.traffic_class = ((label_low_tc_s & 0xf) >> 1)
612 self.label = (label_high << 4) | (label_low_tc_s >> 4)
613 self.value = self.label
614 self.value_int = self.value
615 self.value_int_str = str(self.value_int)
616
617 except struct.error:
618 self.value = None
619 self.value_int = None
620 self.value_int_str = None
621 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
622 raise
623
624 def dump_lines(self, dump_buffer, line_number, color):
625 line_number = self.dump_first_line(dump_buffer, line_number, color)
626 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8],
627 'label %s, TC %s, bottom-of-stack %s, TTL %d' %
628 (self.label, self.traffic_class, self.s_bit, self.ttl)))
629 line_number += 1
630
631 return line_number
632
633
198ded6a
JF
634class AttributeGeneric(Attribute):
635
9f25ff0d 636 def __init__(self, atype, string, family, logger):
198ded6a
JF
637 Attribute.__init__(self, atype, string, logger)
638 self.PACK = None
639 self.LEN = None
640
641 def decode(self, parent_msg, data):
642 self.decode_length_type(data)
643 wordcount = (self.attr_end - 4)/4
644 self.PACK = '=%dL' % wordcount
645 self.LEN = calcsize(self.PACK)
646
647 try:
648 self.value = ''.join(map(str, unpack(self.PACK, self.data[4:])))
649 except struct.error:
650 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
651 raise
652
653
26e7207b
JF
654class AttributeOneByteValue(AttributeGeneric):
655
9f25ff0d
SE
656 def __init__(self, atype, string, family, logger):
657 AttributeGeneric.__init__(self, atype, string, family, logger)
d486dd0d 658 self.PACK = '=Bxxx'
26e7207b
JF
659 self.LEN = calcsize(self.PACK)
660
d486dd0d
JF
661 def decode(self, parent_msg, data):
662 self.decode_length_type(data)
663 assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
664
665 try:
666 self.value = int(unpack(self.PACK, self.data[4:8])[0])
667 except struct.error:
668 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:5])))
669 raise
670
671 def encode(self):
672 length = self.HEADER_LEN + self.LEN
673 raw = pack(self.HEADER_PACK, length-3, self.atype) + pack(self.PACK, self.value)
674 raw = self.pad(length, raw)
675 return raw
676
677 def dump_lines(self, dump_buffer, line_number, color):
678 line_number = self.dump_first_line(dump_buffer, line_number, color)
679 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
680 return line_number + 1
681
26e7207b 682
198ded6a
JF
683class AttributeIFLA_AF_SPEC(Attribute):
684 """
685 value will be a dictionary such as:
686 {
687 Link.IFLA_BRIDGE_FLAGS: flags,
688 Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid)
689 }
690 """
9f25ff0d
SE
691 def __init__(self, atype, string, family, logger):
692 Attribute.__init__(self, atype, string, logger)
d486dd0d 693 self.family = family
198ded6a
JF
694
695 def encode(self):
696 pack_layout = [self.HEADER_PACK]
d486dd0d 697 payload = [0, self.atype | NLA_F_NESTED]
198ded6a
JF
698 attr_length_index = 0
699
700 # For now this assumes that all data will be packed in the native endian
701 # order (=). If a field is added that needs to be packed via network
702 # order (>) then some smarts will need to be added to split the pack_layout
703 # string at the >, split the payload and make the needed pack() calls.
704 #
705 # Until we cross that bridge though we will keep things nice and simple and
706 # pack everything via a single pack() call.
26d1e82b
JF
707 sub_attr_to_add = []
708
198ded6a 709 for (sub_attr_type, sub_attr_value) in self.value.iteritems():
26d1e82b
JF
710
711 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
712 sub_attr_to_add.append((sub_attr_type, sub_attr_value))
713
714 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
715 for (vlan_flag, vlan_id) in sub_attr_value:
716 sub_attr_to_add.append((sub_attr_type, (vlan_flag, vlan_id)))
717
718 else:
d486dd0d 719 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_AF_SPEC sub-attribute type %d' % sub_attr_type)
26d1e82b
JF
720 continue
721
722 for (sub_attr_type, sub_attr_value) in sub_attr_to_add:
198ded6a
JF
723 sub_attr_pack_layout = ['=', 'HH']
724 sub_attr_payload = [0, sub_attr_type]
725 sub_attr_length_index = 0
726
727 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
728 sub_attr_pack_layout.append('H')
729 sub_attr_payload.append(sub_attr_value)
730
731 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
732 sub_attr_pack_layout.append('HH')
733 sub_attr_payload.append(sub_attr_value[0])
734 sub_attr_payload.append(sub_attr_value[1])
735
198ded6a
JF
736 sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
737 sub_attr_payload[sub_attr_length_index] = sub_attr_length
738
739 # add padding
740 for x in xrange(self.pad_bytes_needed(sub_attr_length)):
741 sub_attr_pack_layout.append('x')
742
743 # The [1:] is to remove the leading = so that when we do the ''.join() later
744 # we do not end up with an = in the middle of the pack layout string. There
745 # will be an = at the beginning via self.HEADER_PACK
746 sub_attr_pack_layout = sub_attr_pack_layout[1:]
747
748 # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
749 pack_layout.extend(sub_attr_pack_layout)
750 payload.extend(sub_attr_payload)
751
752 pack_layout = ''.join(pack_layout)
753
754 # Fill in the length field
755 length = calcsize(pack_layout)
756 payload[attr_length_index] = length
757
758 raw = pack(pack_layout, *payload)
759 raw = self.pad(length, raw)
760 return raw
761
762 def decode(self, parent_msg, data):
763 """
764 value is a dictionary such as:
765 {
766 Link.IFLA_BRIDGE_FLAGS: flags,
767 Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid)
768 }
d486dd0d
JF
769
770 FROM: David Ahern
771 The encoding of the IFLA_AF_SPEC attribute varies depending on the family
772 used for the request (RTM_GETLINK) message. For AF_UNSPEC the encoding
773 has another level of nesting for each address family with the type encoded
774 first. i.e.,
775 af_spec = nla_nest_start(skb, IFLA_AF_SPEC)
776 for each family:
777 af = nla_nest_start(skb, af_ops->family)
778 af_ops->fill_link_af(skb, dev, ext_filter_mask)
779 nest_end
780 nest_end
781
782 This allows the parser to find the address family by looking at the first
783 type.
784
785 Whereas AF_BRIDGE encoding is just:
786 af_spec = nla_nest_start(skb, IFLA_AF_SPEC)
787 br_fill_ifvlaninfo{_compressed}(skb, vg)
788 nest_end
789
790 which means the parser can not use the attribute itself to know the family
791 to which the attribute belongs.
792
793 /include/uapi/linux/if_link.h
794 /*
795 * IFLA_AF_SPEC
796 * Contains nested attributes for address family specific attributes.
797 * Each address family may create a attribute with the address family
798 * number as type and create its own attribute structure in it.
799 *
800 * Example:
801 * [IFLA_AF_SPEC] = {
802 * [AF_INET] = {
803 * [IFLA_INET_CONF] = ...,
804 * },
805 * [AF_INET6] = {
806 * [IFLA_INET6_FLAGS] = ...,
807 * [IFLA_INET6_CONF] = ...,
808 * }
809 * }
810 */
811
198ded6a
JF
812 """
813 self.decode_length_type(data)
814 self.value = {}
815
816 data = self.data[4:]
817
818 while data:
819 (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
820 sub_attr_end = padded_length(sub_attr_length)
821
822 if not sub_attr_length:
823 self.log.error('parsed a zero length sub-attr')
824 return
825
826 sub_attr_data = data[4:sub_attr_end]
827
d486dd0d
JF
828 if self.family == AF_BRIDGE:
829 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
830 self.value[Link.IFLA_BRIDGE_FLAGS] = unpack("=H", sub_attr_data[0:2])[0]
198ded6a 831
d486dd0d
JF
832 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
833 if Link.IFLA_BRIDGE_VLAN_INFO not in self.value:
834 self.value[Link.IFLA_BRIDGE_VLAN_INFO] = []
835 self.value[Link.IFLA_BRIDGE_VLAN_INFO].append(tuple(unpack("=HH", sub_attr_data[0:4])))
836
837 else:
838 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_AF_SPEC sub-attribute '
839 'type %s (%d), length %d, padded to %d' %
840 (parent_msg.get_ifla_bridge_af_spec_to_string(sub_attr_type),
841 sub_attr_type, sub_attr_length, sub_attr_end))
198ded6a 842
d486dd0d 843 elif self.family == AF_UNSPEC:
d486dd0d 844
f8f6549b
JF
845 if sub_attr_type == AF_INET6:
846 inet6_attr = {}
847
848 while sub_attr_data:
849 (inet6_attr_length, inet6_attr_type) = unpack('=HH', sub_attr_data[:4])
850 inet6_attr_end = padded_length(inet6_attr_length)
851
852 # 1 byte attr
853 if inet6_attr_type == Link.IFLA_INET6_ADDR_GEN_MODE:
854 inet6_attr[inet6_attr_type] = unpack('=B', sub_attr_data[4])[0]
855 # nlmanager doesn't support multiple kernel version
856 # all the other attributes like IFLA_INET6_CONF are
857 # based on DEVCONF_MAX from _UAPI_IPV6_H.
858 # we can opti the code and break this loop once we
859 # found the attribute that we are interested in.
860 # It's not really worth going through all the other
861 # attributes to log that we don't support them yet
862 break
863 else:
864 self.log.log(
865 SYSLOG_EXTRA_DEBUG,
866 'Add support for decoding AF_INET6 IFLA_AF_SPEC '
867 'sub-attribute type %s (%d), length %d, padded to %d'
868 % (
869 parent_msg.get_ifla_inet6_af_spec_to_string(inet6_attr_type),
870 inet6_attr_type, inet6_attr_length, inet6_attr_end
871 )
872 )
873
874 sub_attr_data = sub_attr_data[inet6_attr_end:]
875 self.value[AF_INET6] = inet6_attr
876 else:
877 self.value[sub_attr_type] = {}
878
879 # Uncomment the following block to implement the AF_INET attributes
880 # see Link.get_ifla_inet_af_spec_to_string (dict)
881 #elif sub_attr_type == AF_INET:
882 # inet_attr = {}
883 #
884 # while sub_attr_data:
885 # (inet_attr_length, inet_attr_type) = unpack('=HH', sub_attr_data[:4])
886 # inet_attr_end = padded_length(inet_attr_length)
887 #
888 # self.log.error(
889 # # SYSLOG_EXTRA_DEBUG,
890 # 'Add support for decoding AF_INET IFLA_AF_SPEC '
891 # 'sub-attribute type %s (%d), length %d, padded to %d'
892 # % (
893 # parent_msg.get_ifla_inet_af_spec_to_string(inet_attr_type),
894 # inet_attr_type, inet_attr_length, inet_attr_end
895 # )
896 # )
897 #
898 # sub_attr_data = sub_attr_data[inet_attr_end:]
899 #
900 # self.value[AF_INET] = inet_attr
d486dd0d
JF
901 else:
902 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_AF_SPEC sub-attribute '
903 'family %d, length %d, padded to %d'
904 % (self.family, sub_attr_length, sub_attr_end))
198ded6a
JF
905
906 data = data[sub_attr_end:]
907
908 def dump_lines(self, dump_buffer, line_number, color):
909 line_number = self.dump_first_line(dump_buffer, line_number, color)
910 extra = ''
911
912 next_sub_attr_line = 0
913 sub_attr_line = True
914
915 for x in xrange(1, self.attr_end/4):
916 start = x * 4
917 end = start + 4
918
919 if line_number == next_sub_attr_line:
920 sub_attr_line = True
921
922 if sub_attr_line:
923 sub_attr_line = False
924
925 (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4])
926 sub_attr_end = padded_length(sub_attr_length)
927
928 next_sub_attr_line = line_number + (sub_attr_end/4)
929
930 if sub_attr_end == sub_attr_length:
f8f6549b 931 padded_to = ','
198ded6a 932 else:
f8f6549b 933 padded_to = ' padded to %d,' % sub_attr_end
198ded6a 934
d486dd0d
JF
935 if self.family == AF_BRIDGE:
936 extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
937 (zfilled_hex(sub_attr_length, 4), sub_attr_length,
938 padded_to,
939 zfilled_hex(sub_attr_type, 4), sub_attr_type,
940 Link.ifla_bridge_af_spec_to_string.get(sub_attr_type))
f8f6549b
JF
941 elif self.family == AF_UNSPEC:
942 if sub_attr_type == AF_INET6:
943 family = 'AF_INET6'
944 elif sub_attr_type == AF_INET:
945 family = 'AF_INET'
946 else:
947 family = 'Unsupported family %d' % sub_attr_type
948
949 extra = 'Nested Attribute Structure for %s - Length %s (%d)%s Type %s (%d)' % (
950 family, zfilled_hex(sub_attr_length, 4), sub_attr_length, padded_to,
951 zfilled_hex(sub_attr_type, 4), sub_attr_type,
952 )
198ded6a
JF
953 else:
954 extra = ''
955
956 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra))
957 line_number += 1
958
959 return line_number
960
d486dd0d
JF
961 def get_pretty_value(self, obj=None):
962
963 if obj and callable(obj):
964 return obj(self.value)
965
198ded6a
JF
966 # We do this so we can print a more human readable dictionary
967 # with the names of the nested keys instead of their numbers
968 value_pretty = {}
969
f8f6549b
JF
970 if self.family == AF_BRIDGE:
971 for (sub_key, sub_value) in self.value.iteritems():
972 sub_key_pretty = "(%2d) %s" % (sub_key, Link.ifla_bridge_af_spec_to_string.get(sub_key))
973 value_pretty[sub_key_pretty] = sub_value
974 elif self.family == AF_UNSPEC:
975 for (family, family_attr) in self.value.iteritems():
976 family_value_pretty = {}
977
978 if family == AF_INET6:
979 family_af_spec_to_string = Link.ifla_inet6_af_spec_to_string
980 elif family == AF_INET:
981 family_af_spec_to_string = Link.ifla_inet_af_spec_to_string
982 else:
983 continue # log error?
984
985 for (sub_key, sub_value) in family_attr.iteritems():
986 sub_key_pretty = "(%2d) %s" % (sub_key, family_af_spec_to_string.get(sub_key))
987 family_value_pretty[sub_key_pretty] = sub_value
988 value_pretty = family_value_pretty
198ded6a
JF
989
990 return value_pretty
991
992
993
994class AttributeRTA_MULTIPATH(Attribute):
995 """
996/* RTA_MULTIPATH --- array of struct rtnexthop.
997 *
998 * "struct rtnexthop" describes all necessary nexthop information,
999 * i.e. parameters of path to a destination via this nexthop.
1000 *
1001 * At the moment it is impossible to set different prefsrc, mtu, window
1002 * and rtt for different paths from multipath.
1003 */
1004
1005struct rtnexthop {
1006 unsigned short rtnh_len;
1007 unsigned char rtnh_flags;
1008 unsigned char rtnh_hops;
1009 int rtnh_ifindex;
1010};
1011 """
1012
1013 def __init__(self, atype, string, family, logger):
1014 Attribute.__init__(self, atype, string, logger)
1015 self.family = family
1016 self.PACK = None
1017 self.LEN = None
1018 self.RTNH_PACK = '=HBBL' # rtnh_len, flags, hops, ifindex
1019 self.RTNH_LEN = calcsize(self.RTNH_PACK)
1020 self.IPV4_LEN = 4
1021 self.IPV6_LEN = 16
1022
1023 def encode(self):
1024
1025 # Calculate the length
1026 if self.family == AF_INET:
1027 ip_len = self.IPV4_LEN
1028 elif self.family == AF_INET6:
1029 ip_len = self.IPV6_LEN
1030
1031 # Attribute header
1032 length = self.HEADER_LEN + ((self.RTNH_LEN + self.HEADER_LEN + ip_len) * len(self.value))
1033 raw = pack(self.HEADER_PACK, length, self.atype)
1034
1035 rtnh_flags = 0
1036 rtnh_hops = 0
1037 rtnh_len = self.RTNH_LEN + self.HEADER_LEN + ip_len
1038
1039 for (nexthop, rtnh_ifindex) in self.value:
1040
1041 # rtnh structure
1042 raw += pack(self.RTNH_PACK, rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex)
1043
1044 # Gateway
1045 raw += pack(self.HEADER_PACK, self.HEADER_LEN + ip_len, Route.RTA_GATEWAY)
1046
1047 if self.family == AF_INET:
1048 raw += pack('>L', nexthop)
1049 elif self.family == AF_INET6:
1050 raw += pack('>QQ', nexthop >> 64, nexthop & 0x0000000000000000FFFFFFFFFFFFFFFF)
1051
1052 raw = self.pad(length, raw)
1053 return raw
1054
1055 def decode(self, parent_msg, data):
1056 self.decode_length_type(data)
1057 self.value = []
1058
1059 data = self.data[4:]
1060
1061 while data:
1062 (rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex) = unpack(self.RTNH_PACK, data[:self.RTNH_LEN])
1063 data = data[self.RTNH_LEN:]
1064
1065 (attr_type, attr_length) = unpack(self.HEADER_PACK, self.data[:self.HEADER_LEN])
1066 data = data[self.HEADER_LEN:]
1067
1068 if self.family == AF_INET:
d486dd0d
JF
1069 if len(data) < self.IPV4_LEN:
1070 break
198ded6a
JF
1071 nexthop = IPv4Address(unpack('>L', data[:self.IPV4_LEN])[0])
1072 self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops))
198ded6a
JF
1073
1074 elif self.family == AF_INET6:
d486dd0d
JF
1075 if len(data) < self.IPV6_LEN:
1076 break
198ded6a
JF
1077 (data1, data2) = unpack('>QQ', data[:self.IPV6_LEN])
1078 nexthop = IPv6Address(data1 << 64 | data2)
1079 self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops))
d486dd0d
JF
1080
1081 data = data[(rtnh_len-self.RTNH_LEN-self.HEADER_LEN):]
198ded6a
JF
1082
1083 self.value = tuple(self.value)
1084
1085
1086class AttributeIFLA_LINKINFO(Attribute):
1087 """
1088 value is a dictionary such as:
1089
1090 {
1091 Link.IFLA_INFO_KIND : 'vlan',
1092 Link.IFLA_INFO_DATA : {
1093 Link.IFLA_VLAN_ID : vlanid,
1094 }
1095 }
1096 """
9f25ff0d
SE
1097 def __init__(self, atype, string, family, logger):
1098 Attribute.__init__(self, atype, string, logger)
1099
198ded6a
JF
1100 def encode(self):
1101 pack_layout = [self.HEADER_PACK]
d486dd0d 1102 payload = [0, self.atype | NLA_F_NESTED]
198ded6a
JF
1103 attr_length_index = 0
1104
d486dd0d
JF
1105 kind = self.value.get(Link.IFLA_INFO_KIND)
1106 slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND)
198ded6a 1107
d486dd0d 1108 if not slave_kind and kind not in ('vlan', 'macvlan', 'vxlan', 'bond', 'bridge'):
198ded6a 1109 raise Exception('Unsupported IFLA_INFO_KIND %s' % kind)
d486dd0d
JF
1110 elif not kind and slave_kind != 'bridge':
1111 # only support brport for now.
1112 raise Exception('Unsupported IFLA_INFO_SLAVE_KIND %s' % slave_kind)
198ded6a
JF
1113
1114 # For now this assumes that all data will be packed in the native endian
1115 # order (=). If a field is added that needs to be packed via network
1116 # order (>) then some smarts will need to be added to split the pack_layout
1117 # string at the >, split the payload and make the needed pack() calls.
1118 #
1119 # Until we cross that bridge though we will keep things nice and simple and
1120 # pack everything via a single pack() call.
1121 for (sub_attr_type, sub_attr_value) in self.value.iteritems():
1122 sub_attr_pack_layout = ['=', 'HH']
1123 sub_attr_payload = [0, sub_attr_type]
1124 sub_attr_length_index = 0
1125
1126 if sub_attr_type == Link.IFLA_INFO_KIND:
1127 sub_attr_pack_layout.append('%ds' % len(sub_attr_value))
1128 sub_attr_payload.append(sub_attr_value)
1129
1130 elif sub_attr_type == Link.IFLA_INFO_DATA:
1131
d486dd0d
JF
1132 sub_attr_payload = [0, sub_attr_type | NLA_F_NESTED]
1133
198ded6a
JF
1134 for (info_data_type, info_data_value) in sub_attr_value.iteritems():
1135
1136 if kind == 'vlan':
1137 if info_data_type == Link.IFLA_VLAN_ID:
1138 sub_attr_pack_layout.append('HH')
1139 sub_attr_payload.append(6) # length
1140 sub_attr_payload.append(info_data_type)
1141
1142 # The vlan-id
1143 sub_attr_pack_layout.append('H')
1144 sub_attr_payload.append(info_data_value)
1145
1146 # pad 2 bytes
1147 sub_attr_pack_layout.extend('xx')
1148
d486dd0d
JF
1149 elif info_data_type == Link.IFLA_VLAN_PROTOCOL:
1150 sub_attr_pack_layout.append('HH')
1151 sub_attr_payload.append(6) # length
1152 sub_attr_payload.append(info_data_type)
1153
1154 # vlan protocol
1155 vlan_protocol = Link.ifla_vlan_protocol_dict.get(info_data_value)
1156 if not vlan_protocol:
1157 raise NotImplementedError('vlan protocol %s not implemented' % info_data_value)
1158
1159 sub_attr_pack_layout.append('H')
1160 sub_attr_payload.append(htons(vlan_protocol))
1161
1162 # pad 2 bytes
1163 sub_attr_pack_layout.extend('xx')
198ded6a 1164 else:
d486dd0d 1165 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA vlan sub-attribute type %d' % info_data_type)
198ded6a
JF
1166
1167 elif kind == 'macvlan':
1168 if info_data_type == Link.IFLA_MACVLAN_MODE:
1169 sub_attr_pack_layout.append('HH')
1170 sub_attr_payload.append(8) # length
1171 sub_attr_payload.append(info_data_type)
1172
1173 # macvlan mode
1174 sub_attr_pack_layout.append('L')
1175 sub_attr_payload.append(info_data_value)
1176
1177 else:
d486dd0d 1178 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA macvlan sub-attribute type %d' % info_data_type)
198ded6a 1179
3696839d
JF
1180 elif kind == 'vxlan':
1181 if info_data_type in (Link.IFLA_VXLAN_ID,
1182 Link.IFLA_VXLAN_LINK,
1183 Link.IFLA_VXLAN_AGEING,
1184 Link.IFLA_VXLAN_LIMIT,
1185 Link.IFLA_VXLAN_PORT_RANGE):
1186 sub_attr_pack_layout.append('HH')
1187 sub_attr_payload.append(8) # length
1188 sub_attr_payload.append(info_data_type)
1189
1190 sub_attr_pack_layout.append('L')
1191 sub_attr_payload.append(info_data_value)
1192
1193 elif info_data_type in (Link.IFLA_VXLAN_GROUP,
1194 Link.IFLA_VXLAN_LOCAL):
1195 sub_attr_pack_layout.append('HH')
1196 sub_attr_payload.append(8) # length
1197 sub_attr_payload.append(info_data_type)
1198
1199 sub_attr_pack_layout.append('L')
1200
1201 reorder = unpack('<L', IPv4Address(info_data_value).packed)[0]
1202 sub_attr_payload.append(IPv4Address(reorder))
1203
1204 elif info_data_type in (Link.IFLA_VXLAN_PORT,):
1205 sub_attr_pack_layout.append('HH')
1206 sub_attr_payload.append(6)
1207 sub_attr_payload.append(info_data_type)
1208
1209 sub_attr_pack_layout.append('H')
f1bec02e
JF
1210
1211 # byte swap
1212 swaped = pack(">H", info_data_value)
1213 sub_attr_payload.append(unpack("<H", swaped)[0])
3696839d
JF
1214
1215 sub_attr_pack_layout.extend('xx')
1216
1217 elif info_data_type in (Link.IFLA_VXLAN_TTL,
1218 Link.IFLA_VXLAN_TOS,
1219 Link.IFLA_VXLAN_LEARNING,
1220 Link.IFLA_VXLAN_PROXY,
1221 Link.IFLA_VXLAN_RSC,
1222 Link.IFLA_VXLAN_L2MISS,
1223 Link.IFLA_VXLAN_L3MISS,
1224 Link.IFLA_VXLAN_UDP_CSUM,
1225 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
1226 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
1227 Link.IFLA_VXLAN_REMCSUM_TX,
1228 Link.IFLA_VXLAN_REMCSUM_RX,
1229 Link.IFLA_VXLAN_REPLICATION_TYPE):
1230 sub_attr_pack_layout.append('HH')
1231 sub_attr_payload.append(6)
1232 sub_attr_payload.append(info_data_type)
1233
1234 sub_attr_pack_layout.append('B')
1235 sub_attr_payload.append(info_data_value)
1236 sub_attr_pack_layout.extend('xxx')
1237
1238 else:
d486dd0d
JF
1239 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA vxlan sub-attribute type %d' % info_data_type)
1240
1241 elif kind == 'bond':
1242 if info_data_type in (Link.IFLA_BOND_AD_ACTOR_SYSTEM, ):
1243 sub_attr_pack_layout.append('HH')
1244 sub_attr_payload.append(10) # length
1245 sub_attr_payload.append(info_data_type)
1246
1247 sub_attr_pack_layout.append('6B')
1248 for mbyte in info_data_value.replace('.', ' ').replace(':', ' ').split():
1249 sub_attr_payload.append(int(mbyte, 16))
1250 sub_attr_pack_layout.extend('xx')
1251
1252 elif info_data_type == Link.IFLA_BOND_AD_ACTOR_SYS_PRIO:
1253 sub_attr_pack_layout.append('HH')
1254 sub_attr_payload.append(6) # length
1255 sub_attr_payload.append(info_data_type)
1256
1257 # 2 bytes
1258 sub_attr_pack_layout.append('H')
1259 sub_attr_payload.append(int(info_data_value))
1260
1261 # pad 2 bytes
1262 sub_attr_pack_layout.extend('xx')
1263
1264 elif info_data_type == Link.IFLA_BOND_NUM_PEER_NOTIF:
1265 sub_attr_pack_layout.append('HH')
1266 sub_attr_payload.append(5) # length
1267 sub_attr_payload.append(info_data_type)
1268
1269 # 1 byte
1270 sub_attr_pack_layout.append('B')
1271 sub_attr_payload.append(int(info_data_value))
1272
1273 # pad 3 bytes
1274 sub_attr_pack_layout.extend('xxx')
1275
1276
1277 elif info_data_type in (Link.IFLA_BOND_AD_LACP_RATE,
1278 Link.IFLA_BOND_AD_LACP_BYPASS,
1279 Link.IFLA_BOND_USE_CARRIER):
1280 # converts yes/no/on/off/0/1 strings to boolean value
1281 bool_value = self.get_bool_value(info_data_value)
1282
1283 sub_attr_pack_layout.append('HH')
1284 sub_attr_payload.append(5) # length
1285 sub_attr_payload.append(info_data_type)
1286
1287 # 1 byte
1288 sub_attr_pack_layout.append('B')
1289 sub_attr_payload.append(bool_value)
1290
1291 # pad 3 bytes
1292 sub_attr_pack_layout.extend('xxx')
1293
1294 elif info_data_type == Link.IFLA_BOND_XMIT_HASH_POLICY:
1295 index = self.get_index(Link.ifla_bond_xmit_hash_policy_tbl,
1296 'bond xmit hash policy',
1297 info_data_value)
1298
1299 sub_attr_pack_layout.append('HH')
1300 sub_attr_payload.append(5) # length
1301 sub_attr_payload.append(info_data_type)
1302
1303 # 1 byte
1304 sub_attr_pack_layout.append('B')
1305 sub_attr_payload.append(index)
1306
1307 # pad 3 bytes
1308 sub_attr_pack_layout.extend('xxx')
1309
1310 elif info_data_type == Link.IFLA_BOND_MODE:
1311 index = self.get_index(Link.ifla_bond_mode_tbl,
1312 'bond mode',
1313 info_data_value)
1314
1315 sub_attr_pack_layout.append('HH')
1316 sub_attr_payload.append(5) # length
1317 sub_attr_payload.append(info_data_type)
1318
1319 # 1 byte
1320 sub_attr_pack_layout.append('B')
1321 sub_attr_payload.append(index)
1322
1323 # pad 3 bytes
1324 sub_attr_pack_layout.extend('xxx')
1325
1326 elif info_data_type in (Link.IFLA_BOND_MIIMON,
1327 Link.IFLA_BOND_UPDELAY,
1328 Link.IFLA_BOND_DOWNDELAY,
1329 Link.IFLA_BOND_MIN_LINKS):
1330 sub_attr_pack_layout.append('HH')
1331 sub_attr_payload.append(8) # length
1332 sub_attr_payload.append(info_data_type)
1333
1334 sub_attr_pack_layout.append('L')
1335 sub_attr_payload.append(int(info_data_value))
1336
1337 else:
1338 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA bond sub-attribute type %d' % info_data_type)
1339
1340 elif kind == 'bridge':
1341 if info_data_type == Link.IFLA_BR_VLAN_PROTOCOL:
1342 sub_attr_pack_layout.append('HH')
1343 sub_attr_payload.append(6) # length
1344 sub_attr_payload.append(info_data_type)
1345
1346 # vlan protocol
1347 vlan_protocol = Link.ifla_vlan_protocol_dict.get(info_data_value)
1348 if not vlan_protocol:
1349 raise NotImplementedError('vlan protocol %s not implemented' % info_data_value)
1350
1351 sub_attr_pack_layout.append('H')
1352 sub_attr_payload.append(htons(vlan_protocol))
1353
1354 # pad 2 bytes
1355 sub_attr_pack_layout.extend('xx')
1356
1357 # 1 byte
1358 elif info_data_type in (Link.IFLA_BR_VLAN_FILTERING,
1359 Link.IFLA_BR_TOPOLOGY_CHANGE,
1360 Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
1361 Link.IFLA_BR_MCAST_ROUTER,
1362 Link.IFLA_BR_MCAST_SNOOPING,
1363 Link.IFLA_BR_MCAST_QUERY_USE_IFADDR,
1364 Link.IFLA_BR_MCAST_QUERIER,
1365 Link.IFLA_BR_NF_CALL_IPTABLES,
1366 Link.IFLA_BR_NF_CALL_IP6TABLES,
1367 Link.IFLA_BR_NF_CALL_ARPTABLES,
1368 Link.IFLA_BR_VLAN_STATS_ENABLED,
1369 Link.IFLA_BR_MCAST_STATS_ENABLED,
1370 Link.IFLA_BR_MCAST_IGMP_VERSION,
1371 Link.IFLA_BR_MCAST_MLD_VERSION):
1372 sub_attr_pack_layout.append('HH')
1373 sub_attr_payload.append(5) # length
1374 sub_attr_payload.append(info_data_type)
1375
1376 # 1 byte
1377 sub_attr_pack_layout.append('B')
1378 sub_attr_payload.append(int(info_data_value))
1379
1380 # pad 3 bytes
1381 sub_attr_pack_layout.extend('xxx')
1382
1383 # 2 bytes
1384 elif info_data_type in (Link.IFLA_BR_PRIORITY,
1385 Link.IFLA_BR_GROUP_FWD_MASK,
1386 Link.IFLA_BR_ROOT_PORT,
1387 Link.IFLA_BR_VLAN_DEFAULT_PVID):
1388 sub_attr_pack_layout.append('HH')
1389 sub_attr_payload.append(6) # length
1390 sub_attr_payload.append(info_data_type)
1391
1392 # 2 bytes
1393 sub_attr_pack_layout.append('H')
1394 sub_attr_payload.append(int(info_data_value))
1395
1396 # pad 2 bytes
1397 sub_attr_pack_layout.extend('xx')
1398
1399 # 4 bytes
1400 elif info_data_type in (Link.IFLA_BR_FORWARD_DELAY,
1401 Link.IFLA_BR_HELLO_TIME,
1402 Link.IFLA_BR_MAX_AGE,
1403 Link.IFLA_BR_AGEING_TIME,
1404 Link.IFLA_BR_STP_STATE,
1405 Link.IFLA_BR_ROOT_PATH_COST,
1406 Link.IFLA_BR_MCAST_QUERIER,
1407 Link.IFLA_BR_MCAST_HASH_ELASTICITY,
1408 Link.IFLA_BR_MCAST_HASH_MAX,
1409 Link.IFLA_BR_MCAST_LAST_MEMBER_CNT,
1410 Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT):
1411 sub_attr_pack_layout.append('HH')
1412 sub_attr_payload.append(8) # length
1413 sub_attr_payload.append(info_data_type)
1414
1415 sub_attr_pack_layout.append('L')
1416 sub_attr_payload.append(int(info_data_value))
1417
1418 # 8 bytes
1419 elif info_data_type in (Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL,
1420 Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
1421 Link.IFLA_BR_MCAST_QUERIER_INTVL,
1422 Link.IFLA_BR_MCAST_QUERY_INTVL,
1423 Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
1424 Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL):
1425 sub_attr_pack_layout.append('HH')
1426 sub_attr_payload.append(12) # length
1427 sub_attr_payload.append(info_data_type)
1428
1429 sub_attr_pack_layout.append('Q')
1430 sub_attr_payload.append(int(info_data_value))
1431
1432 else:
1433 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA bridge sub-attribute type %d' % info_data_type)
1434
1435 elif sub_attr_type == Link.IFLA_INFO_SLAVE_DATA:
1436
1437 sub_attr_payload = [0, sub_attr_type | NLA_F_NESTED]
1438
1439 for (info_slave_data_type, info_slave_data_value) in sub_attr_value.iteritems():
1440
1441 if slave_kind == 'bridge':
1442
1443 # 1 byte
1444 if info_slave_data_type in (Link.IFLA_BRPORT_STATE,
1445 Link.IFLA_BRPORT_MODE,
1446 Link.IFLA_BRPORT_GUARD,
1447 Link.IFLA_BRPORT_PROTECT,
1448 Link.IFLA_BRPORT_FAST_LEAVE,
1449 Link.IFLA_BRPORT_LEARNING,
1450 Link.IFLA_BRPORT_UNICAST_FLOOD,
1451 Link.IFLA_BRPORT_PROXYARP,
1452 Link.IFLA_BRPORT_LEARNING_SYNC,
1453 Link.IFLA_BRPORT_PROXYARP_WIFI,
1454 Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
1455 Link.IFLA_BRPORT_CONFIG_PENDING,
1456 Link.IFLA_BRPORT_MULTICAST_ROUTER,
1457 Link.IFLA_BRPORT_MCAST_FLOOD,
1458 Link.IFLA_BRPORT_MCAST_TO_UCAST,
1459 Link.IFLA_BRPORT_VLAN_TUNNEL,
1460 Link.IFLA_BRPORT_BCAST_FLOOD,
1461 Link.IFLA_BRPORT_PEER_LINK,
1462 Link.IFLA_BRPORT_DUAL_LINK,
1463 Link.IFLA_BRPORT_ARP_SUPPRESS,
1464 Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
1465 sub_attr_pack_layout.append('HH')
1466 sub_attr_payload.append(5) # length
1467 sub_attr_payload.append(info_slave_data_type)
1468
1469 # 1 byte
1470 sub_attr_pack_layout.append('B')
1471 sub_attr_payload.append(int(info_slave_data_value))
1472
1473 # pad 3 bytes
1474 sub_attr_pack_layout.extend('xxx')
1475
1476 # 2 bytes
1477 elif info_slave_data_type in (Link.IFLA_BRPORT_PRIORITY,
1478 Link.IFLA_BRPORT_DESIGNATED_PORT,
1479 Link.IFLA_BRPORT_DESIGNATED_COST,
1480 Link.IFLA_BRPORT_ID,
1481 Link.IFLA_BRPORT_NO,
1482 Link.IFLA_BRPORT_GROUP_FWD_MASK,
1483 Link.IFLA_BRPORT_GROUP_FWD_MASKHI):
1484 sub_attr_pack_layout.append('HH')
1485 sub_attr_payload.append(6) # length
1486 sub_attr_payload.append(info_slave_data_type)
1487
1488 # 2 bytes
1489 sub_attr_pack_layout.append('H')
1490 sub_attr_payload.append(int(info_slave_data_value))
1491
1492 # pad 2 bytes
1493 sub_attr_pack_layout.extend('xx')
1494
1495 # 4 bytes
1496 elif info_slave_data_type == Link.IFLA_BRPORT_COST:
1497 sub_attr_pack_layout.append('HH')
1498 sub_attr_payload.append(8) # length
1499 sub_attr_payload.append(info_slave_data_type)
1500
1501 sub_attr_pack_layout.append('L')
1502 sub_attr_payload.append(int(info_slave_data_value))
1503
1504 else:
1505 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_SLAVE_DATA bond sub-attribute type %d' % info_slave_data_type)
1506
1507 else:
1508 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_LINKINFO kind %s' % slave_kind)
3696839d 1509
198ded6a 1510 else:
d486dd0d 1511 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_LINKINFO sub-attribute type %d' % sub_attr_type)
198ded6a
JF
1512 continue
1513
1514 sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
1515 sub_attr_payload[sub_attr_length_index] = sub_attr_length
1516
1517 # add padding
1518 for x in xrange(self.pad_bytes_needed(sub_attr_length)):
1519 sub_attr_pack_layout.append('x')
1520
1521 # The [1:] is to remove the leading = so that when we do the ''.join() later
1522 # we do not end up with an = in the middle of the pack layout string. There
1523 # will be an = at the beginning via self.HEADER_PACK
1524 sub_attr_pack_layout = sub_attr_pack_layout[1:]
1525
1526 # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
1527 pack_layout.extend(sub_attr_pack_layout)
1528 payload.extend(sub_attr_payload)
1529
1530 pack_layout = ''.join(pack_layout)
1531
1532 # Fill in the length field
1533 length = calcsize(pack_layout)
1534 payload[attr_length_index] = length
1535
1536 raw = pack(pack_layout, *payload)
1537 raw = self.pad(length, raw)
1538 return raw
1539
d486dd0d
JF
1540 def get_bool_value(self, value, default=None):
1541 try:
1542 return value_to_bool_dict[value]
1543 except KeyError:
1544 self.log.debug('%s: unsupported boolean value' % value)
1545 return default
1546
1547 def get_index(self, tbl, attr, value, default=None):
1548 try:
1549 return tbl[value]
1550 except KeyError:
1551 self.log.debug('unsupported %s value %s (%s)' % (attr, value, tbl.keys()))
1552 return default
1553
198ded6a
JF
1554 def decode(self, parent_msg, data):
1555 """
1556 value is a dictionary such as:
1557
1558 {
1559 Link.IFLA_INFO_KIND : 'vlan',
1560 Link.IFLA_INFO_DATA : {
1561 Link.IFLA_VLAN_ID : vlanid,
1562 }
1563 }
1564 """
1565 self.decode_length_type(data)
1566 self.value = {}
1567
1568 data = self.data[4:]
1569
1570 # IFLA_MACVLAN_MODE and IFLA_VLAN_ID both have a value of 1 and both are
1571 # valid IFLA_INFO_DATA entries :( The sender must TX IFLA_INFO_KIND
1572 # first in order for us to know if "1" is IFLA_MACVLAN_MODE vs IFLA_VLAN_ID.
d486dd0d 1573
198ded6a
JF
1574 while data:
1575 (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
1576 sub_attr_end = padded_length(sub_attr_length)
1577
1578 if not sub_attr_length:
1579 self.log.error('parsed a zero length sub-attr')
1580 return
1581
d486dd0d
JF
1582 if sub_attr_type in (Link.IFLA_INFO_KIND, Link.IFLA_INFO_SLAVE_KIND):
1583 self.value[sub_attr_type] = remove_trailing_null(unpack('%ds' % (sub_attr_length - 4), data[4:sub_attr_length])[0])
198ded6a 1584
d486dd0d 1585 elif sub_attr_type == Link.IFLA_INFO_SLAVE_DATA:
198ded6a 1586 sub_attr_data = data[4:sub_attr_end]
198ded6a 1587
d486dd0d
JF
1588 ifla_info_slave_data = dict()
1589 ifla_info_slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND)
9f25ff0d 1590
d486dd0d
JF
1591 if not ifla_info_slave_kind:
1592 self.log.warning('IFLA_INFO_SLAVE_KIND is not known...we cannot parse IFLA_INFO_SLAVE_DATA')
1593 else:
1594 while sub_attr_data:
1595 (info_data_length, info_data_type) = unpack('=HH', sub_attr_data[:4])
1596 info_data_end = padded_length(info_data_length)
1597 try:
1598 if ifla_info_slave_kind == 'bridge':
1599 # 1 byte
1600 if info_data_type in (Link.IFLA_BRPORT_STATE,
1601 Link.IFLA_BRPORT_MODE,
1602 Link.IFLA_BRPORT_GUARD,
1603 Link.IFLA_BRPORT_PROTECT,
1604 Link.IFLA_BRPORT_FAST_LEAVE,
1605 Link.IFLA_BRPORT_LEARNING,
1606 Link.IFLA_BRPORT_UNICAST_FLOOD,
1607 Link.IFLA_BRPORT_PROXYARP,
1608 Link.IFLA_BRPORT_LEARNING_SYNC,
1609 Link.IFLA_BRPORT_PROXYARP_WIFI,
1610 Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
1611 Link.IFLA_BRPORT_CONFIG_PENDING,
1612 Link.IFLA_BRPORT_MULTICAST_ROUTER,
1613 Link.IFLA_BRPORT_MCAST_FLOOD,
1614 Link.IFLA_BRPORT_MCAST_TO_UCAST,
1615 Link.IFLA_BRPORT_VLAN_TUNNEL,
1616 Link.IFLA_BRPORT_PEER_LINK,
1617 Link.IFLA_BRPORT_DUAL_LINK,
1618 Link.IFLA_BRPORT_ARP_SUPPRESS,
1619 Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
1620 ifla_info_slave_data[info_data_type] = unpack('=B', sub_attr_data[4])[0]
1621
1622 # 2 bytes
1623 elif info_data_type in (Link.IFLA_BRPORT_PRIORITY,
1624 Link.IFLA_BRPORT_DESIGNATED_PORT,
1625 Link.IFLA_BRPORT_DESIGNATED_COST,
1626 Link.IFLA_BRPORT_ID,
1627 Link.IFLA_BRPORT_NO,
1628 Link.IFLA_BRPORT_GROUP_FWD_MASK,
1629 Link.IFLA_BRPORT_GROUP_FWD_MASKHI):
1630 ifla_info_slave_data[info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
1631
1632 # 4 bytes
1633 elif info_data_type == Link.IFLA_BRPORT_COST:
1634 ifla_info_slave_data[info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1635
1636 elif ifla_info_slave_kind == 'bond':
1637
1638 # 1 byte
1639 if info_data_type in (
1640 Link.IFLA_BOND_SLAVE_STATE,
1641 Link.IFLA_BOND_SLAVE_MII_STATUS,
1642 Link.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
1643 Link.IFLA_BOND_SLAVE_AD_RX_BYPASS,
1644 ):
1645 ifla_info_slave_data[info_data_type] = unpack('=B', sub_attr_data[4])[0]
1646
1647 # 2 bytes
1648 elif info_data_type in (
1649 Link.IFLA_BOND_SLAVE_QUEUE_ID,
1650 Link.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID
1651 ):
1652 ifla_info_slave_data[info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
1653
1654 # 4 bytes
1655 elif info_data_type == (
1656 Link.IFLA_BOND_SLAVE_PERM_HWADDR,
1657 Link.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT
1658 ):
1659 ifla_info_slave_data[info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1660
1661 except Exception as e:
1662 self.log.debug('%s: attribute %s: %s'
1663 % (self.value[Link.IFLA_INFO_SLAVE_KIND],
1664 info_data_type,
1665 str(e)))
1666 sub_attr_data = sub_attr_data[info_data_end:]
1667
1668 self.value[Link.IFLA_INFO_SLAVE_DATA] = ifla_info_slave_data
198ded6a 1669
d486dd0d
JF
1670 elif sub_attr_type == Link.IFLA_INFO_DATA:
1671 sub_attr_data = data[4:sub_attr_end]
1672 self.value[Link.IFLA_INFO_DATA] = {}
198ded6a 1673
d486dd0d
JF
1674 ifla_info_kind = self.value.get(Link.IFLA_INFO_KIND)
1675 if not ifla_info_kind:
1676 self.log.warning('IFLA_INFO_KIND is not known...we cannot parse IFLA_INFO_DATA')
1677 else:
1678 while sub_attr_data:
1679 (info_data_length, info_data_type) = unpack('=HH', sub_attr_data[:4])
1680 info_data_end = padded_length(info_data_length)
1681 try:
1682 if ifla_info_kind == 'vlan':
1683 if info_data_type == Link.IFLA_VLAN_ID:
1684 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
1685
1686 elif info_data_type == Link.IFLA_VLAN_PROTOCOL:
1687 hex_value = '0x%s' % sub_attr_data[4:6].encode('hex')
1688 vlan_protocol = Link.ifla_vlan_protocol_dict.get(int(hex_value, base=16))
1689
1690 if vlan_protocol:
1691 self.value[Link.IFLA_INFO_DATA][info_data_type] = vlan_protocol
1692 else:
1693 self.log.warning('IFLA_VLAN_PROTOCOL: cannot decode vlan protocol %s' % hex_value)
1694
1695 else:
1696 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND vlan type %s (%d), length %d, padded to %d' %
1697 (parent_msg.get_ifla_vlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
1698
1699 elif ifla_info_kind == 'macvlan':
1700 if info_data_type == Link.IFLA_MACVLAN_MODE:
1701 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1702 else:
1703 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND macvlan type %s (%d), length %d, padded to %d' %
1704 (parent_msg.get_ifla_macvlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
1705
1706 elif ifla_info_kind == 'vxlan':
1707
1708 # IPv4Address
1709 if info_data_type in (Link.IFLA_VXLAN_GROUP,
1710 Link.IFLA_VXLAN_LOCAL):
1711 self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack('>L', sub_attr_data[4:8])[0])
1712
1713 # 4-byte int
1714 elif info_data_type in (Link.IFLA_VXLAN_ID,
1715 Link.IFLA_VXLAN_LINK,
1716 Link.IFLA_VXLAN_AGEING,
1717 Link.IFLA_VXLAN_LIMIT,
1718 Link.IFLA_VXLAN_PORT_RANGE):
1719 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1720
1721 # 2-byte int
1722 elif info_data_type in (Link.IFLA_VXLAN_PORT, ):
1723 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('!H', sub_attr_data[4:6])[0]
1724 # The form '!' is available for those poor souls who claim they can't
1725 # remember whether network byte order is big-endian or little-endian.
1726
1727 # 1-byte int
1728 elif info_data_type in (Link.IFLA_VXLAN_TTL,
1729 Link.IFLA_VXLAN_TOS,
1730 Link.IFLA_VXLAN_LEARNING,
1731 Link.IFLA_VXLAN_PROXY,
1732 Link.IFLA_VXLAN_RSC,
1733 Link.IFLA_VXLAN_L2MISS,
1734 Link.IFLA_VXLAN_L3MISS,
1735 Link.IFLA_VXLAN_UDP_CSUM,
1736 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
1737 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
1738 Link.IFLA_VXLAN_REMCSUM_TX,
1739 Link.IFLA_VXLAN_REMCSUM_RX,
1740 Link.IFLA_VXLAN_REPLICATION_TYPE):
1741 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
1742
1743 else:
1744 # sub_attr_end = padded_length(sub_attr_length)
1745 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND vxlan type %s (%d), length %d, padded to %d' %
1746 (parent_msg.get_ifla_vxlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
1747
1748 elif ifla_info_kind == 'bond':
1749
1750 if info_data_type in (Link.IFLA_BOND_AD_INFO, ):
1751 ad_attr_data = sub_attr_data[4:info_data_end]
1752 self.value[Link.IFLA_INFO_DATA][Link.IFLA_BOND_AD_INFO] = {}
1753
1754 while ad_attr_data:
1755 (ad_data_length, ad_data_type) = unpack('=HH', ad_attr_data[:4])
1756 ad_data_end = padded_length(ad_data_length)
1757
1758 if ad_data_type in (Link.IFLA_BOND_AD_INFO_PARTNER_MAC,):
1759 (data1, data2) = unpack('>LHxx', ad_attr_data[4:12])
1760 self.value[Link.IFLA_INFO_DATA][Link.IFLA_BOND_AD_INFO][ad_data_type] = mac_int_to_str(data1 << 16 | data2)
1761
1762 ad_attr_data = ad_attr_data[ad_data_end:]
1763
1764 # 1-byte int
1765 elif info_data_type in (Link.IFLA_BOND_MODE,
1766 Link.IFLA_BOND_USE_CARRIER,
1767 Link.IFLA_BOND_AD_LACP_RATE,
1768 Link.IFLA_BOND_AD_LACP_BYPASS,
1769 Link.IFLA_BOND_XMIT_HASH_POLICY,
1770 Link.IFLA_BOND_NUM_PEER_NOTIF):
1771 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
1772
1773 # 2-bytes int
1774 elif info_data_type == Link.IFLA_BOND_AD_ACTOR_SYS_PRIO:
1775 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
1776
1777 # 4-bytes int
1778 elif info_data_type in (Link.IFLA_BOND_MIIMON,
1779 Link.IFLA_BOND_UPDELAY,
1780 Link.IFLA_BOND_DOWNDELAY,
1781 Link.IFLA_BOND_MIN_LINKS):
1782 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1783
1784 # mac address
1785 elif info_data_type in (Link.IFLA_BOND_AD_ACTOR_SYSTEM, ):
1786 (data1, data2) = unpack('>LHxx', sub_attr_data[4:12])
1787 self.value[Link.IFLA_INFO_DATA][info_data_type] = mac_int_to_str(data1 << 16 | data2)
1788
1789 else:
1790 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND bond type %s (%d), length %d, padded to %d' %
1791 (parent_msg.get_ifla_bond_string(info_data_type), info_data_type, info_data_length, info_data_end))
1792
1793 elif ifla_info_kind == 'bridge':
1794 # 4 bytes
1795 if info_data_type in (Link.IFLA_BR_AGEING_TIME,
1796 Link.IFLA_BR_FORWARD_DELAY,
1797 Link.IFLA_BR_HELLO_TIME,
1798 Link.IFLA_BR_MAX_AGE,
1799 Link.IFLA_BR_STP_STATE,
1800 Link.IFLA_BR_ROOT_PATH_COST,
1801 Link.IFLA_BR_MCAST_HASH_ELASTICITY,
1802 Link.IFLA_BR_MCAST_HASH_MAX,
1803 Link.IFLA_BR_MCAST_LAST_MEMBER_CNT,
1804 Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT):
1805 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1806
1807 # 2 bytes
1808 elif info_data_type in (Link.IFLA_BR_PRIORITY,
1809 Link.IFLA_BR_GROUP_FWD_MASK,
1810 Link.IFLA_BR_ROOT_PORT,
1811 Link.IFLA_BR_VLAN_DEFAULT_PVID):
1812 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
1813
1814 elif info_data_type == Link.IFLA_BR_VLAN_PROTOCOL:
1815 hex_value = '0x%s' % sub_attr_data[4:6].encode('hex')
1816 vlan_protocol = Link.ifla_vlan_protocol_dict.get(int(hex_value, base=16))
1817
1818 if vlan_protocol:
1819 self.value[Link.IFLA_INFO_DATA][info_data_type] = vlan_protocol
1820 else:
1821 self.log.warning('IFLA_VLAN_PROTOCOL: cannot decode vlan protocol %s' % hex_value)
1822
1823 # 8 bytes
1824 elif info_data_type in (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
1825 Link.IFLA_BR_MCAST_QUERIER_INTVL,
1826 Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL,
1827 Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL,
1828 Link.IFLA_BR_MCAST_QUERIER_INTVL,
1829 Link.IFLA_BR_MCAST_QUERY_INTVL,
1830 Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
1831 Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL):
1832 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=Q', sub_attr_data[4:12])[0]
1833
1834 # 1 bytes
1835 elif info_data_type in (Link.IFLA_BR_VLAN_FILTERING,
1836 Link.IFLA_BR_TOPOLOGY_CHANGE,
1837 Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
1838 Link.IFLA_BR_MCAST_ROUTER,
1839 Link.IFLA_BR_MCAST_SNOOPING,
1840 Link.IFLA_BR_MCAST_QUERY_USE_IFADDR,
1841 Link.IFLA_BR_MCAST_QUERIER,
1842 Link.IFLA_BR_NF_CALL_IPTABLES,
1843 Link.IFLA_BR_NF_CALL_IP6TABLES,
1844 Link.IFLA_BR_NF_CALL_ARPTABLES,
1845 Link.IFLA_BR_VLAN_STATS_ENABLED,
1846 Link.IFLA_BR_MCAST_STATS_ENABLED,
1847 Link.IFLA_BR_MCAST_IGMP_VERSION,
1848 Link.IFLA_BR_MCAST_MLD_VERSION):
1849 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
1850 else:
1851 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND bridge type %s (%d), length %d, padded to %d' %
1852 (parent_msg.get_ifla_br_string(info_data_type), info_data_type, info_data_length, info_data_end))
1853
1854 elif ifla_info_kind == 'vrf':
1855
1856 if info_data_type in (Link.IFLA_VRF_TABLE,):
1857 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1858
1859
1860 else:
1861 self.log.log(SYSLOG_EXTRA_DEBUG, "Add support for decoding IFLA_INFO_KIND %s (%d), length %d, padded to %d" %
1862 (ifla_info_kind, info_data_type, info_data_length, info_data_end))
1863
1864 except Exception as e:
1865 self.log.debug('%s: attribute %s: %s'
1866 % (self.value[Link.IFLA_INFO_KIND],
1867 info_data_type,
1868 str(e)))
1869 sub_attr_data = sub_attr_data[info_data_end:]
198ded6a 1870
d486dd0d
JF
1871 else:
1872 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_LINKINFO sub-attribute type %s (%d), length %d, padded to %d' %
1873 (parent_msg.get_ifla_info_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end))
198ded6a
JF
1874
1875 data = data[sub_attr_end:]
1876
1877 # self.log.info('IFLA_LINKINFO values %s' % pformat(self.value))
1878
1879 def dump_lines(self, dump_buffer, line_number, color):
1880 line_number = self.dump_first_line(dump_buffer, line_number, color)
1881 extra = ''
1882
1883 next_sub_attr_line = 0
1884 sub_attr_line = True
1885
1886 for x in xrange(1, self.attr_end/4):
1887 start = x * 4
1888 end = start + 4
1889
1890 if line_number == next_sub_attr_line:
1891 sub_attr_line = True
1892
1893 if sub_attr_line:
1894 sub_attr_line = False
1895
1896 (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4])
1897 sub_attr_end = padded_length(sub_attr_length)
1898
1899 next_sub_attr_line = line_number + (sub_attr_end/4)
1900
1901 if sub_attr_end == sub_attr_length:
1902 padded_to = ', '
1903 else:
1904 padded_to = ' padded to %d, ' % sub_attr_end
1905
1906 extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
1907 (zfilled_hex(sub_attr_length, 4), sub_attr_length,
1908 padded_to,
1909 zfilled_hex(sub_attr_type, 4), sub_attr_type,
1910 Link.ifla_info_to_string.get(sub_attr_type))
1911 else:
1912 extra = ''
1913
1914 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra))
1915 line_number += 1
1916
1917 return line_number
1918
d486dd0d
JF
1919 def get_pretty_value(self, obj=None):
1920
1921 if obj and callable(obj):
1922 return obj(self.value)
1923
1924 value_pretty = self.value
1925 ifla_info_kind = self.value.get(Link.IFLA_INFO_KIND)
1926 ifla_info_slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND)
1927
1928 kind_dict = dict()
198ded6a
JF
1929
1930 # We do this so we can print a more human readable dictionary
1931 # with the names of the nested keys instead of their numbers
1932
1933 # Most of these are placeholders...we need to add support
1934 # for more human readable dictionaries for bond, bridge, etc
d486dd0d
JF
1935 kind_dict[Link.IFLA_INFO_DATA] = {
1936 'bond': Link.ifla_bond_to_string,
1937 'vlan': Link.ifla_vlan_to_string,
1938 'vxlan': Link.ifla_vxlan_to_string,
1939 'bridge': Link.ifla_br_to_string,
1940 'macvlan': Link.ifla_macvlan_to_string
1941 }.get(ifla_info_kind, {})
1942
1943 kind_dict[Link.IFLA_INFO_SLAVE_DATA] = {
1944 'bridge': Link.ifla_brport_to_string,
1945 'bond': Link.ifla_bond_slave_to_string
1946 }.get(ifla_info_slave_kind, {})
1947
1948 if ifla_info_kind or ifla_info_slave_kind:
198ded6a
JF
1949 value_pretty = {}
1950
1951 for (sub_key, sub_value) in self.value.iteritems():
d486dd0d 1952 sub_key_pretty = "(%2d) %s" % (sub_key, Link.ifla_info_to_string.get(sub_key, 'UNKNOWN'))
198ded6a
JF
1953 sub_value_pretty = sub_value
1954
d486dd0d
JF
1955 if sub_key in (Link.IFLA_INFO_DATA, Link.IFLA_INFO_SLAVE_DATA):
1956 kind_to_string_dict = kind_dict.get(sub_key, {})
198ded6a
JF
1957 sub_value_pretty = {}
1958
1959 for (sub_sub_key, sub_sub_value) in sub_value.iteritems():
d486dd0d 1960 sub_sub_key_pretty = "(%2d) %s" % (sub_sub_key, kind_to_string_dict.get(sub_sub_key, 'UNKNOWN'))
198ded6a
JF
1961 sub_value_pretty[sub_sub_key_pretty] = sub_sub_value
1962
1963 value_pretty[sub_key_pretty] = sub_value_pretty
1964
1965 return value_pretty
1966
1967
d486dd0d
JF
1968class AttributeIFLA_PROTINFO(Attribute):
1969 """
1970 IFLA_PROTINFO nested attributes.
1971 """
1972 def __init__(self, atype, string, family, logger):
1973 Attribute.__init__(self, atype, string, logger)
1974 self.family = family
1975
1976 def encode(self):
1977 pack_layout = [self.HEADER_PACK]
1978 payload = [0, self.atype | NLA_F_NESTED]
1979 attr_length_index = 0
1980
1981 if self.family not in (AF_BRIDGE,):
1982 raise Exception('Unsupported IFLA_PROTINFO family %d' % self.family)
1983
1984 # For now this assumes that all data will be packed in the native endian
1985 # order (=). If a field is added that needs to be packed via network
1986 # order (>) then some smarts will need to be added to split the pack_layout
1987 # string at the >, split the payload and make the needed pack() calls.
1988 #
1989 # Until we cross that bridge though we will keep things nice and simple and
1990 # pack everything via a single pack() call.
1991 for (sub_attr_type, sub_attr_value) in self.value.iteritems():
1992 sub_attr_pack_layout = ['=', 'HH']
1993 sub_attr_payload = [0, sub_attr_type]
1994 sub_attr_length_index = 0
1995
1996 if self.family == AF_BRIDGE:
1997 # 1 Byte attributes
1998 if sub_attr_type in (Link.IFLA_BRPORT_STATE,
1999 Link.IFLA_BRPORT_MODE,
2000 Link.IFLA_BRPORT_GUARD,
2001 Link.IFLA_BRPORT_PROTECT,
2002 Link.IFLA_BRPORT_FAST_LEAVE,
2003 Link.IFLA_BRPORT_LEARNING,
2004 Link.IFLA_BRPORT_UNICAST_FLOOD,
2005 Link.IFLA_BRPORT_PROXYARP,
2006 Link.IFLA_BRPORT_LEARNING_SYNC,
2007 Link.IFLA_BRPORT_PROXYARP_WIFI,
2008 Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
2009 Link.IFLA_BRPORT_CONFIG_PENDING,
2010 Link.IFLA_BRPORT_FLUSH,
2011 Link.IFLA_BRPORT_MULTICAST_ROUTER,
2012 Link.IFLA_BRPORT_PEER_LINK,
2013 Link.IFLA_BRPORT_DUAL_LINK,
2014 Link.IFLA_BRPORT_ARP_SUPPRESS,
2015 Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
2016 sub_attr_pack_layout.append('B')
2017 sub_attr_payload.append(sub_attr_value)
2018 sub_attr_pack_layout.extend('xxx')
2019
2020 # 2 Byte attributes
2021 elif sub_attr_type in (Link.IFLA_BRPORT_PRIORITY,
2022 Link.IFLA_BRPORT_DESIGNATED_PORT,
2023 Link.IFLA_BRPORT_DESIGNATED_COST,
2024 Link.IFLA_BRPORT_ID,
2025 Link.IFLA_BRPORT_NO):
2026 sub_attr_pack_layout.append('H')
2027 sub_attr_payload.append(sub_attr_value)
2028 sub_attr_pack_layout.extend('xx')
2029
2030 # 4 Byte attributes
2031 elif sub_attr_type in (Link.IFLA_BRPORT_COST,):
2032 sub_attr_pack_layout.append('L')
2033 sub_attr_payload.append(sub_attr_value)
2034
2035 # 8 Byte attributes
2036 elif sub_attr_type in (Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
2037 Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
2038 Link.IFLA_BRPORT_HOLD_TIMER):
2039 sub_attr_pack_layout.append('Q')
2040 sub_attr_payload.append(sub_attr_value)
2041
2042 else:
2043 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_PROTINFO sub-attribute type %d' % sub_attr_type)
2044
2045 sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
2046 sub_attr_payload[sub_attr_length_index] = sub_attr_length
2047
2048 # add padding
2049 for x in xrange(self.pad_bytes_needed(sub_attr_length)):
2050 sub_attr_pack_layout.append('x')
2051
2052 # The [1:] is to remove the leading = so that when we do the ''.join() later
2053 # we do not end up with an = in the middle of the pack layout string. There
2054 # will be an = at the beginning via self.HEADER_PACK
2055 sub_attr_pack_layout = sub_attr_pack_layout[1:]
2056
2057 # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
2058 pack_layout.extend(sub_attr_pack_layout)
2059 payload.extend(sub_attr_payload)
2060
2061 pack_layout = ''.join(pack_layout)
2062
2063 # Fill in the length field
2064 length = calcsize(pack_layout)
2065 payload[attr_length_index] = length
2066
2067 raw = pack(pack_layout, *payload)
2068 raw = self.pad(length, raw)
2069 return raw
2070
2071 def decode(self, parent_msg, data):
2072 """
2073 value is a dictionary such as:
2074 {
2075 Link.IFLA_BRPORT_STATE : 3,
2076 Link.IFLA_BRPORT_PRIORITY : 8
2077 Link.IFLA_BRPORT_COST : 2
2078 ...
2079 }
2080 """
2081 self.decode_length_type(data)
2082 self.value = {}
2083
2084 data = self.data[4:]
2085
2086 while data:
2087 (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
2088 sub_attr_end = padded_length(sub_attr_length)
2089
2090 if not sub_attr_length:
2091 self.log.error('parsed a zero length sub-attr')
2092 return
2093
2094 if self.family == AF_BRIDGE:
2095
2096 # 1 Byte attributes
2097 if sub_attr_type in (Link.IFLA_BRPORT_STATE,
2098 Link.IFLA_BRPORT_MODE,
2099 Link.IFLA_BRPORT_GUARD,
2100 Link.IFLA_BRPORT_PROTECT,
2101 Link.IFLA_BRPORT_FAST_LEAVE,
2102 Link.IFLA_BRPORT_LEARNING,
2103 Link.IFLA_BRPORT_UNICAST_FLOOD,
2104 Link.IFLA_BRPORT_PROXYARP,
2105 Link.IFLA_BRPORT_LEARNING_SYNC,
2106 Link.IFLA_BRPORT_PROXYARP_WIFI,
2107 Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
2108 Link.IFLA_BRPORT_CONFIG_PENDING,
2109 Link.IFLA_BRPORT_FLUSH,
2110 Link.IFLA_BRPORT_MULTICAST_ROUTER,
2111 Link.IFLA_BRPORT_PEER_LINK,
2112 Link.IFLA_BRPORT_DUAL_LINK,
2113 Link.IFLA_BRPORT_ARP_SUPPRESS,
2114 Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT):
2115 self.value[sub_attr_type] = unpack('=B', data[4])[0]
2116
2117 # 2 Byte attributes
2118 elif sub_attr_type in (Link.IFLA_BRPORT_PRIORITY,
2119 Link.IFLA_BRPORT_DESIGNATED_PORT,
2120 Link.IFLA_BRPORT_DESIGNATED_COST,
2121 Link.IFLA_BRPORT_ID,
2122 Link.IFLA_BRPORT_NO):
2123 self.value[sub_attr_type] = unpack('=H', data[4:6])[0]
2124
2125 # 4 Byte attributes
2126 elif sub_attr_type in (Link.IFLA_BRPORT_COST,):
2127 self.value[sub_attr_type] = unpack('=L', data[4:8])[0]
2128
2129 # 8 Byte attributes
2130 elif sub_attr_type in (Link.IFLA_BRPORT_MESSAGE_AGE_TIMER,
2131 Link.IFLA_BRPORT_FORWARD_DELAY_TIMER,
2132 Link.IFLA_BRPORT_HOLD_TIMER):
2133 self.value[sub_attr_type] = unpack('=Q', data[4:12])[0]
2134
2135 else:
2136 self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_PROTINFO sub-attribute type %s (%d), length %d, padded to %d' %
2137 (parent_msg.get_ifla_brport_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end))
2138
2139 data = data[sub_attr_end:]
2140
2141 def dump_lines(self, dump_buffer, line_number, color):
2142 line_number = self.dump_first_line(dump_buffer, line_number, color)
2143 extra = ''
2144
2145 next_sub_attr_line = 0
2146 sub_attr_line = True
2147
2148 for x in xrange(1, self.attr_end/4):
2149 start = x * 4
2150 end = start + 4
2151
2152 if line_number == next_sub_attr_line:
2153 sub_attr_line = True
2154
2155 if sub_attr_line:
2156 sub_attr_line = False
2157
2158 (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4])
2159 sub_attr_end = padded_length(sub_attr_length)
2160
2161 next_sub_attr_line = line_number + (sub_attr_end/4)
2162
2163 if sub_attr_end == sub_attr_length:
2164 padded_to = ', '
2165 else:
2166 padded_to = ' padded to %d, ' % sub_attr_end
2167
2168 extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
2169 (zfilled_hex(sub_attr_length, 4), sub_attr_length,
2170 padded_to,
2171 zfilled_hex(sub_attr_type, 4), sub_attr_type,
2172 Link.ifla_brport_to_string.get(sub_attr_type))
2173 else:
2174 extra = ''
2175
2176 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra))
2177 line_number += 1
2178
2179 return line_number
2180
2181 def get_pretty_value(self, obj=None):
2182
2183 if obj and callable(obj):
2184 return obj(self.value)
2185
2186 value_pretty = {}
2187
2188 for (sub_key, sub_value) in self.value.iteritems():
2189 sub_key_pretty = "(%2d) %s" % (sub_key, Link.ifla_brport_to_string.get(sub_key, 'UNKNOWN'))
2190 sub_value_pretty = sub_value
2191 value_pretty[sub_key_pretty] = sub_value_pretty
2192
2193 return value_pretty
2194
2195
2196
198ded6a
JF
2197class NetlinkPacket(object):
2198 """
2199 Netlink Header
2200
2201 0 1 2 3
2202 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
2203 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2204 | Length |
2205 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2206 | Type | Flags |
2207 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2208 | Sequence Number |
2209 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2210 | Process ID (PID) |
2211 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2212 """
2213
2214 header_PACK = 'IHHII'
2215 header_LEN = calcsize(header_PACK)
2216
2217 # Netlink packet types
2218 # /usr/include/linux/rtnetlink.h
2219 type_to_string = {
2220 NLMSG_NOOP : 'NLMSG_NOOP',
2221 NLMSG_ERROR : 'NLMSG_ERROR',
2222 NLMSG_DONE : 'NLMSG_DONE',
2223 NLMSG_OVERRUN : 'NLMSG_OVERRUN',
2224 RTM_NEWLINK : 'RTM_NEWLINK',
2225 RTM_DELLINK : 'RTM_DELLINK',
2226 RTM_GETLINK : 'RTM_GETLINK',
2227 RTM_SETLINK : 'RTM_SETLINK',
2228 RTM_NEWADDR : 'RTM_NEWADDR',
2229 RTM_DELADDR : 'RTM_DELADDR',
2230 RTM_GETADDR : 'RTM_GETADDR',
2231 RTM_NEWNEIGH : 'RTM_NEWNEIGH',
2232 RTM_DELNEIGH : 'RTM_DELNEIGH',
2233 RTM_GETNEIGH : 'RTM_GETNEIGH',
2234 RTM_NEWROUTE : 'RTM_NEWROUTE',
2235 RTM_DELROUTE : 'RTM_DELROUTE',
2236 RTM_GETROUTE : 'RTM_GETROUTE',
2237 RTM_NEWQDISC : 'RTM_NEWQDISC',
2238 RTM_DELQDISC : 'RTM_DELQDISC',
3479a0c3
JF
2239 RTM_GETQDISC : 'RTM_GETQDISC',
2240 RTM_NEWNETCONF: 'RTM_NEWNETCONF',
2241 RTM_GETNETCONF: 'RTM_GETNETCONF'
198ded6a
JF
2242 }
2243
d486dd0d
JF
2244 af_family_to_string = {
2245 AF_INET : 'inet',
2246 AF_INET6 : 'inet6'
2247 }
2248
a61d1777 2249 def __init__(self, msgtype, debug, owner_logger=None, use_color=True):
198ded6a
JF
2250 self.msgtype = msgtype
2251 self.attributes = {}
2252 self.dump_buffer = ['']
2253 self.line_number = 1
2254 self.debug = debug
2255 self.message = None
a61d1777 2256 self.use_color = use_color
c4fd4972 2257 self.family = None
198ded6a
JF
2258
2259 if owner_logger:
2260 self.log = owner_logger
2261 else:
2262 self.log = log
2263
2264 def __str__(self):
2265 return self.get_type_string()
2266
2267 def get_string(self, to_string, index):
2268 """
2269 Used to do lookups in all of the various FOO_to_string dictionaries
2270 but returns 'UNKNOWN' if the key is bogus
2271 """
2272 if index in to_string:
2273 return to_string[index]
2274 return 'UNKNOWN'
2275
2276 def get_type_string(self, msgtype=None):
2277 if not msgtype:
2278 msgtype = self.msgtype
2279 return self.get_string(self.type_to_string, msgtype)
2280
2281 def get_flags_string(self):
2282 foo = []
2283
2284 for (flag, flag_string) in self.flag_to_string.iteritems():
2285 if self.flags & flag:
2286 foo.append(flag_string)
2287
2288 return ', '.join(foo)
2289
2290 def decode_packet(self, length, flags, seq, pid, data):
2291 self.length = length
2292 self.flags = flags
2293 self.seq = seq
2294 self.pid = pid
2295 self.header_data = data[0:self.header_LEN]
2296 self.msg_data = data[self.header_LEN:length]
2297
2298 self.decode_netlink_header()
2299 self.decode_service_header()
2300
2301 # NLMSG_ERROR is special case, it does not have attributes to decode
2302 if self.msgtype != NLMSG_ERROR:
2303 self.decode_attributes()
2304
2305 def get_netlink_header_flags_string(self, msg_type, flags):
2306 foo = []
2307
2308 if flags & NLM_F_REQUEST:
2309 foo.append('NLM_F_REQUEST')
2310
2311 if flags & NLM_F_MULTI:
2312 foo.append('NLM_F_MULTI')
2313
2314 if flags & NLM_F_ACK:
2315 foo.append('NLM_F_ACK')
2316
2317 if flags & NLM_F_ECHO:
2318 foo.append('NLM_F_ECHO')
2319
2320 # Modifiers to GET query
3479a0c3 2321 if msg_type in (RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH, RTM_GETROUTE, RTM_GETQDISC, RTM_GETNETCONF):
198ded6a
JF
2322 if flags & NLM_F_DUMP:
2323 foo.append('NLM_F_DUMP')
26d1e82b
JF
2324 else:
2325 if flags & NLM_F_MATCH:
2326 foo.append('NLM_F_MATCH')
2327
2328 if flags & NLM_F_ROOT:
2329 foo.append('NLM_F_ROOT')
198ded6a
JF
2330
2331 if flags & NLM_F_ATOMIC:
2332 foo.append('NLM_F_ATOMIC')
2333
2334 # Modifiers to NEW query
2335 elif msg_type in (RTM_NEWLINK, RTM_NEWADDR, RTM_NEWNEIGH, RTM_NEWROUTE, RTM_NEWQDISC):
2336 if flags & NLM_F_REPLACE:
2337 foo.append('NLM_F_REPLACE')
2338
2339 if flags & NLM_F_EXCL:
2340 foo.append('NLM_F_EXCL')
2341
2342 if flags & NLM_F_CREATE:
2343 foo.append('NLM_F_CREATE')
2344
2345 if flags & NLM_F_APPEND:
2346 foo.append('NLM_F_APPEND')
2347
2348 return ', '.join(foo)
2349
2350 # When we first RXed the netlink message we had to decode the header to
2351 # determine what type of netlink message we were dealing with. So the
2352 # header has actually already been decoded...what we do here is
2353 # populate the dump_buffer lines with the header content.
2354 def decode_netlink_header(self):
2355
2356 if not self.debug:
2357 return
2358
2359 header_data = self.header_data
2360
2361 # Print the netlink header in red
198ded6a 2362 netlink_header_length = 16
a61d1777
SE
2363 color = red if self.use_color else None
2364 color_start = "\033[%dm" % color if color else ""
2365 color_end = "\033[0m" if color else ""
2366 self.dump_buffer.append(" %sNetlink Header%s" % (color_start, color_end))
198ded6a
JF
2367
2368 for x in range(0, netlink_header_length/4):
2369 start = x * 4
2370 end = start + 4
2371
2372 if self.line_number == 1:
2373 data = unpack('=L', header_data[start:end])[0]
2374 extra = "Length %s (%d)" % (zfilled_hex(data, 8), data)
2375
2376 elif self.line_number == 2:
2377 (data1, data2) = unpack('HH', header_data[start:end])
2378 extra = "Type %s (%d - %s), Flags %s (%s)" % \
2379 (zfilled_hex(data1, 4), data1, self.get_type_string(data1),
2380 zfilled_hex(data2, 4), self.get_netlink_header_flags_string(data1, data2))
2381
2382 elif self.line_number == 3:
2383 data = unpack('=L', header_data[start:end])[0]
2384 extra = "Sequence Number %s (%d)" % (zfilled_hex(data, 8), data)
2385
2386 elif self.line_number == 4:
2387 data = unpack('=L', header_data[start:end])[0]
2388 extra = "Process ID %s (%d)" % (zfilled_hex(data, 8), data)
2389 else:
2390 extra = "Unexpected line number %d" % self.line_number
2391
2392 self.dump_buffer.append(data_to_color_text(self.line_number, color, header_data[start:end], extra))
2393 self.line_number += 1
2394
2395 def decode_attributes(self):
2396 """
2397 Decode the attributes and populate the dump_buffer
2398 """
2399
2400 if self.debug:
2401 self.dump_buffer.append(" Attributes")
a61d1777 2402 color = green if self.use_color else None
198ded6a
JF
2403
2404 data = self.msg_data[self.LEN:]
2405
2406 while data:
2407 (length, attr_type) = unpack('=HH', data[:4])
2408
2409 # If this is zero we will stay in this loop for forever
2410 if not length:
2411 self.log.error('Length is zero')
2412 return
2413
2414 if len(data) < length:
2415 self.log.error("Buffer underrun %d < %d" % (len(data), length))
2416 return
2417
2418 attr = self.add_attribute(attr_type, None)
2419
2420 # Find the end of 'data' for this attribute and decode our section
2421 # of 'data'. attributes are padded for alignment thus the attr_end.
2422 #
2423 # How the attribute is decoded/unpacked is specific per AttributeXXXX class.
2424 attr_end = padded_length(length)
2425 attr.decode(self, data[0:attr_end])
2426
2427 if self.debug:
2428 self.line_number = attr.dump_lines(self.dump_buffer, self.line_number, color)
2429
2430 # Alternate back and forth between green and blue
a61d1777
SE
2431 if self.use_color:
2432 if color == green:
2433 color = blue
2434 else:
2435 color = green
198ded6a
JF
2436
2437 data = data[attr_end:]
2438
2439 def add_attribute(self, attr_type, value):
2440 nested = True if attr_type & NLA_F_NESTED else False
2441 net_byteorder = True if attr_type & NLA_F_NET_BYTEORDER else False
2442 attr_type = attr_type & NLA_TYPE_MASK
2443
2444 # Given an attr_type (say RTA_DST) find the type of AttributeXXXX class
2445 # that we will use to store this attribute...AttributeIPAddress in the
2446 # case of RTA_DST.
2447 if attr_type in self.attribute_to_class:
2448 (attr_string, attr_class) = self.attribute_to_class[attr_type]
d486dd0d
JF
2449
2450 '''
2451 attribute_to_class is a dictionary where the key is the attr_type, it doesn't
2452 take the family into account. For now we'll handle this as a special case for
2453 MPLS but long term we may need to make key a tuple of the attr_type and family.
2454 '''
3479a0c3 2455 if self.msgtype not in (RTM_NEWNETCONF, RTM_GETNETCONF) and attr_type == Route.RTA_DST and self.family == AF_MPLS:
d486dd0d
JF
2456 attr_string = 'RTA_DST'
2457 attr_class = AttributeMplsLabel
2458
198ded6a
JF
2459 else:
2460 attr_string = "UNKNOWN_ATTRIBUTE_%d" % attr_type
2461 attr_class = AttributeGeneric
2462 self.log.debug("Attribute %d is not defined in %s.attribute_to_class, assuming AttributeGeneric" %
2463 (attr_type, self.__class__.__name__))
2464
9f25ff0d 2465 attr = attr_class(attr_type, attr_string, self.family, self.log)
198ded6a 2466
4e979b1b
JF
2467 attr.set_value(value)
2468 attr.set_nested(nested)
2469 attr.set_net_byteorder(net_byteorder)
198ded6a
JF
2470
2471 # self.attributes is a dictionary keyed by the attribute type where
2472 # the value is an instance of the corresponding AttributeXXXX class.
2473 self.attributes[attr_type] = attr
2474
2475 return attr
2476
d486dd0d 2477 def get_attribute_value(self, attr_type, default=None):
198ded6a 2478 if attr_type not in self.attributes:
d486dd0d 2479 return default
198ded6a
JF
2480
2481 return self.attributes[attr_type].value
2482
2483 def get_attr_string(self, attr_type):
2484 """
2485 Example: If attr_type is Address.IFA_CACHEINFO return the string 'IFA_CACHEINFO'
2486 """
2487 if attr_type in self.attribute_to_class:
2488 (attr_string, attr_class) = self.attribute_to_class[attr_type]
2489 return attr_string
2490 return str(attr_type)
2491
2492 def build_message(self, seq, pid):
2493 self.seq = seq
2494 self.pid = pid
2495 attrs = ''
2496
2497 for attr in self.attributes.itervalues():
2498 attrs += attr.encode()
2499
2500 self.length = self.header_LEN + len(self.body) + len(attrs)
2501 self.header_data = pack(self.header_PACK, self.length, self.msgtype, self.flags, self.seq, self.pid)
2502 self.msg_data = self.body + attrs
2503 self.message = self.header_data + self.msg_data
2504
2505 if self.debug:
2506 self.decode_netlink_header()
2507 self.decode_service_header()
2508 self.decode_attributes()
2509 self.dump("TXed %s, length %d, seq %d, pid %d, flags 0x%x (%s)" %
2510 (self, self.length, self.seq, self.pid, self.flags,
2511 self.get_netlink_header_flags_string(self.msgtype, self.flags)))
2512
a61d1777
SE
2513 def pretty_display_dict(self, dic, level):
2514 for k,v in dic.iteritems():
2515 if isinstance(v, dict):
2516 self.log.debug(' '*level + str(k) + ':')
d486dd0d 2517 self.pretty_display_dict(v, level+5)
a61d1777
SE
2518 else:
2519 self.log.debug(' '*level + str(k) + ': ' + str(v))
2520
198ded6a
JF
2521 # Print the netlink message in hex. This is only used for debugging.
2522 def dump(self, desc=None):
2523 attr_string = {}
2524
2525 if desc is None:
2526 desc = "RXed %s, length %d, seq %d, pid %d, flags 0x%x" % (self, self.length, self.seq, self.pid, self.flags)
2527
2528 for (attr_type, attr_obj) in self.attributes.iteritems():
2529 key_string = "(%2d) %s" % (attr_type, self.get_attr_string(attr_type))
2530 attr_string[key_string] = attr_obj.get_pretty_value()
2531
a61d1777
SE
2532 if self.use_color:
2533 self.log.debug("%s\n%s\n\nAttributes Summary\n%s\n" %
2534 (desc, '\n'.join(self.dump_buffer), pformat(attr_string)))
2535 else:
2536 # Assume if we are not allowing color output we also don't want embedded
2537 # newline characters in the output. Output each line individually.
2538 self.log.debug(desc)
2539 for line in self.dump_buffer:
2540 self.log.debug(line)
2541 self.log.debug("")
2542 self.log.debug("Attributes Summary")
2543 self.pretty_display_dict(attr_string, 1)
198ded6a
JF
2544
2545
2546class Address(NetlinkPacket):
2547 """
2548 Service Header
2549 0 1 2 3
2550 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
2551 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2552 | Family | Length | Flags | Scope |
2553 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2554 | Interface Index |
2555 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2556 """
2557
2558 # Address attributes
2559 # /usr/include/linux/if_addr.h
2560 IFA_UNSPEC = 0x00
2561 IFA_ADDRESS = 0x01
2562 IFA_LOCAL = 0x02
2563 IFA_LABEL = 0x03
2564 IFA_BROADCAST = 0x04
2565 IFA_ANYCAST = 0x05
2566 IFA_CACHEINFO = 0x06
2567 IFA_MULTICAST = 0x07
2568 IFA_FLAGS = 0x08
2569
2570 attribute_to_class = {
2571 IFA_UNSPEC : ('IFA_UNSPEC', AttributeGeneric),
2572 IFA_ADDRESS : ('IFA_ADDRESS', AttributeIPAddress),
2573 IFA_LOCAL : ('IFA_LOCAL', AttributeIPAddress),
2574 IFA_LABEL : ('IFA_LABEL', AttributeString),
2575 IFA_BROADCAST : ('IFA_BROADCAST', AttributeIPAddress),
2576 IFA_ANYCAST : ('IFA_ANYCAST', AttributeIPAddress),
2577 IFA_CACHEINFO : ('IFA_CACHEINFO', AttributeGeneric),
2578 IFA_MULTICAST : ('IFA_MULTICAST', AttributeIPAddress),
2579 IFA_FLAGS : ('IFA_FLAGS', AttributeGeneric)
2580 }
2581
2582 # Address flags
2583 # /usr/include/linux/if_addr.h
2584 IFA_F_SECONDARY = 0x01
2585 IFA_F_NODAD = 0x02
2586 IFA_F_OPTIMISTIC = 0x04
2587 IFA_F_DADFAILED = 0x08
2588 IFA_F_HOMEADDRESS = 0x10
2589 IFA_F_DEPRECATED = 0x20
2590 IFA_F_TENTATIVE = 0x40
2591 IFA_F_PERMANENT = 0x80
2592
2593 flag_to_string = {
2594 IFA_F_SECONDARY : 'IFA_F_SECONDARY',
2595 IFA_F_NODAD : 'IFA_F_NODAD',
2596 IFA_F_OPTIMISTIC : 'IFA_F_OPTIMISTIC',
2597 IFA_F_DADFAILED : 'IFA_F_DADFAILED',
2598 IFA_F_HOMEADDRESS : 'IFA_F_HOMEADDRESS',
2599 IFA_F_DEPRECATED : 'IFA_F_DEPRECATED',
2600 IFA_F_TENTATIVE : 'IFA_F_TENTATIVE',
2601 IFA_F_PERMANENT : 'IFA_F_PERMANENT'
2602 }
2603
a61d1777
SE
2604 def __init__(self, msgtype, debug=False, logger=None, use_color=True):
2605 NetlinkPacket.__init__(self, msgtype, debug, logger, use_color)
198ded6a
JF
2606 self.PACK = '4Bi'
2607 self.LEN = calcsize(self.PACK)
2608
2609 def decode_service_header(self):
2610
2611 # Nothing to do if the message did not contain a service header
2612 if self.length == self.header_LEN:
2613 return
2614
2615 (self.family, self.prefixlen, self.flags, self.scope,
2616 self.ifindex) = \
2617 unpack(self.PACK, self.msg_data[:self.LEN])
2618
2619 if self.debug:
a61d1777
SE
2620 color = yellow if self.use_color else None
2621 color_start = "\033[%dm" % color if color else ""
2622 color_end = "\033[0m" if color else ""
2623 self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
198ded6a
JF
2624
2625 for x in range(0, self.LEN/4):
2626 if self.line_number == 5:
4d4aac88
JF
2627 extra = "Family %s (%s:%d), Length %s (%d), Flags %s, Scope %s (%d)" % \
2628 (zfilled_hex(self.family, 2), get_family_str(self.family), self.family,
198ded6a
JF
2629 zfilled_hex(self.prefixlen, 2), self.prefixlen,
2630 zfilled_hex(self.flags, 2),
2631 zfilled_hex(self.scope, 2), self.scope)
2632 elif self.line_number == 6:
2633 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
2634 else:
2635 extra = "Unexpected line number %d" % self.line_number
2636
2637 start = x * 4
2638 end = start + 4
2639 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2640 self.line_number += 1
2641
2642
2643class Error(NetlinkPacket):
2644
2645 # Error codes
2646 # /include/netlink/errno.h
2647 NLE_SUCCESS = 0x00
2648 NLE_FAILURE = 0x01
2649 NLE_INTR = 0x02
2650 NLE_BAD_SOCK = 0x03
2651 NLE_AGAIN = 0x04
2652 NLE_NOMEM = 0x05
2653 NLE_EXIST = 0x06
2654 NLE_INVAL = 0x07
2655 NLE_RANGE = 0x08
2656 NLE_MSGSIZE = 0x09
2657 NLE_OPNOTSUPP = 0x0A
2658 NLE_AF_NOSUPPORT = 0x0B
2659 NLE_OBJ_NOTFOUND = 0x0C
2660 NLE_NOATTR = 0x0D
2661 NLE_MISSING_ATTR = 0x0E
2662 NLE_AF_MISMATCH = 0x0F
2663 NLE_SEQ_MISMATCH = 0x10
2664 NLE_MSG_OVERFLOW = 0x11
2665 NLE_MSG_TRUNC = 0x12
2666 NLE_NOADDR = 0x13
2667 NLE_SRCRT_NOSUPPORT = 0x14
2668 NLE_MSG_TOOSHORT = 0x15
2669 NLE_MSGTYPE_NOSUPPORT = 0x16
2670 NLE_OBJ_MISMATCH = 0x17
2671 NLE_NOCACHE = 0x18
2672 NLE_BUSY = 0x19
2673 NLE_PROTO_MISMATCH = 0x1A
2674 NLE_NOACCESS = 0x1B
2675 NLE_PERM = 0x1C
2676 NLE_PKTLOC_FILE = 0x1D
2677 NLE_PARSE_ERR = 0x1E
2678 NLE_NODEV = 0x1F
2679 NLE_IMMUTABLE = 0x20
2680 NLE_DUMP_INTR = 0x21
2681
2682 error_to_string = {
2683 NLE_SUCCESS : 'NLE_SUCCESS',
2684 NLE_FAILURE : 'NLE_FAILURE',
2685 NLE_INTR : 'NLE_INTR',
2686 NLE_BAD_SOCK : 'NLE_BAD_SOCK',
2687 NLE_AGAIN : 'NLE_AGAIN',
2688 NLE_NOMEM : 'NLE_NOMEM',
2689 NLE_EXIST : 'NLE_EXIST',
2690 NLE_INVAL : 'NLE_INVAL',
2691 NLE_RANGE : 'NLE_RANGE',
2692 NLE_MSGSIZE : 'NLE_MSGSIZE',
2693 NLE_OPNOTSUPP : 'NLE_OPNOTSUPP',
2694 NLE_AF_NOSUPPORT : 'NLE_AF_NOSUPPORT',
2695 NLE_OBJ_NOTFOUND : 'NLE_OBJ_NOTFOUND',
2696 NLE_NOATTR : 'NLE_NOATTR',
2697 NLE_MISSING_ATTR : 'NLE_MISSING_ATTR',
2698 NLE_AF_MISMATCH : 'NLE_AF_MISMATCH',
2699 NLE_SEQ_MISMATCH : 'NLE_SEQ_MISMATCH',
2700 NLE_MSG_OVERFLOW : 'NLE_MSG_OVERFLOW',
2701 NLE_MSG_TRUNC : 'NLE_MSG_TRUNC',
2702 NLE_NOADDR : 'NLE_NOADDR',
2703 NLE_SRCRT_NOSUPPORT : 'NLE_SRCRT_NOSUPPORT',
2704 NLE_MSG_TOOSHORT : 'NLE_MSG_TOOSHORT',
2705 NLE_MSGTYPE_NOSUPPORT : 'NLE_MSGTYPE_NOSUPPORT',
2706 NLE_OBJ_MISMATCH : 'NLE_OBJ_MISMATCH',
2707 NLE_NOCACHE : 'NLE_NOCACHE',
2708 NLE_BUSY : 'NLE_BUSY',
2709 NLE_PROTO_MISMATCH : 'NLE_PROTO_MISMATCH',
2710 NLE_NOACCESS : 'NLE_NOACCESS',
2711 NLE_PERM : 'NLE_PERM',
2712 NLE_PKTLOC_FILE : 'NLE_PKTLOC_FILE',
2713 NLE_PARSE_ERR : 'NLE_PARSE_ERR',
2714 NLE_NODEV : 'NLE_NODEV',
2715 NLE_IMMUTABLE : 'NLE_IMMUTABLE',
2716 NLE_DUMP_INTR : 'NLE_DUMP_INTR'
2717 }
2718
a61d1777
SE
2719 def __init__(self, msgtype, debug=False, logger=None, use_color=True):
2720 NetlinkPacket.__init__(self, msgtype, debug, logger, use_color)
198ded6a
JF
2721 self.PACK = '=iLHHLL'
2722 self.LEN = calcsize(self.PACK)
2723
2724 def decode_service_header(self):
2725
2726 # Nothing to do if the message did not contain a service header
2727 if self.length == self.header_LEN:
2728 return
2729
2730 (self.negative_errno, self.bad_msg_len, self.bad_msg_type,
2731 self.bad_msg_flag, self.bad_msg_seq, self.bad_msg_pid) =\
2732 unpack(self.PACK, self.msg_data[:self.LEN])
2733
2734 if self.debug:
a61d1777
SE
2735 color = yellow if self.use_color else None
2736 color_start = "\033[%dm" % color if color else ""
2737 color_end = "\033[0m" if color else ""
2738 self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
198ded6a
JF
2739
2740 for x in range(0, self.LEN/4):
2741
2742 if self.line_number == 5:
2743 extra = "Error Number %s is %s" % (self.negative_errno, self.error_to_string.get(abs(self.negative_errno)))
2744 # zfilled_hex(self.negative_errno, 2)
2745
2746 elif self.line_number == 6:
2747 extra = "Length %s (%d)" % (zfilled_hex(self.bad_msg_len, 8), self.bad_msg_len)
2748
2749 elif self.line_number == 7:
2750 extra = "Type %s (%d - %s), Flags %s (%s)" % \
2751 (zfilled_hex(self.bad_msg_type, 4), self.bad_msg_type, self.get_type_string(self.bad_msg_type),
2752 zfilled_hex(self.bad_msg_flag, 4), self.get_netlink_header_flags_string(self.bad_msg_type, self.bad_msg_flag))
2753
2754 elif self.line_number == 8:
2755 extra = "Sequence Number %s (%d)" % (zfilled_hex(self.bad_msg_seq, 8), self.bad_msg_seq)
2756
2757 elif self.line_number == 9:
2758 extra = "Process ID %s (%d)" % (zfilled_hex(self.bad_msg_pid, 8), self.bad_msg_pid)
2759
2760 else:
2761 extra = "Unexpected line number %d" % self.line_number
2762
2763 start = x * 4
2764 end = start + 4
2765 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2766 self.line_number += 1
2767
2768
2769class Link(NetlinkPacket):
2770 """
2771 Service Header
2772
2773 0 1 2 3
2774 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
2775 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2776 | Family | Reserved | Device Type |
2777 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2778 | Interface Index |
2779 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2780 | Device Flags |
2781 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2782 | Change Mask |
2783 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2784 """
2785
2786 # Link attributes
2787 # /usr/include/linux/if_link.h
2788 IFLA_UNSPEC = 0
2789 IFLA_ADDRESS = 1
2790 IFLA_BROADCAST = 2
2791 IFLA_IFNAME = 3
2792 IFLA_MTU = 4
2793 IFLA_LINK = 5
2794 IFLA_QDISC = 6
2795 IFLA_STATS = 7
2796 IFLA_COST = 8
2797 IFLA_PRIORITY = 9
2798 IFLA_MASTER = 10
2799 IFLA_WIRELESS = 11
2800 IFLA_PROTINFO = 12
2801 IFLA_TXQLEN = 13
2802 IFLA_MAP = 14
2803 IFLA_WEIGHT = 15
2804 IFLA_OPERSTATE = 16
2805 IFLA_LINKMODE = 17
2806 IFLA_LINKINFO = 18
2807 IFLA_NET_NS_PID = 19
2808 IFLA_IFALIAS = 20
2809 IFLA_NUM_VF = 21
2810 IFLA_VFINFO_LIST = 22
2811 IFLA_STATS64 = 23
2812 IFLA_VF_PORTS = 24
2813 IFLA_PORT_SELF = 25
2814 IFLA_AF_SPEC = 26
2815 IFLA_GROUP = 27
2816 IFLA_NET_NS_FD = 28
2817 IFLA_EXT_MASK = 29
2818 IFLA_PROMISCUITY = 30
2819 IFLA_NUM_TX_QUEUES = 31
2820 IFLA_NUM_RX_QUEUES = 32
2821 IFLA_CARRIER = 33
2822 IFLA_PHYS_PORT_ID = 34
2823 IFLA_CARRIER_CHANGES = 35
2824 IFLA_PHYS_SWITCH_ID = 36
2825 IFLA_LINK_NETNSID = 37
2826 IFLA_PHYS_PORT_NAME = 38
2827 IFLA_PROTO_DOWN = 39
d486dd0d
JF
2828 IFLA_GSO_MAX_SEGS = 40
2829 IFLA_GSO_MAX_SIZE = 41
198ded6a
JF
2830
2831 attribute_to_class = {
2832 IFLA_UNSPEC : ('IFLA_UNSPEC', AttributeGeneric),
2833 IFLA_ADDRESS : ('IFLA_ADDRESS', AttributeMACAddress),
2834 IFLA_BROADCAST : ('IFLA_BROADCAST', AttributeMACAddress),
4e979b1b 2835 IFLA_IFNAME : ('IFLA_IFNAME', AttributeStringInterfaceName),
198ded6a
JF
2836 IFLA_MTU : ('IFLA_MTU', AttributeFourByteValue),
2837 IFLA_LINK : ('IFLA_LINK', AttributeFourByteValue),
2838 IFLA_QDISC : ('IFLA_QDISC', AttributeString),
2839 IFLA_STATS : ('IFLA_STATS', AttributeGeneric),
2840 IFLA_COST : ('IFLA_COST', AttributeGeneric),
2841 IFLA_PRIORITY : ('IFLA_PRIORITY', AttributeGeneric),
2842 IFLA_MASTER : ('IFLA_MASTER', AttributeFourByteValue),
2843 IFLA_WIRELESS : ('IFLA_WIRELESS', AttributeGeneric),
d486dd0d 2844 IFLA_PROTINFO : ('IFLA_PROTINFO', AttributeIFLA_PROTINFO),
198ded6a
JF
2845 IFLA_TXQLEN : ('IFLA_TXQLEN', AttributeFourByteValue),
2846 IFLA_MAP : ('IFLA_MAP', AttributeGeneric),
2847 IFLA_WEIGHT : ('IFLA_WEIGHT', AttributeGeneric),
d486dd0d
JF
2848 IFLA_OPERSTATE : ('IFLA_OPERSTATE', AttributeOneByteValue),
2849 IFLA_LINKMODE : ('IFLA_LINKMODE', AttributeOneByteValue),
198ded6a
JF
2850 IFLA_LINKINFO : ('IFLA_LINKINFO', AttributeIFLA_LINKINFO),
2851 IFLA_NET_NS_PID : ('IFLA_NET_NS_PID', AttributeGeneric),
2852 IFLA_IFALIAS : ('IFLA_IFALIAS', AttributeGeneric),
2853 IFLA_NUM_VF : ('IFLA_NUM_VF', AttributeGeneric),
2854 IFLA_VFINFO_LIST : ('IFLA_VFINFO_LIST', AttributeGeneric),
2855 IFLA_STATS64 : ('IFLA_STATS64', AttributeGeneric),
2856 IFLA_VF_PORTS : ('IFLA_VF_PORTS', AttributeGeneric),
2857 IFLA_PORT_SELF : ('IFLA_PORT_SELF', AttributeGeneric),
2858 IFLA_AF_SPEC : ('IFLA_AF_SPEC', AttributeIFLA_AF_SPEC),
2859 IFLA_GROUP : ('IFLA_GROUP', AttributeFourByteValue),
2860 IFLA_NET_NS_FD : ('IFLA_NET_NS_FD', AttributeGeneric),
26d1e82b 2861 IFLA_EXT_MASK : ('IFLA_EXT_MASK', AttributeFourByteValue),
198ded6a
JF
2862 IFLA_PROMISCUITY : ('IFLA_PROMISCUITY', AttributeGeneric),
2863 IFLA_NUM_TX_QUEUES : ('IFLA_NUM_TX_QUEUES', AttributeGeneric),
2864 IFLA_NUM_RX_QUEUES : ('IFLA_NUM_RX_QUEUES', AttributeGeneric),
2865 IFLA_CARRIER : ('IFLA_CARRIER', AttributeGeneric),
2866 IFLA_PHYS_PORT_ID : ('IFLA_PHYS_PORT_ID', AttributeGeneric),
2867 IFLA_CARRIER_CHANGES : ('IFLA_CARRIER_CHANGES', AttributeGeneric),
2868 IFLA_PHYS_SWITCH_ID : ('IFLA_PHYS_SWITCH_ID', AttributeGeneric),
2869 IFLA_LINK_NETNSID : ('IFLA_LINK_NETNSID', AttributeGeneric),
2870 IFLA_PHYS_PORT_NAME : ('IFLA_PHYS_PORT_NAME', AttributeGeneric),
26e7207b 2871 IFLA_PROTO_DOWN : ('IFLA_PROTO_DOWN', AttributeOneByteValue),
d486dd0d
JF
2872 IFLA_GSO_MAX_SEGS : ('IFLA_GSO_MAX_SEGS', AttributeFourByteValue),
2873 IFLA_GSO_MAX_SIZE : ('IFLA_GSO_MAX_SIZE', AttributeFourByteValue)
198ded6a
JF
2874 }
2875
2876 # Link flags
2877 # /usr/include/linux/if.h
2878 IFF_UP = 0x0001 # Interface is administratively up.
2879 IFF_BROADCAST = 0x0002 # Valid broadcast address set.
2880 IFF_DEBUG = 0x0004 # Internal debugging flag.
2881 IFF_LOOPBACK = 0x0008 # Interface is a loopback interface.
2882 IFF_POINTOPOINT = 0x0010 # Interface is a point-to-point link.
2883 IFF_NOTRAILERS = 0x0020 # Avoid use of trailers.
2884 IFF_RUNNING = 0x0040 # Interface is operationally up.
2885 IFF_NOARP = 0x0080 # No ARP protocol needed for this interface.
2886 IFF_PROMISC = 0x0100 # Interface is in promiscuous mode.
2887 IFF_ALLMULTI = 0x0200 # Receive all multicast packets.
2888 IFF_MASTER = 0x0400 # Master of a load balancing bundle.
2889 IFF_SLAVE = 0x0800 # Slave of a load balancing bundle.
2890 IFF_MULTICAST = 0x1000 # Supports multicast.
2891 IFF_PORTSEL = 0x2000 # Is able to select media type via ifmap.
2892 IFF_AUTOMEDIA = 0x4000 # Auto media selection active.
2893 IFF_DYNAMIC = 0x8000 # Interface was dynamically created.
2894 IFF_LOWER_UP = 0x10000 # driver signals L1 up
2895 IFF_DORMANT = 0x20000 # driver signals dormant
2896 IFF_ECHO = 0x40000 # echo sent packet
2897 IFF_PROTO_DOWN = 0x1000000 # protocol is down on the interface
2898
2899 flag_to_string = {
2900 IFF_UP : 'IFF_UP',
2901 IFF_BROADCAST : 'IFF_BROADCAST',
2902 IFF_DEBUG : 'IFF_DEBUG',
2903 IFF_LOOPBACK : 'IFF_LOOPBACK',
2904 IFF_POINTOPOINT : 'IFF_POINTOPOINT',
2905 IFF_NOTRAILERS : 'IFF_NOTRAILERS',
2906 IFF_RUNNING : 'IFF_RUNNING',
2907 IFF_NOARP : 'IFF_NOARP',
2908 IFF_PROMISC : 'IFF_PROMISC',
2909 IFF_ALLMULTI : 'IFF_ALLMULTI',
2910 IFF_MASTER : 'IFF_MASTER',
2911 IFF_SLAVE : 'IFF_SLAVE',
2912 IFF_MULTICAST : 'IFF_MULTICAST',
2913 IFF_PORTSEL : 'IFF_PORTSEL',
2914 IFF_AUTOMEDIA : 'IFF_AUTOMEDIA',
2915 IFF_DYNAMIC : 'IFF_DYNAMIC',
2916 IFF_LOWER_UP : 'IFF_LOWER_UP',
2917 IFF_DORMANT : 'IFF_DORMANT',
2918 IFF_ECHO : 'IFF_ECHO',
2919 IFF_PROTO_DOWN : 'IFF_PROTO_DOWN'
2920 }
2921
2922 # RFC 2863 operational status
2923 IF_OPER_UNKNOWN = 0
2924 IF_OPER_NOTPRESENT = 1
2925 IF_OPER_DOWN = 2
2926 IF_OPER_LOWERLAYERDOWN = 3
2927 IF_OPER_TESTING = 4
2928 IF_OPER_DORMANT = 5
2929 IF_OPER_UP = 6
2930
2931 oper_to_string = {
2932 IF_OPER_UNKNOWN : 'IF_OPER_UNKNOWN',
2933 IF_OPER_NOTPRESENT : 'IF_OPER_NOTPRESENT',
2934 IF_OPER_DOWN : 'IF_OPER_DOWN',
2935 IF_OPER_LOWERLAYERDOWN : 'IF_OPER_LOWERLAYERDOWN',
2936 IF_OPER_TESTING : 'IF_OPER_TESTING',
2937 IF_OPER_DORMANT : 'IF_OPER_DORMANT',
2938 IF_OPER_UP : 'IF_OPER_UP'
2939 }
2940
2941 # Link types
2942 # /usr/include/linux/if_arp.h
2943 # ARP protocol HARDWARE identifiers
2944 ARPHRD_NETROM = 0 # from KA9Q: NET/ROM pseudo
2945 ARPHRD_ETHER = 1 # Ethernet 10Mbps
2946 ARPHRD_EETHER = 2 # Experimental Ethernet
2947 ARPHRD_AX25 = 3 # AX.25 Level 2
2948 ARPHRD_PRONET = 4 # PROnet token ring
2949 ARPHRD_CHAOS = 5 # Chaosnet
2950 ARPHRD_IEEE802 = 6 # IEEE 802.2 Ethernet/TR/TB
2951 ARPHRD_ARCNET = 7 # ARCnet
2952 ARPHRD_APPLETLK = 8 # APPLEtalk
2953 ARPHRD_DLCI = 15 # Frame Relay DLCI
2954 ARPHRD_ATM = 19 # ATM
2955 ARPHRD_METRICOM = 23 # Metricom STRIP (new IANA id)
2956 ARPHRD_IEEE1394 = 24 # IEEE 1394 IPv4 - RFC 2734
2957 ARPHRD_EUI64 = 27 # EUI-64
2958 ARPHRD_INFINIBAND = 32 # InfiniBand
2959 # Dummy types for non ARP hardware
2960 ARPHRD_SLIP = 256
2961 ARPHRD_CSLIP = 257
2962 ARPHRD_SLIP6 = 258
2963 ARPHRD_CSLIP6 = 259
2964 ARPHRD_RSRVD = 260 # Notional KISS type
2965 ARPHRD_ADAPT = 264
2966 ARPHRD_ROSE = 270
2967 ARPHRD_X25 = 271 # CCITT X.25
2968 ARPHRD_HWX25 = 272 # Boards with X.25 in firmware
2969 ARPHRD_CAN = 280 # Controller Area Network
2970 ARPHRD_PPP = 512
2971 ARPHRD_CISCO = 513 # Cisco HDLC
2972 ARPHRD_HDLC = ARPHRD_CISCO
2973 ARPHRD_LAPB = 516 # LAPB
2974 ARPHRD_DDCMP = 517 # Digital's DDCMP protocol
2975 ARPHRD_RAWHDLC = 518 # Raw HDLC
2976 ARPHRD_TUNNEL = 768 # IPIP tunnel
2977 ARPHRD_TUNNEL6 = 769 # IP6IP6 tunnel
2978 ARPHRD_FRAD = 770 # Frame Relay Access Device
2979 ARPHRD_SKIP = 771 # SKIP vif
2980 ARPHRD_LOOPBACK = 772 # Loopback device
2981 ARPHRD_LOCALTLK = 773 # Localtalk device
2982 ARPHRD_FDDI = 774 # Fiber Distributed Data Interface
2983 ARPHRD_BIF = 775 # AP1000 BIF
2984 ARPHRD_SIT = 776 # sit0 device - IPv6-in-IPv4
2985 ARPHRD_IPDDP = 777 # IP over DDP tunneller
2986 ARPHRD_IPGRE = 778 # GRE over IP
2987 ARPHRD_PIMREG = 779 # PIMSM register interface
2988 ARPHRD_HIPPI = 780 # High Performance Parallel Interface
2989 ARPHRD_ASH = 781 # Nexus 64Mbps Ash
2990 ARPHRD_ECONET = 782 # Acorn Econet
2991 ARPHRD_IRDA = 783 # Linux-IrDA
2992 ARPHRD_FCPP = 784 # Point to point fibrechannel
2993 ARPHRD_FCAL = 785 # Fibrechannel arbitrated loop
2994 ARPHRD_FCPL = 786 # Fibrechannel public loop
2995 ARPHRD_FCFABRIC = 787 # Fibrechannel fabric
2996 # 787->799 reserved for fibrechannel media types
2997 ARPHRD_IEEE802_TR = 800 # Magic type ident for TR
2998 ARPHRD_IEEE80211 = 801 # IEEE 802.11
2999 ARPHRD_IEEE80211_PRISM = 802 # IEEE 802.11 + Prism2 header
3000 ARPHRD_IEEE80211_RADIOTAP = 803 # IEEE 802.11 + radiotap header
3001 ARPHRD_IEEE802154 = 804
3002 ARPHRD_PHONET = 820 # PhoNet media type
3003 ARPHRD_PHONET_PIPE = 821 # PhoNet pipe header
3004 ARPHRD_CAIF = 822 # CAIF media type
3005 ARPHRD_VOID = 0xFFFF # Void type, nothing is known
3006 ARPHRD_NONE = 0xFFFE # zero header length
3007
3008 link_type_to_string = {
3009 ARPHRD_NETROM : 'ARPHRD_NETROM',
3010 ARPHRD_ETHER : 'ARPHRD_ETHER',
3011 ARPHRD_EETHER : 'ARPHRD_EETHER',
3012 ARPHRD_AX25 : 'ARPHRD_AX25',
3013 ARPHRD_PRONET : 'ARPHRD_PRONET',
3014 ARPHRD_CHAOS : 'ARPHRD_CHAOS',
3015 ARPHRD_IEEE802 : 'ARPHRD_IEEE802',
3016 ARPHRD_ARCNET : 'ARPHRD_ARCNET',
3017 ARPHRD_APPLETLK : 'ARPHRD_APPLETLK',
3018 ARPHRD_DLCI : 'ARPHRD_DLCI',
3019 ARPHRD_ATM : 'ARPHRD_ATM',
3020 ARPHRD_METRICOM : 'ARPHRD_METRICOM',
3021 ARPHRD_IEEE1394 : 'ARPHRD_IEEE1394',
3022 ARPHRD_EUI64 : 'ARPHRD_EUI64',
3023 ARPHRD_INFINIBAND : 'ARPHRD_INFINIBAND',
3024 ARPHRD_SLIP : 'ARPHRD_SLIP',
3025 ARPHRD_CSLIP : 'ARPHRD_CSLIP',
3026 ARPHRD_SLIP6 : 'ARPHRD_SLIP6',
3027 ARPHRD_CSLIP6 : 'ARPHRD_CSLIP6',
3028 ARPHRD_RSRVD : 'ARPHRD_RSRVD',
3029 ARPHRD_ADAPT : 'ARPHRD_ADAPT',
3030 ARPHRD_ROSE : 'ARPHRD_ROSE',
3031 ARPHRD_X25 : 'ARPHRD_X25',
3032 ARPHRD_HWX25 : 'ARPHRD_HWX25',
3033 ARPHRD_CAN : 'ARPHRD_CAN',
3034 ARPHRD_PPP : 'ARPHRD_PPP',
3035 ARPHRD_CISCO : 'ARPHRD_CISCO',
3036 ARPHRD_HDLC : 'ARPHRD_HDLC',
3037 ARPHRD_LAPB : 'ARPHRD_LAPB',
3038 ARPHRD_DDCMP : 'ARPHRD_DDCMP',
3039 ARPHRD_RAWHDLC : 'ARPHRD_RAWHDLC',
3040 ARPHRD_TUNNEL : 'ARPHRD_TUNNEL',
3041 ARPHRD_TUNNEL6 : 'ARPHRD_TUNNEL6',
3042 ARPHRD_FRAD : 'ARPHRD_FRAD',
3043 ARPHRD_SKIP : 'ARPHRD_SKIP',
3044 ARPHRD_LOOPBACK : 'ARPHRD_LOOPBACK',
3045 ARPHRD_LOCALTLK : 'ARPHRD_LOCALTLK',
3046 ARPHRD_FDDI : 'ARPHRD_FDDI',
3047 ARPHRD_BIF : 'ARPHRD_BIF',
3048 ARPHRD_SIT : 'ARPHRD_SIT',
3049 ARPHRD_IPDDP : 'ARPHRD_IPDDP',
3050 ARPHRD_IPGRE : 'ARPHRD_IPGRE',
3051 ARPHRD_PIMREG : 'ARPHRD_PIMREG',
3052 ARPHRD_HIPPI : 'ARPHRD_HIPPI',
3053 ARPHRD_ASH : 'ARPHRD_ASH',
3054 ARPHRD_ECONET : 'ARPHRD_ECONET',
3055 ARPHRD_IRDA : 'ARPHRD_IRDA',
3056 ARPHRD_FCPP : 'ARPHRD_FCPP',
3057 ARPHRD_FCAL : 'ARPHRD_FCAL',
3058 ARPHRD_FCPL : 'ARPHRD_FCPL',
3059 ARPHRD_FCFABRIC : 'ARPHRD_FCFABRIC',
3060 ARPHRD_IEEE802_TR : 'ARPHRD_IEEE802_TR',
3061 ARPHRD_IEEE80211 : 'ARPHRD_IEEE80211',
3062 ARPHRD_IEEE80211_PRISM : 'ARPHRD_IEEE80211_PRISM',
3063 ARPHRD_IEEE80211_RADIOTAP : 'ARPHRD_IEEE80211_RADIOTAP',
3064 ARPHRD_IEEE802154 : 'ARPHRD_IEEE802154',
3065 ARPHRD_PHONET : 'ARPHRD_PHONET',
3066 ARPHRD_PHONET_PIPE : 'ARPHRD_PHONET_PIPE',
3067 ARPHRD_CAIF : 'ARPHRD_CAIF',
3068 ARPHRD_VOID : 'ARPHRD_VOID',
3069 ARPHRD_NONE : 'ARPHRD_NONE'
3070 }
3071
3072 # =========================================
3073 # IFLA_LINKINFO attributes
3074 # =========================================
3075 IFLA_INFO_UNSPEC = 0
3076 IFLA_INFO_KIND = 1
3077 IFLA_INFO_DATA = 2
3078 IFLA_INFO_XSTATS = 3
3079 IFLA_INFO_SLAVE_KIND = 4
3080 IFLA_INFO_SLAVE_DATA = 5
3081 IFLA_INFO_MAX = 6
3082
3083 ifla_info_to_string = {
3084 IFLA_INFO_UNSPEC : 'IFLA_INFO_UNSPEC',
3085 IFLA_INFO_KIND : 'IFLA_INFO_KIND',
3086 IFLA_INFO_DATA : 'IFLA_INFO_DATA',
3087 IFLA_INFO_XSTATS : 'IFLA_INFO_XSTATS',
3088 IFLA_INFO_SLAVE_KIND : 'IFLA_INFO_SLAVE_KIND',
3089 IFLA_INFO_SLAVE_DATA : 'IFLA_INFO_SLAVE_DATA',
3090 IFLA_INFO_MAX : 'IFLA_INFO_MAX'
3091 }
3092
3093 # =========================================
3094 # IFLA_INFO_DATA attributes for vlan
3095 # =========================================
3096 IFLA_VLAN_UNSPEC = 0
3097 IFLA_VLAN_ID = 1
3098 IFLA_VLAN_FLAGS = 2
3099 IFLA_VLAN_EGRESS_QOS = 3
3100 IFLA_VLAN_INGRESS_QOS = 4
3101 IFLA_VLAN_PROTOCOL = 5
3102
3103 ifla_vlan_to_string = {
3104 IFLA_VLAN_UNSPEC : 'IFLA_VLAN_UNSPEC',
3105 IFLA_VLAN_ID : 'IFLA_VLAN_ID',
3106 IFLA_VLAN_FLAGS : 'IFLA_VLAN_FLAGS',
3107 IFLA_VLAN_EGRESS_QOS : 'IFLA_VLAN_EGRESS_QOS',
3108 IFLA_VLAN_INGRESS_QOS : 'IFLA_VLAN_INGRESS_QOS',
3109 IFLA_VLAN_PROTOCOL : 'IFLA_VLAN_PROTOCOL'
3110 }
3111
d486dd0d
JF
3112 ifla_vlan_protocol_dict = {
3113 '802.1Q': 0x8100,
3114 '802.1q': 0x8100,
3115
3116 '802.1ad': 0x88A8,
3117 '802.1AD': 0x88A8,
3118 '802.1Ad': 0x88A8,
3119 '802.1aD': 0x88A8,
3120
3121 0x8100: '802.1Q',
3122 0x88A8: '802.1ad'
3123 }
3124
198ded6a
JF
3125 # =========================================
3126 # IFLA_INFO_DATA attributes for macvlan
3127 # =========================================
3128 IFLA_MACVLAN_UNSPEC = 0
3129 IFLA_MACVLAN_MODE = 1
3130
3131 ifla_macvlan_to_string = {
3132 IFLA_MACVLAN_UNSPEC : 'IFLA_MACVLAN_UNSPEC',
3133 IFLA_MACVLAN_MODE : 'IFLA_MACVLAN_MODE'
3134 }
3135
3136 # macvlan modes
3137 MACVLAN_MODE_PRIVATE = 1
3138 MACVLAN_MODE_VEPA = 2
3139 MACVLAN_MODE_BRIDGE = 3
3140 MACVLAN_MODE_PASSTHRU = 4
3141
3142 macvlan_mode_to_string = {
3143 MACVLAN_MODE_PRIVATE : 'MACVLAN_MODE_PRIVATE',
3144 MACVLAN_MODE_VEPA : 'MACVLAN_MODE_VEPA',
3145 MACVLAN_MODE_BRIDGE : 'MACVLAN_MODE_BRIDGE',
3146 MACVLAN_MODE_PASSTHRU : 'MACVLAN_MODE_PASSTHRU'
3147 }
3148
3149 # =========================================
3150 # IFLA_INFO_DATA attributes for vxlan
3151 # =========================================
3152 IFLA_VXLAN_UNSPEC = 0
3153 IFLA_VXLAN_ID = 1
3154 IFLA_VXLAN_GROUP = 2
3155 IFLA_VXLAN_LINK = 3
3156 IFLA_VXLAN_LOCAL = 4
3157 IFLA_VXLAN_TTL = 5
3158 IFLA_VXLAN_TOS = 6
3159 IFLA_VXLAN_LEARNING = 7
3160 IFLA_VXLAN_AGEING = 8
3161 IFLA_VXLAN_LIMIT = 9
3162 IFLA_VXLAN_PORT_RANGE = 10
3163 IFLA_VXLAN_PROXY = 11
3164 IFLA_VXLAN_RSC = 12
3165 IFLA_VXLAN_L2MISS = 13
3166 IFLA_VXLAN_L3MISS = 14
3167 IFLA_VXLAN_PORT = 15
3168 IFLA_VXLAN_GROUP6 = 16
3169 IFLA_VXLAN_LOCAL6 = 17
3170 IFLA_VXLAN_UDP_CSUM = 18
3171 IFLA_VXLAN_UDP_ZERO_CSUM6_TX = 19
3172 IFLA_VXLAN_UDP_ZERO_CSUM6_RX = 20
3173 IFLA_VXLAN_REMCSUM_TX = 21
3174 IFLA_VXLAN_REMCSUM_RX = 22
3175 IFLA_VXLAN_GBP = 23
3176 IFLA_VXLAN_REMCSUM_NOPARTIAL = 24
3177 IFLA_VXLAN_COLLECT_METADATA = 25
3178 IFLA_VXLAN_REPLICATION_NODE = 253
3179 IFLA_VXLAN_REPLICATION_TYPE = 254
3180
3181 ifla_vxlan_to_string = {
3182 IFLA_VXLAN_UNSPEC : 'IFLA_VXLAN_UNSPEC',
3183 IFLA_VXLAN_ID : 'IFLA_VXLAN_ID',
3184 IFLA_VXLAN_GROUP : 'IFLA_VXLAN_GROUP',
3185 IFLA_VXLAN_LINK : 'IFLA_VXLAN_LINK',
3186 IFLA_VXLAN_LOCAL : 'IFLA_VXLAN_LOCAL',
3187 IFLA_VXLAN_TTL : 'IFLA_VXLAN_TTL',
3188 IFLA_VXLAN_TOS : 'IFLA_VXLAN_TOS',
3189 IFLA_VXLAN_LEARNING : 'IFLA_VXLAN_LEARNING',
3190 IFLA_VXLAN_AGEING : 'IFLA_VXLAN_AGEING',
3191 IFLA_VXLAN_LIMIT : 'IFLA_VXLAN_LIMIT',
3192 IFLA_VXLAN_PORT_RANGE : 'IFLA_VXLAN_PORT_RANGE',
3193 IFLA_VXLAN_PROXY : 'IFLA_VXLAN_PROXY',
3194 IFLA_VXLAN_RSC : 'IFLA_VXLAN_RSC',
3195 IFLA_VXLAN_L2MISS : 'IFLA_VXLAN_L2MISS',
3196 IFLA_VXLAN_L3MISS : 'IFLA_VXLAN_L3MISS',
3197 IFLA_VXLAN_PORT : 'IFLA_VXLAN_PORT',
3198 IFLA_VXLAN_GROUP6 : 'IFLA_VXLAN_GROUP6',
3199 IFLA_VXLAN_LOCAL6 : 'IFLA_VXLAN_LOCAL6',
3200 IFLA_VXLAN_UDP_CSUM : 'IFLA_VXLAN_UDP_CSUM',
3201 IFLA_VXLAN_UDP_ZERO_CSUM6_TX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_TX',
3202 IFLA_VXLAN_UDP_ZERO_CSUM6_RX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_RX',
3203 IFLA_VXLAN_REMCSUM_TX : 'IFLA_VXLAN_REMCSUM_TX',
3204 IFLA_VXLAN_REMCSUM_RX : 'IFLA_VXLAN_REMCSUM_RX',
3205 IFLA_VXLAN_GBP : 'IFLA_VXLAN_GBP',
3206 IFLA_VXLAN_REMCSUM_NOPARTIAL : 'IFLA_VXLAN_REMCSUM_NOPARTIAL',
3207 IFLA_VXLAN_COLLECT_METADATA : 'IFLA_VXLAN_COLLECT_METADATA',
3208 IFLA_VXLAN_REPLICATION_NODE : 'IFLA_VXLAN_REPLICATION_NODE',
3209 IFLA_VXLAN_REPLICATION_TYPE : 'IFLA_VXLAN_REPLICATION_TYPE'
3210 }
3211
3212 # =========================================
3213 # IFLA_INFO_DATA attributes for bonds
3214 # =========================================
3215 IFLA_BOND_UNSPEC = 0
3216 IFLA_BOND_MODE = 1
3217 IFLA_BOND_ACTIVE_SLAVE = 2
3218 IFLA_BOND_MIIMON = 3
3219 IFLA_BOND_UPDELAY = 4
3220 IFLA_BOND_DOWNDELAY = 5
3221 IFLA_BOND_USE_CARRIER = 6
3222 IFLA_BOND_ARP_INTERVAL = 7
3223 IFLA_BOND_ARP_IP_TARGET = 8
3224 IFLA_BOND_ARP_VALIDATE = 9
3225 IFLA_BOND_ARP_ALL_TARGETS = 10
3226 IFLA_BOND_PRIMARY = 11
3227 IFLA_BOND_PRIMARY_RESELECT = 12
3228 IFLA_BOND_FAIL_OVER_MAC = 13
3229 IFLA_BOND_XMIT_HASH_POLICY = 14
3230 IFLA_BOND_RESEND_IGMP = 15
3231 IFLA_BOND_NUM_PEER_NOTIF = 16
3232 IFLA_BOND_ALL_SLAVES_ACTIVE = 17
3233 IFLA_BOND_MIN_LINKS = 18
3234 IFLA_BOND_LP_INTERVAL = 19
3235 IFLA_BOND_PACKETS_PER_SLAVE = 20
3236 IFLA_BOND_AD_LACP_RATE = 21
3237 IFLA_BOND_AD_SELECT = 22
3238 IFLA_BOND_AD_INFO = 23
3239 IFLA_BOND_AD_ACTOR_SYS_PRIO = 24
3240 IFLA_BOND_AD_USER_PORT_KEY = 25
3241 IFLA_BOND_AD_ACTOR_SYSTEM = 26
d486dd0d 3242 IFLA_BOND_AD_LACP_BYPASS = 100
198ded6a
JF
3243
3244 ifla_bond_to_string = {
3245 IFLA_BOND_UNSPEC : 'IFLA_BOND_UNSPEC',
3246 IFLA_BOND_MODE : 'IFLA_BOND_MODE',
3247 IFLA_BOND_ACTIVE_SLAVE : 'IFLA_BOND_ACTIVE_SLAVE',
3248 IFLA_BOND_MIIMON : 'IFLA_BOND_MIIMON',
3249 IFLA_BOND_UPDELAY : 'IFLA_BOND_UPDELAY',
3250 IFLA_BOND_DOWNDELAY : 'IFLA_BOND_DOWNDELAY',
3251 IFLA_BOND_USE_CARRIER : 'IFLA_BOND_USE_CARRIER',
3252 IFLA_BOND_ARP_INTERVAL : 'IFLA_BOND_ARP_INTERVAL',
3253 IFLA_BOND_ARP_IP_TARGET : 'IFLA_BOND_ARP_IP_TARGET',
3254 IFLA_BOND_ARP_VALIDATE : 'IFLA_BOND_ARP_VALIDATE',
3255 IFLA_BOND_ARP_ALL_TARGETS : 'IFLA_BOND_ARP_ALL_TARGETS',
3256 IFLA_BOND_PRIMARY : 'IFLA_BOND_PRIMARY',
3257 IFLA_BOND_PRIMARY_RESELECT : 'IFLA_BOND_PRIMARY_RESELECT',
3258 IFLA_BOND_FAIL_OVER_MAC : 'IFLA_BOND_FAIL_OVER_MAC',
3259 IFLA_BOND_XMIT_HASH_POLICY : 'IFLA_BOND_XMIT_HASH_POLICY',
3260 IFLA_BOND_RESEND_IGMP : 'IFLA_BOND_RESEND_IGMP',
3261 IFLA_BOND_NUM_PEER_NOTIF : 'IFLA_BOND_NUM_PEER_NOTIF',
3262 IFLA_BOND_ALL_SLAVES_ACTIVE : 'IFLA_BOND_ALL_SLAVES_ACTIVE',
3263 IFLA_BOND_MIN_LINKS : 'IFLA_BOND_MIN_LINKS',
3264 IFLA_BOND_LP_INTERVAL : 'IFLA_BOND_LP_INTERVAL',
3265 IFLA_BOND_PACKETS_PER_SLAVE : 'IFLA_BOND_PACKETS_PER_SLAVE',
3266 IFLA_BOND_AD_LACP_RATE : 'IFLA_BOND_AD_LACP_RATE',
3267 IFLA_BOND_AD_SELECT : 'IFLA_BOND_AD_SELECT',
3268 IFLA_BOND_AD_INFO : 'IFLA_BOND_AD_INFO',
3269 IFLA_BOND_AD_ACTOR_SYS_PRIO : 'IFLA_BOND_AD_ACTOR_SYS_PRIO',
3270 IFLA_BOND_AD_USER_PORT_KEY : 'IFLA_BOND_AD_USER_PORT_KEY',
3271 IFLA_BOND_AD_ACTOR_SYSTEM : 'IFLA_BOND_AD_ACTOR_SYSTEM',
d486dd0d
JF
3272 IFLA_BOND_AD_LACP_BYPASS : 'IFLA_BOND_AD_LACP_BYPASS'
3273 }
3274
3275 IFLA_BOND_AD_INFO_UNSPEC = 0
3276 IFLA_BOND_AD_INFO_AGGREGATOR = 1
3277 IFLA_BOND_AD_INFO_NUM_PORTS = 2
3278 IFLA_BOND_AD_INFO_ACTOR_KEY = 3
3279 IFLA_BOND_AD_INFO_PARTNER_KEY = 4
3280 IFLA_BOND_AD_INFO_PARTNER_MAC = 5
3281
3282 ifla_bond_ad_to_string = {
3283 IFLA_BOND_AD_INFO_UNSPEC : 'IFLA_BOND_AD_INFO_UNSPEC',
3284 IFLA_BOND_AD_INFO_AGGREGATOR : 'IFLA_BOND_AD_INFO_AGGREGATOR',
3285 IFLA_BOND_AD_INFO_NUM_PORTS : 'IFLA_BOND_AD_INFO_NUM_PORTS',
3286 IFLA_BOND_AD_INFO_ACTOR_KEY : 'IFLA_BOND_AD_INFO_ACTOR_KEY',
3287 IFLA_BOND_AD_INFO_PARTNER_KEY : 'IFLA_BOND_AD_INFO_PARTNER_KEY',
3288 IFLA_BOND_AD_INFO_PARTNER_MAC : 'IFLA_BOND_AD_INFO_PARTNER_MAC'
3289 }
3290
3291 ifla_bond_mode_tbl = {
3292 'balance-rr': 0,
3293 'active-backup': 1,
3294 'balance-xor': 2,
3295 'broadcast': 3,
3296 '802.3ad': 4,
3297 'balance-tlb': 5,
3298 'balance-alb': 6,
3299 '0': 0,
3300 '1': 1,
3301 '2': 2,
3302 '3': 3,
3303 '4': 4,
3304 '5': 5,
3305 '6': 6,
3306 0: 0,
3307 1: 1,
3308 2: 2,
3309 3: 3,
3310 4: 4,
3311 5: 5,
3312 6: 6
3313 }
3314
3315 ifla_bond_mode_pretty_tbl = {
3316 0: 'balance-rr',
3317 1: 'active-backup',
3318 2: 'balance-xor',
3319 3: 'broadcast',
3320 4: '802.3ad',
3321 5: 'balance-tlb',
3322 6: 'balance-alb'
3323 }
3324
3325 ifla_bond_xmit_hash_policy_tbl = {
3326 'layer2': 0,
3327 'layer3+4': 1,
3328 'layer2+3': 2,
3329 'encap2+3': 3,
3330 'encap3+4': 4,
3331 '0': 0,
3332 '1': 1,
3333 '2': 2,
3334 '3': 3,
3335 '4': 4,
3336 0: 0,
3337 1: 1,
3338 2: 2,
3339 3: 3,
3340 4: 4
3341 }
3342
3343 ifla_bond_xmit_hash_policy_pretty_tbl = {
3344 0: 'layer2',
3345 1: 'layer3+4',
3346 2: 'layer2+3',
3347 3: 'encap2+3',
3348 4: 'encap3+4',
198ded6a
JF
3349 }
3350
3351 # =========================================
d486dd0d
JF
3352 # IFLA_INFO_SLAVE_DATA attributes for bonds
3353 # =========================================
3354 IFLA_BOND_SLAVE_UNSPEC = 0
3355 IFLA_BOND_SLAVE_STATE = 1
3356 IFLA_BOND_SLAVE_MII_STATUS = 2
3357 IFLA_BOND_SLAVE_LINK_FAILURE_COUNT = 3
3358 IFLA_BOND_SLAVE_PERM_HWADDR = 4
3359 IFLA_BOND_SLAVE_QUEUE_ID = 5
3360 IFLA_BOND_SLAVE_AD_AGGREGATOR_ID = 6
3361 IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE = 7
3362 IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE = 8
3363 IFLA_BOND_SLAVE_CL_START = 50
3364 IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START
3365
3366 ifla_bond_slave_to_string = {
3367 IFLA_BOND_SLAVE_UNSPEC : 'IFLA_BOND_SLAVE_UNSPEC',
3368 IFLA_BOND_SLAVE_STATE : 'IFLA_BOND_SLAVE_STATE',
3369 IFLA_BOND_SLAVE_MII_STATUS : 'IFLA_BOND_SLAVE_MII_STATUS',
3370 IFLA_BOND_SLAVE_LINK_FAILURE_COUNT : 'IFLA_BOND_SLAVE_LINK_FAILURE_COUNT',
3371 IFLA_BOND_SLAVE_PERM_HWADDR : 'IFLA_BOND_SLAVE_PERM_HWADDR',
3372 IFLA_BOND_SLAVE_QUEUE_ID : 'IFLA_BOND_SLAVE_QUEUE_ID',
3373 IFLA_BOND_SLAVE_AD_AGGREGATOR_ID : 'IFLA_BOND_SLAVE_AD_AGGREGATOR_ID',
3374 IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE',
3375 IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE',
3376 IFLA_BOND_SLAVE_CL_START : 'IFLA_BOND_SLAVE_CL_START',
3377 IFLA_BOND_SLAVE_AD_RX_BYPASS : 'IFLA_BOND_SLAVE_AD_RX_BYPASS'
3378 }
3379
3380 # =========================================
3381 # IFLA_PROTINFO attributes for bridge ports
198ded6a
JF
3382 # =========================================
3383 IFLA_BRPORT_UNSPEC = 0
3384 IFLA_BRPORT_STATE = 1
3385 IFLA_BRPORT_PRIORITY = 2
3386 IFLA_BRPORT_COST = 3
3387 IFLA_BRPORT_MODE = 4
3388 IFLA_BRPORT_GUARD = 5
3389 IFLA_BRPORT_PROTECT = 6
3390 IFLA_BRPORT_FAST_LEAVE = 7
3391 IFLA_BRPORT_LEARNING = 8
3392 IFLA_BRPORT_UNICAST_FLOOD = 9
3393 IFLA_BRPORT_PROXYARP = 10
3394 IFLA_BRPORT_LEARNING_SYNC = 11
3395 IFLA_BRPORT_PROXYARP_WIFI = 12
3396 IFLA_BRPORT_ROOT_ID = 13
3397 IFLA_BRPORT_BRIDGE_ID = 14
3398 IFLA_BRPORT_DESIGNATED_PORT = 15
3399 IFLA_BRPORT_DESIGNATED_COST = 16
3400 IFLA_BRPORT_ID = 17
3401 IFLA_BRPORT_NO = 18
3402 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19
3403 IFLA_BRPORT_CONFIG_PENDING = 20
3404 IFLA_BRPORT_MESSAGE_AGE_TIMER = 21
3405 IFLA_BRPORT_FORWARD_DELAY_TIMER = 22
3406 IFLA_BRPORT_HOLD_TIMER = 23
3407 IFLA_BRPORT_FLUSH = 24
3408 IFLA_BRPORT_MULTICAST_ROUTER = 25
d486dd0d
JF
3409 IFLA_BRPORT_PAD = 26
3410 IFLA_BRPORT_MCAST_FLOOD = 27
3411 IFLA_BRPORT_MCAST_TO_UCAST = 28
3412 IFLA_BRPORT_VLAN_TUNNEL = 29
3413 IFLA_BRPORT_BCAST_FLOOD = 30
3414 IFLA_BRPORT_GROUP_FWD_MASK = 31
aab17506 3415 IFLA_BRPORT_ARP_SUPPRESS = 32
198ded6a
JF
3416 IFLA_BRPORT_PEER_LINK = 150
3417 IFLA_BRPORT_DUAL_LINK = 151
d486dd0d
JF
3418 IFLA_BRPORT_GROUP_FWD_MASKHI = 153
3419 IFLA_BRPORT_DOWN_PEERLINK_REDIRECT = 154
198ded6a 3420
d486dd0d 3421 ifla_brport_to_string = {
198ded6a
JF
3422 IFLA_BRPORT_UNSPEC : 'IFLA_BRPORT_UNSPEC',
3423 IFLA_BRPORT_STATE : 'IFLA_BRPORT_STATE',
3424 IFLA_BRPORT_PRIORITY : 'IFLA_BRPORT_PRIORITY',
3425 IFLA_BRPORT_COST : 'IFLA_BRPORT_COST',
3426 IFLA_BRPORT_MODE : 'IFLA_BRPORT_MODE',
3427 IFLA_BRPORT_GUARD : 'IFLA_BRPORT_GUARD',
3428 IFLA_BRPORT_PROTECT : 'IFLA_BRPORT_PROTECT',
3429 IFLA_BRPORT_FAST_LEAVE : 'IFLA_BRPORT_FAST_LEAVE',
3430 IFLA_BRPORT_LEARNING : 'IFLA_BRPORT_LEARNING',
3431 IFLA_BRPORT_UNICAST_FLOOD : 'IFLA_BRPORT_UNICAST_FLOOD',
3432 IFLA_BRPORT_PROXYARP : 'IFLA_BRPORT_PROXYARP',
3433 IFLA_BRPORT_LEARNING_SYNC : 'IFLA_BRPORT_LEARNING_SYNC',
3434 IFLA_BRPORT_PROXYARP_WIFI : 'IFLA_BRPORT_PROXYARP_WIFI',
3435 IFLA_BRPORT_ROOT_ID : 'IFLA_BRPORT_ROOT_ID',
3436 IFLA_BRPORT_BRIDGE_ID : 'IFLA_BRPORT_BRIDGE_ID',
3437 IFLA_BRPORT_DESIGNATED_PORT : 'IFLA_BRPORT_DESIGNATED_PORT',
3438 IFLA_BRPORT_DESIGNATED_COST : 'IFLA_BRPORT_DESIGNATED_COST',
3439 IFLA_BRPORT_ID : 'IFLA_BRPORT_ID',
3440 IFLA_BRPORT_NO : 'IFLA_BRPORT_NO',
3441 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK : 'IFLA_BRPORT_TOPOLOGY_CHANGE_ACK',
3442 IFLA_BRPORT_CONFIG_PENDING : 'IFLA_BRPORT_CONFIG_PENDING',
3443 IFLA_BRPORT_MESSAGE_AGE_TIMER : 'IFLA_BRPORT_MESSAGE_AGE_TIMER',
3444 IFLA_BRPORT_FORWARD_DELAY_TIMER : 'IFLA_BRPORT_FORWARD_DELAY_TIMER',
3445 IFLA_BRPORT_HOLD_TIMER : 'IFLA_BRPORT_HOLD_TIMER',
3446 IFLA_BRPORT_FLUSH : 'IFLA_BRPORT_FLUSH',
3447 IFLA_BRPORT_MULTICAST_ROUTER : 'IFLA_BRPORT_MULTICAST_ROUTER',
d486dd0d
JF
3448 IFLA_BRPORT_PAD : 'IFLA_BRPORT_PAD',
3449 IFLA_BRPORT_MCAST_FLOOD : 'IFLA_BRPORT_MCAST_FLOOD',
3450 IFLA_BRPORT_MCAST_TO_UCAST : 'IFLA_BRPORT_MCAST_TO_UCAST',
3451 IFLA_BRPORT_VLAN_TUNNEL : 'IFLA_BRPORT_VLAN_TUNNEL',
3452 IFLA_BRPORT_BCAST_FLOOD : 'IFLA_BRPORT_BCAST_FLOOD',
3453 IFLA_BRPORT_GROUP_FWD_MASK : 'IFLA_BRPORT_GROUP_FWD_MASK',
198ded6a 3454 IFLA_BRPORT_PEER_LINK : 'IFLA_BRPORT_PEER_LINK',
d486dd0d
JF
3455 IFLA_BRPORT_DUAL_LINK : 'IFLA_BRPORT_DUAL_LINK',
3456 IFLA_BRPORT_ARP_SUPPRESS : 'IFLA_BRPORT_ARP_SUPPRESS',
3457 IFLA_BRPORT_GROUP_FWD_MASKHI : 'IFLA_BRPORT_GROUP_FWD_MASKHI',
3458 IFLA_BRPORT_DOWN_PEERLINK_REDIRECT : 'IFLA_BRPORT_DOWN_PEERLINK_REDIRECT'
198ded6a
JF
3459 }
3460
f8f6549b
JF
3461 # Subtype attributes for IFLA_AF_SPEC
3462 IFLA_INET6_UNSPEC = 0
3463 IFLA_INET6_FLAGS = 1 # link flags
3464 IFLA_INET6_CONF = 2 # sysctl parameters
3465 IFLA_INET6_STATS = 3 # statistics
3466 IFLA_INET6_MCAST = 4 # MC things. What of them?
3467 IFLA_INET6_CACHEINFO = 5 # time values and max reasm size
3468 IFLA_INET6_ICMP6STATS = 6 # statistics (icmpv6)
3469 IFLA_INET6_TOKEN = 7 # device token
3470 IFLA_INET6_ADDR_GEN_MODE = 8 # implicit address generator mode
3471 __IFLA_INET6_MAX = 9
3472
3473 ifla_inet6_af_spec_to_string = {
3474 IFLA_INET6_UNSPEC : 'IFLA_INET6_UNSPEC',
3475 IFLA_INET6_FLAGS : 'IFLA_INET6_FLAGS',
3476 IFLA_INET6_CONF : 'IFLA_INET6_CONF',
3477 IFLA_INET6_STATS : 'IFLA_INET6_STATS',
3478 IFLA_INET6_MCAST : 'IFLA_INET6_MCAST',
3479 IFLA_INET6_CACHEINFO : 'IFLA_INET6_CACHEINFO',
3480 IFLA_INET6_ICMP6STATS : 'IFLA_INET6_ICMP6STATS',
3481 IFLA_INET6_TOKEN : 'IFLA_INET6_TOKEN',
3482 IFLA_INET6_ADDR_GEN_MODE : 'IFLA_INET6_ADDR_GEN_MODE',
3483 }
3484
3485 # Subtype attrbutes AF_INET
3486 IFLA_INET_UNSPEC = 0
3487 IFLA_INET_CONF = 1
3488 __IFLA_INET_MAX = 2
3489
3490 ifla_inet_af_spec_to_string = {
3491 IFLA_INET_UNSPEC : 'IFLA_INET_UNSPEC',
3492 IFLA_INET_CONF : 'IFLA_INET_CONF',
3493 }
3494
198ded6a
JF
3495 # BRIDGE IFLA_AF_SPEC attributes
3496 IFLA_BRIDGE_FLAGS = 0
3497 IFLA_BRIDGE_MODE = 1
3498 IFLA_BRIDGE_VLAN_INFO = 2
3499
3500 ifla_bridge_af_spec_to_string = {
3501 IFLA_BRIDGE_FLAGS : 'IFLA_BRIDGE_FLAGS',
3502 IFLA_BRIDGE_MODE : 'IFLA_BRIDGE_MODE',
3503 IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO'
3504 }
3505
3506 # BRIDGE_VLAN_INFO flags
d486dd0d
JF
3507 BRIDGE_VLAN_INFO_MASTER = 1 << 0 # Operate on Bridge device as well
3508 BRIDGE_VLAN_INFO_PVID = 1 << 1 # VLAN is PVID, ingress untagged
3509 BRIDGE_VLAN_INFO_UNTAGGED = 1 << 2 # VLAN egresses untagged
3510 BRIDGE_VLAN_INFO_RANGE_BEGIN = 1 << 3 # VLAN is start of vlan range
3511 BRIDGE_VLAN_INFO_RANGE_END = 1 << 4 # VLAN is end of vlan range
3512 BRIDGE_VLAN_INFO_BRENTRY = 1 << 5 # Global bridge VLAN entry
198ded6a
JF
3513
3514 bridge_vlan_to_string = {
26d1e82b
JF
3515 BRIDGE_VLAN_INFO_MASTER : 'BRIDGE_VLAN_INFO_MASTER',
3516 BRIDGE_VLAN_INFO_PVID : 'BRIDGE_VLAN_INFO_PVID',
3517 BRIDGE_VLAN_INFO_UNTAGGED : 'BRIDGE_VLAN_INFO_UNTAGGED',
3518 BRIDGE_VLAN_INFO_RANGE_BEGIN : 'BRIDGE_VLAN_INFO_RANGE_BEGIN',
d486dd0d
JF
3519 BRIDGE_VLAN_INFO_RANGE_END : 'BRIDGE_VLAN_INFO_RANGE_END',
3520 BRIDGE_VLAN_INFO_BRENTRY : 'BRIDGE_VLAN_INFO_BRENTRY'
198ded6a
JF
3521 }
3522
3523 # Bridge flags
3524 BRIDGE_FLAGS_MASTER = 1
3525 BRIDGE_FLAGS_SELF = 2
3526
3527 bridge_flags_to_string = {
3528 BRIDGE_FLAGS_MASTER : 'BRIDGE_FLAGS_MASTER',
3529 BRIDGE_FLAGS_SELF : 'BRIDGE_FLAGS_SELF'
3530 }
3531
26d1e82b
JF
3532 # filters for IFLA_EXT_MASK
3533 RTEXT_FILTER_VF = 1 << 0
3534 RTEXT_FILTER_BRVLAN = 1 << 1
3535 RTEXT_FILTER_BRVLAN_COMPRESSED = 1 << 2
3536 RTEXT_FILTER_SKIP_STATS = 1 << 3
3537
3538 rtext_to_string = {
3539 RTEXT_FILTER_VF : 'RTEXT_FILTER_VF',
3540 RTEXT_FILTER_BRVLAN : 'RTEXT_FILTER_BRVLAN',
3541 RTEXT_FILTER_BRVLAN_COMPRESSED : 'RTEXT_FILTER_BRVLAN_COMPRESSED',
3542 RTEXT_FILTER_SKIP_STATS : 'RTEXT_FILTER_SKIP_STATS'
3543 }
3544
c4fd4972
JF
3545 IFLA_BR_UNSPEC = 0
3546 IFLA_BR_FORWARD_DELAY = 1
3547 IFLA_BR_HELLO_TIME = 2
3548 IFLA_BR_MAX_AGE = 3
3549 IFLA_BR_AGEING_TIME = 4
3550 IFLA_BR_STP_STATE = 5
3551 IFLA_BR_PRIORITY = 6
3552 IFLA_BR_VLAN_FILTERING = 7
3553 IFLA_BR_VLAN_PROTOCOL = 8
3554 IFLA_BR_GROUP_FWD_MASK = 9
3555 IFLA_BR_ROOT_ID = 10
3556 IFLA_BR_BRIDGE_ID = 11
3557 IFLA_BR_ROOT_PORT = 12
3558 IFLA_BR_ROOT_PATH_COST = 13
3559 IFLA_BR_TOPOLOGY_CHANGE = 14
3560 IFLA_BR_TOPOLOGY_CHANGE_DETECTED = 15
3561 IFLA_BR_HELLO_TIMER = 16
3562 IFLA_BR_TCN_TIMER = 17
3563 IFLA_BR_TOPOLOGY_CHANGE_TIMER = 18
3564 IFLA_BR_GC_TIMER = 19
3565 IFLA_BR_GROUP_ADDR = 20
3566 IFLA_BR_FDB_FLUSH = 21
3567 IFLA_BR_MCAST_ROUTER = 22
3568 IFLA_BR_MCAST_SNOOPING = 23
3569 IFLA_BR_MCAST_QUERY_USE_IFADDR = 24
3570 IFLA_BR_MCAST_QUERIER = 25
3571 IFLA_BR_MCAST_HASH_ELASTICITY = 26
3572 IFLA_BR_MCAST_HASH_MAX = 27
3573 IFLA_BR_MCAST_LAST_MEMBER_CNT = 28
3574 IFLA_BR_MCAST_STARTUP_QUERY_CNT = 29
3575 IFLA_BR_MCAST_LAST_MEMBER_INTVL = 30
3576 IFLA_BR_MCAST_MEMBERSHIP_INTVL = 31
3577 IFLA_BR_MCAST_QUERIER_INTVL = 32
3578 IFLA_BR_MCAST_QUERY_INTVL = 33
3579 IFLA_BR_MCAST_QUERY_RESPONSE_INTVL = 34
3580 IFLA_BR_MCAST_STARTUP_QUERY_INTVL = 35
3581 IFLA_BR_NF_CALL_IPTABLES = 36
3582 IFLA_BR_NF_CALL_IP6TABLES = 37
3583 IFLA_BR_NF_CALL_ARPTABLES = 38
3584 IFLA_BR_VLAN_DEFAULT_PVID = 39
d486dd0d
JF
3585 IFLA_BR_PAD = 40
3586 IFLA_BR_VLAN_STATS_ENABLED = 41
3587 IFLA_BR_MCAST_STATS_ENABLED = 42
3588 IFLA_BR_MCAST_IGMP_VERSION = 43
3589 IFLA_BR_MCAST_MLD_VERSION = 44
c4fd4972
JF
3590
3591 ifla_br_to_string = {
3592 IFLA_BR_UNSPEC : 'IFLA_BR_UNSPEC',
3593 IFLA_BR_FORWARD_DELAY : 'IFLA_BR_FORWARD_DELAY',
3594 IFLA_BR_HELLO_TIME : 'IFLA_BR_HELLO_TIME',
3595 IFLA_BR_MAX_AGE : 'IFLA_BR_MAX_AGE',
3596 IFLA_BR_AGEING_TIME : 'IFLA_BR_AGEING_TIME',
3597 IFLA_BR_STP_STATE : 'IFLA_BR_STP_STATE',
3598 IFLA_BR_PRIORITY : 'IFLA_BR_PRIORITY',
3599 IFLA_BR_VLAN_FILTERING : 'IFLA_BR_VLAN_FILTERING',
3600 IFLA_BR_VLAN_PROTOCOL : 'IFLA_BR_VLAN_PROTOCOL',
3601 IFLA_BR_GROUP_FWD_MASK : 'IFLA_BR_GROUP_FWD_MASK',
3602 IFLA_BR_ROOT_ID : 'IFLA_BR_ROOT_ID',
3603 IFLA_BR_BRIDGE_ID : 'IFLA_BR_BRIDGE_ID',
3604 IFLA_BR_ROOT_PORT : 'IFLA_BR_ROOT_PORT',
3605 IFLA_BR_ROOT_PATH_COST : 'IFLA_BR_ROOT_PATH_COST',
3606 IFLA_BR_TOPOLOGY_CHANGE : 'IFLA_BR_TOPOLOGY_CHANGE',
3607 IFLA_BR_TOPOLOGY_CHANGE_DETECTED : 'IFLA_BR_TOPOLOGY_CHANGE_DETECTED',
3608 IFLA_BR_HELLO_TIMER : 'IFLA_BR_HELLO_TIMER',
3609 IFLA_BR_TCN_TIMER : 'IFLA_BR_TCN_TIMER',
3610 IFLA_BR_TOPOLOGY_CHANGE_TIMER : 'IFLA_BR_TOPOLOGY_CHANGE_TIMER',
3611 IFLA_BR_GC_TIMER : 'IFLA_BR_GC_TIMER',
3612 IFLA_BR_GROUP_ADDR : 'IFLA_BR_GROUP_ADDR',
3613 IFLA_BR_FDB_FLUSH : 'IFLA_BR_FDB_FLUSH',
3614 IFLA_BR_MCAST_ROUTER : 'IFLA_BR_MCAST_ROUTER',
3615 IFLA_BR_MCAST_SNOOPING : 'IFLA_BR_MCAST_SNOOPING',
3616 IFLA_BR_MCAST_QUERY_USE_IFADDR : 'IFLA_BR_MCAST_QUERY_USE_IFADDR',
3617 IFLA_BR_MCAST_QUERIER : 'IFLA_BR_MCAST_QUERIER',
3618 IFLA_BR_MCAST_HASH_ELASTICITY : 'IFLA_BR_MCAST_HASH_ELASTICITY',
3619 IFLA_BR_MCAST_HASH_MAX : 'IFLA_BR_MCAST_HASH_MAX',
3620 IFLA_BR_MCAST_LAST_MEMBER_CNT : 'IFLA_BR_MCAST_LAST_MEMBER_CNT',
3621 IFLA_BR_MCAST_STARTUP_QUERY_CNT : 'IFLA_BR_MCAST_STARTUP_QUERY_CNT',
3622 IFLA_BR_MCAST_LAST_MEMBER_INTVL : 'IFLA_BR_MCAST_LAST_MEMBER_INTVL',
3623 IFLA_BR_MCAST_MEMBERSHIP_INTVL : 'IFLA_BR_MCAST_MEMBERSHIP_INTVL',
3624 IFLA_BR_MCAST_QUERIER_INTVL : 'IFLA_BR_MCAST_QUERIER_INTVL',
3625 IFLA_BR_MCAST_QUERY_INTVL : 'IFLA_BR_MCAST_QUERY_INTVL',
3626 IFLA_BR_MCAST_QUERY_RESPONSE_INTVL : 'IFLA_BR_MCAST_QUERY_RESPONSE_INTVL',
3627 IFLA_BR_MCAST_STARTUP_QUERY_INTVL : 'IFLA_BR_MCAST_STARTUP_QUERY_INTVL',
3628 IFLA_BR_NF_CALL_IPTABLES : 'IFLA_BR_NF_CALL_IPTABLES',
3629 IFLA_BR_NF_CALL_IP6TABLES : 'IFLA_BR_NF_CALL_IP6TABLES',
3630 IFLA_BR_NF_CALL_ARPTABLES : 'IFLA_BR_NF_CALL_ARPTABLES',
3631 IFLA_BR_VLAN_DEFAULT_PVID : 'IFLA_BR_VLAN_DEFAULT_PVID',
d486dd0d
JF
3632 IFLA_BR_PAD : 'IFLA_BR_PAD',
3633 IFLA_BR_VLAN_STATS_ENABLED : 'IFLA_BR_VLAN_STATS_ENABLED',
3634 IFLA_BR_MCAST_STATS_ENABLED : 'IFLA_BR_MCAST_STATS_ENABLED',
3635 IFLA_BR_MCAST_IGMP_VERSION : 'IFLA_BR_MCAST_IGMP_VERSION',
3636 IFLA_BR_MCAST_MLD_VERSION : 'IFLA_BR_MCAST_MLD_VERSION'
3637 }
3638
3639 # =========================================
3640 # IFLA_INFO_DATA attributes for vrfs
3641 # =========================================
3642 IFLA_VRF_UNSPEC = 0
3643 IFLA_VRF_TABLE = 1
3644
3645 ifla_vrf_to_string = {
3646 IFLA_VRF_UNSPEC : 'IFLA_VRF_UNSPEC',
3647 IFLA_VRF_TABLE : 'IFLA_VRF_TABLE'
c4fd4972
JF
3648 }
3649
a61d1777
SE
3650 def __init__(self, msgtype, debug=False, logger=None, use_color=True):
3651 NetlinkPacket.__init__(self, msgtype, debug, logger, use_color)
198ded6a
JF
3652 self.PACK = 'BxHiII'
3653 self.LEN = calcsize(self.PACK)
3654
3655 def get_link_type_string(self, index):
3656 return self.get_string(self.link_type_to_string, index)
3657
f8f6549b
JF
3658 def get_ifla_inet6_af_spec_to_string(self, index):
3659 return self.get_string(self.ifla_inet6_af_spec_to_string, index)
3660
3661 def get_ifla_inet_af_spec_to_string(self, index):
3662 return self.get_string(self.ifla_inet_af_spec_to_string, index)
3663
198ded6a
JF
3664 def get_ifla_bridge_af_spec_to_string(self, index):
3665 return self.get_string(self.ifla_bridge_af_spec_to_string, index)
3666
3667 def get_ifla_info_string(self, index):
3668 return self.get_string(self.ifla_info_to_string, index)
3669
3670 def get_ifla_vlan_string(self, index):
3671 return self.get_string(self.ifla_vlan_to_string, index)
3672
3673 def get_ifla_vxlan_string(self, index):
3674 return self.get_string(self.ifla_vxlan_to_string, index)
3675
3676 def get_ifla_macvlan_string(self, index):
3677 return self.get_string(self.ifla_macvlan_to_string, index)
3678
3679 def get_macvlan_mode_string(self, index):
3680 return self.get_string(self.macvlan_mode_to_string, index)
3681
3682 def get_ifla_bond_string(self, index):
3683 return self.get_string(self.ifla_bond_to_string, index)
3684
d486dd0d
JF
3685 def get_ifla_bond_ad_string(self, index):
3686 return self.get_string(self.ifla_bond_ad_to_string, index)
3687
3688 def get_ifla_brport_string(self, index):
3689 return self.get_string(self.ifla_brport_to_string, index)
198ded6a 3690
c4fd4972
JF
3691 def get_ifla_br_string(self, index):
3692 return self.get_string(self.ifla_br_to_string, index)
3693
198ded6a
JF
3694 def get_bridge_vlan_string(self, index):
3695 return self.get_string(self.bridge_vlan_to_string, index)
3696
3697 def get_bridge_flags_string(self, index):
3698 return self.get_string(self.bridge_flags_to_string, index)
3699
3700 def decode_service_header(self):
3701
3702 # Nothing to do if the message did not contain a service header
3703 if self.length == self.header_LEN:
3704 return
3705
3706 (self.family, self.device_type,
3707 self.ifindex,
3708 self.flags,
3709 self.change_mask) = \
3710 unpack(self.PACK, self.msg_data[:self.LEN])
3711
3712 if self.debug:
a61d1777
SE
3713 color = yellow if self.use_color else None
3714 color_start = "\033[%dm" % color if color else ""
3715 color_end = "\033[0m" if color else ""
3716 self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
3717
198ded6a
JF
3718 for x in range(0, self.LEN/4):
3719 if self.line_number == 5:
4d4aac88
JF
3720 extra = "Family %s (%s:%d), Device Type %s (%d - %s)" % \
3721 (zfilled_hex(self.family, 2), get_family_str(self.family), self.family,
198ded6a
JF
3722 zfilled_hex(self.device_type, 4), self.device_type, self.get_link_type_string(self.device_type))
3723 elif self.line_number == 6:
3724 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
3725 elif self.line_number == 7:
3726 extra = "Device Flags %s (%s)" % (zfilled_hex(self.flags, 8), self.get_flags_string())
3727 elif self.line_number == 8:
3728 extra = "Change Mask %s" % zfilled_hex(self.change_mask, 8)
3729 else:
3730 extra = "Unexpected line number %d" % self.line_number
3731
3732 start = x * 4
3733 end = start + 4
3734 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
3735 self.line_number += 1
3736
3737 def is_up(self):
3738 if self.flags & Link.IFF_UP:
3739 return True
3740 return False
3741
3742
3479a0c3
JF
3743class Netconf(Link):
3744 """
3745 RTM_NEWNETCONF - Service Header
3746
3747 0 1
3748 0 1 2 3 4 5 6 7 8
3749 +-+-+-+-+-+-+-+-+
3750 | Family |
3751 +-+-+-+-+-+-+-+-+
3752
3753 RTM_GETNETCONF - Service Header
3754
3755 0 1 2 3
3756 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
3757 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3758 | Family | Reserved | Device Type |
3759 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3760 | Interface Index |
3761 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3762 | Device Flags |
3763 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3764 | Change Mask |
3765 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3766 """
3767 # Netconf attributes
3768 # /usr/include/linux/netconf.h
3769 NETCONFA_UNSPEC = 0
3770 NETCONFA_IFINDEX = 1
3771 NETCONFA_FORWARDING = 2
3772 NETCONFA_RP_FILTER = 3
3773 NETCONFA_MC_FORWARDING = 4
3774 NETCONFA_PROXY_NEIGH = 5
3775 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN = 6
3776 NETCONFA_INPUT = 7
3777 __NETCONFA_MAX = 8
3778
3779 NETCONFA_MAX = (__NETCONFA_MAX - 1)
3780
3781 NETCONFA_ALL = -1
3782 NETCONFA_IFINDEX_ALL = -1
3783 NETCONFA_IFINDEX_DEFAULT = -2
3784
3785 NETCONF_ATTR_FAMILY = 0x0001
3786 NETCONF_ATTR_IFINDEX = 0x0002
3787 NETCONF_ATTR_RP_FILTER = 0x0004
3788 NETCONF_ATTR_FWDING = 0x0008
3789 NETCONF_ATTR_MC_FWDING = 0x0010
3790 NETCONF_ATTR_PROXY_NEIGH = 0x0020
3791 NETCONF_ATTR_IGNORE_RT_LINKDWN = 0x0040
3792
3793 attribute_to_class = {
3794 NETCONFA_UNSPEC : ('NETCONFA_UNSPEC', AttributeGeneric),
3795 NETCONFA_IFINDEX : ('NETCONFA_IFINDEX', AttributeFourByteValue),
3796 NETCONFA_FORWARDING : ('NETCONFA_FORWARDING', AttributeFourByteValue),
3797 NETCONFA_RP_FILTER : ('NETCONFA_RP_FILTER', AttributeFourByteValue),
3798 NETCONFA_MC_FORWARDING : ('NETCONFA_MC_FORWARDING', AttributeFourByteValue),
3799 NETCONFA_PROXY_NEIGH : ('NETCONFA_PROXY_NEIGH', AttributeFourByteValue),
3800 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN : ('NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN', AttributeFourByteValue),
3801 NETCONFA_INPUT : ('NETCONFA_INPUT', AttributeFourByteValue),
3802 }
3803
3804 def __init__(self, msgtype, debug=False, logger=None, use_color=True):
3805 NetlinkPacket.__init__(self, msgtype, debug, logger, use_color)
3806 if msgtype == RTM_GETNETCONF: # same as RTM_GETLINK
3807 self.PACK = 'BxHiII'
3808 self.LEN = calcsize(self.PACK)
3809 elif msgtype == RTM_NEWNETCONF:
3810 self.PACK = 'Bxxx'
3811 self.LEN = calcsize(self.PACK)
3812
3813 def decode_service_header(self):
3814 # Nothing to do if the message did not contain a service header
3815 if self.length == self.header_LEN:
3816 return
3817
3818 if self.msgtype == RTM_GETNETCONF:
3819 super(Netconf, self).decode_service_header()
3820
3821 elif self.msgtype == RTM_NEWNETCONF:
3822 (self.family,) = unpack(self.PACK, self.msg_data[:self.LEN])
3823
3824 if self.debug:
3825 color = yellow if self.use_color else None
3826 color_start = "\033[%dm" % color if color else ""
3827 color_end = "\033[0m" if color else ""
3828 self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
4d4aac88 3829 self.dump_buffer.append(data_to_color_text(1, color, bytearray(struct.pack('!I', self.family)), "Family %s (%s:%d)" % (zfilled_hex(self.family, 2), get_family_str(self.family), self.family)))
3479a0c3
JF
3830
3831
198ded6a
JF
3832class Neighbor(NetlinkPacket):
3833 """
3834 Service Header
3835
3836 0 1 2 3
3837 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
3838 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3839 | Family | Reserved1 | Reserved2 |
3840 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3841 | Interface Index |
3842 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3843 | State | Flags | Type |
3844 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3845 """
3846
3847 # Neighbor attributes
3848 # /usr/include/linux/neighbour.h
3849 NDA_UNSPEC = 0x00 # Unknown type
3850 NDA_DST = 0x01 # A neighbour cache network. layer destination address
3851 NDA_LLADDR = 0x02 # A neighbor cache link layer address.
3852 NDA_CACHEINFO = 0x03 # Cache statistics
3853 NDA_PROBES = 0x04
3854 NDA_VLAN = 0x05
3855 NDA_PORT = 0x06
3856 NDA_VNI = 0x07
3857 NDA_IFINDEX = 0x08
3858 NDA_MASTER = 0x09
3859 NDA_LINK_NETNSID = 0x0A
3860
3861 attribute_to_class = {
3862 NDA_UNSPEC : ('NDA_UNSPEC', AttributeGeneric),
3863 NDA_DST : ('NDA_DST', AttributeIPAddress),
3864 NDA_LLADDR : ('NDA_LLADDR', AttributeMACAddress),
9f25ff0d 3865 NDA_CACHEINFO : ('NDA_CACHEINFO', AttributeFourByteList),
198ded6a 3866 NDA_PROBES : ('NDA_PROBES', AttributeFourByteValue),
9f25ff0d 3867 NDA_VLAN : ('NDA_VLAN', AttributeTwoByteValue),
198ded6a 3868 NDA_PORT : ('NDA_PORT', AttributeGeneric),
9f25ff0d
SE
3869 NDA_VNI : ('NDA_VNI', AttributeFourByteValue),
3870 NDA_IFINDEX : ('NDA_IFINDEX', AttributeFourByteValue),
3871 NDA_MASTER : ('NDA_MASTER', AttributeFourByteValue),
198ded6a
JF
3872 NDA_LINK_NETNSID : ('NDA_LINK_NETNSID', AttributeGeneric)
3873 }
3874
3875 # Neighbor flags
3876 # /usr/include/linux/neighbour.h
d486dd0d
JF
3877 NTF_USE = 0x01
3878 NTF_SELF = 0x02
3879 NTF_MASTER = 0x04
3880 NTF_PROXY = 0x08 # A proxy ARP entry
3881 NTF_EXT_LEARNED = 0x10 # neigh entry installed by an external APP
3882 NTF_ROUTER = 0x80 # An IPv6 router
198ded6a
JF
3883
3884 flag_to_string = {
d486dd0d
JF
3885 NTF_USE : 'NTF_USE',
3886 NTF_SELF : 'NTF_SELF',
3887 NTF_MASTER : 'NTF_MASTER',
3888 NTF_PROXY : 'NTF_PROXY',
3889 NTF_EXT_LEARNED : 'NTF_EXT_LEARNED',
3890 NTF_ROUTER : 'NTF_ROUTER'
198ded6a
JF
3891 }
3892
3893 # Neighbor states
3894 # /usr/include/linux/neighbour.h
3895 NUD_NONE = 0x00
3896 NUD_INCOMPLETE = 0x01 # Still attempting to resolve
3897 NUD_REACHABLE = 0x02 # A confirmed working cache entry
3898 NUD_STALE = 0x04 # an expired cache entry
3899 NUD_DELAY = 0x08 # Neighbor no longer reachable. Traffic sent, waiting for confirmatio.
3900 NUD_PROBE = 0x10 # A cache entry that is currently being re-solicited
3901 NUD_FAILED = 0x20 # An invalid cache entry
3902 NUD_NOARP = 0x40 # A device which does not do neighbor discovery(ARP)
3903 NUD_PERMANENT = 0x80 # A static entry
3904
3905 state_to_string = {
3906 NUD_NONE : 'NUD_NONE',
3907 NUD_INCOMPLETE : 'NUD_INCOMPLETE',
3908 NUD_REACHABLE : 'NUD_REACHABLE',
3909 NUD_STALE : 'NUD_STALE',
3910 NUD_DELAY : 'NUD_DELAY',
3911 NUD_PROBE : 'NUD_PROBE',
3912 NUD_FAILED : 'NUD_FAILED',
3913 NUD_NOARP : 'NUD_NOARP',
3914 NUD_PERMANENT : 'NUD_PERMANENT'
3915 }
3916
a61d1777
SE
3917 def __init__(self, msgtype, debug=False, logger=None, use_color=True):
3918 NetlinkPacket.__init__(self, msgtype, debug, logger, use_color)
198ded6a
JF
3919 self.PACK = 'BxxxiHBB'
3920 self.LEN = calcsize(self.PACK)
3921
3922 def get_state_string(self, index):
3923 return self.get_string(self.state_to_string, index)
3924
d486dd0d
JF
3925 def get_states_string(self, states):
3926 for_string = []
3927
3928 if states & Neighbor.NUD_INCOMPLETE:
3929 for_string.append('NUD_INCOMPLETE')
3930
3931 if states & Neighbor.NUD_REACHABLE:
3932 for_string.append('NUD_REACHABLE')
3933
3934 if states & Neighbor.NUD_STALE:
3935 for_string.append('NUD_STALE')
3936
3937 if states & Neighbor.NUD_DELAY:
3938 for_string.append('NUD_DELAY')
3939
3940 if states & Neighbor.NUD_PROBE:
3941 for_string.append('NUD_PROBE')
3942
3943 if states & Neighbor.NUD_FAILED:
3944 for_string.append('NUD_FAILED')
3945
3946 if states & Neighbor.NUD_NOARP:
3947 for_string.append('NUD_NOARP')
3948
3949 if states & Neighbor.NUD_PERMANENT:
3950 for_string.append('NUD_PERMANENT')
3951
3952 return ', '.join(for_string)
3953
3954 def get_flags_string(self, flags):
3955 for_string = []
3956
3957 if flags & Neighbor.NTF_USE:
3958 for_string.append('NTF_USE')
3959
3960 if flags & Neighbor.NTF_SELF:
3961 for_string.append('NTF_SELF')
3962
3963 if flags & Neighbor.NTF_MASTER:
3964 for_string.append('NTF_MASTER')
3965
3966 if flags & Neighbor.NTF_PROXY:
3967 for_string.append('NTF_PROXY')
3968
3969 if flags & Neighbor.NTF_ROUTER:
3970 for_string.append('NTF_ROUTER')
3971
3972 return ', '.join(for_string)
3973
198ded6a
JF
3974 def decode_service_header(self):
3975
3976 # Nothing to do if the message did not contain a service header
3977 if self.length == self.header_LEN:
3978 return
3979
3980 (self.family,
3981 self.ifindex,
3982 self.state, self.flags, self.neighbor_type) = \
3983 unpack(self.PACK, self.msg_data[:self.LEN])
3984
3985 if self.debug:
a61d1777
SE
3986 color = yellow if self.use_color else None
3987 color_start = "\033[%dm" % color if color else ""
3988 color_end = "\033[0m" if color else ""
3989 self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
198ded6a
JF
3990
3991 for x in range(0, self.LEN/4):
3992 if self.line_number == 5:
4d4aac88 3993 extra = "Family %s (%s:%d)" % (zfilled_hex(self.family, 2), get_family_str(self.family), self.family)
198ded6a
JF
3994 elif self.line_number == 6:
3995 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
3996 elif self.line_number == 7:
d486dd0d
JF
3997 extra = "State %s (%d) %s, Flags %s (%s) %s, Type %s (%d)" % \
3998 (zfilled_hex(self.state, 4), self.state, self.get_states_string(self.state),
3999 zfilled_hex(self.flags, 2), self.flags, self.get_flags_string(self.flags),
198ded6a
JF
4000 zfilled_hex(self.neighbor_type, 4), self.neighbor_type)
4001 else:
4002 extra = "Unexpected line number %d" % self.line_number
4003
4004 start = x * 4
4005 end = start + 4
4006 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
4007 self.line_number += 1
4008
4009
4010class Route(NetlinkPacket):
4011 """
4012 Service Header
4013
4014 0 1 2 3
4015 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
4016 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4017 | Family | Dest length | Src length | TOS |
4018 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4019 | Table ID | Protocol | Scope | Type |
4020 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4021 | Flags |
4022 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4023 """
4024
4025 # Route attributes
4026 # /usr/include/linux/rtnetlink.h
4027 RTA_UNSPEC = 0x00 # Ignored.
4028 RTA_DST = 0x01 # Protocol address for route destination address.
4029 RTA_SRC = 0x02 # Protocol address for route source address.
4030 RTA_IIF = 0x03 # Input interface index.
4031 RTA_OIF = 0x04 # Output interface index.
4032 RTA_GATEWAY = 0x05 # Protocol address for the gateway of the route
4033 RTA_PRIORITY = 0x06 # Priority of broker.
4034 RTA_PREFSRC = 0x07 # Preferred source address in cases where more than one source address could be used.
4035 RTA_METRICS = 0x08 # Route metrics attributed to route and associated protocols(e.g., RTT, initial TCP window, etc.).
4036 RTA_MULTIPATH = 0x09 # Multipath route next hop's attributes.
4037 RTA_PROTOINFO = 0x0A # Firewall based policy routing attribute.
4038 RTA_FLOW = 0x0B # Route realm.
4039 RTA_CACHEINFO = 0x0C # Cached route information.
4040 RTA_SESSION = 0x0D
4041 RTA_MP_ALGO = 0x0E
4042 RTA_TABLE = 0x0F
4043 RTA_MARK = 0x10
ea2bf79d
JF
4044 RTA_MFC_STATS = 0x11
4045 RTA_VIA = 0x12
4046 RTA_NEWDST = 0x13
4047 RTA_PREF = 0x14
4048 RTA_ENCAP_TYPE= 0x15
4049 RTA_ENCAP = 0x16
198ded6a
JF
4050
4051 attribute_to_class = {
4052 RTA_UNSPEC : ('RTA_UNSPEC', AttributeGeneric),
4053 RTA_DST : ('RTA_DST', AttributeIPAddress),
4054 RTA_SRC : ('RTA_SRC', AttributeIPAddress),
4055 RTA_IIF : ('RTA_IIF', AttributeFourByteValue),
4056 RTA_OIF : ('RTA_OIF', AttributeFourByteValue),
4057 RTA_GATEWAY : ('RTA_GATEWAY', AttributeIPAddress),
4058 RTA_PRIORITY : ('RTA_PRIORITY', AttributeFourByteValue),
4059 RTA_PREFSRC : ('RTA_PREFSRC', AttributeIPAddress),
4060 RTA_METRICS : ('RTA_METRICS', AttributeGeneric),
4061 RTA_MULTIPATH : ('RTA_MULTIPATH', AttributeRTA_MULTIPATH),
4062 RTA_PROTOINFO : ('RTA_PROTOINFO', AttributeGeneric),
4063 RTA_FLOW : ('RTA_FLOW', AttributeGeneric),
4064 RTA_CACHEINFO : ('RTA_CACHEINFO', AttributeGeneric),
4065 RTA_SESSION : ('RTA_SESSION', AttributeGeneric),
4066 RTA_MP_ALGO : ('RTA_MP_ALGO', AttributeGeneric),
4067 RTA_TABLE : ('RTA_TABLE', AttributeFourByteValue),
ea2bf79d
JF
4068 RTA_MARK : ('RTA_MARK', AttributeGeneric),
4069 RTA_MFC_STATS : ('RTA_MFC_STATS', AttributeGeneric),
4070 RTA_VIA : ('RTA_VIA', AttributeGeneric),
4071 RTA_NEWDST : ('RTA_NEWDST', AttributeGeneric),
4072 RTA_PREF : ('RTA_PREF', AttributeGeneric),
4073 RTA_ENCAP_TYPE: ('RTA_ENCAP_TYPE', AttributeGeneric),
4074 RTA_ENCAP : ('RTA_ENCAP', AttributeGeneric)
198ded6a
JF
4075 }
4076
4077 # Route tables
4078 # /usr/include/linux/rtnetlink.h
4079 RT_TABLE_UNSPEC = 0x00 # An unspecified routing table
4080 RT_TABLE_COMPAT = 0xFC
4081 RT_TABLE_DEFAULT = 0xFD # The default table
4082 RT_TABLE_MAIN = 0xFE # The main table
4083 RT_TABLE_LOCAL = 0xFF # The local table
4084
4085 table_to_string = {
4086 RT_TABLE_UNSPEC : 'RT_TABLE_UNSPEC',
4087 RT_TABLE_COMPAT : 'RT_TABLE_COMPAT',
4088 RT_TABLE_DEFAULT : 'RT_TABLE_DEFAULT',
4089 RT_TABLE_MAIN : 'RT_TABLE_MAIN',
4090 RT_TABLE_LOCAL : 'RT_TABLE_LOCAL'
4091 }
4092
4093 # Route scope
4094 # /usr/include/linux/rtnetlink.h
4095 RT_SCOPE_UNIVERSE = 0x00 # Global route
4096 RT_SCOPE_SITE = 0xC8 # Interior route in the local autonomous system
4097 RT_SCOPE_LINK = 0xFD # Route on this link
4098 RT_SCOPE_HOST = 0xFE # Route on the local host
4099 RT_SCOPE_NOWHERE = 0xFF # Destination does not exist
4100
4101 scope_to_string = {
4102 RT_SCOPE_UNIVERSE : 'RT_SCOPE_UNIVERSE',
4103 RT_SCOPE_SITE : 'RT_SCOPE_SITE',
4104 RT_SCOPE_LINK : 'RT_SCOPE_LINK',
4105 RT_SCOPE_HOST : 'RT_SCOPE_HOST',
4106 RT_SCOPE_NOWHERE : 'RT_SCOPE_NOWHERE'
4107 }
4108
d486dd0d
JF
4109 # Route scope to string
4110 # iproute2/lib/rt_names.c
4111 rtnl_rtscope_tab = {
4112 RT_SCOPE_UNIVERSE: 'global',
4113 RT_SCOPE_NOWHERE: 'nowhere',
4114 RT_SCOPE_HOST: 'host',
4115 RT_SCOPE_LINK: 'link',
4116 RT_SCOPE_SITE: 'site'
4117 }
4118
198ded6a
JF
4119 # Routing stack
4120 # /usr/include/linux/rtnetlink.h
4121 RT_PROT_UNSPEC = 0x00 # Identifies what/who added the route
4122 RT_PROT_REDIRECT = 0x01 # By an ICMP redirect
4123 RT_PROT_KERNEL = 0x02 # By the kernel
4124 RT_PROT_BOOT = 0x03 # During bootup
4125 RT_PROT_STATIC = 0x04 # By the administrator
4126 RT_PROT_GATED = 0x08 # GateD
4127 RT_PROT_RA = 0x09 # RDISC/ND router advertissements
4128 RT_PROT_MRT = 0x0A # Merit MRT
4129 RT_PROT_ZEBRA = 0x0B # ZEBRA
4130 RT_PROT_BIRD = 0x0C # BIRD
4131 RT_PROT_DNROUTED = 0x0D # DECnet routing daemon
4132 RT_PROT_XORP = 0x0E # XORP
4133 RT_PROT_NTK = 0x0F # Netsukuku
4134 RT_PROT_DHCP = 0x10 # DHCP client
4135 RT_PROT_EXABGP = 0x11 # Exa Networks ExaBGP
4136
4137 prot_to_string = {
4138 RT_PROT_UNSPEC : 'RT_PROT_UNSPEC',
4139 RT_PROT_REDIRECT : 'RT_PROT_REDIRECT',
4140 RT_PROT_KERNEL : 'RT_PROT_KERNEL',
4141 RT_PROT_BOOT : 'RT_PROT_BOOT',
4142 RT_PROT_STATIC : 'RT_PROT_STATIC',
4143 RT_PROT_GATED : 'RT_PROT_GATED',
4144 RT_PROT_RA : 'RT_PROT_RA',
4145 RT_PROT_MRT : 'RT_PROT_MRT',
4146 RT_PROT_ZEBRA : 'RT_PROT_ZEBRA',
4147 RT_PROT_BIRD : 'RT_PROT_BIRD',
4148 RT_PROT_DNROUTED : 'RT_PROT_DNROUTED',
4149 RT_PROT_XORP : 'RT_PROT_XORP',
4150 RT_PROT_NTK : 'RT_PROT_NTK',
4151 RT_PROT_DHCP : 'RT_PROT_DHCP',
4152 RT_PROT_EXABGP : 'RT_PROT_EXABGP'
4153 }
4154
4155 # Route types
4156 # /usr/include/linux/rtnetlink.h
4157 RTN_UNSPEC = 0x00 # Unknown broker.
4158 RTN_UNICAST = 0x01 # A gateway or direct broker.
4159 RTN_LOCAL = 0x02 # A local interface broker.
4160 RTN_BROADCAST = 0x03 # A local broadcast route(sent as a broadcast).
4161 RTN_ANYCAST = 0x04 # An anycast broker.
4162 RTN_MULTICAST = 0x05 # A multicast broker.
4163 RTN_BLACKHOLE = 0x06 # A silent packet dropping broker.
4164 RTN_UNREACHABLE = 0x07 # An unreachable destination. Packets dropped and
4165 # host unreachable ICMPs are sent to the originator.
4166 RTN_PROHIBIT = 0x08 # A packet rejection broker. Packets are dropped and
4167 # communication prohibited ICMPs are sent to the originator.
4168 RTN_THROW = 0x09 # When used with policy routing, continue routing lookup
4169 # in another table. Under normal routing, packets are
4170 # dropped and net unreachable ICMPs are sent to the originator.
4171 RTN_NAT = 0x0A # A network address translation rule.
4172 RTN_XRESOLVE = 0x0B # Refer to an external resolver(not implemented).
4173
4174 rt_type_to_string = {
4175 RTN_UNSPEC : 'RTN_UNSPEC',
4176 RTN_UNICAST : 'RTN_UNICAST',
4177 RTN_LOCAL : 'RTN_LOCAL',
4178 RTN_BROADCAST : 'RTN_BROADCAST',
4179 RTN_ANYCAST : 'RTN_ANYCAST',
4180 RTN_MULTICAST : 'RTN_MULTICAST',
4181 RTN_BLACKHOLE : 'RTN_BLACKHOLE',
4182 RTN_UNREACHABLE : 'RTN_UNREACHABLE',
4183 RTN_PROHIBIT : 'RTN_PROHIBIT',
4184 RTN_THROW : 'RTN_THROW',
4185 RTN_NAT : 'RTN_NAT',
4186 RTN_XRESOLVE : 'RTN_XRESOLVE'
4187 }
4188
4189 # Route flags
4190 # /usr/include/linux/rtnetlink.h
4191 RTM_F_NOTIFY = 0x100 # If the route changes, notify the user
4192 RTM_F_CLONED = 0x200 # Route is cloned from another route
4193 RTM_F_EQUALIZE = 0x400 # Allow randomization of next hop path in multi-path routing(currently not implemented)
4194 RTM_F_PREFIX = 0x800 # Prefix Address
4195
4196 flag_to_string = {
4197 RTM_F_NOTIFY : 'RTM_F_NOTIFY',
4198 RTM_F_CLONED : 'RTM_F_CLONED',
4199 RTM_F_EQUALIZE : 'RTM_F_EQUALIZE',
4200 RTM_F_PREFIX : 'RTM_F_PREFIX'
4201 }
4202
a61d1777
SE
4203 def __init__(self, msgtype, debug=False, logger=None, use_color=True):
4204 NetlinkPacket.__init__(self, msgtype, debug, logger, use_color)
198ded6a
JF
4205 self.PACK = '=8BI' # or is it 8Bi ?
4206 self.LEN = calcsize(self.PACK)
198ded6a
JF
4207
4208 def get_prefix_string(self):
4209 dst = self.get_attribute_value(self.RTA_DST)
4210
4211 if dst:
4212 return "%s/%d" % (dst, self.src_len)
4213 else:
4214 if self.family == AF_INET:
4215 return "0.0.0.0/0"
4216 elif self.family == AF_INET6:
4217 return "::/0"
4218
4219 def get_protocol_string(self, index=None):
4220 if index is None:
4221 index = self.protocol
4222 return self.get_string(self.prot_to_string, index)
4223
4224 def get_rt_type_string(self, index=None):
4225 if index is None:
4226 index = self.route_type
4227 return self.get_string(self.rt_type_to_string, index)
4228
4229 def get_scope_string(self, index=None):
4230 if index is None:
4231 index = self.scope
4232 return self.get_string(self.scope_to_string, index)
4233
4234 def get_table_id_string(self, index=None):
4235 if index is None:
4236 index = self.table_id
4237 return self.get_string(self.table_to_string, index)
4238
4239 def _get_ifname_from_index(self, ifindex, ifname_by_index):
4240 if ifindex:
4241 ifname = ifname_by_index.get(ifindex)
4242
4243 if ifname is None:
4244 ifname = str(ifindex)
4245 else:
4246 ifname = None
4247
4248 return ifname
4249
4250 def get_nexthops(self, ifname_by_index={}):
4251 nexthop = self.get_attribute_value(self.RTA_GATEWAY)
4252 multipath = self.get_attribute_value(self.RTA_MULTIPATH)
4253 nexthops = []
4254
4255 if nexthop:
4256 rta_oif = self.get_attribute_value(self.RTA_OIF)
4257 ifname = self._get_ifname_from_index(rta_oif, ifname_by_index)
4258 nexthops.append((nexthop, ifname))
4259
4260 elif multipath:
4261 for (nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops) in multipath:
4262 ifname = self._get_ifname_from_index(rtnh_ifindex, ifname_by_index)
4263 nexthops.append((nexthop, ifname))
4264
4265 return nexthops
4266
4267 def get_nexthops_string(self, ifname_by_index={}):
4268 output = []
4269
4270 for (nexthop, ifname) in self.get_nexthops(ifname_by_index):
4271 output.append(" via %s on %s" % (nexthop, ifname))
4272
4273 return ",".join(output)
4274
4275 def decode_service_header(self):
4276
4277 # Nothing to do if the message did not contain a service header
4278 if self.length == self.header_LEN:
4279 return
4280
4281 (self.family, self.src_len, self.dst_len, self.tos,
4282 self.table_id, self.protocol, self.scope, self.route_type,
4283 self.flags) = \
4284 unpack(self.PACK, self.msg_data[:self.LEN])
4285
4286 if self.debug:
a61d1777
SE
4287 color = yellow if self.use_color else None
4288 color_start = "\033[%dm" % color if color else ""
4289 color_end = "\033[0m" if color else ""
4290 self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
198ded6a
JF
4291
4292 for x in range(0, self.LEN/4):
4293 if self.line_number == 5:
4d4aac88
JF
4294 extra = "Family %s (%s:%d), Source Length %s (%d), Destination Length %s (%d), TOS %s (%d)" % \
4295 (zfilled_hex(self.family, 2), get_family_str(self.family), self.family,
198ded6a
JF
4296 zfilled_hex(self.src_len, 2), self.src_len,
4297 zfilled_hex(self.dst_len, 2), self.dst_len,
4298 zfilled_hex(self.tos, 2), self.tos)
4299 elif self.line_number == 6:
4300 extra = "Table ID %s (%d - %s), Protocol %s (%d - %s), Scope %s (%d - %s), Type %s (%d - %s)" % \
4301 (zfilled_hex(self.table_id, 2), self.table_id, self.get_table_id_string(),
4302 zfilled_hex(self.protocol, 2), self.protocol, self.get_protocol_string(),
4303 zfilled_hex(self.scope, 2), self.scope, self.get_scope_string(),
4304 zfilled_hex(self.route_type, 2), self.route_type, self.get_rt_type_string())
4305 elif self.line_number == 7:
4306 extra = "Flags %s" % zfilled_hex(self.flags, 8)
4307 else:
4308 extra = "Unexpected line number %d" % self.line_number
4309
4310 start = x * 4
4311 end = start + 4
4312 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
4313 self.line_number += 1
d486dd0d
JF
4314
4315class Done(NetlinkPacket):
4316 """
4317 NLMSG_DONE
4318
4319 Service Header
4320 0 1 2 3
4321 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
4322 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4323 | TBD |
4324 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4325 """
4326
4327 def __init__(self, msgtype, debug=False, logger=None, use_color=True):
4328 NetlinkPacket.__init__(self, msgtype, debug, logger, use_color)
4329 self.PACK = 'i'
4330 self.LEN = calcsize(self.PACK)
4331
4332 def decode_service_header(self):
4333 foo = unpack(self.PACK, self.msg_data[:self.LEN])
4334
4335 if self.debug:
4336 color = yellow if self.use_color else None
4337 color_start = "\033[%dm" % color if color else ""
4338 color_end = "\033[0m" if color else ""
4339 self.dump_buffer.append(" %sService Header%s" % (color_start, color_end))
4340
4341 for x in range(0, self.LEN/4):
4342 extra = ''
4343 start = x * 4
4344 end = start + 4
4345 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
4346 self.line_number += 1