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