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