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