]> git.proxmox.com Git - mirror_ifupdown2.git/blame - nlmanager/nlpacket.py
nlmanager: Support new attribute types
[mirror_ifupdown2.git] / nlmanager / nlpacket.py
CommitLineData
198ded6a
JF
1# Copyright (c) 2009-2013, Exa Networks Limited
2# Copyright (c) 2009-2013, Thomas Mangin
3# Copyright (c) 2015 Cumulus Networks, Inc.
4#
5# All rights reserved.
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions are met:
8#
9# Redistributions of source code must retain the above copyright notice, this
10# list of conditions and the following disclaimer.
11#
12# Redistributions in binary form must reproduce the above copyright notice,
13# this list of conditions and the following disclaimer in the documentation
14# and/or other materials provided with the distribution.
15#
16# The names of the Exa Networks Limited, Cumulus Networks, Inc. nor the names
17# of its contributors may be used to endorse or promote products derived from
18# this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31import logging
32import struct
33from ipaddr import IPv4Address, IPv6Address
34from binascii import hexlify
35from pprint import pformat
36from socket import AF_INET, AF_INET6, AF_BRIDGE
37from string import printable
38from struct import pack, unpack, calcsize
39
40log = logging.getLogger(__name__)
41
4e979b1b
JF
42# Interface name buffer size #define IFNAMSIZ 16 (kernel source)
43IF_NAME_SIZE = 15 # 15 because python doesn't have \0
44
198ded6a
JF
45# Netlink message types
46NLMSG_NOOP = 0x01
47NLMSG_ERROR = 0x02
48NLMSG_DONE = 0x03
49NLMSG_OVERRUN = 0x04
50
51RTM_NEWLINK = 0x10 # Create a new network interface
52RTM_DELLINK = 0x11 # Destroy a network interface
53RTM_GETLINK = 0x12 # Retrieve information about a network interface(ifinfomsg)
54RTM_SETLINK = 0x13 #
55
56RTM_NEWADDR = 0x14
57RTM_DELADDR = 0x15
58RTM_GETADDR = 0x16
59
60RTM_NEWNEIGH = 0x1C
61RTM_DELNEIGH = 0x1D
62RTM_GETNEIGH = 0x1E
63
64RTM_NEWROUTE = 0x18
65RTM_DELROUTE = 0x19
66RTM_GETROUTE = 0x1A
67
68RTM_NEWQDISC = 0x24
69RTM_DELQDISC = 0x25
70RTM_GETQDISC = 0x26
71
72# Netlink message flags
73NLM_F_REQUEST = 0x01 # It is query message.
74NLM_F_MULTI = 0x02 # Multipart message, terminated by NLMSG_DONE
75NLM_F_ACK = 0x04 # Reply with ack, with zero or error code
76NLM_F_ECHO = 0x08 # Echo this query
77
78# Modifiers to GET query
79NLM_F_ROOT = 0x100 # specify tree root
80NLM_F_MATCH = 0x200 # return all matching
81NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH
82NLM_F_ATOMIC = 0x400 # atomic GET
83
84# Modifiers to NEW query
85NLM_F_REPLACE = 0x100 # Override existing
86NLM_F_EXCL = 0x200 # Do not touch, if it exists
87NLM_F_CREATE = 0x400 # Create, if it does not exist
88NLM_F_APPEND = 0x800 # Add to end of list
89
90NLA_F_NESTED = 0x8000
91NLA_F_NET_BYTEORDER = 0x4000
92NLA_TYPE_MASK = ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
93
94# Groups
95RTMGRP_LINK = 0x1
96RTMGRP_NOTIFY = 0x2
97RTMGRP_NEIGH = 0x4
98RTMGRP_TC = 0x8
99RTMGRP_IPV4_IFADDR = 0x10
100RTMGRP_IPV4_MROUTE = 0x20
101RTMGRP_IPV4_ROUTE = 0x40
102RTMGRP_IPV4_RULE = 0x80
103RTMGRP_IPV6_IFADDR = 0x100
104RTMGRP_IPV6_MROUTE = 0x200
105RTMGRP_IPV6_ROUTE = 0x400
106RTMGRP_IPV6_IFINFO = 0x800
107RTMGRP_DECnet_IFADDR = 0x1000
108RTMGRP_DECnet_ROUTE = 0x4000
109RTMGRP_IPV6_PREFIX = 0x20000
110
111RTMGRP_ALL = (RTMGRP_LINK | RTMGRP_NOTIFY | RTMGRP_NEIGH | RTMGRP_TC |
112 RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_MROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE |
113 RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO |
114 RTMGRP_DECnet_IFADDR | RTMGRP_DECnet_ROUTE |
115 RTMGRP_IPV6_PREFIX)
116
117# Colors for logging
118red = 91
119green = 92
120yellow = 93
121blue = 94
122
123
124def zfilled_hex(value, digits):
125 return '0x' + hex(value)[2:].zfill(digits)
126
127
128def remove_trailing_null(line):
129 """
130 Remove the last character if it is a NULL...having that NULL
131 causes python to print a garbage character
132 """
133
134 if ord(line[-1]) == 0:
135 line = line[:-1]
136
137 return line
138
139
140def mac_int_to_str(mac_int):
141 """
142 Return an integer in MAC string format
143 """
144
145 # [2:] to remove the leading 0x, then fill out to 12 zeroes, then uppercase
146 all_caps = hex(int(mac_int))[2:].zfill(12).upper()
147
148 if all_caps[-1] == 'L':
149 all_caps = all_caps[:-1]
150 all_caps = all_caps.zfill(12).upper()
151
152 return "%s.%s.%s" % (all_caps[0:4], all_caps[4:8], all_caps[8:12])
153
154
155def data_to_color_text(line_number, color, data, extra=''):
156 (c1, c2, c3, c4) = unpack('BBBB', data[0:4])
157 in_ascii = []
158
159 for c in (c1, c2, c3, c4):
160 char_c = chr(c)
161
162 if char_c in printable[:-5]:
163 in_ascii.append(char_c)
164 else:
165 in_ascii.append('.')
166
167 return ' %2d: \033[%dm0x%02x%02x%02x%02x\033[0m %s %s' % (line_number, color, c1, c2, c3, c4, ''.join(in_ascii), extra)
168
169
170def padded_length(length):
171 return int((length + 3) / 4) * 4
172
173
174class Attribute(object):
175
176 def __init__(self, atype, string, logger):
177 self.atype = atype
178 self.string = string
179 self.HEADER_PACK = '=HH'
180 self.HEADER_LEN = calcsize(self.HEADER_PACK)
181 self.PACK = None
182 self.LEN = None
183 self.value = None
184 self.nested = False
185 self.net_byteorder = False
186 self.log = logger
187
188 def __str__(self):
189 return self.string
190
4e979b1b
JF
191 def set_value(self, value):
192 self.value = value
193
194 def set_nested(self, nested):
195 self.nested = nested
196
197 def set_net_byteorder(self, net_byteorder):
198 self.net_byteorder = net_byteorder
199
198ded6a
JF
200 def pad_bytes_needed(self, length):
201 """
202 Return the number of bytes that should be added to align on a 4-byte boundry
203 """
204 remainder = length % 4
205
206 if remainder:
207 return 4 - remainder
208
209 return 0
210
211 def pad(self, length, raw):
212 pad = self.pad_bytes_needed(length)
213
214 if pad:
215 raw += '\0' * pad
216
217 return raw
218
219 def encode(self):
26e7207b
JF
220
221 if not self.LEN:
222 raise Exception('Please define an encode() method in your child attribute class, or do not use AttributeGeneric')
223
198ded6a
JF
224 length = self.HEADER_LEN + self.LEN
225 attr_type_with_flags = self.atype
226
227 if self.nested:
228 attr_type_with_flags = attr_type_with_flags | NLA_F_NESTED
229
230 if self.net_byteorder:
231 attr_type_with_flags = attr_type_with_flags | NLA_F_NET_BYTEORDER
232
233 raw = pack(self.HEADER_PACK, length, attr_type_with_flags) + pack(self.PACK, self.value)
234 raw = self.pad(length, raw)
235 return raw
236
237 def decode_length_type(self, data):
238 """
239 The first two bytes of an attribute are the length, the next two bytes are the type
240 """
241 self.data = data
242 prev_atype = self.atype
243 (data1, data2) = unpack(self.HEADER_PACK, data[:self.HEADER_LEN])
244 self.length = int(data1)
245 self.atype = int(data2)
246 self.attr_end = padded_length(self.length)
247
248 self.nested = True if self.atype & NLA_F_NESTED else False
249 self.net_byteorder = True if self.atype & NLA_F_NET_BYTEORDER else False
250 self.atype = self.atype & NLA_TYPE_MASK
251
252 # Should never happen
253 assert self.atype == prev_atype, "This object changes attribute type from %d to %d, this is bad" % (prev_atype, self.atype)
254
255 def dump_first_line(self, dump_buffer, line_number, color):
256 """
257 Add the "Length....Type..." line to the dump buffer
258 """
259 if self.attr_end == self.length:
260 padded_to = ', '
261 else:
262 padded_to = ' padded to %d, ' % self.attr_end
263
264 extra = 'Length %s (%d)%sType %s%s%s (%d) %s' % \
265 (zfilled_hex(self.length, 4), self.length,
266 padded_to,
267 zfilled_hex(self.atype, 4),
268 " (NLA_F_NESTED set)" if self.nested else "",
269 " (NLA_F_NET_BYTEORDER set)" if self.net_byteorder else "",
270 self.atype,
271 self)
272
273 dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], extra))
274 return line_number + 1
275
276 def dump_lines(self, dump_buffer, line_number, color):
277 line_number = self.dump_first_line(dump_buffer, line_number, color)
278
279 for x in xrange(1, self.attr_end/4):
280 start = x * 4
281 end = start + 4
282 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], ''))
283 line_number += 1
284
285 return line_number
286
287 def get_pretty_value(self):
288 return self.value
289
290
9f25ff0d
SE
291class AttributeFourByteList(Attribute):
292
293 def __init__(self, atype, string, family, logger):
294 Attribute.__init__(self, atype, string, logger)
295
296 def decode(self, parent_msg, data):
297 self.decode_length_type(data)
298 wordcount = (self.attr_end - 4)/4
299 self.PACK = '=%dL' % wordcount
300 self.LEN = calcsize(self.PACK)
301
302 try:
303 self.value = unpack(self.PACK, self.data[4:])
304 except struct.error:
305 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
306 raise
307
308 def dump_lines(self, dump_buffer, line_number, color):
309 line_number = self.dump_first_line(dump_buffer, line_number, color)
310 idx = 1
311 for val in self.value:
312 dump_buffer.append(data_to_color_text(line_number, color, self.data[4*idx:4*(idx+1)], val))
313 line_number += 1
314 idx += 1
315 return line_number
316
317
198ded6a
JF
318class AttributeFourByteValue(Attribute):
319
9f25ff0d 320 def __init__(self, atype, string, family, logger):
198ded6a
JF
321 Attribute.__init__(self, atype, string, logger)
322 self.PACK = '=L'
323 self.LEN = calcsize(self.PACK)
324
325 def decode(self, parent_msg, data):
326 self.decode_length_type(data)
327 assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
328
329 try:
330 self.value = int(unpack(self.PACK, self.data[4:])[0])
331 except struct.error:
332 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
333 raise
334
335 def dump_lines(self, dump_buffer, line_number, color):
336 line_number = self.dump_first_line(dump_buffer, line_number, color)
337 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
338 return line_number + 1
339
340
9f25ff0d
SE
341class AttributeTwoByteValue(Attribute):
342
343 def __init__(self, atype, string, family, logger):
344 Attribute.__init__(self, atype, string, logger)
345 self.PACK = '=Hxx'
346 self.LEN = calcsize(self.PACK)
347
348 def decode(self, parent_msg, data):
349 self.decode_length_type(data)
350 assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end)
351
352 try:
353 self.value = int(unpack(self.PACK, self.data[4:8])[0])
354 except struct.error:
355 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:6])))
356 raise
357
358 def encode(self):
359 length = self.HEADER_LEN + self.LEN
360 raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, self.value)
361 raw = self.pad(length, raw)
362 return raw
363
364 def dump_lines(self, dump_buffer, line_number, color):
365 line_number = self.dump_first_line(dump_buffer, line_number, color)
366 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
367 return line_number + 1
368
369
198ded6a
JF
370class AttributeString(Attribute):
371
9f25ff0d 372 def __init__(self, atype, string, family, logger):
198ded6a
JF
373 Attribute.__init__(self, atype, string, logger)
374 self.PACK = None
375 self.LEN = None
376
377 def encode(self):
26d1e82b 378 # some interface names come from JSON as unicode strings
198ded6a
JF
379 # and cannot be packed as is so we must convert them to strings
380 if isinstance(self.value, unicode):
381 self.value = str(self.value)
382 self.PACK = '%ds' % len(self.value)
383 self.LEN = calcsize(self.PACK)
384
385 length = self.HEADER_LEN + self.LEN
386 raw = pack(self.HEADER_PACK, length, self.atype) + pack(self.PACK, self.value)
387 raw = self.pad(length, raw)
388 return raw
389
390 def decode(self, parent_msg, data):
391 self.decode_length_type(data)
392 self.PACK = '%ds' % (self.length - 4)
393 self.LEN = calcsize(self.PACK)
394
395 try:
396 self.value = remove_trailing_null(unpack(self.PACK, self.data[4:self.length])[0])
397 except struct.error:
398 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:self.length])))
399 raise
400
401
4e979b1b
JF
402class AttributeStringInterfaceName(AttributeString):
403
9f25ff0d
SE
404 def __init__(self, atype, string, family, logger):
405 AttributeString.__init__(self, atype, string, family, logger)
4e979b1b
JF
406
407 def set_value(self, value):
408 if value and len(value) > IF_NAME_SIZE:
409 raise Exception('interface name exceeds max length of %d' % IF_NAME_SIZE)
410 self.value = value
411
412
198ded6a
JF
413class AttributeIPAddress(Attribute):
414
415 def __init__(self, atype, string, family, logger):
416 Attribute.__init__(self, atype, string, logger)
417 self.value_int = None
418 self.value_int_str = None
419 self.family = family
420
421 if self.family == AF_INET:
422 self.PACK = '>L'
423
424 elif self.family == AF_INET6:
425 self.PACK = '>QQ'
426
427 elif self.family == AF_BRIDGE:
428 self.PACK = '>L'
429
430 else:
431 raise Exception("%s is not a supported address family" % self.family)
432
433 self.LEN = calcsize(self.PACK)
434
435 def decode(self, parent_msg, data):
436 self.decode_length_type(data)
437
438 try:
439 if self.family == AF_INET:
440 self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0])
441
442 elif self.family == AF_INET6:
443 (data1, data2) = unpack(self.PACK, self.data[4:])
444 self.value = IPv6Address(data1 << 64 | data2)
445
446 elif self.family == AF_BRIDGE:
9f25ff0d 447 self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0])
198ded6a
JF
448
449 self.value_int = int(self.value)
450 self.value_int_str = str(self.value_int)
451
452 except struct.error:
453 self.value = None
454 self.value_int = None
455 self.value_int_str = None
456 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
457 raise
458
9f25ff0d
SE
459 def encode(self):
460 length = self.HEADER_LEN + self.LEN
461
462 if self.family not in [AF_INET, AF_INET6, AF_BRIDGE]:
463 raise Exception("%s is not a supported address family" % self.family)
464
465 raw = pack(self.HEADER_PACK, length, self.atype) + self.value.packed
466 raw = self.pad(length, raw)
467 return raw
468
198ded6a
JF
469 def dump_lines(self, dump_buffer, line_number, color):
470 line_number = self.dump_first_line(dump_buffer, line_number, color)
471
472 if self.family == AF_INET:
473 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
474 line_number += 1
475
476 elif self.family == AF_INET6:
477
478 for x in xrange(1, self.attr_end/4):
479 start = x * 4
480 end = start + 4
481 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], self.value))
482 line_number += 1
483
484 elif self.family == AF_BRIDGE:
485 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
486 line_number += 1
487
488 return line_number
489
490
491class AttributeMACAddress(Attribute):
492
9f25ff0d 493 def __init__(self, atype, string, family, logger):
198ded6a
JF
494 Attribute.__init__(self, atype, string, logger)
495 self.PACK = '>LHxx'
496 self.LEN = calcsize(self.PACK)
497
498 def decode(self, parent_msg, data):
499 self.decode_length_type(data)
500
501 try:
502 (data1, data2) = unpack(self.PACK, self.data[4:])
503 self.value = mac_int_to_str(data1 << 16 | data2)
504
505 except struct.error:
506 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
507 raise
508
509 def encode(self):
510 length = self.HEADER_LEN + self.LEN
511 mac_raw = int(self.value.replace('.', '').replace(':', ''), 16)
9f25ff0d 512 raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, mac_raw >> 16, mac_raw & 0x0000FFFF)
198ded6a
JF
513 raw = self.pad(length, raw)
514 return raw
515
516 def dump_lines(self, dump_buffer, line_number, color):
517 line_number = self.dump_first_line(dump_buffer, line_number, color)
518 dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value))
9f25ff0d
SE
519 dump_buffer.append(data_to_color_text(line_number+1, color, self.data[8:12]))
520 return line_number + 2
198ded6a
JF
521
522
523class AttributeGeneric(Attribute):
524
9f25ff0d 525 def __init__(self, atype, string, family, logger):
198ded6a
JF
526 Attribute.__init__(self, atype, string, logger)
527 self.PACK = None
528 self.LEN = None
529
530 def decode(self, parent_msg, data):
531 self.decode_length_type(data)
532 wordcount = (self.attr_end - 4)/4
533 self.PACK = '=%dL' % wordcount
534 self.LEN = calcsize(self.PACK)
535
536 try:
537 self.value = ''.join(map(str, unpack(self.PACK, self.data[4:])))
538 except struct.error:
539 self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:])))
540 raise
541
542
26e7207b
JF
543class AttributeOneByteValue(AttributeGeneric):
544
9f25ff0d
SE
545 def __init__(self, atype, string, family, logger):
546 AttributeGeneric.__init__(self, atype, string, family, logger)
26e7207b
JF
547 self.PACK = '=B'
548 self.LEN = calcsize(self.PACK)
549
550
198ded6a
JF
551class AttributeIFLA_AF_SPEC(Attribute):
552 """
553 value will be a dictionary such as:
554 {
555 Link.IFLA_BRIDGE_FLAGS: flags,
556 Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid)
557 }
558 """
9f25ff0d
SE
559 def __init__(self, atype, string, family, logger):
560 Attribute.__init__(self, atype, string, logger)
198ded6a
JF
561
562 def encode(self):
563 pack_layout = [self.HEADER_PACK]
564 payload = [0, self.atype]
565 attr_length_index = 0
566
567 # For now this assumes that all data will be packed in the native endian
568 # order (=). If a field is added that needs to be packed via network
569 # order (>) then some smarts will need to be added to split the pack_layout
570 # string at the >, split the payload and make the needed pack() calls.
571 #
572 # Until we cross that bridge though we will keep things nice and simple and
573 # pack everything via a single pack() call.
26d1e82b
JF
574 sub_attr_to_add = []
575
198ded6a 576 for (sub_attr_type, sub_attr_value) in self.value.iteritems():
26d1e82b
JF
577
578 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
579 sub_attr_to_add.append((sub_attr_type, sub_attr_value))
580
581 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
582 for (vlan_flag, vlan_id) in sub_attr_value:
583 sub_attr_to_add.append((sub_attr_type, (vlan_flag, vlan_id)))
584
585 else:
586 self.log.debug('Add support for encoding IFLA_AF_SPEC sub-attribute type %d' % sub_attr_type)
587 continue
588
589 for (sub_attr_type, sub_attr_value) in sub_attr_to_add:
198ded6a
JF
590 sub_attr_pack_layout = ['=', 'HH']
591 sub_attr_payload = [0, sub_attr_type]
592 sub_attr_length_index = 0
593
594 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
595 sub_attr_pack_layout.append('H')
596 sub_attr_payload.append(sub_attr_value)
597
598 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
599 sub_attr_pack_layout.append('HH')
600 sub_attr_payload.append(sub_attr_value[0])
601 sub_attr_payload.append(sub_attr_value[1])
602
198ded6a
JF
603 sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
604 sub_attr_payload[sub_attr_length_index] = sub_attr_length
605
606 # add padding
607 for x in xrange(self.pad_bytes_needed(sub_attr_length)):
608 sub_attr_pack_layout.append('x')
609
610 # The [1:] is to remove the leading = so that when we do the ''.join() later
611 # we do not end up with an = in the middle of the pack layout string. There
612 # will be an = at the beginning via self.HEADER_PACK
613 sub_attr_pack_layout = sub_attr_pack_layout[1:]
614
615 # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
616 pack_layout.extend(sub_attr_pack_layout)
617 payload.extend(sub_attr_payload)
618
619 pack_layout = ''.join(pack_layout)
620
621 # Fill in the length field
622 length = calcsize(pack_layout)
623 payload[attr_length_index] = length
624
625 raw = pack(pack_layout, *payload)
626 raw = self.pad(length, raw)
627 return raw
628
629 def decode(self, parent_msg, data):
630 """
631 value is a dictionary such as:
632 {
633 Link.IFLA_BRIDGE_FLAGS: flags,
634 Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid)
635 }
636 """
637 self.decode_length_type(data)
638 self.value = {}
639
640 data = self.data[4:]
641
642 while data:
643 (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
644 sub_attr_end = padded_length(sub_attr_length)
645
646 if not sub_attr_length:
647 self.log.error('parsed a zero length sub-attr')
648 return
649
650 sub_attr_data = data[4:sub_attr_end]
651
652 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS:
653 self.value[Link.IFLA_BRIDGE_FLAGS] = unpack("=H", sub_attr_data[0:2])[0]
654
655 elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO:
26d1e82b
JF
656 if Link.IFLA_BRIDGE_VLAN_INFO not in self.value:
657 self.value[Link.IFLA_BRIDGE_VLAN_INFO] = []
658 self.value[Link.IFLA_BRIDGE_VLAN_INFO].append(tuple(unpack("=HH", sub_attr_data[0:4])))
198ded6a
JF
659
660 else:
661 self.log.debug('Add support for decoding IFLA_AF_SPEC sub-attribute type %s (%d), length %d, padded to %d' %
662 (parent_msg.get_ifla_bridge_af_spec_to_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end))
663
664 data = data[sub_attr_end:]
665
666 def dump_lines(self, dump_buffer, line_number, color):
667 line_number = self.dump_first_line(dump_buffer, line_number, color)
668 extra = ''
669
670 next_sub_attr_line = 0
671 sub_attr_line = True
672
673 for x in xrange(1, self.attr_end/4):
674 start = x * 4
675 end = start + 4
676
677 if line_number == next_sub_attr_line:
678 sub_attr_line = True
679
680 if sub_attr_line:
681 sub_attr_line = False
682
683 (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4])
684 sub_attr_end = padded_length(sub_attr_length)
685
686 next_sub_attr_line = line_number + (sub_attr_end/4)
687
688 if sub_attr_end == sub_attr_length:
689 padded_to = ', '
690 else:
691 padded_to = ' padded to %d, ' % sub_attr_end
692
693 extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
694 (zfilled_hex(sub_attr_length, 4), sub_attr_length,
695 padded_to,
696 zfilled_hex(sub_attr_type, 4), sub_attr_type,
697 Link.ifla_bridge_af_spec_to_string.get(sub_attr_type))
698 else:
699 extra = ''
700
701 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra))
702 line_number += 1
703
704 return line_number
705
706 def get_pretty_value(self):
707 # We do this so we can print a more human readable dictionary
708 # with the names of the nested keys instead of their numbers
709 value_pretty = {}
710
711 for (sub_key, sub_value) in self.value.iteritems():
712 sub_key_pretty = "(%2d) % s" % (sub_key, Link.ifla_bridge_af_spec_to_string.get(sub_key))
713 value_pretty[sub_key_pretty] = sub_value
714
715 return value_pretty
716
717
718
719class AttributeRTA_MULTIPATH(Attribute):
720 """
721/* RTA_MULTIPATH --- array of struct rtnexthop.
722 *
723 * "struct rtnexthop" describes all necessary nexthop information,
724 * i.e. parameters of path to a destination via this nexthop.
725 *
726 * At the moment it is impossible to set different prefsrc, mtu, window
727 * and rtt for different paths from multipath.
728 */
729
730struct rtnexthop {
731 unsigned short rtnh_len;
732 unsigned char rtnh_flags;
733 unsigned char rtnh_hops;
734 int rtnh_ifindex;
735};
736 """
737
738 def __init__(self, atype, string, family, logger):
739 Attribute.__init__(self, atype, string, logger)
740 self.family = family
741 self.PACK = None
742 self.LEN = None
743 self.RTNH_PACK = '=HBBL' # rtnh_len, flags, hops, ifindex
744 self.RTNH_LEN = calcsize(self.RTNH_PACK)
745 self.IPV4_LEN = 4
746 self.IPV6_LEN = 16
747
748 def encode(self):
749
750 # Calculate the length
751 if self.family == AF_INET:
752 ip_len = self.IPV4_LEN
753 elif self.family == AF_INET6:
754 ip_len = self.IPV6_LEN
755
756 # Attribute header
757 length = self.HEADER_LEN + ((self.RTNH_LEN + self.HEADER_LEN + ip_len) * len(self.value))
758 raw = pack(self.HEADER_PACK, length, self.atype)
759
760 rtnh_flags = 0
761 rtnh_hops = 0
762 rtnh_len = self.RTNH_LEN + self.HEADER_LEN + ip_len
763
764 for (nexthop, rtnh_ifindex) in self.value:
765
766 # rtnh structure
767 raw += pack(self.RTNH_PACK, rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex)
768
769 # Gateway
770 raw += pack(self.HEADER_PACK, self.HEADER_LEN + ip_len, Route.RTA_GATEWAY)
771
772 if self.family == AF_INET:
773 raw += pack('>L', nexthop)
774 elif self.family == AF_INET6:
775 raw += pack('>QQ', nexthop >> 64, nexthop & 0x0000000000000000FFFFFFFFFFFFFFFF)
776
777 raw = self.pad(length, raw)
778 return raw
779
780 def decode(self, parent_msg, data):
781 self.decode_length_type(data)
782 self.value = []
783
784 data = self.data[4:]
785
786 while data:
787 (rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex) = unpack(self.RTNH_PACK, data[:self.RTNH_LEN])
788 data = data[self.RTNH_LEN:]
789
790 (attr_type, attr_length) = unpack(self.HEADER_PACK, self.data[:self.HEADER_LEN])
791 data = data[self.HEADER_LEN:]
792
793 if self.family == AF_INET:
794 nexthop = IPv4Address(unpack('>L', data[:self.IPV4_LEN])[0])
795 self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops))
796 data = data[self.IPV4_LEN:]
797
798 elif self.family == AF_INET6:
799 (data1, data2) = unpack('>QQ', data[:self.IPV6_LEN])
800 nexthop = IPv6Address(data1 << 64 | data2)
801 self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops))
802 data = data[self.IPV6_LEN:]
803
804 self.value = tuple(self.value)
805
806
807class AttributeIFLA_LINKINFO(Attribute):
808 """
809 value is a dictionary such as:
810
811 {
812 Link.IFLA_INFO_KIND : 'vlan',
813 Link.IFLA_INFO_DATA : {
814 Link.IFLA_VLAN_ID : vlanid,
815 }
816 }
817 """
9f25ff0d
SE
818 def __init__(self, atype, string, family, logger):
819 Attribute.__init__(self, atype, string, logger)
820
198ded6a
JF
821 def encode(self):
822 pack_layout = [self.HEADER_PACK]
823 payload = [0, self.atype]
824 attr_length_index = 0
825
826 kind = self.value[Link.IFLA_INFO_KIND]
827
3696839d 828 if kind not in ('vlan', 'macvlan', 'vxlan'):
198ded6a
JF
829 raise Exception('Unsupported IFLA_INFO_KIND %s' % kind)
830
831 # For now this assumes that all data will be packed in the native endian
832 # order (=). If a field is added that needs to be packed via network
833 # order (>) then some smarts will need to be added to split the pack_layout
834 # string at the >, split the payload and make the needed pack() calls.
835 #
836 # Until we cross that bridge though we will keep things nice and simple and
837 # pack everything via a single pack() call.
838 for (sub_attr_type, sub_attr_value) in self.value.iteritems():
839 sub_attr_pack_layout = ['=', 'HH']
840 sub_attr_payload = [0, sub_attr_type]
841 sub_attr_length_index = 0
842
843 if sub_attr_type == Link.IFLA_INFO_KIND:
844 sub_attr_pack_layout.append('%ds' % len(sub_attr_value))
845 sub_attr_payload.append(sub_attr_value)
846
847 elif sub_attr_type == Link.IFLA_INFO_DATA:
848
849 for (info_data_type, info_data_value) in sub_attr_value.iteritems():
850
851 if kind == 'vlan':
852 if info_data_type == Link.IFLA_VLAN_ID:
853 sub_attr_pack_layout.append('HH')
854 sub_attr_payload.append(6) # length
855 sub_attr_payload.append(info_data_type)
856
857 # The vlan-id
858 sub_attr_pack_layout.append('H')
859 sub_attr_payload.append(info_data_value)
860
861 # pad 2 bytes
862 sub_attr_pack_layout.extend('xx')
863
864 else:
865 self.log.debug('Add support for encoding IFLA_INFO_DATA vlan sub-attribute type %d' % info_data_type)
866
867 elif kind == 'macvlan':
868 if info_data_type == Link.IFLA_MACVLAN_MODE:
869 sub_attr_pack_layout.append('HH')
870 sub_attr_payload.append(8) # length
871 sub_attr_payload.append(info_data_type)
872
873 # macvlan mode
874 sub_attr_pack_layout.append('L')
875 sub_attr_payload.append(info_data_value)
876
877 else:
878 self.log.debug('Add support for encoding IFLA_INFO_DATA macvlan sub-attribute type %d' % info_data_type)
879
3696839d
JF
880 elif kind == 'vxlan':
881 if info_data_type in (Link.IFLA_VXLAN_ID,
882 Link.IFLA_VXLAN_LINK,
883 Link.IFLA_VXLAN_AGEING,
884 Link.IFLA_VXLAN_LIMIT,
885 Link.IFLA_VXLAN_PORT_RANGE):
886 sub_attr_pack_layout.append('HH')
887 sub_attr_payload.append(8) # length
888 sub_attr_payload.append(info_data_type)
889
890 sub_attr_pack_layout.append('L')
891 sub_attr_payload.append(info_data_value)
892
893 elif info_data_type in (Link.IFLA_VXLAN_GROUP,
894 Link.IFLA_VXLAN_LOCAL):
895 sub_attr_pack_layout.append('HH')
896 sub_attr_payload.append(8) # length
897 sub_attr_payload.append(info_data_type)
898
899 sub_attr_pack_layout.append('L')
900
901 reorder = unpack('<L', IPv4Address(info_data_value).packed)[0]
902 sub_attr_payload.append(IPv4Address(reorder))
903
904 elif info_data_type in (Link.IFLA_VXLAN_PORT,):
905 sub_attr_pack_layout.append('HH')
906 sub_attr_payload.append(6)
907 sub_attr_payload.append(info_data_type)
908
909 sub_attr_pack_layout.append('H')
f1bec02e
JF
910
911 # byte swap
912 swaped = pack(">H", info_data_value)
913 sub_attr_payload.append(unpack("<H", swaped)[0])
3696839d
JF
914
915 sub_attr_pack_layout.extend('xx')
916
917 elif info_data_type in (Link.IFLA_VXLAN_TTL,
918 Link.IFLA_VXLAN_TOS,
919 Link.IFLA_VXLAN_LEARNING,
920 Link.IFLA_VXLAN_PROXY,
921 Link.IFLA_VXLAN_RSC,
922 Link.IFLA_VXLAN_L2MISS,
923 Link.IFLA_VXLAN_L3MISS,
924 Link.IFLA_VXLAN_UDP_CSUM,
925 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
926 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
927 Link.IFLA_VXLAN_REMCSUM_TX,
928 Link.IFLA_VXLAN_REMCSUM_RX,
929 Link.IFLA_VXLAN_REPLICATION_TYPE):
930 sub_attr_pack_layout.append('HH')
931 sub_attr_payload.append(6)
932 sub_attr_payload.append(info_data_type)
933
934 sub_attr_pack_layout.append('B')
935 sub_attr_payload.append(info_data_value)
936 sub_attr_pack_layout.extend('xxx')
937
938 else:
939 self.log.debug('Add support for encoding IFLA_INFO_DATA vxlan sub-attribute type %d' % info_data_type)
940
198ded6a
JF
941 else:
942 self.log.debug('Add support for encoding IFLA_LINKINFO sub-attribute type %d' % sub_attr_type)
943 continue
944
945 sub_attr_length = calcsize(''.join(sub_attr_pack_layout))
946 sub_attr_payload[sub_attr_length_index] = sub_attr_length
947
948 # add padding
949 for x in xrange(self.pad_bytes_needed(sub_attr_length)):
950 sub_attr_pack_layout.append('x')
951
952 # The [1:] is to remove the leading = so that when we do the ''.join() later
953 # we do not end up with an = in the middle of the pack layout string. There
954 # will be an = at the beginning via self.HEADER_PACK
955 sub_attr_pack_layout = sub_attr_pack_layout[1:]
956
957 # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute
958 pack_layout.extend(sub_attr_pack_layout)
959 payload.extend(sub_attr_payload)
960
961 pack_layout = ''.join(pack_layout)
962
963 # Fill in the length field
964 length = calcsize(pack_layout)
965 payload[attr_length_index] = length
966
967 raw = pack(pack_layout, *payload)
968 raw = self.pad(length, raw)
969 return raw
970
971 def decode(self, parent_msg, data):
972 """
973 value is a dictionary such as:
974
975 {
976 Link.IFLA_INFO_KIND : 'vlan',
977 Link.IFLA_INFO_DATA : {
978 Link.IFLA_VLAN_ID : vlanid,
979 }
980 }
981 """
982 self.decode_length_type(data)
983 self.value = {}
984
985 data = self.data[4:]
986
987 # IFLA_MACVLAN_MODE and IFLA_VLAN_ID both have a value of 1 and both are
988 # valid IFLA_INFO_DATA entries :( The sender must TX IFLA_INFO_KIND
989 # first in order for us to know if "1" is IFLA_MACVLAN_MODE vs IFLA_VLAN_ID.
990 while data:
991 (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4])
992 sub_attr_end = padded_length(sub_attr_length)
993
994 if not sub_attr_length:
995 self.log.error('parsed a zero length sub-attr')
996 return
997
998 if sub_attr_type == Link.IFLA_INFO_KIND:
999 self.value[Link.IFLA_INFO_KIND] = remove_trailing_null(unpack('%ds' % (sub_attr_length - 4), data[4:sub_attr_length])[0])
1000
1001 elif sub_attr_type == Link.IFLA_INFO_DATA:
1002
1003 sub_attr_data = data[4:sub_attr_end]
1004 self.value[Link.IFLA_INFO_DATA] = {}
1005
1006 while sub_attr_data:
1007 (info_data_length, info_data_type) = unpack('=HH', sub_attr_data[:4])
1008 info_data_end = padded_length(info_data_length)
1009 # self.log.info('sub attr length %d, end %d, type %d' % (info_data_length, info_data_end, info_data_type))
1010
1011 if not sub_attr_data:
1012 self.log.error('RXed zero length sub-attribute')
1013 break
1014
1015 if Link.IFLA_INFO_KIND not in self.value:
1016 self.log.warning('IFLA_INFO_KIND is not known...we cannot parse IFLA_INFO_DATA')
1017
1018 elif self.value[Link.IFLA_INFO_KIND] == 'vlan':
1019 if info_data_type == Link.IFLA_VLAN_ID:
1020 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
1021 else:
1022 self.log.debug('Add support for decoding IFLA_INFO_KIND vlan type %s (%d), length %d, padded to %d' %
1023 (parent_msg.get_ifla_vlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
1024
1025 elif self.value[Link.IFLA_INFO_KIND] == 'macvlan':
1026 if info_data_type == Link.IFLA_MACVLAN_MODE:
1027 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1028 else:
1029 self.log.debug('Add support for decoding IFLA_INFO_KIND macvlan type %s (%d), length %d, padded to %d' %
1030 (parent_msg.get_ifla_macvlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
1031
1032 elif self.value[Link.IFLA_INFO_KIND] == 'vxlan':
1033
1034 # IPv4Address
1035 if info_data_type in (Link.IFLA_VXLAN_GROUP,
1036 Link.IFLA_VXLAN_LOCAL):
1037 self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack('>L', sub_attr_data[4:8])[0])
1038
1039 # 4-byte int
1040 elif info_data_type in (Link.IFLA_VXLAN_ID,
1041 Link.IFLA_VXLAN_LINK,
1042 Link.IFLA_VXLAN_AGEING,
1043 Link.IFLA_VXLAN_LIMIT,
1044 Link.IFLA_VXLAN_PORT_RANGE):
1045 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1046
1047 # 2-byte int
1048 elif info_data_type in (Link.IFLA_VXLAN_PORT, ):
1049 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0]
1050
1051 # 1-byte int
1052 elif info_data_type in (Link.IFLA_VXLAN_TTL,
1053 Link.IFLA_VXLAN_TOS,
1054 Link.IFLA_VXLAN_LEARNING,
1055 Link.IFLA_VXLAN_PROXY,
1056 Link.IFLA_VXLAN_RSC,
1057 Link.IFLA_VXLAN_L2MISS,
1058 Link.IFLA_VXLAN_L3MISS,
1059 Link.IFLA_VXLAN_UDP_CSUM,
1060 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
1061 Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
1062 Link.IFLA_VXLAN_REMCSUM_TX,
1063 Link.IFLA_VXLAN_REMCSUM_RX,
1064 Link.IFLA_VXLAN_REPLICATION_TYPE):
1065 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
1066
1067 else:
1068 # sub_attr_end = padded_length(sub_attr_length)
1069 self.log.debug('Add support for decoding IFLA_INFO_KIND vxlan type %s (%d), length %d, padded to %d' %
1070 (parent_msg.get_ifla_vxlan_string(info_data_type), info_data_type, info_data_length, info_data_end))
1071
1072 elif self.value[Link.IFLA_INFO_KIND] == 'bond':
9f25ff0d
SE
1073
1074 if info_data_type in (Link.IFLA_BOND_AD_INFO, ):
1075 bond_value = {}
1076
1077 self.value[Link.IFLA_INFO_DATA][info_data_type] = bond_value
1078 else:
1079 self.log.debug('Add support for decoding IFLA_INFO_KIND bond type %s (%d), length %d, padded to %d' %
1080 (parent_msg.get_ifla_bond_string(info_data_type), info_data_type, info_data_length, info_data_end))
198ded6a
JF
1081
1082 elif self.value[Link.IFLA_INFO_KIND] == 'bridge':
1083
1084 if info_data_type in (Link.IFLA_BRPORT_STATE,
1085 Link.IFLA_BRPORT_PRIORITY,
1086 Link.IFLA_BRPORT_COST):
1087 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0]
1088
1089 elif info_data_type in (Link.IFLA_BRPORT_FAST_LEAVE, ):
1090 self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0]
1091
1092 else:
1093 self.log.debug('Add support for decoding IFLA_INFO_KIND bridge type %s (%d), length %d, padded to %d' %
1094 (parent_msg.get_ifla_bridge_string(info_data_type), info_data_type, info_data_length, info_data_end))
1095
1096 else:
1097 self.log.debug("Add support for decoding IFLA_INFO_KIND %s (%d), length %d, padded to %d" %
1098 (self.value[Link.IFLA_INFO_KIND], info_data_type, info_data_length, info_data_end))
1099
1100 sub_attr_data = sub_attr_data[info_data_end:]
1101
1102 elif sub_attr_type == Link.IFLA_INFO_SLAVE_KIND:
1103 self.value[Link.IFLA_INFO_SLAVE_KIND] = remove_trailing_null(unpack('%ds' % (sub_attr_length - 4), data[4:sub_attr_length])[0])
1104
1105 else:
1106 self.log.debug('Add support for decoding IFLA_LINKINFO sub-attribute type %s (%d), length %d, padded to %d' %
1107 (parent_msg.get_ifla_info_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end))
1108
1109 data = data[sub_attr_end:]
1110
1111 # self.log.info('IFLA_LINKINFO values %s' % pformat(self.value))
1112
1113 def dump_lines(self, dump_buffer, line_number, color):
1114 line_number = self.dump_first_line(dump_buffer, line_number, color)
1115 extra = ''
1116
1117 next_sub_attr_line = 0
1118 sub_attr_line = True
1119
1120 for x in xrange(1, self.attr_end/4):
1121 start = x * 4
1122 end = start + 4
1123
1124 if line_number == next_sub_attr_line:
1125 sub_attr_line = True
1126
1127 if sub_attr_line:
1128 sub_attr_line = False
1129
1130 (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4])
1131 sub_attr_end = padded_length(sub_attr_length)
1132
1133 next_sub_attr_line = line_number + (sub_attr_end/4)
1134
1135 if sub_attr_end == sub_attr_length:
1136 padded_to = ', '
1137 else:
1138 padded_to = ' padded to %d, ' % sub_attr_end
1139
1140 extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
1141 (zfilled_hex(sub_attr_length, 4), sub_attr_length,
1142 padded_to,
1143 zfilled_hex(sub_attr_type, 4), sub_attr_type,
1144 Link.ifla_info_to_string.get(sub_attr_type))
1145 else:
1146 extra = ''
1147
1148 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra))
1149 line_number += 1
1150
1151 return line_number
1152
1153 def get_pretty_value(self):
1154 value_pretty = self.value
1155 ifla_info_kind = self.value.get(Link.IFLA_INFO_KIND)
1156
1157 # We do this so we can print a more human readable dictionary
1158 # with the names of the nested keys instead of their numbers
1159
1160 # Most of these are placeholders...we need to add support
1161 # for more human readable dictionaries for bond, bridge, etc
1162 if ifla_info_kind == 'bond':
1163 pass
1164
1165 elif ifla_info_kind == 'bridge':
1166 pass
1167
1168 elif ifla_info_kind == 'macvlan':
1169 pass
1170
1171 elif ifla_info_kind == 'vlan':
1172 pass
1173
1174 elif ifla_info_kind == 'vxlan':
1175 value_pretty = {}
1176
1177 for (sub_key, sub_value) in self.value.iteritems():
1178 sub_key_pretty = "(%2d) % s" % (sub_key, Link.ifla_info_to_string[sub_key])
1179 sub_value_pretty = sub_value
1180
1181 if sub_key == Link.IFLA_INFO_DATA:
1182 sub_value_pretty = {}
1183
1184 for (sub_sub_key, sub_sub_value) in sub_value.iteritems():
1185 sub_sub_key_pretty = "(%2d) %s" % (sub_sub_key, Link.ifla_vxlan_to_string[sub_sub_key])
1186 sub_value_pretty[sub_sub_key_pretty] = sub_sub_value
1187
1188 value_pretty[sub_key_pretty] = sub_value_pretty
1189
1190 return value_pretty
1191
1192
1193class NetlinkPacket(object):
1194 """
1195 Netlink Header
1196
1197 0 1 2 3
1198 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
1199 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1200 | Length |
1201 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1202 | Type | Flags |
1203 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1204 | Sequence Number |
1205 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1206 | Process ID (PID) |
1207 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1208 """
1209
1210 header_PACK = 'IHHII'
1211 header_LEN = calcsize(header_PACK)
1212
1213 # Netlink packet types
1214 # /usr/include/linux/rtnetlink.h
1215 type_to_string = {
1216 NLMSG_NOOP : 'NLMSG_NOOP',
1217 NLMSG_ERROR : 'NLMSG_ERROR',
1218 NLMSG_DONE : 'NLMSG_DONE',
1219 NLMSG_OVERRUN : 'NLMSG_OVERRUN',
1220 RTM_NEWLINK : 'RTM_NEWLINK',
1221 RTM_DELLINK : 'RTM_DELLINK',
1222 RTM_GETLINK : 'RTM_GETLINK',
1223 RTM_SETLINK : 'RTM_SETLINK',
1224 RTM_NEWADDR : 'RTM_NEWADDR',
1225 RTM_DELADDR : 'RTM_DELADDR',
1226 RTM_GETADDR : 'RTM_GETADDR',
1227 RTM_NEWNEIGH : 'RTM_NEWNEIGH',
1228 RTM_DELNEIGH : 'RTM_DELNEIGH',
1229 RTM_GETNEIGH : 'RTM_GETNEIGH',
1230 RTM_NEWROUTE : 'RTM_NEWROUTE',
1231 RTM_DELROUTE : 'RTM_DELROUTE',
1232 RTM_GETROUTE : 'RTM_GETROUTE',
1233 RTM_NEWQDISC : 'RTM_NEWQDISC',
1234 RTM_DELQDISC : 'RTM_DELQDISC',
1235 RTM_GETQDISC : 'RTM_GETQDISC'
1236 }
1237
1238 def __init__(self, msgtype, debug, owner_logger=None):
1239 self.msgtype = msgtype
1240 self.attributes = {}
1241 self.dump_buffer = ['']
1242 self.line_number = 1
1243 self.debug = debug
1244 self.message = None
1245
1246 if owner_logger:
1247 self.log = owner_logger
1248 else:
1249 self.log = log
1250
1251 def __str__(self):
1252 return self.get_type_string()
1253
1254 def get_string(self, to_string, index):
1255 """
1256 Used to do lookups in all of the various FOO_to_string dictionaries
1257 but returns 'UNKNOWN' if the key is bogus
1258 """
1259 if index in to_string:
1260 return to_string[index]
1261 return 'UNKNOWN'
1262
1263 def get_type_string(self, msgtype=None):
1264 if not msgtype:
1265 msgtype = self.msgtype
1266 return self.get_string(self.type_to_string, msgtype)
1267
1268 def get_flags_string(self):
1269 foo = []
1270
1271 for (flag, flag_string) in self.flag_to_string.iteritems():
1272 if self.flags & flag:
1273 foo.append(flag_string)
1274
1275 return ', '.join(foo)
1276
1277 def decode_packet(self, length, flags, seq, pid, data):
1278 self.length = length
1279 self.flags = flags
1280 self.seq = seq
1281 self.pid = pid
1282 self.header_data = data[0:self.header_LEN]
1283 self.msg_data = data[self.header_LEN:length]
1284
1285 self.decode_netlink_header()
1286 self.decode_service_header()
1287
1288 # NLMSG_ERROR is special case, it does not have attributes to decode
1289 if self.msgtype != NLMSG_ERROR:
1290 self.decode_attributes()
1291
1292 def get_netlink_header_flags_string(self, msg_type, flags):
1293 foo = []
1294
1295 if flags & NLM_F_REQUEST:
1296 foo.append('NLM_F_REQUEST')
1297
1298 if flags & NLM_F_MULTI:
1299 foo.append('NLM_F_MULTI')
1300
1301 if flags & NLM_F_ACK:
1302 foo.append('NLM_F_ACK')
1303
1304 if flags & NLM_F_ECHO:
1305 foo.append('NLM_F_ECHO')
1306
1307 # Modifiers to GET query
1308 if msg_type in (RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH, RTM_GETROUTE, RTM_GETQDISC):
198ded6a
JF
1309 if flags & NLM_F_DUMP:
1310 foo.append('NLM_F_DUMP')
26d1e82b
JF
1311 else:
1312 if flags & NLM_F_MATCH:
1313 foo.append('NLM_F_MATCH')
1314
1315 if flags & NLM_F_ROOT:
1316 foo.append('NLM_F_ROOT')
198ded6a
JF
1317
1318 if flags & NLM_F_ATOMIC:
1319 foo.append('NLM_F_ATOMIC')
1320
1321 # Modifiers to NEW query
1322 elif msg_type in (RTM_NEWLINK, RTM_NEWADDR, RTM_NEWNEIGH, RTM_NEWROUTE, RTM_NEWQDISC):
1323 if flags & NLM_F_REPLACE:
1324 foo.append('NLM_F_REPLACE')
1325
1326 if flags & NLM_F_EXCL:
1327 foo.append('NLM_F_EXCL')
1328
1329 if flags & NLM_F_CREATE:
1330 foo.append('NLM_F_CREATE')
1331
1332 if flags & NLM_F_APPEND:
1333 foo.append('NLM_F_APPEND')
1334
1335 return ', '.join(foo)
1336
1337 # When we first RXed the netlink message we had to decode the header to
1338 # determine what type of netlink message we were dealing with. So the
1339 # header has actually already been decoded...what we do here is
1340 # populate the dump_buffer lines with the header content.
1341 def decode_netlink_header(self):
1342
1343 if not self.debug:
1344 return
1345
1346 header_data = self.header_data
1347
1348 # Print the netlink header in red
1349 color = red
1350 netlink_header_length = 16
1351 self.dump_buffer.append(" \033[%dmNetlink Header\033[0m" % color)
1352
1353 for x in range(0, netlink_header_length/4):
1354 start = x * 4
1355 end = start + 4
1356
1357 if self.line_number == 1:
1358 data = unpack('=L', header_data[start:end])[0]
1359 extra = "Length %s (%d)" % (zfilled_hex(data, 8), data)
1360
1361 elif self.line_number == 2:
1362 (data1, data2) = unpack('HH', header_data[start:end])
1363 extra = "Type %s (%d - %s), Flags %s (%s)" % \
1364 (zfilled_hex(data1, 4), data1, self.get_type_string(data1),
1365 zfilled_hex(data2, 4), self.get_netlink_header_flags_string(data1, data2))
1366
1367 elif self.line_number == 3:
1368 data = unpack('=L', header_data[start:end])[0]
1369 extra = "Sequence Number %s (%d)" % (zfilled_hex(data, 8), data)
1370
1371 elif self.line_number == 4:
1372 data = unpack('=L', header_data[start:end])[0]
1373 extra = "Process ID %s (%d)" % (zfilled_hex(data, 8), data)
1374 else:
1375 extra = "Unexpected line number %d" % self.line_number
1376
1377 self.dump_buffer.append(data_to_color_text(self.line_number, color, header_data[start:end], extra))
1378 self.line_number += 1
1379
1380 def decode_attributes(self):
1381 """
1382 Decode the attributes and populate the dump_buffer
1383 """
1384
1385 if self.debug:
1386 self.dump_buffer.append(" Attributes")
1387 color = green
1388
1389 data = self.msg_data[self.LEN:]
1390
1391 while data:
1392 (length, attr_type) = unpack('=HH', data[:4])
1393
1394 # If this is zero we will stay in this loop for forever
1395 if not length:
1396 self.log.error('Length is zero')
1397 return
1398
1399 if len(data) < length:
1400 self.log.error("Buffer underrun %d < %d" % (len(data), length))
1401 return
1402
1403 attr = self.add_attribute(attr_type, None)
1404
1405 # Find the end of 'data' for this attribute and decode our section
1406 # of 'data'. attributes are padded for alignment thus the attr_end.
1407 #
1408 # How the attribute is decoded/unpacked is specific per AttributeXXXX class.
1409 attr_end = padded_length(length)
1410 attr.decode(self, data[0:attr_end])
1411
1412 if self.debug:
1413 self.line_number = attr.dump_lines(self.dump_buffer, self.line_number, color)
1414
1415 # Alternate back and forth between green and blue
1416 if color == green:
1417 color = blue
1418 else:
1419 color = green
1420
1421 data = data[attr_end:]
1422
1423 def add_attribute(self, attr_type, value):
1424 nested = True if attr_type & NLA_F_NESTED else False
1425 net_byteorder = True if attr_type & NLA_F_NET_BYTEORDER else False
1426 attr_type = attr_type & NLA_TYPE_MASK
1427
1428 # Given an attr_type (say RTA_DST) find the type of AttributeXXXX class
1429 # that we will use to store this attribute...AttributeIPAddress in the
1430 # case of RTA_DST.
1431 if attr_type in self.attribute_to_class:
1432 (attr_string, attr_class) = self.attribute_to_class[attr_type]
1433 else:
1434 attr_string = "UNKNOWN_ATTRIBUTE_%d" % attr_type
1435 attr_class = AttributeGeneric
1436 self.log.debug("Attribute %d is not defined in %s.attribute_to_class, assuming AttributeGeneric" %
1437 (attr_type, self.__class__.__name__))
1438
9f25ff0d 1439 attr = attr_class(attr_type, attr_string, self.family, self.log)
198ded6a 1440
4e979b1b
JF
1441 attr.set_value(value)
1442 attr.set_nested(nested)
1443 attr.set_net_byteorder(net_byteorder)
198ded6a
JF
1444
1445 # self.attributes is a dictionary keyed by the attribute type where
1446 # the value is an instance of the corresponding AttributeXXXX class.
1447 self.attributes[attr_type] = attr
1448
1449 return attr
1450
1451 def get_attribute_value(self, attr_type):
1452 if attr_type not in self.attributes:
1453 return None
1454
1455 return self.attributes[attr_type].value
1456
1457 def get_attr_string(self, attr_type):
1458 """
1459 Example: If attr_type is Address.IFA_CACHEINFO return the string 'IFA_CACHEINFO'
1460 """
1461 if attr_type in self.attribute_to_class:
1462 (attr_string, attr_class) = self.attribute_to_class[attr_type]
1463 return attr_string
1464 return str(attr_type)
1465
1466 def build_message(self, seq, pid):
1467 self.seq = seq
1468 self.pid = pid
1469 attrs = ''
1470
1471 for attr in self.attributes.itervalues():
1472 attrs += attr.encode()
1473
1474 self.length = self.header_LEN + len(self.body) + len(attrs)
1475 self.header_data = pack(self.header_PACK, self.length, self.msgtype, self.flags, self.seq, self.pid)
1476 self.msg_data = self.body + attrs
1477 self.message = self.header_data + self.msg_data
1478
1479 if self.debug:
1480 self.decode_netlink_header()
1481 self.decode_service_header()
1482 self.decode_attributes()
1483 self.dump("TXed %s, length %d, seq %d, pid %d, flags 0x%x (%s)" %
1484 (self, self.length, self.seq, self.pid, self.flags,
1485 self.get_netlink_header_flags_string(self.msgtype, self.flags)))
1486
1487 # Print the netlink message in hex. This is only used for debugging.
1488 def dump(self, desc=None):
1489 attr_string = {}
1490
1491 if desc is None:
1492 desc = "RXed %s, length %d, seq %d, pid %d, flags 0x%x" % (self, self.length, self.seq, self.pid, self.flags)
1493
1494 for (attr_type, attr_obj) in self.attributes.iteritems():
1495 key_string = "(%2d) %s" % (attr_type, self.get_attr_string(attr_type))
1496 attr_string[key_string] = attr_obj.get_pretty_value()
1497
1498 self.log.debug("%s\n%s\n\nAttributes Summary\n%s\n" %
1499 (desc, '\n'.join(self.dump_buffer), pformat(attr_string)))
1500
1501
1502class Address(NetlinkPacket):
1503 """
1504 Service Header
1505 0 1 2 3
1506 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
1507 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1508 | Family | Length | Flags | Scope |
1509 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1510 | Interface Index |
1511 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1512 """
1513
1514 # Address attributes
1515 # /usr/include/linux/if_addr.h
1516 IFA_UNSPEC = 0x00
1517 IFA_ADDRESS = 0x01
1518 IFA_LOCAL = 0x02
1519 IFA_LABEL = 0x03
1520 IFA_BROADCAST = 0x04
1521 IFA_ANYCAST = 0x05
1522 IFA_CACHEINFO = 0x06
1523 IFA_MULTICAST = 0x07
1524 IFA_FLAGS = 0x08
1525
1526 attribute_to_class = {
1527 IFA_UNSPEC : ('IFA_UNSPEC', AttributeGeneric),
1528 IFA_ADDRESS : ('IFA_ADDRESS', AttributeIPAddress),
1529 IFA_LOCAL : ('IFA_LOCAL', AttributeIPAddress),
1530 IFA_LABEL : ('IFA_LABEL', AttributeString),
1531 IFA_BROADCAST : ('IFA_BROADCAST', AttributeIPAddress),
1532 IFA_ANYCAST : ('IFA_ANYCAST', AttributeIPAddress),
1533 IFA_CACHEINFO : ('IFA_CACHEINFO', AttributeGeneric),
1534 IFA_MULTICAST : ('IFA_MULTICAST', AttributeIPAddress),
1535 IFA_FLAGS : ('IFA_FLAGS', AttributeGeneric)
1536 }
1537
1538 # Address flags
1539 # /usr/include/linux/if_addr.h
1540 IFA_F_SECONDARY = 0x01
1541 IFA_F_NODAD = 0x02
1542 IFA_F_OPTIMISTIC = 0x04
1543 IFA_F_DADFAILED = 0x08
1544 IFA_F_HOMEADDRESS = 0x10
1545 IFA_F_DEPRECATED = 0x20
1546 IFA_F_TENTATIVE = 0x40
1547 IFA_F_PERMANENT = 0x80
1548
1549 flag_to_string = {
1550 IFA_F_SECONDARY : 'IFA_F_SECONDARY',
1551 IFA_F_NODAD : 'IFA_F_NODAD',
1552 IFA_F_OPTIMISTIC : 'IFA_F_OPTIMISTIC',
1553 IFA_F_DADFAILED : 'IFA_F_DADFAILED',
1554 IFA_F_HOMEADDRESS : 'IFA_F_HOMEADDRESS',
1555 IFA_F_DEPRECATED : 'IFA_F_DEPRECATED',
1556 IFA_F_TENTATIVE : 'IFA_F_TENTATIVE',
1557 IFA_F_PERMANENT : 'IFA_F_PERMANENT'
1558 }
1559
1560 def __init__(self, msgtype, debug=False, logger=None):
1561 NetlinkPacket.__init__(self, msgtype, debug, logger)
1562 self.PACK = '4Bi'
1563 self.LEN = calcsize(self.PACK)
1564
1565 def decode_service_header(self):
1566
1567 # Nothing to do if the message did not contain a service header
1568 if self.length == self.header_LEN:
1569 return
1570
1571 (self.family, self.prefixlen, self.flags, self.scope,
1572 self.ifindex) = \
1573 unpack(self.PACK, self.msg_data[:self.LEN])
1574
1575 if self.debug:
1576 color = yellow
1577 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
1578
1579 for x in range(0, self.LEN/4):
1580 if self.line_number == 5:
1581 extra = "Family %s (%d), Length %s (%d), Flags %s, Scope %s (%d)" % \
1582 (zfilled_hex(self.family, 2), self.family,
1583 zfilled_hex(self.prefixlen, 2), self.prefixlen,
1584 zfilled_hex(self.flags, 2),
1585 zfilled_hex(self.scope, 2), self.scope)
1586 elif self.line_number == 6:
1587 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
1588 else:
1589 extra = "Unexpected line number %d" % self.line_number
1590
1591 start = x * 4
1592 end = start + 4
1593 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
1594 self.line_number += 1
1595
1596
1597class Error(NetlinkPacket):
1598
1599 # Error codes
1600 # /include/netlink/errno.h
1601 NLE_SUCCESS = 0x00
1602 NLE_FAILURE = 0x01
1603 NLE_INTR = 0x02
1604 NLE_BAD_SOCK = 0x03
1605 NLE_AGAIN = 0x04
1606 NLE_NOMEM = 0x05
1607 NLE_EXIST = 0x06
1608 NLE_INVAL = 0x07
1609 NLE_RANGE = 0x08
1610 NLE_MSGSIZE = 0x09
1611 NLE_OPNOTSUPP = 0x0A
1612 NLE_AF_NOSUPPORT = 0x0B
1613 NLE_OBJ_NOTFOUND = 0x0C
1614 NLE_NOATTR = 0x0D
1615 NLE_MISSING_ATTR = 0x0E
1616 NLE_AF_MISMATCH = 0x0F
1617 NLE_SEQ_MISMATCH = 0x10
1618 NLE_MSG_OVERFLOW = 0x11
1619 NLE_MSG_TRUNC = 0x12
1620 NLE_NOADDR = 0x13
1621 NLE_SRCRT_NOSUPPORT = 0x14
1622 NLE_MSG_TOOSHORT = 0x15
1623 NLE_MSGTYPE_NOSUPPORT = 0x16
1624 NLE_OBJ_MISMATCH = 0x17
1625 NLE_NOCACHE = 0x18
1626 NLE_BUSY = 0x19
1627 NLE_PROTO_MISMATCH = 0x1A
1628 NLE_NOACCESS = 0x1B
1629 NLE_PERM = 0x1C
1630 NLE_PKTLOC_FILE = 0x1D
1631 NLE_PARSE_ERR = 0x1E
1632 NLE_NODEV = 0x1F
1633 NLE_IMMUTABLE = 0x20
1634 NLE_DUMP_INTR = 0x21
1635
1636 error_to_string = {
1637 NLE_SUCCESS : 'NLE_SUCCESS',
1638 NLE_FAILURE : 'NLE_FAILURE',
1639 NLE_INTR : 'NLE_INTR',
1640 NLE_BAD_SOCK : 'NLE_BAD_SOCK',
1641 NLE_AGAIN : 'NLE_AGAIN',
1642 NLE_NOMEM : 'NLE_NOMEM',
1643 NLE_EXIST : 'NLE_EXIST',
1644 NLE_INVAL : 'NLE_INVAL',
1645 NLE_RANGE : 'NLE_RANGE',
1646 NLE_MSGSIZE : 'NLE_MSGSIZE',
1647 NLE_OPNOTSUPP : 'NLE_OPNOTSUPP',
1648 NLE_AF_NOSUPPORT : 'NLE_AF_NOSUPPORT',
1649 NLE_OBJ_NOTFOUND : 'NLE_OBJ_NOTFOUND',
1650 NLE_NOATTR : 'NLE_NOATTR',
1651 NLE_MISSING_ATTR : 'NLE_MISSING_ATTR',
1652 NLE_AF_MISMATCH : 'NLE_AF_MISMATCH',
1653 NLE_SEQ_MISMATCH : 'NLE_SEQ_MISMATCH',
1654 NLE_MSG_OVERFLOW : 'NLE_MSG_OVERFLOW',
1655 NLE_MSG_TRUNC : 'NLE_MSG_TRUNC',
1656 NLE_NOADDR : 'NLE_NOADDR',
1657 NLE_SRCRT_NOSUPPORT : 'NLE_SRCRT_NOSUPPORT',
1658 NLE_MSG_TOOSHORT : 'NLE_MSG_TOOSHORT',
1659 NLE_MSGTYPE_NOSUPPORT : 'NLE_MSGTYPE_NOSUPPORT',
1660 NLE_OBJ_MISMATCH : 'NLE_OBJ_MISMATCH',
1661 NLE_NOCACHE : 'NLE_NOCACHE',
1662 NLE_BUSY : 'NLE_BUSY',
1663 NLE_PROTO_MISMATCH : 'NLE_PROTO_MISMATCH',
1664 NLE_NOACCESS : 'NLE_NOACCESS',
1665 NLE_PERM : 'NLE_PERM',
1666 NLE_PKTLOC_FILE : 'NLE_PKTLOC_FILE',
1667 NLE_PARSE_ERR : 'NLE_PARSE_ERR',
1668 NLE_NODEV : 'NLE_NODEV',
1669 NLE_IMMUTABLE : 'NLE_IMMUTABLE',
1670 NLE_DUMP_INTR : 'NLE_DUMP_INTR'
1671 }
1672
1673 def __init__(self, msgtype, debug=False, logger=None):
1674 NetlinkPacket.__init__(self, msgtype, debug, logger)
1675 self.PACK = '=iLHHLL'
1676 self.LEN = calcsize(self.PACK)
1677
1678 def decode_service_header(self):
1679
1680 # Nothing to do if the message did not contain a service header
1681 if self.length == self.header_LEN:
1682 return
1683
1684 (self.negative_errno, self.bad_msg_len, self.bad_msg_type,
1685 self.bad_msg_flag, self.bad_msg_seq, self.bad_msg_pid) =\
1686 unpack(self.PACK, self.msg_data[:self.LEN])
1687
1688 if self.debug:
1689 color = yellow
1690 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
1691
1692 for x in range(0, self.LEN/4):
1693
1694 if self.line_number == 5:
1695 extra = "Error Number %s is %s" % (self.negative_errno, self.error_to_string.get(abs(self.negative_errno)))
1696 # zfilled_hex(self.negative_errno, 2)
1697
1698 elif self.line_number == 6:
1699 extra = "Length %s (%d)" % (zfilled_hex(self.bad_msg_len, 8), self.bad_msg_len)
1700
1701 elif self.line_number == 7:
1702 extra = "Type %s (%d - %s), Flags %s (%s)" % \
1703 (zfilled_hex(self.bad_msg_type, 4), self.bad_msg_type, self.get_type_string(self.bad_msg_type),
1704 zfilled_hex(self.bad_msg_flag, 4), self.get_netlink_header_flags_string(self.bad_msg_type, self.bad_msg_flag))
1705
1706 elif self.line_number == 8:
1707 extra = "Sequence Number %s (%d)" % (zfilled_hex(self.bad_msg_seq, 8), self.bad_msg_seq)
1708
1709 elif self.line_number == 9:
1710 extra = "Process ID %s (%d)" % (zfilled_hex(self.bad_msg_pid, 8), self.bad_msg_pid)
1711
1712 else:
1713 extra = "Unexpected line number %d" % self.line_number
1714
1715 start = x * 4
1716 end = start + 4
1717 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
1718 self.line_number += 1
1719
1720
1721class Link(NetlinkPacket):
1722 """
1723 Service Header
1724
1725 0 1 2 3
1726 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
1727 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1728 | Family | Reserved | Device Type |
1729 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1730 | Interface Index |
1731 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1732 | Device Flags |
1733 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1734 | Change Mask |
1735 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1736 """
1737
1738 # Link attributes
1739 # /usr/include/linux/if_link.h
1740 IFLA_UNSPEC = 0
1741 IFLA_ADDRESS = 1
1742 IFLA_BROADCAST = 2
1743 IFLA_IFNAME = 3
1744 IFLA_MTU = 4
1745 IFLA_LINK = 5
1746 IFLA_QDISC = 6
1747 IFLA_STATS = 7
1748 IFLA_COST = 8
1749 IFLA_PRIORITY = 9
1750 IFLA_MASTER = 10
1751 IFLA_WIRELESS = 11
1752 IFLA_PROTINFO = 12
1753 IFLA_TXQLEN = 13
1754 IFLA_MAP = 14
1755 IFLA_WEIGHT = 15
1756 IFLA_OPERSTATE = 16
1757 IFLA_LINKMODE = 17
1758 IFLA_LINKINFO = 18
1759 IFLA_NET_NS_PID = 19
1760 IFLA_IFALIAS = 20
1761 IFLA_NUM_VF = 21
1762 IFLA_VFINFO_LIST = 22
1763 IFLA_STATS64 = 23
1764 IFLA_VF_PORTS = 24
1765 IFLA_PORT_SELF = 25
1766 IFLA_AF_SPEC = 26
1767 IFLA_GROUP = 27
1768 IFLA_NET_NS_FD = 28
1769 IFLA_EXT_MASK = 29
1770 IFLA_PROMISCUITY = 30
1771 IFLA_NUM_TX_QUEUES = 31
1772 IFLA_NUM_RX_QUEUES = 32
1773 IFLA_CARRIER = 33
1774 IFLA_PHYS_PORT_ID = 34
1775 IFLA_CARRIER_CHANGES = 35
1776 IFLA_PHYS_SWITCH_ID = 36
1777 IFLA_LINK_NETNSID = 37
1778 IFLA_PHYS_PORT_NAME = 38
1779 IFLA_PROTO_DOWN = 39
1780 IFLA_LINKPROTODOWN = 200
1781
1782 attribute_to_class = {
1783 IFLA_UNSPEC : ('IFLA_UNSPEC', AttributeGeneric),
1784 IFLA_ADDRESS : ('IFLA_ADDRESS', AttributeMACAddress),
1785 IFLA_BROADCAST : ('IFLA_BROADCAST', AttributeMACAddress),
4e979b1b 1786 IFLA_IFNAME : ('IFLA_IFNAME', AttributeStringInterfaceName),
198ded6a
JF
1787 IFLA_MTU : ('IFLA_MTU', AttributeFourByteValue),
1788 IFLA_LINK : ('IFLA_LINK', AttributeFourByteValue),
1789 IFLA_QDISC : ('IFLA_QDISC', AttributeString),
1790 IFLA_STATS : ('IFLA_STATS', AttributeGeneric),
1791 IFLA_COST : ('IFLA_COST', AttributeGeneric),
1792 IFLA_PRIORITY : ('IFLA_PRIORITY', AttributeGeneric),
1793 IFLA_MASTER : ('IFLA_MASTER', AttributeFourByteValue),
1794 IFLA_WIRELESS : ('IFLA_WIRELESS', AttributeGeneric),
1795 IFLA_PROTINFO : ('IFLA_PROTINFO', AttributeGeneric),
1796 IFLA_TXQLEN : ('IFLA_TXQLEN', AttributeFourByteValue),
1797 IFLA_MAP : ('IFLA_MAP', AttributeGeneric),
1798 IFLA_WEIGHT : ('IFLA_WEIGHT', AttributeGeneric),
1799 IFLA_OPERSTATE : ('IFLA_OPERSTATE', AttributeFourByteValue),
1800 IFLA_LINKMODE : ('IFLA_LINKMODE', AttributeFourByteValue),
1801 IFLA_LINKINFO : ('IFLA_LINKINFO', AttributeIFLA_LINKINFO),
1802 IFLA_NET_NS_PID : ('IFLA_NET_NS_PID', AttributeGeneric),
1803 IFLA_IFALIAS : ('IFLA_IFALIAS', AttributeGeneric),
1804 IFLA_NUM_VF : ('IFLA_NUM_VF', AttributeGeneric),
1805 IFLA_VFINFO_LIST : ('IFLA_VFINFO_LIST', AttributeGeneric),
1806 IFLA_STATS64 : ('IFLA_STATS64', AttributeGeneric),
1807 IFLA_VF_PORTS : ('IFLA_VF_PORTS', AttributeGeneric),
1808 IFLA_PORT_SELF : ('IFLA_PORT_SELF', AttributeGeneric),
1809 IFLA_AF_SPEC : ('IFLA_AF_SPEC', AttributeIFLA_AF_SPEC),
1810 IFLA_GROUP : ('IFLA_GROUP', AttributeFourByteValue),
1811 IFLA_NET_NS_FD : ('IFLA_NET_NS_FD', AttributeGeneric),
26d1e82b 1812 IFLA_EXT_MASK : ('IFLA_EXT_MASK', AttributeFourByteValue),
198ded6a
JF
1813 IFLA_PROMISCUITY : ('IFLA_PROMISCUITY', AttributeGeneric),
1814 IFLA_NUM_TX_QUEUES : ('IFLA_NUM_TX_QUEUES', AttributeGeneric),
1815 IFLA_NUM_RX_QUEUES : ('IFLA_NUM_RX_QUEUES', AttributeGeneric),
1816 IFLA_CARRIER : ('IFLA_CARRIER', AttributeGeneric),
1817 IFLA_PHYS_PORT_ID : ('IFLA_PHYS_PORT_ID', AttributeGeneric),
1818 IFLA_CARRIER_CHANGES : ('IFLA_CARRIER_CHANGES', AttributeGeneric),
1819 IFLA_PHYS_SWITCH_ID : ('IFLA_PHYS_SWITCH_ID', AttributeGeneric),
1820 IFLA_LINK_NETNSID : ('IFLA_LINK_NETNSID', AttributeGeneric),
1821 IFLA_PHYS_PORT_NAME : ('IFLA_PHYS_PORT_NAME', AttributeGeneric),
26e7207b 1822 IFLA_PROTO_DOWN : ('IFLA_PROTO_DOWN', AttributeOneByteValue),
198ded6a
JF
1823 IFLA_LINKPROTODOWN : ('IFLA_LINKPROTODOWN', AttributeGeneric)
1824 }
1825
1826 # Link flags
1827 # /usr/include/linux/if.h
1828 IFF_UP = 0x0001 # Interface is administratively up.
1829 IFF_BROADCAST = 0x0002 # Valid broadcast address set.
1830 IFF_DEBUG = 0x0004 # Internal debugging flag.
1831 IFF_LOOPBACK = 0x0008 # Interface is a loopback interface.
1832 IFF_POINTOPOINT = 0x0010 # Interface is a point-to-point link.
1833 IFF_NOTRAILERS = 0x0020 # Avoid use of trailers.
1834 IFF_RUNNING = 0x0040 # Interface is operationally up.
1835 IFF_NOARP = 0x0080 # No ARP protocol needed for this interface.
1836 IFF_PROMISC = 0x0100 # Interface is in promiscuous mode.
1837 IFF_ALLMULTI = 0x0200 # Receive all multicast packets.
1838 IFF_MASTER = 0x0400 # Master of a load balancing bundle.
1839 IFF_SLAVE = 0x0800 # Slave of a load balancing bundle.
1840 IFF_MULTICAST = 0x1000 # Supports multicast.
1841 IFF_PORTSEL = 0x2000 # Is able to select media type via ifmap.
1842 IFF_AUTOMEDIA = 0x4000 # Auto media selection active.
1843 IFF_DYNAMIC = 0x8000 # Interface was dynamically created.
1844 IFF_LOWER_UP = 0x10000 # driver signals L1 up
1845 IFF_DORMANT = 0x20000 # driver signals dormant
1846 IFF_ECHO = 0x40000 # echo sent packet
1847 IFF_PROTO_DOWN = 0x1000000 # protocol is down on the interface
1848
1849 flag_to_string = {
1850 IFF_UP : 'IFF_UP',
1851 IFF_BROADCAST : 'IFF_BROADCAST',
1852 IFF_DEBUG : 'IFF_DEBUG',
1853 IFF_LOOPBACK : 'IFF_LOOPBACK',
1854 IFF_POINTOPOINT : 'IFF_POINTOPOINT',
1855 IFF_NOTRAILERS : 'IFF_NOTRAILERS',
1856 IFF_RUNNING : 'IFF_RUNNING',
1857 IFF_NOARP : 'IFF_NOARP',
1858 IFF_PROMISC : 'IFF_PROMISC',
1859 IFF_ALLMULTI : 'IFF_ALLMULTI',
1860 IFF_MASTER : 'IFF_MASTER',
1861 IFF_SLAVE : 'IFF_SLAVE',
1862 IFF_MULTICAST : 'IFF_MULTICAST',
1863 IFF_PORTSEL : 'IFF_PORTSEL',
1864 IFF_AUTOMEDIA : 'IFF_AUTOMEDIA',
1865 IFF_DYNAMIC : 'IFF_DYNAMIC',
1866 IFF_LOWER_UP : 'IFF_LOWER_UP',
1867 IFF_DORMANT : 'IFF_DORMANT',
1868 IFF_ECHO : 'IFF_ECHO',
1869 IFF_PROTO_DOWN : 'IFF_PROTO_DOWN'
1870 }
1871
1872 # RFC 2863 operational status
1873 IF_OPER_UNKNOWN = 0
1874 IF_OPER_NOTPRESENT = 1
1875 IF_OPER_DOWN = 2
1876 IF_OPER_LOWERLAYERDOWN = 3
1877 IF_OPER_TESTING = 4
1878 IF_OPER_DORMANT = 5
1879 IF_OPER_UP = 6
1880
1881 oper_to_string = {
1882 IF_OPER_UNKNOWN : 'IF_OPER_UNKNOWN',
1883 IF_OPER_NOTPRESENT : 'IF_OPER_NOTPRESENT',
1884 IF_OPER_DOWN : 'IF_OPER_DOWN',
1885 IF_OPER_LOWERLAYERDOWN : 'IF_OPER_LOWERLAYERDOWN',
1886 IF_OPER_TESTING : 'IF_OPER_TESTING',
1887 IF_OPER_DORMANT : 'IF_OPER_DORMANT',
1888 IF_OPER_UP : 'IF_OPER_UP'
1889 }
1890
1891 # Link types
1892 # /usr/include/linux/if_arp.h
1893 # ARP protocol HARDWARE identifiers
1894 ARPHRD_NETROM = 0 # from KA9Q: NET/ROM pseudo
1895 ARPHRD_ETHER = 1 # Ethernet 10Mbps
1896 ARPHRD_EETHER = 2 # Experimental Ethernet
1897 ARPHRD_AX25 = 3 # AX.25 Level 2
1898 ARPHRD_PRONET = 4 # PROnet token ring
1899 ARPHRD_CHAOS = 5 # Chaosnet
1900 ARPHRD_IEEE802 = 6 # IEEE 802.2 Ethernet/TR/TB
1901 ARPHRD_ARCNET = 7 # ARCnet
1902 ARPHRD_APPLETLK = 8 # APPLEtalk
1903 ARPHRD_DLCI = 15 # Frame Relay DLCI
1904 ARPHRD_ATM = 19 # ATM
1905 ARPHRD_METRICOM = 23 # Metricom STRIP (new IANA id)
1906 ARPHRD_IEEE1394 = 24 # IEEE 1394 IPv4 - RFC 2734
1907 ARPHRD_EUI64 = 27 # EUI-64
1908 ARPHRD_INFINIBAND = 32 # InfiniBand
1909 # Dummy types for non ARP hardware
1910 ARPHRD_SLIP = 256
1911 ARPHRD_CSLIP = 257
1912 ARPHRD_SLIP6 = 258
1913 ARPHRD_CSLIP6 = 259
1914 ARPHRD_RSRVD = 260 # Notional KISS type
1915 ARPHRD_ADAPT = 264
1916 ARPHRD_ROSE = 270
1917 ARPHRD_X25 = 271 # CCITT X.25
1918 ARPHRD_HWX25 = 272 # Boards with X.25 in firmware
1919 ARPHRD_CAN = 280 # Controller Area Network
1920 ARPHRD_PPP = 512
1921 ARPHRD_CISCO = 513 # Cisco HDLC
1922 ARPHRD_HDLC = ARPHRD_CISCO
1923 ARPHRD_LAPB = 516 # LAPB
1924 ARPHRD_DDCMP = 517 # Digital's DDCMP protocol
1925 ARPHRD_RAWHDLC = 518 # Raw HDLC
1926 ARPHRD_TUNNEL = 768 # IPIP tunnel
1927 ARPHRD_TUNNEL6 = 769 # IP6IP6 tunnel
1928 ARPHRD_FRAD = 770 # Frame Relay Access Device
1929 ARPHRD_SKIP = 771 # SKIP vif
1930 ARPHRD_LOOPBACK = 772 # Loopback device
1931 ARPHRD_LOCALTLK = 773 # Localtalk device
1932 ARPHRD_FDDI = 774 # Fiber Distributed Data Interface
1933 ARPHRD_BIF = 775 # AP1000 BIF
1934 ARPHRD_SIT = 776 # sit0 device - IPv6-in-IPv4
1935 ARPHRD_IPDDP = 777 # IP over DDP tunneller
1936 ARPHRD_IPGRE = 778 # GRE over IP
1937 ARPHRD_PIMREG = 779 # PIMSM register interface
1938 ARPHRD_HIPPI = 780 # High Performance Parallel Interface
1939 ARPHRD_ASH = 781 # Nexus 64Mbps Ash
1940 ARPHRD_ECONET = 782 # Acorn Econet
1941 ARPHRD_IRDA = 783 # Linux-IrDA
1942 ARPHRD_FCPP = 784 # Point to point fibrechannel
1943 ARPHRD_FCAL = 785 # Fibrechannel arbitrated loop
1944 ARPHRD_FCPL = 786 # Fibrechannel public loop
1945 ARPHRD_FCFABRIC = 787 # Fibrechannel fabric
1946 # 787->799 reserved for fibrechannel media types
1947 ARPHRD_IEEE802_TR = 800 # Magic type ident for TR
1948 ARPHRD_IEEE80211 = 801 # IEEE 802.11
1949 ARPHRD_IEEE80211_PRISM = 802 # IEEE 802.11 + Prism2 header
1950 ARPHRD_IEEE80211_RADIOTAP = 803 # IEEE 802.11 + radiotap header
1951 ARPHRD_IEEE802154 = 804
1952 ARPHRD_PHONET = 820 # PhoNet media type
1953 ARPHRD_PHONET_PIPE = 821 # PhoNet pipe header
1954 ARPHRD_CAIF = 822 # CAIF media type
1955 ARPHRD_VOID = 0xFFFF # Void type, nothing is known
1956 ARPHRD_NONE = 0xFFFE # zero header length
1957
1958 link_type_to_string = {
1959 ARPHRD_NETROM : 'ARPHRD_NETROM',
1960 ARPHRD_ETHER : 'ARPHRD_ETHER',
1961 ARPHRD_EETHER : 'ARPHRD_EETHER',
1962 ARPHRD_AX25 : 'ARPHRD_AX25',
1963 ARPHRD_PRONET : 'ARPHRD_PRONET',
1964 ARPHRD_CHAOS : 'ARPHRD_CHAOS',
1965 ARPHRD_IEEE802 : 'ARPHRD_IEEE802',
1966 ARPHRD_ARCNET : 'ARPHRD_ARCNET',
1967 ARPHRD_APPLETLK : 'ARPHRD_APPLETLK',
1968 ARPHRD_DLCI : 'ARPHRD_DLCI',
1969 ARPHRD_ATM : 'ARPHRD_ATM',
1970 ARPHRD_METRICOM : 'ARPHRD_METRICOM',
1971 ARPHRD_IEEE1394 : 'ARPHRD_IEEE1394',
1972 ARPHRD_EUI64 : 'ARPHRD_EUI64',
1973 ARPHRD_INFINIBAND : 'ARPHRD_INFINIBAND',
1974 ARPHRD_SLIP : 'ARPHRD_SLIP',
1975 ARPHRD_CSLIP : 'ARPHRD_CSLIP',
1976 ARPHRD_SLIP6 : 'ARPHRD_SLIP6',
1977 ARPHRD_CSLIP6 : 'ARPHRD_CSLIP6',
1978 ARPHRD_RSRVD : 'ARPHRD_RSRVD',
1979 ARPHRD_ADAPT : 'ARPHRD_ADAPT',
1980 ARPHRD_ROSE : 'ARPHRD_ROSE',
1981 ARPHRD_X25 : 'ARPHRD_X25',
1982 ARPHRD_HWX25 : 'ARPHRD_HWX25',
1983 ARPHRD_CAN : 'ARPHRD_CAN',
1984 ARPHRD_PPP : 'ARPHRD_PPP',
1985 ARPHRD_CISCO : 'ARPHRD_CISCO',
1986 ARPHRD_HDLC : 'ARPHRD_HDLC',
1987 ARPHRD_LAPB : 'ARPHRD_LAPB',
1988 ARPHRD_DDCMP : 'ARPHRD_DDCMP',
1989 ARPHRD_RAWHDLC : 'ARPHRD_RAWHDLC',
1990 ARPHRD_TUNNEL : 'ARPHRD_TUNNEL',
1991 ARPHRD_TUNNEL6 : 'ARPHRD_TUNNEL6',
1992 ARPHRD_FRAD : 'ARPHRD_FRAD',
1993 ARPHRD_SKIP : 'ARPHRD_SKIP',
1994 ARPHRD_LOOPBACK : 'ARPHRD_LOOPBACK',
1995 ARPHRD_LOCALTLK : 'ARPHRD_LOCALTLK',
1996 ARPHRD_FDDI : 'ARPHRD_FDDI',
1997 ARPHRD_BIF : 'ARPHRD_BIF',
1998 ARPHRD_SIT : 'ARPHRD_SIT',
1999 ARPHRD_IPDDP : 'ARPHRD_IPDDP',
2000 ARPHRD_IPGRE : 'ARPHRD_IPGRE',
2001 ARPHRD_PIMREG : 'ARPHRD_PIMREG',
2002 ARPHRD_HIPPI : 'ARPHRD_HIPPI',
2003 ARPHRD_ASH : 'ARPHRD_ASH',
2004 ARPHRD_ECONET : 'ARPHRD_ECONET',
2005 ARPHRD_IRDA : 'ARPHRD_IRDA',
2006 ARPHRD_FCPP : 'ARPHRD_FCPP',
2007 ARPHRD_FCAL : 'ARPHRD_FCAL',
2008 ARPHRD_FCPL : 'ARPHRD_FCPL',
2009 ARPHRD_FCFABRIC : 'ARPHRD_FCFABRIC',
2010 ARPHRD_IEEE802_TR : 'ARPHRD_IEEE802_TR',
2011 ARPHRD_IEEE80211 : 'ARPHRD_IEEE80211',
2012 ARPHRD_IEEE80211_PRISM : 'ARPHRD_IEEE80211_PRISM',
2013 ARPHRD_IEEE80211_RADIOTAP : 'ARPHRD_IEEE80211_RADIOTAP',
2014 ARPHRD_IEEE802154 : 'ARPHRD_IEEE802154',
2015 ARPHRD_PHONET : 'ARPHRD_PHONET',
2016 ARPHRD_PHONET_PIPE : 'ARPHRD_PHONET_PIPE',
2017 ARPHRD_CAIF : 'ARPHRD_CAIF',
2018 ARPHRD_VOID : 'ARPHRD_VOID',
2019 ARPHRD_NONE : 'ARPHRD_NONE'
2020 }
2021
2022 # =========================================
2023 # IFLA_LINKINFO attributes
2024 # =========================================
2025 IFLA_INFO_UNSPEC = 0
2026 IFLA_INFO_KIND = 1
2027 IFLA_INFO_DATA = 2
2028 IFLA_INFO_XSTATS = 3
2029 IFLA_INFO_SLAVE_KIND = 4
2030 IFLA_INFO_SLAVE_DATA = 5
2031 IFLA_INFO_MAX = 6
2032
2033 ifla_info_to_string = {
2034 IFLA_INFO_UNSPEC : 'IFLA_INFO_UNSPEC',
2035 IFLA_INFO_KIND : 'IFLA_INFO_KIND',
2036 IFLA_INFO_DATA : 'IFLA_INFO_DATA',
2037 IFLA_INFO_XSTATS : 'IFLA_INFO_XSTATS',
2038 IFLA_INFO_SLAVE_KIND : 'IFLA_INFO_SLAVE_KIND',
2039 IFLA_INFO_SLAVE_DATA : 'IFLA_INFO_SLAVE_DATA',
2040 IFLA_INFO_MAX : 'IFLA_INFO_MAX'
2041 }
2042
2043 # =========================================
2044 # IFLA_INFO_DATA attributes for vlan
2045 # =========================================
2046 IFLA_VLAN_UNSPEC = 0
2047 IFLA_VLAN_ID = 1
2048 IFLA_VLAN_FLAGS = 2
2049 IFLA_VLAN_EGRESS_QOS = 3
2050 IFLA_VLAN_INGRESS_QOS = 4
2051 IFLA_VLAN_PROTOCOL = 5
2052
2053 ifla_vlan_to_string = {
2054 IFLA_VLAN_UNSPEC : 'IFLA_VLAN_UNSPEC',
2055 IFLA_VLAN_ID : 'IFLA_VLAN_ID',
2056 IFLA_VLAN_FLAGS : 'IFLA_VLAN_FLAGS',
2057 IFLA_VLAN_EGRESS_QOS : 'IFLA_VLAN_EGRESS_QOS',
2058 IFLA_VLAN_INGRESS_QOS : 'IFLA_VLAN_INGRESS_QOS',
2059 IFLA_VLAN_PROTOCOL : 'IFLA_VLAN_PROTOCOL'
2060 }
2061
2062 # =========================================
2063 # IFLA_INFO_DATA attributes for macvlan
2064 # =========================================
2065 IFLA_MACVLAN_UNSPEC = 0
2066 IFLA_MACVLAN_MODE = 1
2067
2068 ifla_macvlan_to_string = {
2069 IFLA_MACVLAN_UNSPEC : 'IFLA_MACVLAN_UNSPEC',
2070 IFLA_MACVLAN_MODE : 'IFLA_MACVLAN_MODE'
2071 }
2072
2073 # macvlan modes
2074 MACVLAN_MODE_PRIVATE = 1
2075 MACVLAN_MODE_VEPA = 2
2076 MACVLAN_MODE_BRIDGE = 3
2077 MACVLAN_MODE_PASSTHRU = 4
2078
2079 macvlan_mode_to_string = {
2080 MACVLAN_MODE_PRIVATE : 'MACVLAN_MODE_PRIVATE',
2081 MACVLAN_MODE_VEPA : 'MACVLAN_MODE_VEPA',
2082 MACVLAN_MODE_BRIDGE : 'MACVLAN_MODE_BRIDGE',
2083 MACVLAN_MODE_PASSTHRU : 'MACVLAN_MODE_PASSTHRU'
2084 }
2085
2086 # =========================================
2087 # IFLA_INFO_DATA attributes for vxlan
2088 # =========================================
2089 IFLA_VXLAN_UNSPEC = 0
2090 IFLA_VXLAN_ID = 1
2091 IFLA_VXLAN_GROUP = 2
2092 IFLA_VXLAN_LINK = 3
2093 IFLA_VXLAN_LOCAL = 4
2094 IFLA_VXLAN_TTL = 5
2095 IFLA_VXLAN_TOS = 6
2096 IFLA_VXLAN_LEARNING = 7
2097 IFLA_VXLAN_AGEING = 8
2098 IFLA_VXLAN_LIMIT = 9
2099 IFLA_VXLAN_PORT_RANGE = 10
2100 IFLA_VXLAN_PROXY = 11
2101 IFLA_VXLAN_RSC = 12
2102 IFLA_VXLAN_L2MISS = 13
2103 IFLA_VXLAN_L3MISS = 14
2104 IFLA_VXLAN_PORT = 15
2105 IFLA_VXLAN_GROUP6 = 16
2106 IFLA_VXLAN_LOCAL6 = 17
2107 IFLA_VXLAN_UDP_CSUM = 18
2108 IFLA_VXLAN_UDP_ZERO_CSUM6_TX = 19
2109 IFLA_VXLAN_UDP_ZERO_CSUM6_RX = 20
2110 IFLA_VXLAN_REMCSUM_TX = 21
2111 IFLA_VXLAN_REMCSUM_RX = 22
2112 IFLA_VXLAN_GBP = 23
2113 IFLA_VXLAN_REMCSUM_NOPARTIAL = 24
2114 IFLA_VXLAN_COLLECT_METADATA = 25
2115 IFLA_VXLAN_REPLICATION_NODE = 253
2116 IFLA_VXLAN_REPLICATION_TYPE = 254
2117
2118 ifla_vxlan_to_string = {
2119 IFLA_VXLAN_UNSPEC : 'IFLA_VXLAN_UNSPEC',
2120 IFLA_VXLAN_ID : 'IFLA_VXLAN_ID',
2121 IFLA_VXLAN_GROUP : 'IFLA_VXLAN_GROUP',
2122 IFLA_VXLAN_LINK : 'IFLA_VXLAN_LINK',
2123 IFLA_VXLAN_LOCAL : 'IFLA_VXLAN_LOCAL',
2124 IFLA_VXLAN_TTL : 'IFLA_VXLAN_TTL',
2125 IFLA_VXLAN_TOS : 'IFLA_VXLAN_TOS',
2126 IFLA_VXLAN_LEARNING : 'IFLA_VXLAN_LEARNING',
2127 IFLA_VXLAN_AGEING : 'IFLA_VXLAN_AGEING',
2128 IFLA_VXLAN_LIMIT : 'IFLA_VXLAN_LIMIT',
2129 IFLA_VXLAN_PORT_RANGE : 'IFLA_VXLAN_PORT_RANGE',
2130 IFLA_VXLAN_PROXY : 'IFLA_VXLAN_PROXY',
2131 IFLA_VXLAN_RSC : 'IFLA_VXLAN_RSC',
2132 IFLA_VXLAN_L2MISS : 'IFLA_VXLAN_L2MISS',
2133 IFLA_VXLAN_L3MISS : 'IFLA_VXLAN_L3MISS',
2134 IFLA_VXLAN_PORT : 'IFLA_VXLAN_PORT',
2135 IFLA_VXLAN_GROUP6 : 'IFLA_VXLAN_GROUP6',
2136 IFLA_VXLAN_LOCAL6 : 'IFLA_VXLAN_LOCAL6',
2137 IFLA_VXLAN_UDP_CSUM : 'IFLA_VXLAN_UDP_CSUM',
2138 IFLA_VXLAN_UDP_ZERO_CSUM6_TX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_TX',
2139 IFLA_VXLAN_UDP_ZERO_CSUM6_RX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_RX',
2140 IFLA_VXLAN_REMCSUM_TX : 'IFLA_VXLAN_REMCSUM_TX',
2141 IFLA_VXLAN_REMCSUM_RX : 'IFLA_VXLAN_REMCSUM_RX',
2142 IFLA_VXLAN_GBP : 'IFLA_VXLAN_GBP',
2143 IFLA_VXLAN_REMCSUM_NOPARTIAL : 'IFLA_VXLAN_REMCSUM_NOPARTIAL',
2144 IFLA_VXLAN_COLLECT_METADATA : 'IFLA_VXLAN_COLLECT_METADATA',
2145 IFLA_VXLAN_REPLICATION_NODE : 'IFLA_VXLAN_REPLICATION_NODE',
2146 IFLA_VXLAN_REPLICATION_TYPE : 'IFLA_VXLAN_REPLICATION_TYPE'
2147 }
2148
2149 # =========================================
2150 # IFLA_INFO_DATA attributes for bonds
2151 # =========================================
2152 IFLA_BOND_UNSPEC = 0
2153 IFLA_BOND_MODE = 1
2154 IFLA_BOND_ACTIVE_SLAVE = 2
2155 IFLA_BOND_MIIMON = 3
2156 IFLA_BOND_UPDELAY = 4
2157 IFLA_BOND_DOWNDELAY = 5
2158 IFLA_BOND_USE_CARRIER = 6
2159 IFLA_BOND_ARP_INTERVAL = 7
2160 IFLA_BOND_ARP_IP_TARGET = 8
2161 IFLA_BOND_ARP_VALIDATE = 9
2162 IFLA_BOND_ARP_ALL_TARGETS = 10
2163 IFLA_BOND_PRIMARY = 11
2164 IFLA_BOND_PRIMARY_RESELECT = 12
2165 IFLA_BOND_FAIL_OVER_MAC = 13
2166 IFLA_BOND_XMIT_HASH_POLICY = 14
2167 IFLA_BOND_RESEND_IGMP = 15
2168 IFLA_BOND_NUM_PEER_NOTIF = 16
2169 IFLA_BOND_ALL_SLAVES_ACTIVE = 17
2170 IFLA_BOND_MIN_LINKS = 18
2171 IFLA_BOND_LP_INTERVAL = 19
2172 IFLA_BOND_PACKETS_PER_SLAVE = 20
2173 IFLA_BOND_AD_LACP_RATE = 21
2174 IFLA_BOND_AD_SELECT = 22
2175 IFLA_BOND_AD_INFO = 23
2176 IFLA_BOND_AD_ACTOR_SYS_PRIO = 24
2177 IFLA_BOND_AD_USER_PORT_KEY = 25
2178 IFLA_BOND_AD_ACTOR_SYSTEM = 26
2179 IFLA_BOND_CL_LACP_BYPASS_ALLOW = 100
2180 IFLA_BOND_CL_LACP_BYPASS_ACTIVE = 101
2181 IFLA_BOND_CL_LACP_BYPASS_PERIOD = 102
2182 IFLA_BOND_CL_CLAG_ENABLE = 103
2183 IFLA_BOND_CL_LACP_BYPASS_ALL_ACTIVE = 104
2184
2185 ifla_bond_to_string = {
2186 IFLA_BOND_UNSPEC : 'IFLA_BOND_UNSPEC',
2187 IFLA_BOND_MODE : 'IFLA_BOND_MODE',
2188 IFLA_BOND_ACTIVE_SLAVE : 'IFLA_BOND_ACTIVE_SLAVE',
2189 IFLA_BOND_MIIMON : 'IFLA_BOND_MIIMON',
2190 IFLA_BOND_UPDELAY : 'IFLA_BOND_UPDELAY',
2191 IFLA_BOND_DOWNDELAY : 'IFLA_BOND_DOWNDELAY',
2192 IFLA_BOND_USE_CARRIER : 'IFLA_BOND_USE_CARRIER',
2193 IFLA_BOND_ARP_INTERVAL : 'IFLA_BOND_ARP_INTERVAL',
2194 IFLA_BOND_ARP_IP_TARGET : 'IFLA_BOND_ARP_IP_TARGET',
2195 IFLA_BOND_ARP_VALIDATE : 'IFLA_BOND_ARP_VALIDATE',
2196 IFLA_BOND_ARP_ALL_TARGETS : 'IFLA_BOND_ARP_ALL_TARGETS',
2197 IFLA_BOND_PRIMARY : 'IFLA_BOND_PRIMARY',
2198 IFLA_BOND_PRIMARY_RESELECT : 'IFLA_BOND_PRIMARY_RESELECT',
2199 IFLA_BOND_FAIL_OVER_MAC : 'IFLA_BOND_FAIL_OVER_MAC',
2200 IFLA_BOND_XMIT_HASH_POLICY : 'IFLA_BOND_XMIT_HASH_POLICY',
2201 IFLA_BOND_RESEND_IGMP : 'IFLA_BOND_RESEND_IGMP',
2202 IFLA_BOND_NUM_PEER_NOTIF : 'IFLA_BOND_NUM_PEER_NOTIF',
2203 IFLA_BOND_ALL_SLAVES_ACTIVE : 'IFLA_BOND_ALL_SLAVES_ACTIVE',
2204 IFLA_BOND_MIN_LINKS : 'IFLA_BOND_MIN_LINKS',
2205 IFLA_BOND_LP_INTERVAL : 'IFLA_BOND_LP_INTERVAL',
2206 IFLA_BOND_PACKETS_PER_SLAVE : 'IFLA_BOND_PACKETS_PER_SLAVE',
2207 IFLA_BOND_AD_LACP_RATE : 'IFLA_BOND_AD_LACP_RATE',
2208 IFLA_BOND_AD_SELECT : 'IFLA_BOND_AD_SELECT',
2209 IFLA_BOND_AD_INFO : 'IFLA_BOND_AD_INFO',
2210 IFLA_BOND_AD_ACTOR_SYS_PRIO : 'IFLA_BOND_AD_ACTOR_SYS_PRIO',
2211 IFLA_BOND_AD_USER_PORT_KEY : 'IFLA_BOND_AD_USER_PORT_KEY',
2212 IFLA_BOND_AD_ACTOR_SYSTEM : 'IFLA_BOND_AD_ACTOR_SYSTEM',
2213 IFLA_BOND_CL_LACP_BYPASS_ALLOW : 'IFLA_BOND_CL_LACP_BYPASS_ALLOW',
2214 IFLA_BOND_CL_LACP_BYPASS_ACTIVE : 'IFLA_BOND_CL_LACP_BYPASS_ACTIVE',
2215 IFLA_BOND_CL_LACP_BYPASS_PERIOD : 'IFLA_BOND_CL_LACP_BYPASS_PERIOD',
2216 IFLA_BOND_CL_CLAG_ENABLE : 'IFLA_BOND_CL_CLAG_ENABLE',
2217 IFLA_BOND_CL_LACP_BYPASS_ALL_ACTIVE : 'IFLA_BOND_CL_LACP_BYPASS_ALL_ACTIVE'
2218 }
2219
2220 # =========================================
2221 # IFLA_INFO_DATA attributes for bridges
2222 # =========================================
2223 IFLA_BRPORT_UNSPEC = 0
2224 IFLA_BRPORT_STATE = 1
2225 IFLA_BRPORT_PRIORITY = 2
2226 IFLA_BRPORT_COST = 3
2227 IFLA_BRPORT_MODE = 4
2228 IFLA_BRPORT_GUARD = 5
2229 IFLA_BRPORT_PROTECT = 6
2230 IFLA_BRPORT_FAST_LEAVE = 7
2231 IFLA_BRPORT_LEARNING = 8
2232 IFLA_BRPORT_UNICAST_FLOOD = 9
2233 IFLA_BRPORT_PROXYARP = 10
2234 IFLA_BRPORT_LEARNING_SYNC = 11
2235 IFLA_BRPORT_PROXYARP_WIFI = 12
2236 IFLA_BRPORT_ROOT_ID = 13
2237 IFLA_BRPORT_BRIDGE_ID = 14
2238 IFLA_BRPORT_DESIGNATED_PORT = 15
2239 IFLA_BRPORT_DESIGNATED_COST = 16
2240 IFLA_BRPORT_ID = 17
2241 IFLA_BRPORT_NO = 18
2242 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19
2243 IFLA_BRPORT_CONFIG_PENDING = 20
2244 IFLA_BRPORT_MESSAGE_AGE_TIMER = 21
2245 IFLA_BRPORT_FORWARD_DELAY_TIMER = 22
2246 IFLA_BRPORT_HOLD_TIMER = 23
2247 IFLA_BRPORT_FLUSH = 24
2248 IFLA_BRPORT_MULTICAST_ROUTER = 25
2249 IFLA_BRPORT_PEER_LINK = 150
2250 IFLA_BRPORT_DUAL_LINK = 151
2251
2252 ifla_bridge_to_string = {
2253 IFLA_BRPORT_UNSPEC : 'IFLA_BRPORT_UNSPEC',
2254 IFLA_BRPORT_STATE : 'IFLA_BRPORT_STATE',
2255 IFLA_BRPORT_PRIORITY : 'IFLA_BRPORT_PRIORITY',
2256 IFLA_BRPORT_COST : 'IFLA_BRPORT_COST',
2257 IFLA_BRPORT_MODE : 'IFLA_BRPORT_MODE',
2258 IFLA_BRPORT_GUARD : 'IFLA_BRPORT_GUARD',
2259 IFLA_BRPORT_PROTECT : 'IFLA_BRPORT_PROTECT',
2260 IFLA_BRPORT_FAST_LEAVE : 'IFLA_BRPORT_FAST_LEAVE',
2261 IFLA_BRPORT_LEARNING : 'IFLA_BRPORT_LEARNING',
2262 IFLA_BRPORT_UNICAST_FLOOD : 'IFLA_BRPORT_UNICAST_FLOOD',
2263 IFLA_BRPORT_PROXYARP : 'IFLA_BRPORT_PROXYARP',
2264 IFLA_BRPORT_LEARNING_SYNC : 'IFLA_BRPORT_LEARNING_SYNC',
2265 IFLA_BRPORT_PROXYARP_WIFI : 'IFLA_BRPORT_PROXYARP_WIFI',
2266 IFLA_BRPORT_ROOT_ID : 'IFLA_BRPORT_ROOT_ID',
2267 IFLA_BRPORT_BRIDGE_ID : 'IFLA_BRPORT_BRIDGE_ID',
2268 IFLA_BRPORT_DESIGNATED_PORT : 'IFLA_BRPORT_DESIGNATED_PORT',
2269 IFLA_BRPORT_DESIGNATED_COST : 'IFLA_BRPORT_DESIGNATED_COST',
2270 IFLA_BRPORT_ID : 'IFLA_BRPORT_ID',
2271 IFLA_BRPORT_NO : 'IFLA_BRPORT_NO',
2272 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK : 'IFLA_BRPORT_TOPOLOGY_CHANGE_ACK',
2273 IFLA_BRPORT_CONFIG_PENDING : 'IFLA_BRPORT_CONFIG_PENDING',
2274 IFLA_BRPORT_MESSAGE_AGE_TIMER : 'IFLA_BRPORT_MESSAGE_AGE_TIMER',
2275 IFLA_BRPORT_FORWARD_DELAY_TIMER : 'IFLA_BRPORT_FORWARD_DELAY_TIMER',
2276 IFLA_BRPORT_HOLD_TIMER : 'IFLA_BRPORT_HOLD_TIMER',
2277 IFLA_BRPORT_FLUSH : 'IFLA_BRPORT_FLUSH',
2278 IFLA_BRPORT_MULTICAST_ROUTER : 'IFLA_BRPORT_MULTICAST_ROUTER',
2279 IFLA_BRPORT_PEER_LINK : 'IFLA_BRPORT_PEER_LINK',
2280 IFLA_BRPORT_DUAL_LINK : 'IFLA_BRPORT_DUAL_LINK'
2281 }
2282
2283 # BRIDGE IFLA_AF_SPEC attributes
2284 IFLA_BRIDGE_FLAGS = 0
2285 IFLA_BRIDGE_MODE = 1
2286 IFLA_BRIDGE_VLAN_INFO = 2
2287
2288 ifla_bridge_af_spec_to_string = {
2289 IFLA_BRIDGE_FLAGS : 'IFLA_BRIDGE_FLAGS',
2290 IFLA_BRIDGE_MODE : 'IFLA_BRIDGE_MODE',
2291 IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO'
2292 }
2293
2294 # BRIDGE_VLAN_INFO flags
26d1e82b
JF
2295 BRIDGE_VLAN_INFO_MASTER = 1 << 0
2296 BRIDGE_VLAN_INFO_PVID = 1 << 1
2297 BRIDGE_VLAN_INFO_UNTAGGED = 1 << 2
2298 BRIDGE_VLAN_INFO_RANGE_BEGIN = 1 << 3
2299 BRIDGE_VLAN_INFO_RANGE_END = 1 << 4
198ded6a
JF
2300
2301 bridge_vlan_to_string = {
26d1e82b
JF
2302 BRIDGE_VLAN_INFO_MASTER : 'BRIDGE_VLAN_INFO_MASTER',
2303 BRIDGE_VLAN_INFO_PVID : 'BRIDGE_VLAN_INFO_PVID',
2304 BRIDGE_VLAN_INFO_UNTAGGED : 'BRIDGE_VLAN_INFO_UNTAGGED',
2305 BRIDGE_VLAN_INFO_RANGE_BEGIN : 'BRIDGE_VLAN_INFO_RANGE_BEGIN',
2306 BRIDGE_VLAN_INFO_RANGE_END : 'BRIDGE_VLAN_INFO_RANGE_END'
198ded6a
JF
2307 }
2308
2309 # Bridge flags
2310 BRIDGE_FLAGS_MASTER = 1
2311 BRIDGE_FLAGS_SELF = 2
2312
2313 bridge_flags_to_string = {
2314 BRIDGE_FLAGS_MASTER : 'BRIDGE_FLAGS_MASTER',
2315 BRIDGE_FLAGS_SELF : 'BRIDGE_FLAGS_SELF'
2316 }
2317
26d1e82b
JF
2318 # filters for IFLA_EXT_MASK
2319 RTEXT_FILTER_VF = 1 << 0
2320 RTEXT_FILTER_BRVLAN = 1 << 1
2321 RTEXT_FILTER_BRVLAN_COMPRESSED = 1 << 2
2322 RTEXT_FILTER_SKIP_STATS = 1 << 3
2323
2324 rtext_to_string = {
2325 RTEXT_FILTER_VF : 'RTEXT_FILTER_VF',
2326 RTEXT_FILTER_BRVLAN : 'RTEXT_FILTER_BRVLAN',
2327 RTEXT_FILTER_BRVLAN_COMPRESSED : 'RTEXT_FILTER_BRVLAN_COMPRESSED',
2328 RTEXT_FILTER_SKIP_STATS : 'RTEXT_FILTER_SKIP_STATS'
2329 }
2330
198ded6a
JF
2331 def __init__(self, msgtype, debug=False, logger=None):
2332 NetlinkPacket.__init__(self, msgtype, debug, logger)
2333 self.PACK = 'BxHiII'
2334 self.LEN = calcsize(self.PACK)
2335
2336 def get_link_type_string(self, index):
2337 return self.get_string(self.link_type_to_string, index)
2338
2339 def get_ifla_bridge_af_spec_to_string(self, index):
2340 return self.get_string(self.ifla_bridge_af_spec_to_string, index)
2341
2342 def get_ifla_info_string(self, index):
2343 return self.get_string(self.ifla_info_to_string, index)
2344
2345 def get_ifla_vlan_string(self, index):
2346 return self.get_string(self.ifla_vlan_to_string, index)
2347
2348 def get_ifla_vxlan_string(self, index):
2349 return self.get_string(self.ifla_vxlan_to_string, index)
2350
2351 def get_ifla_macvlan_string(self, index):
2352 return self.get_string(self.ifla_macvlan_to_string, index)
2353
2354 def get_macvlan_mode_string(self, index):
2355 return self.get_string(self.macvlan_mode_to_string, index)
2356
2357 def get_ifla_bond_string(self, index):
2358 return self.get_string(self.ifla_bond_to_string, index)
2359
2360 def get_ifla_bridge_string(self, index):
2361 return self.get_string(self.ifla_bridge_to_string, index)
2362
2363 def get_bridge_vlan_string(self, index):
2364 return self.get_string(self.bridge_vlan_to_string, index)
2365
2366 def get_bridge_flags_string(self, index):
2367 return self.get_string(self.bridge_flags_to_string, index)
2368
2369 def decode_service_header(self):
2370
2371 # Nothing to do if the message did not contain a service header
2372 if self.length == self.header_LEN:
2373 return
2374
2375 (self.family, self.device_type,
2376 self.ifindex,
2377 self.flags,
2378 self.change_mask) = \
2379 unpack(self.PACK, self.msg_data[:self.LEN])
2380
2381 if self.debug:
2382 color = yellow
2383 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
2384 for x in range(0, self.LEN/4):
2385 if self.line_number == 5:
2386 extra = "Family %s (%d), Device Type %s (%d - %s)" % \
2387 (zfilled_hex(self.family, 2), self.family,
2388 zfilled_hex(self.device_type, 4), self.device_type, self.get_link_type_string(self.device_type))
2389 elif self.line_number == 6:
2390 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
2391 elif self.line_number == 7:
2392 extra = "Device Flags %s (%s)" % (zfilled_hex(self.flags, 8), self.get_flags_string())
2393 elif self.line_number == 8:
2394 extra = "Change Mask %s" % zfilled_hex(self.change_mask, 8)
2395 else:
2396 extra = "Unexpected line number %d" % self.line_number
2397
2398 start = x * 4
2399 end = start + 4
2400 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2401 self.line_number += 1
2402
2403 def is_up(self):
2404 if self.flags & Link.IFF_UP:
2405 return True
2406 return False
2407
2408
2409class Neighbor(NetlinkPacket):
2410 """
2411 Service Header
2412
2413 0 1 2 3
2414 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
2415 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2416 | Family | Reserved1 | Reserved2 |
2417 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2418 | Interface Index |
2419 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2420 | State | Flags | Type |
2421 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2422 """
2423
2424 # Neighbor attributes
2425 # /usr/include/linux/neighbour.h
2426 NDA_UNSPEC = 0x00 # Unknown type
2427 NDA_DST = 0x01 # A neighbour cache network. layer destination address
2428 NDA_LLADDR = 0x02 # A neighbor cache link layer address.
2429 NDA_CACHEINFO = 0x03 # Cache statistics
2430 NDA_PROBES = 0x04
2431 NDA_VLAN = 0x05
2432 NDA_PORT = 0x06
2433 NDA_VNI = 0x07
2434 NDA_IFINDEX = 0x08
2435 NDA_MASTER = 0x09
2436 NDA_LINK_NETNSID = 0x0A
2437
2438 attribute_to_class = {
2439 NDA_UNSPEC : ('NDA_UNSPEC', AttributeGeneric),
2440 NDA_DST : ('NDA_DST', AttributeIPAddress),
2441 NDA_LLADDR : ('NDA_LLADDR', AttributeMACAddress),
9f25ff0d 2442 NDA_CACHEINFO : ('NDA_CACHEINFO', AttributeFourByteList),
198ded6a 2443 NDA_PROBES : ('NDA_PROBES', AttributeFourByteValue),
9f25ff0d 2444 NDA_VLAN : ('NDA_VLAN', AttributeTwoByteValue),
198ded6a 2445 NDA_PORT : ('NDA_PORT', AttributeGeneric),
9f25ff0d
SE
2446 NDA_VNI : ('NDA_VNI', AttributeFourByteValue),
2447 NDA_IFINDEX : ('NDA_IFINDEX', AttributeFourByteValue),
2448 NDA_MASTER : ('NDA_MASTER', AttributeFourByteValue),
198ded6a
JF
2449 NDA_LINK_NETNSID : ('NDA_LINK_NETNSID', AttributeGeneric)
2450 }
2451
2452 # Neighbor flags
2453 # /usr/include/linux/neighbour.h
2454 NTF_USE = 0x01
9f25ff0d
SE
2455 NTF_SELF = 0x02
2456 NTF_MASTER = 0x04
198ded6a
JF
2457 NTF_PROXY = 0x08 # A proxy ARP entry
2458 NTF_ROUTER = 0x80 # An IPv6 router
2459
2460 flag_to_string = {
2461 NTF_USE : 'NTF_USE',
9f25ff0d
SE
2462 NTF_SELF : 'NTF_SELF',
2463 NTF_MASTER : 'NTF_MASTER',
198ded6a
JF
2464 NTF_PROXY : 'NTF_PROXY',
2465 NTF_ROUTER : 'NTF_ROUTER'
2466 }
2467
2468 # Neighbor states
2469 # /usr/include/linux/neighbour.h
2470 NUD_NONE = 0x00
2471 NUD_INCOMPLETE = 0x01 # Still attempting to resolve
2472 NUD_REACHABLE = 0x02 # A confirmed working cache entry
2473 NUD_STALE = 0x04 # an expired cache entry
2474 NUD_DELAY = 0x08 # Neighbor no longer reachable. Traffic sent, waiting for confirmatio.
2475 NUD_PROBE = 0x10 # A cache entry that is currently being re-solicited
2476 NUD_FAILED = 0x20 # An invalid cache entry
2477 NUD_NOARP = 0x40 # A device which does not do neighbor discovery(ARP)
2478 NUD_PERMANENT = 0x80 # A static entry
2479
2480 state_to_string = {
2481 NUD_NONE : 'NUD_NONE',
2482 NUD_INCOMPLETE : 'NUD_INCOMPLETE',
2483 NUD_REACHABLE : 'NUD_REACHABLE',
2484 NUD_STALE : 'NUD_STALE',
2485 NUD_DELAY : 'NUD_DELAY',
2486 NUD_PROBE : 'NUD_PROBE',
2487 NUD_FAILED : 'NUD_FAILED',
2488 NUD_NOARP : 'NUD_NOARP',
2489 NUD_PERMANENT : 'NUD_PERMANENT'
2490 }
2491
2492 def __init__(self, msgtype, debug=False, logger=None):
2493 NetlinkPacket.__init__(self, msgtype, debug, logger)
2494 self.PACK = 'BxxxiHBB'
2495 self.LEN = calcsize(self.PACK)
2496
2497 def get_state_string(self, index):
2498 return self.get_string(self.state_to_string, index)
2499
2500 def decode_service_header(self):
2501
2502 # Nothing to do if the message did not contain a service header
2503 if self.length == self.header_LEN:
2504 return
2505
2506 (self.family,
2507 self.ifindex,
2508 self.state, self.flags, self.neighbor_type) = \
2509 unpack(self.PACK, self.msg_data[:self.LEN])
2510
2511 if self.debug:
2512 color = yellow
2513 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
2514
2515 for x in range(0, self.LEN/4):
2516 if self.line_number == 5:
2517 extra = "Family %s (%d)" % (zfilled_hex(self.family, 2), self.family)
2518 elif self.line_number == 6:
2519 extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex)
2520 elif self.line_number == 7:
2521 extra = "State %s (%d), Flags %s, Type %s (%d)" % \
2522 (zfilled_hex(self.state, 4), self.state,
2523 zfilled_hex(self.flags, 2),
2524 zfilled_hex(self.neighbor_type, 4), self.neighbor_type)
2525 else:
2526 extra = "Unexpected line number %d" % self.line_number
2527
2528 start = x * 4
2529 end = start + 4
2530 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2531 self.line_number += 1
2532
2533
2534class Route(NetlinkPacket):
2535 """
2536 Service Header
2537
2538 0 1 2 3
2539 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
2540 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2541 | Family | Dest length | Src length | TOS |
2542 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2543 | Table ID | Protocol | Scope | Type |
2544 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2545 | Flags |
2546 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2547 """
2548
2549 # Route attributes
2550 # /usr/include/linux/rtnetlink.h
2551 RTA_UNSPEC = 0x00 # Ignored.
2552 RTA_DST = 0x01 # Protocol address for route destination address.
2553 RTA_SRC = 0x02 # Protocol address for route source address.
2554 RTA_IIF = 0x03 # Input interface index.
2555 RTA_OIF = 0x04 # Output interface index.
2556 RTA_GATEWAY = 0x05 # Protocol address for the gateway of the route
2557 RTA_PRIORITY = 0x06 # Priority of broker.
2558 RTA_PREFSRC = 0x07 # Preferred source address in cases where more than one source address could be used.
2559 RTA_METRICS = 0x08 # Route metrics attributed to route and associated protocols(e.g., RTT, initial TCP window, etc.).
2560 RTA_MULTIPATH = 0x09 # Multipath route next hop's attributes.
2561 RTA_PROTOINFO = 0x0A # Firewall based policy routing attribute.
2562 RTA_FLOW = 0x0B # Route realm.
2563 RTA_CACHEINFO = 0x0C # Cached route information.
2564 RTA_SESSION = 0x0D
2565 RTA_MP_ALGO = 0x0E
2566 RTA_TABLE = 0x0F
2567 RTA_MARK = 0x10
ea2bf79d
JF
2568 RTA_MFC_STATS = 0x11
2569 RTA_VIA = 0x12
2570 RTA_NEWDST = 0x13
2571 RTA_PREF = 0x14
2572 RTA_ENCAP_TYPE= 0x15
2573 RTA_ENCAP = 0x16
198ded6a
JF
2574
2575 attribute_to_class = {
2576 RTA_UNSPEC : ('RTA_UNSPEC', AttributeGeneric),
2577 RTA_DST : ('RTA_DST', AttributeIPAddress),
2578 RTA_SRC : ('RTA_SRC', AttributeIPAddress),
2579 RTA_IIF : ('RTA_IIF', AttributeFourByteValue),
2580 RTA_OIF : ('RTA_OIF', AttributeFourByteValue),
2581 RTA_GATEWAY : ('RTA_GATEWAY', AttributeIPAddress),
2582 RTA_PRIORITY : ('RTA_PRIORITY', AttributeFourByteValue),
2583 RTA_PREFSRC : ('RTA_PREFSRC', AttributeIPAddress),
2584 RTA_METRICS : ('RTA_METRICS', AttributeGeneric),
2585 RTA_MULTIPATH : ('RTA_MULTIPATH', AttributeRTA_MULTIPATH),
2586 RTA_PROTOINFO : ('RTA_PROTOINFO', AttributeGeneric),
2587 RTA_FLOW : ('RTA_FLOW', AttributeGeneric),
2588 RTA_CACHEINFO : ('RTA_CACHEINFO', AttributeGeneric),
2589 RTA_SESSION : ('RTA_SESSION', AttributeGeneric),
2590 RTA_MP_ALGO : ('RTA_MP_ALGO', AttributeGeneric),
2591 RTA_TABLE : ('RTA_TABLE', AttributeFourByteValue),
ea2bf79d
JF
2592 RTA_MARK : ('RTA_MARK', AttributeGeneric),
2593 RTA_MFC_STATS : ('RTA_MFC_STATS', AttributeGeneric),
2594 RTA_VIA : ('RTA_VIA', AttributeGeneric),
2595 RTA_NEWDST : ('RTA_NEWDST', AttributeGeneric),
2596 RTA_PREF : ('RTA_PREF', AttributeGeneric),
2597 RTA_ENCAP_TYPE: ('RTA_ENCAP_TYPE', AttributeGeneric),
2598 RTA_ENCAP : ('RTA_ENCAP', AttributeGeneric)
198ded6a
JF
2599 }
2600
2601 # Route tables
2602 # /usr/include/linux/rtnetlink.h
2603 RT_TABLE_UNSPEC = 0x00 # An unspecified routing table
2604 RT_TABLE_COMPAT = 0xFC
2605 RT_TABLE_DEFAULT = 0xFD # The default table
2606 RT_TABLE_MAIN = 0xFE # The main table
2607 RT_TABLE_LOCAL = 0xFF # The local table
2608
2609 table_to_string = {
2610 RT_TABLE_UNSPEC : 'RT_TABLE_UNSPEC',
2611 RT_TABLE_COMPAT : 'RT_TABLE_COMPAT',
2612 RT_TABLE_DEFAULT : 'RT_TABLE_DEFAULT',
2613 RT_TABLE_MAIN : 'RT_TABLE_MAIN',
2614 RT_TABLE_LOCAL : 'RT_TABLE_LOCAL'
2615 }
2616
2617 # Route scope
2618 # /usr/include/linux/rtnetlink.h
2619 RT_SCOPE_UNIVERSE = 0x00 # Global route
2620 RT_SCOPE_SITE = 0xC8 # Interior route in the local autonomous system
2621 RT_SCOPE_LINK = 0xFD # Route on this link
2622 RT_SCOPE_HOST = 0xFE # Route on the local host
2623 RT_SCOPE_NOWHERE = 0xFF # Destination does not exist
2624
2625 scope_to_string = {
2626 RT_SCOPE_UNIVERSE : 'RT_SCOPE_UNIVERSE',
2627 RT_SCOPE_SITE : 'RT_SCOPE_SITE',
2628 RT_SCOPE_LINK : 'RT_SCOPE_LINK',
2629 RT_SCOPE_HOST : 'RT_SCOPE_HOST',
2630 RT_SCOPE_NOWHERE : 'RT_SCOPE_NOWHERE'
2631 }
2632
2633 # Routing stack
2634 # /usr/include/linux/rtnetlink.h
2635 RT_PROT_UNSPEC = 0x00 # Identifies what/who added the route
2636 RT_PROT_REDIRECT = 0x01 # By an ICMP redirect
2637 RT_PROT_KERNEL = 0x02 # By the kernel
2638 RT_PROT_BOOT = 0x03 # During bootup
2639 RT_PROT_STATIC = 0x04 # By the administrator
2640 RT_PROT_GATED = 0x08 # GateD
2641 RT_PROT_RA = 0x09 # RDISC/ND router advertissements
2642 RT_PROT_MRT = 0x0A # Merit MRT
2643 RT_PROT_ZEBRA = 0x0B # ZEBRA
2644 RT_PROT_BIRD = 0x0C # BIRD
2645 RT_PROT_DNROUTED = 0x0D # DECnet routing daemon
2646 RT_PROT_XORP = 0x0E # XORP
2647 RT_PROT_NTK = 0x0F # Netsukuku
2648 RT_PROT_DHCP = 0x10 # DHCP client
2649 RT_PROT_EXABGP = 0x11 # Exa Networks ExaBGP
2650
2651 prot_to_string = {
2652 RT_PROT_UNSPEC : 'RT_PROT_UNSPEC',
2653 RT_PROT_REDIRECT : 'RT_PROT_REDIRECT',
2654 RT_PROT_KERNEL : 'RT_PROT_KERNEL',
2655 RT_PROT_BOOT : 'RT_PROT_BOOT',
2656 RT_PROT_STATIC : 'RT_PROT_STATIC',
2657 RT_PROT_GATED : 'RT_PROT_GATED',
2658 RT_PROT_RA : 'RT_PROT_RA',
2659 RT_PROT_MRT : 'RT_PROT_MRT',
2660 RT_PROT_ZEBRA : 'RT_PROT_ZEBRA',
2661 RT_PROT_BIRD : 'RT_PROT_BIRD',
2662 RT_PROT_DNROUTED : 'RT_PROT_DNROUTED',
2663 RT_PROT_XORP : 'RT_PROT_XORP',
2664 RT_PROT_NTK : 'RT_PROT_NTK',
2665 RT_PROT_DHCP : 'RT_PROT_DHCP',
2666 RT_PROT_EXABGP : 'RT_PROT_EXABGP'
2667 }
2668
2669 # Route types
2670 # /usr/include/linux/rtnetlink.h
2671 RTN_UNSPEC = 0x00 # Unknown broker.
2672 RTN_UNICAST = 0x01 # A gateway or direct broker.
2673 RTN_LOCAL = 0x02 # A local interface broker.
2674 RTN_BROADCAST = 0x03 # A local broadcast route(sent as a broadcast).
2675 RTN_ANYCAST = 0x04 # An anycast broker.
2676 RTN_MULTICAST = 0x05 # A multicast broker.
2677 RTN_BLACKHOLE = 0x06 # A silent packet dropping broker.
2678 RTN_UNREACHABLE = 0x07 # An unreachable destination. Packets dropped and
2679 # host unreachable ICMPs are sent to the originator.
2680 RTN_PROHIBIT = 0x08 # A packet rejection broker. Packets are dropped and
2681 # communication prohibited ICMPs are sent to the originator.
2682 RTN_THROW = 0x09 # When used with policy routing, continue routing lookup
2683 # in another table. Under normal routing, packets are
2684 # dropped and net unreachable ICMPs are sent to the originator.
2685 RTN_NAT = 0x0A # A network address translation rule.
2686 RTN_XRESOLVE = 0x0B # Refer to an external resolver(not implemented).
2687
2688 rt_type_to_string = {
2689 RTN_UNSPEC : 'RTN_UNSPEC',
2690 RTN_UNICAST : 'RTN_UNICAST',
2691 RTN_LOCAL : 'RTN_LOCAL',
2692 RTN_BROADCAST : 'RTN_BROADCAST',
2693 RTN_ANYCAST : 'RTN_ANYCAST',
2694 RTN_MULTICAST : 'RTN_MULTICAST',
2695 RTN_BLACKHOLE : 'RTN_BLACKHOLE',
2696 RTN_UNREACHABLE : 'RTN_UNREACHABLE',
2697 RTN_PROHIBIT : 'RTN_PROHIBIT',
2698 RTN_THROW : 'RTN_THROW',
2699 RTN_NAT : 'RTN_NAT',
2700 RTN_XRESOLVE : 'RTN_XRESOLVE'
2701 }
2702
2703 # Route flags
2704 # /usr/include/linux/rtnetlink.h
2705 RTM_F_NOTIFY = 0x100 # If the route changes, notify the user
2706 RTM_F_CLONED = 0x200 # Route is cloned from another route
2707 RTM_F_EQUALIZE = 0x400 # Allow randomization of next hop path in multi-path routing(currently not implemented)
2708 RTM_F_PREFIX = 0x800 # Prefix Address
2709
2710 flag_to_string = {
2711 RTM_F_NOTIFY : 'RTM_F_NOTIFY',
2712 RTM_F_CLONED : 'RTM_F_CLONED',
2713 RTM_F_EQUALIZE : 'RTM_F_EQUALIZE',
2714 RTM_F_PREFIX : 'RTM_F_PREFIX'
2715 }
2716
2717 def __init__(self, msgtype, debug=False, logger=None):
2718 NetlinkPacket.__init__(self, msgtype, debug, logger)
2719 self.PACK = '=8BI' # or is it 8Bi ?
2720 self.LEN = calcsize(self.PACK)
2721 self.family = None
2722
2723 def get_prefix_string(self):
2724 dst = self.get_attribute_value(self.RTA_DST)
2725
2726 if dst:
2727 return "%s/%d" % (dst, self.src_len)
2728 else:
2729 if self.family == AF_INET:
2730 return "0.0.0.0/0"
2731 elif self.family == AF_INET6:
2732 return "::/0"
2733
2734 def get_protocol_string(self, index=None):
2735 if index is None:
2736 index = self.protocol
2737 return self.get_string(self.prot_to_string, index)
2738
2739 def get_rt_type_string(self, index=None):
2740 if index is None:
2741 index = self.route_type
2742 return self.get_string(self.rt_type_to_string, index)
2743
2744 def get_scope_string(self, index=None):
2745 if index is None:
2746 index = self.scope
2747 return self.get_string(self.scope_to_string, index)
2748
2749 def get_table_id_string(self, index=None):
2750 if index is None:
2751 index = self.table_id
2752 return self.get_string(self.table_to_string, index)
2753
2754 def _get_ifname_from_index(self, ifindex, ifname_by_index):
2755 if ifindex:
2756 ifname = ifname_by_index.get(ifindex)
2757
2758 if ifname is None:
2759 ifname = str(ifindex)
2760 else:
2761 ifname = None
2762
2763 return ifname
2764
2765 def get_nexthops(self, ifname_by_index={}):
2766 nexthop = self.get_attribute_value(self.RTA_GATEWAY)
2767 multipath = self.get_attribute_value(self.RTA_MULTIPATH)
2768 nexthops = []
2769
2770 if nexthop:
2771 rta_oif = self.get_attribute_value(self.RTA_OIF)
2772 ifname = self._get_ifname_from_index(rta_oif, ifname_by_index)
2773 nexthops.append((nexthop, ifname))
2774
2775 elif multipath:
2776 for (nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops) in multipath:
2777 ifname = self._get_ifname_from_index(rtnh_ifindex, ifname_by_index)
2778 nexthops.append((nexthop, ifname))
2779
2780 return nexthops
2781
2782 def get_nexthops_string(self, ifname_by_index={}):
2783 output = []
2784
2785 for (nexthop, ifname) in self.get_nexthops(ifname_by_index):
2786 output.append(" via %s on %s" % (nexthop, ifname))
2787
2788 return ",".join(output)
2789
2790 def decode_service_header(self):
2791
2792 # Nothing to do if the message did not contain a service header
2793 if self.length == self.header_LEN:
2794 return
2795
2796 (self.family, self.src_len, self.dst_len, self.tos,
2797 self.table_id, self.protocol, self.scope, self.route_type,
2798 self.flags) = \
2799 unpack(self.PACK, self.msg_data[:self.LEN])
2800
2801 if self.debug:
2802 color = yellow
2803 self.dump_buffer.append(" \033[%dmService Header\033[0m" % color)
2804
2805 for x in range(0, self.LEN/4):
2806 if self.line_number == 5:
2807 extra = "Family %s (%d), Source Length %s (%d), Destination Length %s (%d), TOS %s (%d)" % \
2808 (zfilled_hex(self.family, 2), self.family,
2809 zfilled_hex(self.src_len, 2), self.src_len,
2810 zfilled_hex(self.dst_len, 2), self.dst_len,
2811 zfilled_hex(self.tos, 2), self.tos)
2812 elif self.line_number == 6:
2813 extra = "Table ID %s (%d - %s), Protocol %s (%d - %s), Scope %s (%d - %s), Type %s (%d - %s)" % \
2814 (zfilled_hex(self.table_id, 2), self.table_id, self.get_table_id_string(),
2815 zfilled_hex(self.protocol, 2), self.protocol, self.get_protocol_string(),
2816 zfilled_hex(self.scope, 2), self.scope, self.get_scope_string(),
2817 zfilled_hex(self.route_type, 2), self.route_type, self.get_rt_type_string())
2818 elif self.line_number == 7:
2819 extra = "Flags %s" % zfilled_hex(self.flags, 8)
2820 else:
2821 extra = "Unexpected line number %d" % self.line_number
2822
2823 start = x * 4
2824 end = start + 4
2825 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra))
2826 self.line_number += 1