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