# Copyright (c) 2009-2013, Exa Networks Limited # Copyright (c) 2009-2013, Thomas Mangin # Copyright (c) 2015-2017 Cumulus Networks, Inc. # # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # The names of the Exa Networks Limited, Cumulus Networks, Inc. nor the names # of its contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import logging import struct from ipaddr import IPv4Address, IPv6Address, IPAddress from binascii import hexlify from pprint import pformat from socket import AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE, htons from string import printable from struct import pack, unpack, calcsize log = logging.getLogger(__name__) SYSLOG_EXTRA_DEBUG = 5 # Interface name buffer size #define IFNAMSIZ 16 (kernel source) IF_NAME_SIZE = 15 # 15 because python doesn't have \0 # Netlink message types NLMSG_NOOP = 0x01 NLMSG_ERROR = 0x02 NLMSG_DONE = 0x03 NLMSG_OVERRUN = 0x04 RTM_NEWLINK = 0x10 # Create a new network interface RTM_DELLINK = 0x11 # Destroy a network interface RTM_GETLINK = 0x12 # Retrieve information about a network interface(ifinfomsg) RTM_SETLINK = 0x13 # RTM_NEWADDR = 0x14 RTM_DELADDR = 0x15 RTM_GETADDR = 0x16 RTM_NEWNEIGH = 0x1C RTM_DELNEIGH = 0x1D RTM_GETNEIGH = 0x1E RTM_NEWROUTE = 0x18 RTM_DELROUTE = 0x19 RTM_GETROUTE = 0x1A RTM_NEWQDISC = 0x24 RTM_DELQDISC = 0x25 RTM_GETQDISC = 0x26 RTM_NEWNETCONF = 80 RTM_GETNETCONF = 82 # Netlink message flags NLM_F_REQUEST = 0x01 # It is query message. NLM_F_MULTI = 0x02 # Multipart message, terminated by NLMSG_DONE NLM_F_ACK = 0x04 # Reply with ack, with zero or error code NLM_F_ECHO = 0x08 # Echo this query # Modifiers to GET query NLM_F_ROOT = 0x100 # specify tree root NLM_F_MATCH = 0x200 # return all matching NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH NLM_F_ATOMIC = 0x400 # atomic GET # Modifiers to NEW query NLM_F_REPLACE = 0x100 # Override existing NLM_F_EXCL = 0x200 # Do not touch, if it exists NLM_F_CREATE = 0x400 # Create, if it does not exist NLM_F_APPEND = 0x800 # Add to end of list NLA_F_NESTED = 0x8000 NLA_F_NET_BYTEORDER = 0x4000 NLA_TYPE_MASK = ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) # Groups RTMGRP_LINK = 0x1 RTMGRP_NOTIFY = 0x2 RTMGRP_NEIGH = 0x4 RTMGRP_TC = 0x8 RTMGRP_IPV4_IFADDR = 0x10 RTMGRP_IPV4_MROUTE = 0x20 RTMGRP_IPV4_ROUTE = 0x40 RTMGRP_IPV4_RULE = 0x80 RTMGRP_IPV6_IFADDR = 0x100 RTMGRP_IPV6_MROUTE = 0x200 RTMGRP_IPV6_ROUTE = 0x400 RTMGRP_IPV6_IFINFO = 0x800 RTMGRP_DECnet_IFADDR = 0x1000 RTMGRP_DECnet_ROUTE = 0x4000 RTMGRP_IPV6_PREFIX = 0x20000 RTMGRP_ALL = (RTMGRP_LINK | RTMGRP_NOTIFY | RTMGRP_NEIGH | RTMGRP_TC | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_MROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_RULE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_MROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFINFO | RTMGRP_DECnet_IFADDR | RTMGRP_DECnet_ROUTE | RTMGRP_IPV6_PREFIX) AF_MPLS = 28 AF_FAMILY = dict() import socket for family in [attr for attr in dir(socket) if attr.startswith('AF_')]: AF_FAMILY[getattr(socket, family)] = family AF_FAMILY[AF_MPLS] = 'AF_MPLS' def get_family_str(family): return AF_FAMILY.get(family, 'UNKNOWN') # Colors for logging red = 91 green = 92 yellow = 93 blue = 94 value_to_bool_dict = { False: False, None: False, 0: False, '0': False, 'no': False, 'off': False, 'slow': False, 'None': False, True: True, 1: True, '1': True, 'on': True, 'yes': True, 'fast': True } def set_log_level(level): log.setLevel(level) def zfilled_hex(value, digits): return '0x' + hex(value)[2:].zfill(digits) def remove_trailing_null(line): """ Remove the last character if it is a NULL...having that NULL causes python to print a garbage character """ if ord(line[-1]) == 0: line = line[:-1] return line def mac_int_to_str(mac_int): """ Return an integer in MAC string format """ # [2:] to remove the leading 0x, then fill out to 12 zeroes, then uppercase all_caps = hex(int(mac_int))[2:].zfill(12).upper() if all_caps[-1] == 'L': all_caps = all_caps[:-1] all_caps = all_caps.zfill(12).upper() return "%s.%s.%s" % (all_caps[0:4], all_caps[4:8], all_caps[8:12]) def data_to_color_text(line_number, color, data, extra=''): (c1, c2, c3, c4) = unpack('BBBB', data[0:4]) in_ascii = [] for c in (c1, c2, c3, c4): char_c = chr(c) if char_c in printable[:-5]: in_ascii.append(char_c) else: in_ascii.append('.') if color: return ' %2d: \033[%dm0x%02x%02x%02x%02x\033[0m %s %s' % (line_number, color, c1, c2, c3, c4, ''.join(in_ascii), extra) return ' %2d: 0x%02x%02x%02x%02x %s %s' % (line_number, c1, c2, c3, c4, ''.join(in_ascii), extra) def padded_length(length): return int((length + 3) / 4) * 4 class Attribute(object): def __init__(self, atype, string, logger): self.atype = atype self.string = string self.HEADER_PACK = '=HH' self.HEADER_LEN = calcsize(self.HEADER_PACK) self.PACK = None self.LEN = None self.value = None self.nested = False self.net_byteorder = False self.log = logger def __str__(self): return self.string def set_value(self, value): self.value = value def set_nested(self, nested): self.nested = nested def set_net_byteorder(self, net_byteorder): self.net_byteorder = net_byteorder def pad_bytes_needed(self, length): """ Return the number of bytes that should be added to align on a 4-byte boundry """ remainder = length % 4 if remainder: return 4 - remainder return 0 def pad(self, length, raw): pad = self.pad_bytes_needed(length) if pad: raw += '\0' * pad return raw def encode(self): if not self.LEN: raise Exception('Please define an encode() method in your child attribute class, or do not use AttributeGeneric') length = self.HEADER_LEN + self.LEN attr_type_with_flags = self.atype if self.nested: attr_type_with_flags = attr_type_with_flags | NLA_F_NESTED if self.net_byteorder: attr_type_with_flags = attr_type_with_flags | NLA_F_NET_BYTEORDER raw = pack(self.HEADER_PACK, length, attr_type_with_flags) + pack(self.PACK, self.value) raw = self.pad(length, raw) return raw def decode_length_type(self, data): """ The first two bytes of an attribute are the length, the next two bytes are the type """ self.data = data prev_atype = self.atype (data1, data2) = unpack(self.HEADER_PACK, data[:self.HEADER_LEN]) self.length = int(data1) self.atype = int(data2) self.attr_end = padded_length(self.length) self.nested = True if self.atype & NLA_F_NESTED else False self.net_byteorder = True if self.atype & NLA_F_NET_BYTEORDER else False self.atype = self.atype & NLA_TYPE_MASK # Should never happen assert self.atype == prev_atype, "This object changes attribute type from %d to %d, this is bad" % (prev_atype, self.atype) def dump_first_line(self, dump_buffer, line_number, color): """ Add the "Length....Type..." line to the dump buffer """ if self.attr_end == self.length: padded_to = ', ' else: padded_to = ' padded to %d, ' % self.attr_end extra = 'Length %s (%d)%sType %s%s%s (%d) %s' % \ (zfilled_hex(self.length, 4), self.length, padded_to, zfilled_hex(self.atype, 4), " (NLA_F_NESTED set)" if self.nested else "", " (NLA_F_NET_BYTEORDER set)" if self.net_byteorder else "", self.atype, self) dump_buffer.append(data_to_color_text(line_number, color, self.data[0:4], extra)) return line_number + 1 def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) for x in xrange(1, self.attr_end/4): start = x * 4 end = start + 4 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], '')) line_number += 1 return line_number def get_pretty_value(self, obj=None): if obj and callable(obj): return obj(self.value) return self.value class AttributeFourByteList(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) def decode(self, parent_msg, data): self.decode_length_type(data) wordcount = (self.attr_end - 4)/4 self.PACK = '=%dL' % wordcount self.LEN = calcsize(self.PACK) try: self.value = unpack(self.PACK, self.data[4:]) except struct.error: self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:]))) raise def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) idx = 1 for val in self.value: dump_buffer.append(data_to_color_text(line_number, color, self.data[4*idx:4*(idx+1)], val)) line_number += 1 idx += 1 return line_number class AttributeFourByteValue(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.PACK = '=L' self.LEN = calcsize(self.PACK) def decode(self, parent_msg, data): self.decode_length_type(data) assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end) try: self.value = int(unpack(self.PACK, self.data[4:])[0]) except struct.error: self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:]))) raise def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value)) return line_number + 1 class AttributeTwoByteValue(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.PACK = '=Hxx' self.LEN = calcsize(self.PACK) def decode(self, parent_msg, data): self.decode_length_type(data) assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end) try: self.value = int(unpack(self.PACK, self.data[4:8])[0]) except struct.error: self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:6]))) raise def encode(self): length = self.HEADER_LEN + self.LEN raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, self.value) raw = self.pad(length, raw) return raw def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value)) return line_number + 1 class AttributeString(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.PACK = None self.LEN = None def encode(self): # some interface names come from JSON as unicode strings # and cannot be packed as is so we must convert them to strings if isinstance(self.value, unicode): self.value = str(self.value) self.PACK = '%ds' % len(self.value) self.LEN = calcsize(self.PACK) length = self.HEADER_LEN + self.LEN raw = pack(self.HEADER_PACK, length, self.atype) + pack(self.PACK, self.value) raw = self.pad(length, raw) return raw def decode(self, parent_msg, data): self.decode_length_type(data) self.PACK = '%ds' % (self.length - 4) self.LEN = calcsize(self.PACK) try: self.value = remove_trailing_null(unpack(self.PACK, self.data[4:self.length])[0]) except struct.error: self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:self.length]))) raise class AttributeStringInterfaceName(AttributeString): def __init__(self, atype, string, family, logger): AttributeString.__init__(self, atype, string, family, logger) def set_value(self, value): if value and len(value) > IF_NAME_SIZE: raise Exception('interface name exceeds max length of %d' % IF_NAME_SIZE) self.value = value class AttributeIPAddress(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.value_int = None self.value_int_str = None self.family = family if self.family == AF_INET: self.PACK = '>L' elif self.family == AF_INET6: self.PACK = '>QQ' elif self.family == AF_BRIDGE: self.PACK = '>L' else: raise Exception("%s is not a supported address family" % self.family) self.LEN = calcsize(self.PACK) def set_value(self, value): if value is None: self.value = None else: self.value = IPAddress(value) def decode(self, parent_msg, data): self.decode_length_type(data) try: if self.family == AF_INET: self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0]) elif self.family == AF_INET6: (data1, data2) = unpack(self.PACK, self.data[4:]) self.value = IPv6Address(data1 << 64 | data2) elif self.family == AF_BRIDGE: self.value = IPv4Address(unpack(self.PACK, self.data[4:])[0]) self.value_int = int(self.value) self.value_int_str = str(self.value_int) except struct.error: self.value = None self.value_int = None self.value_int_str = None self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:]))) raise def encode(self): length = self.HEADER_LEN + self.LEN if self.family not in [AF_INET, AF_INET6, AF_BRIDGE]: raise Exception("%s is not a supported address family" % self.family) raw = pack(self.HEADER_PACK, length, self.atype) + self.value.packed raw = self.pad(length, raw) return raw def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) if self.family == AF_INET: dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value)) line_number += 1 elif self.family == AF_INET6: for x in xrange(1, self.attr_end/4): start = x * 4 end = start + 4 dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], self.value)) line_number += 1 elif self.family == AF_BRIDGE: dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value)) line_number += 1 return line_number class AttributeMACAddress(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.PACK = '>LHxx' self.LEN = calcsize(self.PACK) def decode(self, parent_msg, data): self.decode_length_type(data) # IFLA_ADDRESS and IFLA_BROADCAST attributes for all interfaces has been a # 6-byte MAC address. But the GRE interface uses a 4-byte IP address and # GREv6 uses a 16-byte IPv6 address for this attribute. try: # GRE interface uses a 4-byte IP address for this attribute if self.length == 8: self.value = IPv4Address(unpack('>L', self.data[4:])[0]) self.value_int = int(self.value) self.value_int_str = str(self.value_int) # MAC Address elif self.length == 10: (data1, data2) = unpack(self.PACK, self.data[4:]) self.value = mac_int_to_str(data1 << 16 | data2) # GREv6 interface uses a 16-byte IP address for this attribute elif self.length == 20: self.value = IPv6Address(unpack('>L', self.data[16:])[0]) self.value_int = int(self.value) self.value_int_str = str(self.value_int) else: raise Exception("Length of MACAddress attribute not supported: %d" % self.length) except struct.error: self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:]))) raise def encode(self): length = self.HEADER_LEN + self.LEN mac_raw = int(self.value.replace('.', '').replace(':', ''), 16) raw = pack(self.HEADER_PACK, length-2, self.atype) + pack(self.PACK, mac_raw >> 16, mac_raw & 0x0000FFFF) raw = self.pad(length, raw) return raw def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value)) line_number += 1 if len(self.data) >= 12: dump_buffer.append(data_to_color_text(line_number, color, self.data[8:12])) line_number += 1 return line_number class AttributeMplsLabel(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.value_int = None self.value_int_str = None self.family = family self.PACK = '>HBB' def decode(self, parent_msg, data): self.decode_length_type(data) try: (label_high, label_low_tc_s, self.ttl) = unpack(self.PACK, self.data[4:]) self.s_bit = label_low_tc_s & 0x1 self.traffic_class = ((label_low_tc_s & 0xf) >> 1) self.label = (label_high << 4) | (label_low_tc_s >> 4) self.value = self.label self.value_int = self.value self.value_int_str = str(self.value_int) except struct.error: self.value = None self.value_int = None self.value_int_str = None self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:]))) raise def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], 'label %s, TC %s, bottom-of-stack %s, TTL %d' % (self.label, self.traffic_class, self.s_bit, self.ttl))) line_number += 1 return line_number class AttributeGeneric(Attribute): def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.PACK = None self.LEN = None def decode(self, parent_msg, data): self.decode_length_type(data) wordcount = (self.attr_end - 4)/4 self.PACK = '=%dL' % wordcount self.LEN = calcsize(self.PACK) try: self.value = ''.join(map(str, unpack(self.PACK, self.data[4:]))) except struct.error: self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:]))) raise class AttributeOneByteValue(AttributeGeneric): def __init__(self, atype, string, family, logger): AttributeGeneric.__init__(self, atype, string, family, logger) self.PACK = '=Bxxx' self.LEN = calcsize(self.PACK) def decode(self, parent_msg, data): self.decode_length_type(data) assert self.attr_end == 8, "Attribute length for %s must be 8, it is %d" % (self, self.attr_end) try: self.value = int(unpack(self.PACK, self.data[4:8])[0]) except struct.error: self.log.error("%s unpack of %s failed, data 0x%s" % (self, self.PACK, hexlify(self.data[4:5]))) raise def encode(self): length = self.HEADER_LEN + self.LEN raw = pack(self.HEADER_PACK, length-3, self.atype) + pack(self.PACK, self.value) raw = self.pad(length, raw) return raw def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) dump_buffer.append(data_to_color_text(line_number, color, self.data[4:8], self.value)) return line_number + 1 class AttributeIFLA_AF_SPEC(Attribute): """ value will be a dictionary such as: { Link.IFLA_BRIDGE_FLAGS: flags, Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid) } """ def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.family = family def encode(self): pack_layout = [self.HEADER_PACK] payload = [0, self.atype | NLA_F_NESTED] attr_length_index = 0 # For now this assumes that all data will be packed in the native endian # order (=). If a field is added that needs to be packed via network # order (>) then some smarts will need to be added to split the pack_layout # string at the >, split the payload and make the needed pack() calls. # # Until we cross that bridge though we will keep things nice and simple and # pack everything via a single pack() call. sub_attr_to_add = [] for (sub_attr_type, sub_attr_value) in self.value.iteritems(): if sub_attr_type == Link.IFLA_BRIDGE_FLAGS: sub_attr_to_add.append((sub_attr_type, sub_attr_value)) elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO: for (vlan_flag, vlan_id) in sub_attr_value: sub_attr_to_add.append((sub_attr_type, (vlan_flag, vlan_id))) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_AF_SPEC sub-attribute type %d' % sub_attr_type) continue for (sub_attr_type, sub_attr_value) in sub_attr_to_add: sub_attr_pack_layout = ['=', 'HH'] sub_attr_payload = [0, sub_attr_type] sub_attr_length_index = 0 if sub_attr_type == Link.IFLA_BRIDGE_FLAGS: sub_attr_pack_layout.append('H') sub_attr_payload.append(sub_attr_value) elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO: sub_attr_pack_layout.append('HH') sub_attr_payload.append(sub_attr_value[0]) sub_attr_payload.append(sub_attr_value[1]) sub_attr_length = calcsize(''.join(sub_attr_pack_layout)) sub_attr_payload[sub_attr_length_index] = sub_attr_length # add padding for x in xrange(self.pad_bytes_needed(sub_attr_length)): sub_attr_pack_layout.append('x') # The [1:] is to remove the leading = so that when we do the ''.join() later # we do not end up with an = in the middle of the pack layout string. There # will be an = at the beginning via self.HEADER_PACK sub_attr_pack_layout = sub_attr_pack_layout[1:] # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute pack_layout.extend(sub_attr_pack_layout) payload.extend(sub_attr_payload) pack_layout = ''.join(pack_layout) # Fill in the length field length = calcsize(pack_layout) payload[attr_length_index] = length raw = pack(pack_layout, *payload) raw = self.pad(length, raw) return raw def decode(self, parent_msg, data): """ value is a dictionary such as: { Link.IFLA_BRIDGE_FLAGS: flags, Link.IFLA_BRIDGE_VLAN_INFO: (vflags, vlanid) } FROM: David Ahern The encoding of the IFLA_AF_SPEC attribute varies depending on the family used for the request (RTM_GETLINK) message. For AF_UNSPEC the encoding has another level of nesting for each address family with the type encoded first. i.e., af_spec = nla_nest_start(skb, IFLA_AF_SPEC) for each family: af = nla_nest_start(skb, af_ops->family) af_ops->fill_link_af(skb, dev, ext_filter_mask) nest_end nest_end This allows the parser to find the address family by looking at the first type. Whereas AF_BRIDGE encoding is just: af_spec = nla_nest_start(skb, IFLA_AF_SPEC) br_fill_ifvlaninfo{_compressed}(skb, vg) nest_end which means the parser can not use the attribute itself to know the family to which the attribute belongs. /include/uapi/linux/if_link.h /* * IFLA_AF_SPEC * Contains nested attributes for address family specific attributes. * Each address family may create a attribute with the address family * number as type and create its own attribute structure in it. * * Example: * [IFLA_AF_SPEC] = { * [AF_INET] = { * [IFLA_INET_CONF] = ..., * }, * [AF_INET6] = { * [IFLA_INET6_FLAGS] = ..., * [IFLA_INET6_CONF] = ..., * } * } */ """ self.decode_length_type(data) self.value = {} data = self.data[4:] while data: (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4]) sub_attr_end = padded_length(sub_attr_length) if not sub_attr_length: self.log.error('parsed a zero length sub-attr') return sub_attr_data = data[4:sub_attr_end] if self.family == AF_BRIDGE: if sub_attr_type == Link.IFLA_BRIDGE_FLAGS: self.value[Link.IFLA_BRIDGE_FLAGS] = unpack("=H", sub_attr_data[0:2])[0] elif sub_attr_type == Link.IFLA_BRIDGE_VLAN_INFO: if Link.IFLA_BRIDGE_VLAN_INFO not in self.value: self.value[Link.IFLA_BRIDGE_VLAN_INFO] = [] self.value[Link.IFLA_BRIDGE_VLAN_INFO].append(tuple(unpack("=HH", sub_attr_data[0:4]))) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_AF_SPEC sub-attribute ' 'type %s (%d), length %d, padded to %d' % (parent_msg.get_ifla_bridge_af_spec_to_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end)) elif self.family == AF_UNSPEC: if sub_attr_type == AF_INET6: inet6_attr = {} while sub_attr_data: (inet6_attr_length, inet6_attr_type) = unpack('=HH', sub_attr_data[:4]) inet6_attr_end = padded_length(inet6_attr_length) # 1 byte attr if inet6_attr_type == Link.IFLA_INET6_ADDR_GEN_MODE: inet6_attr[inet6_attr_type] = unpack('=B', sub_attr_data[4])[0] # nlmanager doesn't support multiple kernel version # all the other attributes like IFLA_INET6_CONF are # based on DEVCONF_MAX from _UAPI_IPV6_H. # we can opti the code and break this loop once we # found the attribute that we are interested in. # It's not really worth going through all the other # attributes to log that we don't support them yet break else: self.log.log( SYSLOG_EXTRA_DEBUG, 'Add support for decoding AF_INET6 IFLA_AF_SPEC ' 'sub-attribute type %s (%d), length %d, padded to %d' % ( parent_msg.get_ifla_inet6_af_spec_to_string(inet6_attr_type), inet6_attr_type, inet6_attr_length, inet6_attr_end ) ) sub_attr_data = sub_attr_data[inet6_attr_end:] self.value[AF_INET6] = inet6_attr else: self.value[sub_attr_type] = {} # Uncomment the following block to implement the AF_INET attributes # see Link.get_ifla_inet_af_spec_to_string (dict) #elif sub_attr_type == AF_INET: # inet_attr = {} # # while sub_attr_data: # (inet_attr_length, inet_attr_type) = unpack('=HH', sub_attr_data[:4]) # inet_attr_end = padded_length(inet_attr_length) # # self.log.error( # # SYSLOG_EXTRA_DEBUG, # 'Add support for decoding AF_INET IFLA_AF_SPEC ' # 'sub-attribute type %s (%d), length %d, padded to %d' # % ( # parent_msg.get_ifla_inet_af_spec_to_string(inet_attr_type), # inet_attr_type, inet_attr_length, inet_attr_end # ) # ) # # sub_attr_data = sub_attr_data[inet_attr_end:] # # self.value[AF_INET] = inet_attr else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_AF_SPEC sub-attribute ' 'family %d, length %d, padded to %d' % (self.family, sub_attr_length, sub_attr_end)) data = data[sub_attr_end:] def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) extra = '' next_sub_attr_line = 0 sub_attr_line = True for x in xrange(1, self.attr_end/4): start = x * 4 end = start + 4 if line_number == next_sub_attr_line: sub_attr_line = True if sub_attr_line: sub_attr_line = False (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4]) sub_attr_end = padded_length(sub_attr_length) next_sub_attr_line = line_number + (sub_attr_end/4) if sub_attr_end == sub_attr_length: padded_to = ',' else: padded_to = ' padded to %d,' % sub_attr_end if self.family == AF_BRIDGE: extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \ (zfilled_hex(sub_attr_length, 4), sub_attr_length, padded_to, zfilled_hex(sub_attr_type, 4), sub_attr_type, Link.ifla_bridge_af_spec_to_string.get(sub_attr_type)) elif self.family == AF_UNSPEC: if sub_attr_type == AF_INET6: family = 'AF_INET6' elif sub_attr_type == AF_INET: family = 'AF_INET' else: family = 'Unsupported family %d' % sub_attr_type extra = 'Nested Attribute Structure for %s - Length %s (%d)%s Type %s (%d)' % ( family, zfilled_hex(sub_attr_length, 4), sub_attr_length, padded_to, zfilled_hex(sub_attr_type, 4), sub_attr_type, ) else: extra = '' dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra)) line_number += 1 return line_number def get_pretty_value(self, obj=None): if obj and callable(obj): return obj(self.value) # We do this so we can print a more human readable dictionary # with the names of the nested keys instead of their numbers value_pretty = {} if self.family == AF_BRIDGE: for (sub_key, sub_value) in self.value.iteritems(): sub_key_pretty = "(%2d) %s" % (sub_key, Link.ifla_bridge_af_spec_to_string.get(sub_key)) value_pretty[sub_key_pretty] = sub_value elif self.family == AF_UNSPEC: for (family, family_attr) in self.value.iteritems(): family_value_pretty = {} if family == AF_INET6: family_af_spec_to_string = Link.ifla_inet6_af_spec_to_string elif family == AF_INET: family_af_spec_to_string = Link.ifla_inet_af_spec_to_string else: continue # log error? for (sub_key, sub_value) in family_attr.iteritems(): sub_key_pretty = "(%2d) %s" % (sub_key, family_af_spec_to_string.get(sub_key)) family_value_pretty[sub_key_pretty] = sub_value value_pretty = family_value_pretty return value_pretty class AttributeRTA_MULTIPATH(Attribute): """ /* RTA_MULTIPATH --- array of struct rtnexthop. * * "struct rtnexthop" describes all necessary nexthop information, * i.e. parameters of path to a destination via this nexthop. * * At the moment it is impossible to set different prefsrc, mtu, window * and rtt for different paths from multipath. */ struct rtnexthop { unsigned short rtnh_len; unsigned char rtnh_flags; unsigned char rtnh_hops; int rtnh_ifindex; }; """ def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.family = family self.PACK = None self.LEN = None self.RTNH_PACK = '=HBBL' # rtnh_len, flags, hops, ifindex self.RTNH_LEN = calcsize(self.RTNH_PACK) self.IPV4_LEN = 4 self.IPV6_LEN = 16 def encode(self): # Calculate the length if self.family == AF_INET: ip_len = self.IPV4_LEN elif self.family == AF_INET6: ip_len = self.IPV6_LEN # Attribute header length = self.HEADER_LEN + ((self.RTNH_LEN + self.HEADER_LEN + ip_len) * len(self.value)) raw = pack(self.HEADER_PACK, length, self.atype) rtnh_flags = 0 rtnh_hops = 0 rtnh_len = self.RTNH_LEN + self.HEADER_LEN + ip_len for (nexthop, rtnh_ifindex) in self.value: # rtnh structure raw += pack(self.RTNH_PACK, rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex) # Gateway raw += pack(self.HEADER_PACK, self.HEADER_LEN + ip_len, Route.RTA_GATEWAY) if self.family == AF_INET: raw += pack('>L', nexthop) elif self.family == AF_INET6: raw += pack('>QQ', nexthop >> 64, nexthop & 0x0000000000000000FFFFFFFFFFFFFFFF) raw = self.pad(length, raw) return raw def decode(self, parent_msg, data): self.decode_length_type(data) self.value = [] data = self.data[4:] while data: (rtnh_len, rtnh_flags, rtnh_hops, rtnh_ifindex) = unpack(self.RTNH_PACK, data[:self.RTNH_LEN]) data = data[self.RTNH_LEN:] (attr_type, attr_length) = unpack(self.HEADER_PACK, self.data[:self.HEADER_LEN]) data = data[self.HEADER_LEN:] if self.family == AF_INET: if len(data) < self.IPV4_LEN: break nexthop = IPv4Address(unpack('>L', data[:self.IPV4_LEN])[0]) self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops)) elif self.family == AF_INET6: if len(data) < self.IPV6_LEN: break (data1, data2) = unpack('>QQ', data[:self.IPV6_LEN]) nexthop = IPv6Address(data1 << 64 | data2) self.value.append((nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops)) data = data[(rtnh_len-self.RTNH_LEN-self.HEADER_LEN):] self.value = tuple(self.value) class AttributeIFLA_LINKINFO(Attribute): """ value is a dictionary such as: { Link.IFLA_INFO_KIND : 'vlan', Link.IFLA_INFO_DATA : { Link.IFLA_VLAN_ID : vlanid, } } """ def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) def encode(self): pack_layout = [self.HEADER_PACK] payload = [0, self.atype | NLA_F_NESTED] attr_length_index = 0 kind = self.value.get(Link.IFLA_INFO_KIND) slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND) if not slave_kind and kind not in ('vlan', 'macvlan', 'vxlan', 'bond', 'bridge'): raise Exception('Unsupported IFLA_INFO_KIND %s' % kind) elif not kind and slave_kind != 'bridge': # only support brport for now. raise Exception('Unsupported IFLA_INFO_SLAVE_KIND %s' % slave_kind) # For now this assumes that all data will be packed in the native endian # order (=). If a field is added that needs to be packed via network # order (>) then some smarts will need to be added to split the pack_layout # string at the >, split the payload and make the needed pack() calls. # # Until we cross that bridge though we will keep things nice and simple and # pack everything via a single pack() call. for (sub_attr_type, sub_attr_value) in self.value.iteritems(): sub_attr_pack_layout = ['=', 'HH'] sub_attr_payload = [0, sub_attr_type] sub_attr_length_index = 0 if sub_attr_type == Link.IFLA_INFO_KIND: sub_attr_pack_layout.append('%ds' % len(sub_attr_value)) sub_attr_payload.append(sub_attr_value) elif sub_attr_type == Link.IFLA_INFO_DATA: sub_attr_payload = [0, sub_attr_type | NLA_F_NESTED] for (info_data_type, info_data_value) in sub_attr_value.iteritems(): if kind == 'vlan': if info_data_type == Link.IFLA_VLAN_ID: sub_attr_pack_layout.append('HH') sub_attr_payload.append(6) # length sub_attr_payload.append(info_data_type) # The vlan-id sub_attr_pack_layout.append('H') sub_attr_payload.append(info_data_value) # pad 2 bytes sub_attr_pack_layout.extend('xx') elif info_data_type == Link.IFLA_VLAN_PROTOCOL: sub_attr_pack_layout.append('HH') sub_attr_payload.append(6) # length sub_attr_payload.append(info_data_type) # vlan protocol vlan_protocol = Link.ifla_vlan_protocol_dict.get(info_data_value) if not vlan_protocol: raise NotImplementedError('vlan protocol %s not implemented' % info_data_value) sub_attr_pack_layout.append('H') sub_attr_payload.append(htons(vlan_protocol)) # pad 2 bytes sub_attr_pack_layout.extend('xx') else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA vlan sub-attribute type %d' % info_data_type) elif kind == 'macvlan': if info_data_type == Link.IFLA_MACVLAN_MODE: sub_attr_pack_layout.append('HH') sub_attr_payload.append(8) # length sub_attr_payload.append(info_data_type) # macvlan mode sub_attr_pack_layout.append('L') sub_attr_payload.append(info_data_value) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_INFO_DATA macvlan sub-attribute type %d' % info_data_type) elif kind == 'vxlan': if info_data_type in (Link.IFLA_VXLAN_ID, Link.IFLA_VXLAN_LINK, Link.IFLA_VXLAN_AGEING, Link.IFLA_VXLAN_LIMIT, Link.IFLA_VXLAN_PORT_RANGE): sub_attr_pack_layout.append('HH') sub_attr_payload.append(8) # length sub_attr_payload.append(info_data_type) sub_attr_pack_layout.append('L') sub_attr_payload.append(info_data_value) elif info_data_type in (Link.IFLA_VXLAN_GROUP, Link.IFLA_VXLAN_LOCAL): sub_attr_pack_layout.append('HH') sub_attr_payload.append(8) # length sub_attr_payload.append(info_data_type) sub_attr_pack_layout.append('L') reorder = unpack('H", info_data_value) sub_attr_payload.append(unpack("L', sub_attr_data[4:8])[0]) # 4-byte int elif info_data_type in (Link.IFLA_VXLAN_ID, Link.IFLA_VXLAN_LINK, Link.IFLA_VXLAN_AGEING, Link.IFLA_VXLAN_LIMIT, Link.IFLA_VXLAN_PORT_RANGE): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0] # 2-byte int elif info_data_type in (Link.IFLA_VXLAN_PORT, ): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('!H', sub_attr_data[4:6])[0] # The form '!' is available for those poor souls who claim they can't # remember whether network byte order is big-endian or little-endian. # 1-byte int elif info_data_type in (Link.IFLA_VXLAN_TTL, Link.IFLA_VXLAN_TOS, Link.IFLA_VXLAN_LEARNING, Link.IFLA_VXLAN_PROXY, Link.IFLA_VXLAN_RSC, Link.IFLA_VXLAN_L2MISS, Link.IFLA_VXLAN_L3MISS, Link.IFLA_VXLAN_UDP_CSUM, Link.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, Link.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, Link.IFLA_VXLAN_REMCSUM_TX, Link.IFLA_VXLAN_REMCSUM_RX, Link.IFLA_VXLAN_REPLICATION_TYPE): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0] else: # sub_attr_end = padded_length(sub_attr_length) self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND vxlan type %s (%d), length %d, padded to %d' % (parent_msg.get_ifla_vxlan_string(info_data_type), info_data_type, info_data_length, info_data_end)) elif ifla_info_kind == 'bond': if info_data_type in (Link.IFLA_BOND_AD_INFO, ): ad_attr_data = sub_attr_data[4:info_data_end] self.value[Link.IFLA_INFO_DATA][Link.IFLA_BOND_AD_INFO] = {} while ad_attr_data: (ad_data_length, ad_data_type) = unpack('=HH', ad_attr_data[:4]) ad_data_end = padded_length(ad_data_length) if ad_data_type in (Link.IFLA_BOND_AD_INFO_PARTNER_MAC,): (data1, data2) = unpack('>LHxx', ad_attr_data[4:12]) self.value[Link.IFLA_INFO_DATA][Link.IFLA_BOND_AD_INFO][ad_data_type] = mac_int_to_str(data1 << 16 | data2) ad_attr_data = ad_attr_data[ad_data_end:] # 1-byte int elif info_data_type in (Link.IFLA_BOND_MODE, Link.IFLA_BOND_USE_CARRIER, Link.IFLA_BOND_AD_LACP_RATE, Link.IFLA_BOND_AD_LACP_BYPASS, Link.IFLA_BOND_XMIT_HASH_POLICY, Link.IFLA_BOND_NUM_PEER_NOTIF): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0] # 2-bytes int elif info_data_type == Link.IFLA_BOND_AD_ACTOR_SYS_PRIO: self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0] # 4-bytes int elif info_data_type in (Link.IFLA_BOND_MIIMON, Link.IFLA_BOND_UPDELAY, Link.IFLA_BOND_DOWNDELAY, Link.IFLA_BOND_MIN_LINKS): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0] # mac address elif info_data_type in (Link.IFLA_BOND_AD_ACTOR_SYSTEM, ): (data1, data2) = unpack('>LHxx', sub_attr_data[4:12]) self.value[Link.IFLA_INFO_DATA][info_data_type] = mac_int_to_str(data1 << 16 | data2) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND bond type %s (%d), length %d, padded to %d' % (parent_msg.get_ifla_bond_string(info_data_type), info_data_type, info_data_length, info_data_end)) elif ifla_info_kind == 'bridge': # 4 bytes if info_data_type in (Link.IFLA_BR_AGEING_TIME, Link.IFLA_BR_FORWARD_DELAY, Link.IFLA_BR_HELLO_TIME, Link.IFLA_BR_MAX_AGE, Link.IFLA_BR_STP_STATE, Link.IFLA_BR_ROOT_PATH_COST, Link.IFLA_BR_MCAST_HASH_ELASTICITY, Link.IFLA_BR_MCAST_HASH_MAX, Link.IFLA_BR_MCAST_LAST_MEMBER_CNT, Link.IFLA_BR_MCAST_STARTUP_QUERY_CNT): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0] # 2 bytes elif info_data_type in (Link.IFLA_BR_PRIORITY, Link.IFLA_BR_GROUP_FWD_MASK, Link.IFLA_BR_ROOT_PORT, Link.IFLA_BR_VLAN_DEFAULT_PVID): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0] elif info_data_type == Link.IFLA_BR_VLAN_PROTOCOL: hex_value = '0x%s' % sub_attr_data[4:6].encode('hex') vlan_protocol = Link.ifla_vlan_protocol_dict.get(int(hex_value, base=16)) if vlan_protocol: self.value[Link.IFLA_INFO_DATA][info_data_type] = vlan_protocol else: self.log.warning('IFLA_VLAN_PROTOCOL: cannot decode vlan protocol %s' % hex_value) # 8 bytes elif info_data_type in (Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, Link.IFLA_BR_MCAST_QUERIER_INTVL, Link.IFLA_BR_MCAST_LAST_MEMBER_INTVL, Link.IFLA_BR_MCAST_MEMBERSHIP_INTVL, Link.IFLA_BR_MCAST_QUERIER_INTVL, Link.IFLA_BR_MCAST_QUERY_INTVL, Link.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, Link.IFLA_BR_MCAST_STARTUP_QUERY_INTVL): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=Q', sub_attr_data[4:12])[0] # 1 bytes elif info_data_type in (Link.IFLA_BR_VLAN_FILTERING, Link.IFLA_BR_TOPOLOGY_CHANGE, Link.IFLA_BR_TOPOLOGY_CHANGE_DETECTED, Link.IFLA_BR_MCAST_ROUTER, Link.IFLA_BR_MCAST_SNOOPING, Link.IFLA_BR_MCAST_QUERY_USE_IFADDR, Link.IFLA_BR_MCAST_QUERIER, Link.IFLA_BR_NF_CALL_IPTABLES, Link.IFLA_BR_NF_CALL_IP6TABLES, Link.IFLA_BR_NF_CALL_ARPTABLES, Link.IFLA_BR_VLAN_STATS_ENABLED, Link.IFLA_BR_MCAST_STATS_ENABLED, Link.IFLA_BR_MCAST_IGMP_VERSION, Link.IFLA_BR_MCAST_MLD_VERSION): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0] else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND bridge type %s (%d), length %d, padded to %d' % (parent_msg.get_ifla_br_string(info_data_type), info_data_type, info_data_length, info_data_end)) elif ifla_info_kind == 'vrf': if info_data_type in (Link.IFLA_VRF_TABLE,): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0] elif ifla_info_kind in ("gre", "gretap", "erspan", "ip6gre", "ip6gretap", "ip6erspan"): # 1-byte if info_data_type in (Link.IFLA_GRE_TTL, Link.IFLA_GRE_TOS, Link.IFLA_GRE_PMTUDISC): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0] # 2-bytes elif info_data_type in ( Link.IFLA_GRE_IFLAGS, Link.IFLA_GRE_OFLAGS, Link.IFLA_GRE_ENCAP_TYPE, Link.IFLA_GRE_ENCAP_SPORT, Link.IFLA_GRE_ENCAP_DPORT, Link.IFLA_GRE_ENCAP_FLAGS ): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[0] # 4 bytes elif info_data_type in (Link.IFLA_GRE_LINK, Link.IFLA_GRE_IKEY, Link.IFLA_GRE_OKEY): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0] # ip addr elif info_data_type in (Link.IFLA_GRE_LOCAL, Link.IFLA_GRE_REMOTE): if ifla_info_kind in ("ip6gre", "ip6gretap", "ip6erspan"): (data1, data2) = unpack(">QQ", sub_attr_data[4:20]) self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv6Address(data1 << 64 | data2) else: self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack(">L", sub_attr_data[4:8])[0]) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND %s type %s (%d), length %d, padded to %d' % (ifla_info_kind, parent_msg.get_ifla_gre_string(info_data_type), info_data_type, info_data_length, info_data_end)) elif ifla_info_kind in ("ipip", "sit", "ip6tnl"): # 1-byte if info_data_type in (Link.IFLA_IPTUN_TTL, Link.IFLA_IPTUN_TOS, Link.IFLA_IPTUN_PMTUDISC): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=B', sub_attr_data[4])[0] # 2-bytes elif info_data_type in (Link.IFLA_IPTUN_ENCAP_TYPE, Link.IFLA_IPTUN_ENCAP_SPORT, Link.IFLA_IPTUN_ENCAP_DPORT, Link.IFLA_IPTUN_ENCAP_FLAGS): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=H', sub_attr_data[4:6])[ 0] # 4 bytes elif info_data_type == Link.IFLA_IPTUN_LINK: self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[ 0] # ip addr elif info_data_type in (Link.IFLA_IPTUN_LOCAL, Link.IFLA_IPTUN_REMOTE): if ifla_info_kind == "ip6tnl": (data1, data2) = unpack(">QQ", sub_attr_data[4:20]) self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv6Address(data1 << 64 | data2) else: self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack(">L", sub_attr_data[4:8])[0]) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND %s type %s (%d), length %d, padded to %d' % (ifla_info_kind, parent_msg.get_ifla_iptun_string(info_data_type), info_data_type, info_data_length, info_data_end)) elif ifla_info_kind in ("vti", "vti6"): # 4 bytes if info_data_type in (Link.IFLA_VTI_LINK, Link.IFLA_VTI_IKEY, Link.IFLA_VTI_OKEY): self.value[Link.IFLA_INFO_DATA][info_data_type] = unpack('=L', sub_attr_data[4:8])[0] # ip addr elif info_data_type in (Link.IFLA_VTI_LOCAL, Link.IFLA_VTI_REMOTE): if ifla_info_kind == "vti6": (data1, data2) = unpack(">QQ", sub_attr_data[4:20]) self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv6Address(data1 << 64 | data2) else: self.value[Link.IFLA_INFO_DATA][info_data_type] = IPv4Address(unpack(">L", sub_attr_data[4:8])[0]) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_INFO_KIND %s type %s (%d), length %d, padded to %d' % (ifla_info_kind, parent_msg.get_ifla_vti_string(info_data_type), info_data_type, info_data_length, info_data_end)) else: self.log.log(SYSLOG_EXTRA_DEBUG, "Add support for decoding IFLA_INFO_KIND %s (%d), length %d, padded to %d" % (ifla_info_kind, info_data_type, info_data_length, info_data_end)) except Exception as e: self.log.debug('%s: attribute %s: %s' % (self.value[Link.IFLA_INFO_KIND], info_data_type, str(e))) sub_attr_data = sub_attr_data[info_data_end:] else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_LINKINFO sub-attribute type %s (%d), length %d, padded to %d' % (parent_msg.get_ifla_info_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end)) data = data[sub_attr_end:] # self.log.info('IFLA_LINKINFO values %s' % pformat(self.value)) def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) extra = '' next_sub_attr_line = 0 sub_attr_line = True for x in xrange(1, self.attr_end/4): start = x * 4 end = start + 4 if line_number == next_sub_attr_line: sub_attr_line = True if sub_attr_line: sub_attr_line = False (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4]) sub_attr_end = padded_length(sub_attr_length) next_sub_attr_line = line_number + (sub_attr_end/4) if sub_attr_end == sub_attr_length: padded_to = ', ' else: padded_to = ' padded to %d, ' % sub_attr_end extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \ (zfilled_hex(sub_attr_length, 4), sub_attr_length, padded_to, zfilled_hex(sub_attr_type, 4), sub_attr_type, Link.ifla_info_to_string.get(sub_attr_type)) else: extra = '' dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra)) line_number += 1 return line_number def get_pretty_value(self, obj=None): if obj and callable(obj): return obj(self.value) value_pretty = self.value ifla_info_kind = self.value.get(Link.IFLA_INFO_KIND) ifla_info_slave_kind = self.value.get(Link.IFLA_INFO_SLAVE_KIND) kind_dict = dict() # We do this so we can print a more human readable dictionary # with the names of the nested keys instead of their numbers # Most of these are placeholders...we need to add support # for more human readable dictionaries for bond, bridge, etc kind_dict[Link.IFLA_INFO_DATA] = { 'bond': Link.ifla_bond_to_string, 'vlan': Link.ifla_vlan_to_string, 'vxlan': Link.ifla_vxlan_to_string, 'bridge': Link.ifla_br_to_string, 'macvlan': Link.ifla_macvlan_to_string, 'gre': Link.ifla_gre_to_string, 'gretap': Link.ifla_gre_to_string, 'erspan': Link.ifla_gre_to_string, 'ip6gre': Link.ifla_gre_to_string, 'ip6gretap': Link.ifla_gre_to_string, 'ip6erspan': Link.ifla_gre_to_string, 'vti': Link.ifla_vti_to_string, 'vti6': Link.ifla_vti_to_string, 'ipip': Link.ifla_iptun_to_string, 'sit': Link.ifla_iptun_to_string, 'ip6tnl': Link.ifla_iptun_to_string }.get(ifla_info_kind, {}) kind_dict[Link.IFLA_INFO_SLAVE_DATA] = { 'bridge': Link.ifla_brport_to_string, 'bond': Link.ifla_bond_slave_to_string }.get(ifla_info_slave_kind, {}) if ifla_info_kind or ifla_info_slave_kind: value_pretty = {} for (sub_key, sub_value) in self.value.iteritems(): sub_key_pretty = "(%2d) %s" % (sub_key, Link.ifla_info_to_string.get(sub_key, 'UNKNOWN')) sub_value_pretty = sub_value if sub_key in (Link.IFLA_INFO_DATA, Link.IFLA_INFO_SLAVE_DATA): kind_to_string_dict = kind_dict.get(sub_key, {}) sub_value_pretty = {} for (sub_sub_key, sub_sub_value) in sub_value.iteritems(): sub_sub_key_pretty = "(%2d) %s" % (sub_sub_key, kind_to_string_dict.get(sub_sub_key, 'UNKNOWN')) sub_value_pretty[sub_sub_key_pretty] = sub_sub_value value_pretty[sub_key_pretty] = sub_value_pretty return value_pretty class AttributeIFLA_PROTINFO(Attribute): """ IFLA_PROTINFO nested attributes. """ def __init__(self, atype, string, family, logger): Attribute.__init__(self, atype, string, logger) self.family = family def encode(self): pack_layout = [self.HEADER_PACK] payload = [0, self.atype | NLA_F_NESTED] attr_length_index = 0 if self.family not in (AF_BRIDGE,): raise Exception('Unsupported IFLA_PROTINFO family %d' % self.family) # For now this assumes that all data will be packed in the native endian # order (=). If a field is added that needs to be packed via network # order (>) then some smarts will need to be added to split the pack_layout # string at the >, split the payload and make the needed pack() calls. # # Until we cross that bridge though we will keep things nice and simple and # pack everything via a single pack() call. for (sub_attr_type, sub_attr_value) in self.value.iteritems(): sub_attr_pack_layout = ['=', 'HH'] sub_attr_payload = [0, sub_attr_type] sub_attr_length_index = 0 if self.family == AF_BRIDGE: # 1 Byte attributes if sub_attr_type in (Link.IFLA_BRPORT_STATE, Link.IFLA_BRPORT_MODE, Link.IFLA_BRPORT_GUARD, Link.IFLA_BRPORT_PROTECT, Link.IFLA_BRPORT_FAST_LEAVE, Link.IFLA_BRPORT_LEARNING, Link.IFLA_BRPORT_UNICAST_FLOOD, Link.IFLA_BRPORT_PROXYARP, Link.IFLA_BRPORT_LEARNING_SYNC, Link.IFLA_BRPORT_PROXYARP_WIFI, Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, Link.IFLA_BRPORT_CONFIG_PENDING, Link.IFLA_BRPORT_FLUSH, Link.IFLA_BRPORT_MULTICAST_ROUTER, Link.IFLA_BRPORT_PEER_LINK, Link.IFLA_BRPORT_DUAL_LINK, Link.IFLA_BRPORT_ARP_SUPPRESS, Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT): sub_attr_pack_layout.append('B') sub_attr_payload.append(sub_attr_value) sub_attr_pack_layout.extend('xxx') # 2 Byte attributes elif sub_attr_type in (Link.IFLA_BRPORT_PRIORITY, Link.IFLA_BRPORT_DESIGNATED_PORT, Link.IFLA_BRPORT_DESIGNATED_COST, Link.IFLA_BRPORT_ID, Link.IFLA_BRPORT_NO): sub_attr_pack_layout.append('H') sub_attr_payload.append(sub_attr_value) sub_attr_pack_layout.extend('xx') # 4 Byte attributes elif sub_attr_type in (Link.IFLA_BRPORT_COST,): sub_attr_pack_layout.append('L') sub_attr_payload.append(sub_attr_value) # 8 Byte attributes elif sub_attr_type in (Link.IFLA_BRPORT_MESSAGE_AGE_TIMER, Link.IFLA_BRPORT_FORWARD_DELAY_TIMER, Link.IFLA_BRPORT_HOLD_TIMER): sub_attr_pack_layout.append('Q') sub_attr_payload.append(sub_attr_value) else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for encoding IFLA_PROTINFO sub-attribute type %d' % sub_attr_type) sub_attr_length = calcsize(''.join(sub_attr_pack_layout)) sub_attr_payload[sub_attr_length_index] = sub_attr_length # add padding for x in xrange(self.pad_bytes_needed(sub_attr_length)): sub_attr_pack_layout.append('x') # The [1:] is to remove the leading = so that when we do the ''.join() later # we do not end up with an = in the middle of the pack layout string. There # will be an = at the beginning via self.HEADER_PACK sub_attr_pack_layout = sub_attr_pack_layout[1:] # Now extend the ovarall attribute pack_layout/payload to include this sub-attribute pack_layout.extend(sub_attr_pack_layout) payload.extend(sub_attr_payload) pack_layout = ''.join(pack_layout) # Fill in the length field length = calcsize(pack_layout) payload[attr_length_index] = length raw = pack(pack_layout, *payload) raw = self.pad(length, raw) return raw def decode(self, parent_msg, data): """ value is a dictionary such as: { Link.IFLA_BRPORT_STATE : 3, Link.IFLA_BRPORT_PRIORITY : 8 Link.IFLA_BRPORT_COST : 2 ... } """ self.decode_length_type(data) self.value = {} data = self.data[4:] while data: (sub_attr_length, sub_attr_type) = unpack('=HH', data[:4]) sub_attr_end = padded_length(sub_attr_length) if not sub_attr_length: self.log.error('parsed a zero length sub-attr') return if self.family == AF_BRIDGE: # 1 Byte attributes if sub_attr_type in (Link.IFLA_BRPORT_STATE, Link.IFLA_BRPORT_MODE, Link.IFLA_BRPORT_GUARD, Link.IFLA_BRPORT_PROTECT, Link.IFLA_BRPORT_FAST_LEAVE, Link.IFLA_BRPORT_LEARNING, Link.IFLA_BRPORT_UNICAST_FLOOD, Link.IFLA_BRPORT_PROXYARP, Link.IFLA_BRPORT_LEARNING_SYNC, Link.IFLA_BRPORT_PROXYARP_WIFI, Link.IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, Link.IFLA_BRPORT_CONFIG_PENDING, Link.IFLA_BRPORT_FLUSH, Link.IFLA_BRPORT_MULTICAST_ROUTER, Link.IFLA_BRPORT_PEER_LINK, Link.IFLA_BRPORT_DUAL_LINK, Link.IFLA_BRPORT_ARP_SUPPRESS, Link.IFLA_BRPORT_DOWN_PEERLINK_REDIRECT): self.value[sub_attr_type] = unpack('=B', data[4])[0] # 2 Byte attributes elif sub_attr_type in (Link.IFLA_BRPORT_PRIORITY, Link.IFLA_BRPORT_DESIGNATED_PORT, Link.IFLA_BRPORT_DESIGNATED_COST, Link.IFLA_BRPORT_ID, Link.IFLA_BRPORT_NO): self.value[sub_attr_type] = unpack('=H', data[4:6])[0] # 4 Byte attributes elif sub_attr_type in (Link.IFLA_BRPORT_COST,): self.value[sub_attr_type] = unpack('=L', data[4:8])[0] # 8 Byte attributes elif sub_attr_type in (Link.IFLA_BRPORT_MESSAGE_AGE_TIMER, Link.IFLA_BRPORT_FORWARD_DELAY_TIMER, Link.IFLA_BRPORT_HOLD_TIMER): self.value[sub_attr_type] = unpack('=Q', data[4:12])[0] else: self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_PROTINFO sub-attribute type %s (%d), length %d, padded to %d' % (parent_msg.get_ifla_brport_string(sub_attr_type), sub_attr_type, sub_attr_length, sub_attr_end)) data = data[sub_attr_end:] def dump_lines(self, dump_buffer, line_number, color): line_number = self.dump_first_line(dump_buffer, line_number, color) extra = '' next_sub_attr_line = 0 sub_attr_line = True for x in xrange(1, self.attr_end/4): start = x * 4 end = start + 4 if line_number == next_sub_attr_line: sub_attr_line = True if sub_attr_line: sub_attr_line = False (sub_attr_length, sub_attr_type) = unpack('=HH', self.data[start:start+4]) sub_attr_end = padded_length(sub_attr_length) next_sub_attr_line = line_number + (sub_attr_end/4) if sub_attr_end == sub_attr_length: padded_to = ', ' else: padded_to = ' padded to %d, ' % sub_attr_end extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \ (zfilled_hex(sub_attr_length, 4), sub_attr_length, padded_to, zfilled_hex(sub_attr_type, 4), sub_attr_type, Link.ifla_brport_to_string.get(sub_attr_type)) else: extra = '' dump_buffer.append(data_to_color_text(line_number, color, self.data[start:end], extra)) line_number += 1 return line_number def get_pretty_value(self, obj=None): if obj and callable(obj): return obj(self.value) value_pretty = {} for (sub_key, sub_value) in self.value.iteritems(): sub_key_pretty = "(%2d) %s" % (sub_key, Link.ifla_brport_to_string.get(sub_key, 'UNKNOWN')) sub_value_pretty = sub_value value_pretty[sub_key_pretty] = sub_value_pretty return value_pretty class NetlinkPacket(object): """ Netlink Header 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Process ID (PID) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ header_PACK = 'IHHII' header_LEN = calcsize(header_PACK) # Netlink packet types # /usr/include/linux/rtnetlink.h type_to_string = { NLMSG_NOOP : 'NLMSG_NOOP', NLMSG_ERROR : 'NLMSG_ERROR', NLMSG_DONE : 'NLMSG_DONE', NLMSG_OVERRUN : 'NLMSG_OVERRUN', RTM_NEWLINK : 'RTM_NEWLINK', RTM_DELLINK : 'RTM_DELLINK', RTM_GETLINK : 'RTM_GETLINK', RTM_SETLINK : 'RTM_SETLINK', RTM_NEWADDR : 'RTM_NEWADDR', RTM_DELADDR : 'RTM_DELADDR', RTM_GETADDR : 'RTM_GETADDR', RTM_NEWNEIGH : 'RTM_NEWNEIGH', RTM_DELNEIGH : 'RTM_DELNEIGH', RTM_GETNEIGH : 'RTM_GETNEIGH', RTM_NEWROUTE : 'RTM_NEWROUTE', RTM_DELROUTE : 'RTM_DELROUTE', RTM_GETROUTE : 'RTM_GETROUTE', RTM_NEWQDISC : 'RTM_NEWQDISC', RTM_DELQDISC : 'RTM_DELQDISC', RTM_GETQDISC : 'RTM_GETQDISC', RTM_NEWNETCONF: 'RTM_NEWNETCONF', RTM_GETNETCONF: 'RTM_GETNETCONF' } af_family_to_string = { AF_INET : 'inet', AF_INET6 : 'inet6' } def __init__(self, msgtype, debug, owner_logger=None, use_color=True): self.msgtype = msgtype self.attributes = {} self.dump_buffer = [''] self.line_number = 1 self.debug = debug self.message = None self.use_color = use_color self.family = None if owner_logger: self.log = owner_logger else: self.log = log def __str__(self): return self.get_type_string() def get_string(self, to_string, index): """ Used to do lookups in all of the various FOO_to_string dictionaries but returns 'UNKNOWN' if the key is bogus """ if index in to_string: return to_string[index] return 'UNKNOWN' def get_type_string(self, msgtype=None): if not msgtype: msgtype = self.msgtype return self.get_string(self.type_to_string, msgtype) def get_flags_string(self): foo = [] for (flag, flag_string) in self.flag_to_string.iteritems(): if self.flags & flag: foo.append(flag_string) return ', '.join(foo) def decode_packet(self, length, flags, seq, pid, data): self.length = length self.flags = flags self.seq = seq self.pid = pid self.header_data = data[0:self.header_LEN] self.msg_data = data[self.header_LEN:length] self.decode_netlink_header() self.decode_service_header() # NLMSG_ERROR is special case, it does not have attributes to decode if self.msgtype != NLMSG_ERROR: self.decode_attributes() def get_netlink_header_flags_string(self, msg_type, flags): foo = [] if flags & NLM_F_REQUEST: foo.append('NLM_F_REQUEST') if flags & NLM_F_MULTI: foo.append('NLM_F_MULTI') if flags & NLM_F_ACK: foo.append('NLM_F_ACK') if flags & NLM_F_ECHO: foo.append('NLM_F_ECHO') # Modifiers to GET query if msg_type in (RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH, RTM_GETROUTE, RTM_GETQDISC, RTM_GETNETCONF): if flags & NLM_F_DUMP: foo.append('NLM_F_DUMP') else: if flags & NLM_F_MATCH: foo.append('NLM_F_MATCH') if flags & NLM_F_ROOT: foo.append('NLM_F_ROOT') if flags & NLM_F_ATOMIC: foo.append('NLM_F_ATOMIC') # Modifiers to NEW query elif msg_type in (RTM_NEWLINK, RTM_NEWADDR, RTM_NEWNEIGH, RTM_NEWROUTE, RTM_NEWQDISC): if flags & NLM_F_REPLACE: foo.append('NLM_F_REPLACE') if flags & NLM_F_EXCL: foo.append('NLM_F_EXCL') if flags & NLM_F_CREATE: foo.append('NLM_F_CREATE') if flags & NLM_F_APPEND: foo.append('NLM_F_APPEND') return ', '.join(foo) # When we first RXed the netlink message we had to decode the header to # determine what type of netlink message we were dealing with. So the # header has actually already been decoded...what we do here is # populate the dump_buffer lines with the header content. def decode_netlink_header(self): if not self.debug: return header_data = self.header_data # Print the netlink header in red netlink_header_length = 16 color = red if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sNetlink Header%s" % (color_start, color_end)) for x in range(0, netlink_header_length/4): start = x * 4 end = start + 4 if self.line_number == 1: data = unpack('=L', header_data[start:end])[0] extra = "Length %s (%d)" % (zfilled_hex(data, 8), data) elif self.line_number == 2: (data1, data2) = unpack('HH', header_data[start:end]) extra = "Type %s (%d - %s), Flags %s (%s)" % \ (zfilled_hex(data1, 4), data1, self.get_type_string(data1), zfilled_hex(data2, 4), self.get_netlink_header_flags_string(data1, data2)) elif self.line_number == 3: data = unpack('=L', header_data[start:end])[0] extra = "Sequence Number %s (%d)" % (zfilled_hex(data, 8), data) elif self.line_number == 4: data = unpack('=L', header_data[start:end])[0] extra = "Process ID %s (%d)" % (zfilled_hex(data, 8), data) else: extra = "Unexpected line number %d" % self.line_number self.dump_buffer.append(data_to_color_text(self.line_number, color, header_data[start:end], extra)) self.line_number += 1 def decode_attributes(self): """ Decode the attributes and populate the dump_buffer """ if self.debug: self.dump_buffer.append(" Attributes") color = green if self.use_color else None data = self.msg_data[self.LEN:] while data: (length, attr_type) = unpack('=HH', data[:4]) # If this is zero we will stay in this loop for forever if not length: self.log.error('Length is zero') return if len(data) < length: self.log.error("Buffer underrun %d < %d" % (len(data), length)) return attr = self.add_attribute(attr_type, None) # Find the end of 'data' for this attribute and decode our section # of 'data'. attributes are padded for alignment thus the attr_end. # # How the attribute is decoded/unpacked is specific per AttributeXXXX class. attr_end = padded_length(length) attr.decode(self, data[0:attr_end]) if self.debug: self.line_number = attr.dump_lines(self.dump_buffer, self.line_number, color) # Alternate back and forth between green and blue if self.use_color: if color == green: color = blue else: color = green data = data[attr_end:] def add_attribute(self, attr_type, value): nested = True if attr_type & NLA_F_NESTED else False net_byteorder = True if attr_type & NLA_F_NET_BYTEORDER else False attr_type = attr_type & NLA_TYPE_MASK # Given an attr_type (say RTA_DST) find the type of AttributeXXXX class # that we will use to store this attribute...AttributeIPAddress in the # case of RTA_DST. if attr_type in self.attribute_to_class: (attr_string, attr_class) = self.attribute_to_class[attr_type] ''' attribute_to_class is a dictionary where the key is the attr_type, it doesn't take the family into account. For now we'll handle this as a special case for MPLS but long term we may need to make key a tuple of the attr_type and family. ''' if self.msgtype not in (RTM_NEWNETCONF, RTM_GETNETCONF) and attr_type == Route.RTA_DST and self.family == AF_MPLS: attr_string = 'RTA_DST' attr_class = AttributeMplsLabel else: attr_string = "UNKNOWN_ATTRIBUTE_%d" % attr_type attr_class = AttributeGeneric self.log.debug("Attribute %d is not defined in %s.attribute_to_class, assuming AttributeGeneric" % (attr_type, self.__class__.__name__)) attr = attr_class(attr_type, attr_string, self.family, self.log) attr.set_value(value) attr.set_nested(nested) attr.set_net_byteorder(net_byteorder) # self.attributes is a dictionary keyed by the attribute type where # the value is an instance of the corresponding AttributeXXXX class. self.attributes[attr_type] = attr return attr def get_attribute_value(self, attr_type, default=None): if attr_type not in self.attributes: return default return self.attributes[attr_type].value def get_attr_string(self, attr_type): """ Example: If attr_type is Address.IFA_CACHEINFO return the string 'IFA_CACHEINFO' """ if attr_type in self.attribute_to_class: (attr_string, attr_class) = self.attribute_to_class[attr_type] return attr_string return str(attr_type) def build_message(self, seq, pid): self.seq = seq self.pid = pid attrs = '' for attr in self.attributes.itervalues(): attrs += attr.encode() self.length = self.header_LEN + len(self.body) + len(attrs) self.header_data = pack(self.header_PACK, self.length, self.msgtype, self.flags, self.seq, self.pid) self.msg_data = self.body + attrs self.message = self.header_data + self.msg_data if self.debug: self.decode_netlink_header() self.decode_service_header() self.decode_attributes() self.dump("TXed %s, length %d, seq %d, pid %d, flags 0x%x (%s)" % (self, self.length, self.seq, self.pid, self.flags, self.get_netlink_header_flags_string(self.msgtype, self.flags))) def pretty_display_dict(self, dic, level): for k,v in dic.iteritems(): if isinstance(v, dict): self.log.debug(' '*level + str(k) + ':') self.pretty_display_dict(v, level+5) else: self.log.debug(' '*level + str(k) + ': ' + str(v)) # Print the netlink message in hex. This is only used for debugging. def dump(self, desc=None): attr_string = {} if desc is None: desc = "RXed %s, length %d, seq %d, pid %d, flags 0x%x" % (self, self.length, self.seq, self.pid, self.flags) for (attr_type, attr_obj) in self.attributes.iteritems(): key_string = "(%2d) %s" % (attr_type, self.get_attr_string(attr_type)) attr_string[key_string] = attr_obj.get_pretty_value() if self.use_color: self.log.debug("%s\n%s\n\nAttributes Summary\n%s\n" % (desc, '\n'.join(self.dump_buffer), pformat(attr_string))) else: # Assume if we are not allowing color output we also don't want embedded # newline characters in the output. Output each line individually. self.log.debug(desc) for line in self.dump_buffer: self.log.debug(line) self.log.debug("") self.log.debug("Attributes Summary") self.pretty_display_dict(attr_string, 1) class Address(NetlinkPacket): """ Service Header 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Family | Length | Flags | Scope | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ # Address attributes # /usr/include/linux/if_addr.h IFA_UNSPEC = 0x00 IFA_ADDRESS = 0x01 IFA_LOCAL = 0x02 IFA_LABEL = 0x03 IFA_BROADCAST = 0x04 IFA_ANYCAST = 0x05 IFA_CACHEINFO = 0x06 IFA_MULTICAST = 0x07 IFA_FLAGS = 0x08 attribute_to_class = { IFA_UNSPEC : ('IFA_UNSPEC', AttributeGeneric), IFA_ADDRESS : ('IFA_ADDRESS', AttributeIPAddress), IFA_LOCAL : ('IFA_LOCAL', AttributeIPAddress), IFA_LABEL : ('IFA_LABEL', AttributeString), IFA_BROADCAST : ('IFA_BROADCAST', AttributeIPAddress), IFA_ANYCAST : ('IFA_ANYCAST', AttributeIPAddress), IFA_CACHEINFO : ('IFA_CACHEINFO', AttributeGeneric), IFA_MULTICAST : ('IFA_MULTICAST', AttributeIPAddress), IFA_FLAGS : ('IFA_FLAGS', AttributeGeneric) } # Address flags # /usr/include/linux/if_addr.h IFA_F_SECONDARY = 0x01 IFA_F_NODAD = 0x02 IFA_F_OPTIMISTIC = 0x04 IFA_F_DADFAILED = 0x08 IFA_F_HOMEADDRESS = 0x10 IFA_F_DEPRECATED = 0x20 IFA_F_TENTATIVE = 0x40 IFA_F_PERMANENT = 0x80 flag_to_string = { IFA_F_SECONDARY : 'IFA_F_SECONDARY', IFA_F_NODAD : 'IFA_F_NODAD', IFA_F_OPTIMISTIC : 'IFA_F_OPTIMISTIC', IFA_F_DADFAILED : 'IFA_F_DADFAILED', IFA_F_HOMEADDRESS : 'IFA_F_HOMEADDRESS', IFA_F_DEPRECATED : 'IFA_F_DEPRECATED', IFA_F_TENTATIVE : 'IFA_F_TENTATIVE', IFA_F_PERMANENT : 'IFA_F_PERMANENT' } def __init__(self, msgtype, debug=False, logger=None, use_color=True): NetlinkPacket.__init__(self, msgtype, debug, logger, use_color) self.PACK = '4Bi' self.LEN = calcsize(self.PACK) def decode_service_header(self): # Nothing to do if the message did not contain a service header if self.length == self.header_LEN: return (self.family, self.prefixlen, self.flags, self.scope, self.ifindex) = \ unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: color = yellow if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sService Header%s" % (color_start, color_end)) for x in range(0, self.LEN/4): if self.line_number == 5: extra = "Family %s (%s:%d), Length %s (%d), Flags %s, Scope %s (%d)" % \ (zfilled_hex(self.family, 2), get_family_str(self.family), self.family, zfilled_hex(self.prefixlen, 2), self.prefixlen, zfilled_hex(self.flags, 2), zfilled_hex(self.scope, 2), self.scope) elif self.line_number == 6: extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex) else: extra = "Unexpected line number %d" % self.line_number start = x * 4 end = start + 4 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra)) self.line_number += 1 class Error(NetlinkPacket): # Error codes # /include/netlink/errno.h NLE_SUCCESS = 0x00 NLE_FAILURE = 0x01 NLE_INTR = 0x02 NLE_BAD_SOCK = 0x03 NLE_AGAIN = 0x04 NLE_NOMEM = 0x05 NLE_EXIST = 0x06 NLE_INVAL = 0x07 NLE_RANGE = 0x08 NLE_MSGSIZE = 0x09 NLE_OPNOTSUPP = 0x0A NLE_AF_NOSUPPORT = 0x0B NLE_OBJ_NOTFOUND = 0x0C NLE_NOATTR = 0x0D NLE_MISSING_ATTR = 0x0E NLE_AF_MISMATCH = 0x0F NLE_SEQ_MISMATCH = 0x10 NLE_MSG_OVERFLOW = 0x11 NLE_MSG_TRUNC = 0x12 NLE_NOADDR = 0x13 NLE_SRCRT_NOSUPPORT = 0x14 NLE_MSG_TOOSHORT = 0x15 NLE_MSGTYPE_NOSUPPORT = 0x16 NLE_OBJ_MISMATCH = 0x17 NLE_NOCACHE = 0x18 NLE_BUSY = 0x19 NLE_PROTO_MISMATCH = 0x1A NLE_NOACCESS = 0x1B NLE_PERM = 0x1C NLE_PKTLOC_FILE = 0x1D NLE_PARSE_ERR = 0x1E NLE_NODEV = 0x1F NLE_IMMUTABLE = 0x20 NLE_DUMP_INTR = 0x21 error_to_string = { NLE_SUCCESS : 'NLE_SUCCESS', NLE_FAILURE : 'NLE_FAILURE', NLE_INTR : 'NLE_INTR', NLE_BAD_SOCK : 'NLE_BAD_SOCK', NLE_AGAIN : 'NLE_AGAIN', NLE_NOMEM : 'NLE_NOMEM', NLE_EXIST : 'NLE_EXIST', NLE_INVAL : 'NLE_INVAL', NLE_RANGE : 'NLE_RANGE', NLE_MSGSIZE : 'NLE_MSGSIZE', NLE_OPNOTSUPP : 'NLE_OPNOTSUPP', NLE_AF_NOSUPPORT : 'NLE_AF_NOSUPPORT', NLE_OBJ_NOTFOUND : 'NLE_OBJ_NOTFOUND', NLE_NOATTR : 'NLE_NOATTR', NLE_MISSING_ATTR : 'NLE_MISSING_ATTR', NLE_AF_MISMATCH : 'NLE_AF_MISMATCH', NLE_SEQ_MISMATCH : 'NLE_SEQ_MISMATCH', NLE_MSG_OVERFLOW : 'NLE_MSG_OVERFLOW', NLE_MSG_TRUNC : 'NLE_MSG_TRUNC', NLE_NOADDR : 'NLE_NOADDR', NLE_SRCRT_NOSUPPORT : 'NLE_SRCRT_NOSUPPORT', NLE_MSG_TOOSHORT : 'NLE_MSG_TOOSHORT', NLE_MSGTYPE_NOSUPPORT : 'NLE_MSGTYPE_NOSUPPORT', NLE_OBJ_MISMATCH : 'NLE_OBJ_MISMATCH', NLE_NOCACHE : 'NLE_NOCACHE', NLE_BUSY : 'NLE_BUSY', NLE_PROTO_MISMATCH : 'NLE_PROTO_MISMATCH', NLE_NOACCESS : 'NLE_NOACCESS', NLE_PERM : 'NLE_PERM', NLE_PKTLOC_FILE : 'NLE_PKTLOC_FILE', NLE_PARSE_ERR : 'NLE_PARSE_ERR', NLE_NODEV : 'NLE_NODEV', NLE_IMMUTABLE : 'NLE_IMMUTABLE', NLE_DUMP_INTR : 'NLE_DUMP_INTR' } def __init__(self, msgtype, debug=False, logger=None, use_color=True): NetlinkPacket.__init__(self, msgtype, debug, logger, use_color) self.PACK = '=iLHHLL' self.LEN = calcsize(self.PACK) def decode_service_header(self): # Nothing to do if the message did not contain a service header if self.length == self.header_LEN: return (self.negative_errno, self.bad_msg_len, self.bad_msg_type, self.bad_msg_flag, self.bad_msg_seq, self.bad_msg_pid) =\ unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: color = yellow if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sService Header%s" % (color_start, color_end)) for x in range(0, self.LEN/4): if self.line_number == 5: extra = "Error Number %s is %s" % (self.negative_errno, self.error_to_string.get(abs(self.negative_errno))) # zfilled_hex(self.negative_errno, 2) elif self.line_number == 6: extra = "Length %s (%d)" % (zfilled_hex(self.bad_msg_len, 8), self.bad_msg_len) elif self.line_number == 7: extra = "Type %s (%d - %s), Flags %s (%s)" % \ (zfilled_hex(self.bad_msg_type, 4), self.bad_msg_type, self.get_type_string(self.bad_msg_type), zfilled_hex(self.bad_msg_flag, 4), self.get_netlink_header_flags_string(self.bad_msg_type, self.bad_msg_flag)) elif self.line_number == 8: extra = "Sequence Number %s (%d)" % (zfilled_hex(self.bad_msg_seq, 8), self.bad_msg_seq) elif self.line_number == 9: extra = "Process ID %s (%d)" % (zfilled_hex(self.bad_msg_pid, 8), self.bad_msg_pid) else: extra = "Unexpected line number %d" % self.line_number start = x * 4 end = start + 4 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra)) self.line_number += 1 class Link(NetlinkPacket): """ Service Header 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Family | Reserved | Device Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Device Flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Change Mask | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ # Link attributes # /usr/include/linux/if_link.h IFLA_UNSPEC = 0 IFLA_ADDRESS = 1 IFLA_BROADCAST = 2 IFLA_IFNAME = 3 IFLA_MTU = 4 IFLA_LINK = 5 IFLA_QDISC = 6 IFLA_STATS = 7 IFLA_COST = 8 IFLA_PRIORITY = 9 IFLA_MASTER = 10 IFLA_WIRELESS = 11 IFLA_PROTINFO = 12 IFLA_TXQLEN = 13 IFLA_MAP = 14 IFLA_WEIGHT = 15 IFLA_OPERSTATE = 16 IFLA_LINKMODE = 17 IFLA_LINKINFO = 18 IFLA_NET_NS_PID = 19 IFLA_IFALIAS = 20 IFLA_NUM_VF = 21 IFLA_VFINFO_LIST = 22 IFLA_STATS64 = 23 IFLA_VF_PORTS = 24 IFLA_PORT_SELF = 25 IFLA_AF_SPEC = 26 IFLA_GROUP = 27 IFLA_NET_NS_FD = 28 IFLA_EXT_MASK = 29 IFLA_PROMISCUITY = 30 IFLA_NUM_TX_QUEUES = 31 IFLA_NUM_RX_QUEUES = 32 IFLA_CARRIER = 33 IFLA_PHYS_PORT_ID = 34 IFLA_CARRIER_CHANGES = 35 IFLA_PHYS_SWITCH_ID = 36 IFLA_LINK_NETNSID = 37 IFLA_PHYS_PORT_NAME = 38 IFLA_PROTO_DOWN = 39 IFLA_GSO_MAX_SEGS = 40 IFLA_GSO_MAX_SIZE = 41 attribute_to_class = { IFLA_UNSPEC : ('IFLA_UNSPEC', AttributeGeneric), IFLA_ADDRESS : ('IFLA_ADDRESS', AttributeMACAddress), IFLA_BROADCAST : ('IFLA_BROADCAST', AttributeMACAddress), IFLA_IFNAME : ('IFLA_IFNAME', AttributeStringInterfaceName), IFLA_MTU : ('IFLA_MTU', AttributeFourByteValue), IFLA_LINK : ('IFLA_LINK', AttributeFourByteValue), IFLA_QDISC : ('IFLA_QDISC', AttributeString), IFLA_STATS : ('IFLA_STATS', AttributeGeneric), IFLA_COST : ('IFLA_COST', AttributeGeneric), IFLA_PRIORITY : ('IFLA_PRIORITY', AttributeGeneric), IFLA_MASTER : ('IFLA_MASTER', AttributeFourByteValue), IFLA_WIRELESS : ('IFLA_WIRELESS', AttributeGeneric), IFLA_PROTINFO : ('IFLA_PROTINFO', AttributeIFLA_PROTINFO), IFLA_TXQLEN : ('IFLA_TXQLEN', AttributeFourByteValue), IFLA_MAP : ('IFLA_MAP', AttributeGeneric), IFLA_WEIGHT : ('IFLA_WEIGHT', AttributeGeneric), IFLA_OPERSTATE : ('IFLA_OPERSTATE', AttributeOneByteValue), IFLA_LINKMODE : ('IFLA_LINKMODE', AttributeOneByteValue), IFLA_LINKINFO : ('IFLA_LINKINFO', AttributeIFLA_LINKINFO), IFLA_NET_NS_PID : ('IFLA_NET_NS_PID', AttributeGeneric), IFLA_IFALIAS : ('IFLA_IFALIAS', AttributeGeneric), IFLA_NUM_VF : ('IFLA_NUM_VF', AttributeGeneric), IFLA_VFINFO_LIST : ('IFLA_VFINFO_LIST', AttributeGeneric), IFLA_STATS64 : ('IFLA_STATS64', AttributeGeneric), IFLA_VF_PORTS : ('IFLA_VF_PORTS', AttributeGeneric), IFLA_PORT_SELF : ('IFLA_PORT_SELF', AttributeGeneric), IFLA_AF_SPEC : ('IFLA_AF_SPEC', AttributeIFLA_AF_SPEC), IFLA_GROUP : ('IFLA_GROUP', AttributeFourByteValue), IFLA_NET_NS_FD : ('IFLA_NET_NS_FD', AttributeGeneric), IFLA_EXT_MASK : ('IFLA_EXT_MASK', AttributeFourByteValue), IFLA_PROMISCUITY : ('IFLA_PROMISCUITY', AttributeGeneric), IFLA_NUM_TX_QUEUES : ('IFLA_NUM_TX_QUEUES', AttributeGeneric), IFLA_NUM_RX_QUEUES : ('IFLA_NUM_RX_QUEUES', AttributeGeneric), IFLA_CARRIER : ('IFLA_CARRIER', AttributeGeneric), IFLA_PHYS_PORT_ID : ('IFLA_PHYS_PORT_ID', AttributeGeneric), IFLA_CARRIER_CHANGES : ('IFLA_CARRIER_CHANGES', AttributeGeneric), IFLA_PHYS_SWITCH_ID : ('IFLA_PHYS_SWITCH_ID', AttributeGeneric), IFLA_LINK_NETNSID : ('IFLA_LINK_NETNSID', AttributeGeneric), IFLA_PHYS_PORT_NAME : ('IFLA_PHYS_PORT_NAME', AttributeGeneric), IFLA_PROTO_DOWN : ('IFLA_PROTO_DOWN', AttributeOneByteValue), IFLA_GSO_MAX_SEGS : ('IFLA_GSO_MAX_SEGS', AttributeFourByteValue), IFLA_GSO_MAX_SIZE : ('IFLA_GSO_MAX_SIZE', AttributeFourByteValue) } # Link flags # /usr/include/linux/if.h IFF_UP = 0x0001 # Interface is administratively up. IFF_BROADCAST = 0x0002 # Valid broadcast address set. IFF_DEBUG = 0x0004 # Internal debugging flag. IFF_LOOPBACK = 0x0008 # Interface is a loopback interface. IFF_POINTOPOINT = 0x0010 # Interface is a point-to-point link. IFF_NOTRAILERS = 0x0020 # Avoid use of trailers. IFF_RUNNING = 0x0040 # Interface is operationally up. IFF_NOARP = 0x0080 # No ARP protocol needed for this interface. IFF_PROMISC = 0x0100 # Interface is in promiscuous mode. IFF_ALLMULTI = 0x0200 # Receive all multicast packets. IFF_MASTER = 0x0400 # Master of a load balancing bundle. IFF_SLAVE = 0x0800 # Slave of a load balancing bundle. IFF_MULTICAST = 0x1000 # Supports multicast. IFF_PORTSEL = 0x2000 # Is able to select media type via ifmap. IFF_AUTOMEDIA = 0x4000 # Auto media selection active. IFF_DYNAMIC = 0x8000 # Interface was dynamically created. IFF_LOWER_UP = 0x10000 # driver signals L1 up IFF_DORMANT = 0x20000 # driver signals dormant IFF_ECHO = 0x40000 # echo sent packet IFF_PROTO_DOWN = 0x1000000 # protocol is down on the interface flag_to_string = { IFF_UP : 'IFF_UP', IFF_BROADCAST : 'IFF_BROADCAST', IFF_DEBUG : 'IFF_DEBUG', IFF_LOOPBACK : 'IFF_LOOPBACK', IFF_POINTOPOINT : 'IFF_POINTOPOINT', IFF_NOTRAILERS : 'IFF_NOTRAILERS', IFF_RUNNING : 'IFF_RUNNING', IFF_NOARP : 'IFF_NOARP', IFF_PROMISC : 'IFF_PROMISC', IFF_ALLMULTI : 'IFF_ALLMULTI', IFF_MASTER : 'IFF_MASTER', IFF_SLAVE : 'IFF_SLAVE', IFF_MULTICAST : 'IFF_MULTICAST', IFF_PORTSEL : 'IFF_PORTSEL', IFF_AUTOMEDIA : 'IFF_AUTOMEDIA', IFF_DYNAMIC : 'IFF_DYNAMIC', IFF_LOWER_UP : 'IFF_LOWER_UP', IFF_DORMANT : 'IFF_DORMANT', IFF_ECHO : 'IFF_ECHO', IFF_PROTO_DOWN : 'IFF_PROTO_DOWN' } # RFC 2863 operational status IF_OPER_UNKNOWN = 0 IF_OPER_NOTPRESENT = 1 IF_OPER_DOWN = 2 IF_OPER_LOWERLAYERDOWN = 3 IF_OPER_TESTING = 4 IF_OPER_DORMANT = 5 IF_OPER_UP = 6 oper_to_string = { IF_OPER_UNKNOWN : 'IF_OPER_UNKNOWN', IF_OPER_NOTPRESENT : 'IF_OPER_NOTPRESENT', IF_OPER_DOWN : 'IF_OPER_DOWN', IF_OPER_LOWERLAYERDOWN : 'IF_OPER_LOWERLAYERDOWN', IF_OPER_TESTING : 'IF_OPER_TESTING', IF_OPER_DORMANT : 'IF_OPER_DORMANT', IF_OPER_UP : 'IF_OPER_UP' } # Link types # /usr/include/linux/if_arp.h # ARP protocol HARDWARE identifiers ARPHRD_NETROM = 0 # from KA9Q: NET/ROM pseudo ARPHRD_ETHER = 1 # Ethernet 10Mbps ARPHRD_EETHER = 2 # Experimental Ethernet ARPHRD_AX25 = 3 # AX.25 Level 2 ARPHRD_PRONET = 4 # PROnet token ring ARPHRD_CHAOS = 5 # Chaosnet ARPHRD_IEEE802 = 6 # IEEE 802.2 Ethernet/TR/TB ARPHRD_ARCNET = 7 # ARCnet ARPHRD_APPLETLK = 8 # APPLEtalk ARPHRD_DLCI = 15 # Frame Relay DLCI ARPHRD_ATM = 19 # ATM ARPHRD_METRICOM = 23 # Metricom STRIP (new IANA id) ARPHRD_IEEE1394 = 24 # IEEE 1394 IPv4 - RFC 2734 ARPHRD_EUI64 = 27 # EUI-64 ARPHRD_INFINIBAND = 32 # InfiniBand # Dummy types for non ARP hardware ARPHRD_SLIP = 256 ARPHRD_CSLIP = 257 ARPHRD_SLIP6 = 258 ARPHRD_CSLIP6 = 259 ARPHRD_RSRVD = 260 # Notional KISS type ARPHRD_ADAPT = 264 ARPHRD_ROSE = 270 ARPHRD_X25 = 271 # CCITT X.25 ARPHRD_HWX25 = 272 # Boards with X.25 in firmware ARPHRD_CAN = 280 # Controller Area Network ARPHRD_PPP = 512 ARPHRD_CISCO = 513 # Cisco HDLC ARPHRD_HDLC = ARPHRD_CISCO ARPHRD_LAPB = 516 # LAPB ARPHRD_DDCMP = 517 # Digital's DDCMP protocol ARPHRD_RAWHDLC = 518 # Raw HDLC ARPHRD_TUNNEL = 768 # IPIP tunnel ARPHRD_TUNNEL6 = 769 # IP6IP6 tunnel ARPHRD_FRAD = 770 # Frame Relay Access Device ARPHRD_SKIP = 771 # SKIP vif ARPHRD_LOOPBACK = 772 # Loopback device ARPHRD_LOCALTLK = 773 # Localtalk device ARPHRD_FDDI = 774 # Fiber Distributed Data Interface ARPHRD_BIF = 775 # AP1000 BIF ARPHRD_SIT = 776 # sit0 device - IPv6-in-IPv4 ARPHRD_IPDDP = 777 # IP over DDP tunneller ARPHRD_IPGRE = 778 # GRE over IP ARPHRD_PIMREG = 779 # PIMSM register interface ARPHRD_HIPPI = 780 # High Performance Parallel Interface ARPHRD_ASH = 781 # Nexus 64Mbps Ash ARPHRD_ECONET = 782 # Acorn Econet ARPHRD_IRDA = 783 # Linux-IrDA ARPHRD_FCPP = 784 # Point to point fibrechannel ARPHRD_FCAL = 785 # Fibrechannel arbitrated loop ARPHRD_FCPL = 786 # Fibrechannel public loop ARPHRD_FCFABRIC = 787 # Fibrechannel fabric # 787->799 reserved for fibrechannel media types ARPHRD_IEEE802_TR = 800 # Magic type ident for TR ARPHRD_IEEE80211 = 801 # IEEE 802.11 ARPHRD_IEEE80211_PRISM = 802 # IEEE 802.11 + Prism2 header ARPHRD_IEEE80211_RADIOTAP = 803 # IEEE 802.11 + radiotap header ARPHRD_IEEE802154 = 804 ARPHRD_PHONET = 820 # PhoNet media type ARPHRD_PHONET_PIPE = 821 # PhoNet pipe header ARPHRD_CAIF = 822 # CAIF media type ARPHRD_VOID = 0xFFFF # Void type, nothing is known ARPHRD_NONE = 0xFFFE # zero header length link_type_to_string = { ARPHRD_NETROM : 'ARPHRD_NETROM', ARPHRD_ETHER : 'ARPHRD_ETHER', ARPHRD_EETHER : 'ARPHRD_EETHER', ARPHRD_AX25 : 'ARPHRD_AX25', ARPHRD_PRONET : 'ARPHRD_PRONET', ARPHRD_CHAOS : 'ARPHRD_CHAOS', ARPHRD_IEEE802 : 'ARPHRD_IEEE802', ARPHRD_ARCNET : 'ARPHRD_ARCNET', ARPHRD_APPLETLK : 'ARPHRD_APPLETLK', ARPHRD_DLCI : 'ARPHRD_DLCI', ARPHRD_ATM : 'ARPHRD_ATM', ARPHRD_METRICOM : 'ARPHRD_METRICOM', ARPHRD_IEEE1394 : 'ARPHRD_IEEE1394', ARPHRD_EUI64 : 'ARPHRD_EUI64', ARPHRD_INFINIBAND : 'ARPHRD_INFINIBAND', ARPHRD_SLIP : 'ARPHRD_SLIP', ARPHRD_CSLIP : 'ARPHRD_CSLIP', ARPHRD_SLIP6 : 'ARPHRD_SLIP6', ARPHRD_CSLIP6 : 'ARPHRD_CSLIP6', ARPHRD_RSRVD : 'ARPHRD_RSRVD', ARPHRD_ADAPT : 'ARPHRD_ADAPT', ARPHRD_ROSE : 'ARPHRD_ROSE', ARPHRD_X25 : 'ARPHRD_X25', ARPHRD_HWX25 : 'ARPHRD_HWX25', ARPHRD_CAN : 'ARPHRD_CAN', ARPHRD_PPP : 'ARPHRD_PPP', ARPHRD_CISCO : 'ARPHRD_CISCO', ARPHRD_HDLC : 'ARPHRD_HDLC', ARPHRD_LAPB : 'ARPHRD_LAPB', ARPHRD_DDCMP : 'ARPHRD_DDCMP', ARPHRD_RAWHDLC : 'ARPHRD_RAWHDLC', ARPHRD_TUNNEL : 'ARPHRD_TUNNEL', ARPHRD_TUNNEL6 : 'ARPHRD_TUNNEL6', ARPHRD_FRAD : 'ARPHRD_FRAD', ARPHRD_SKIP : 'ARPHRD_SKIP', ARPHRD_LOOPBACK : 'ARPHRD_LOOPBACK', ARPHRD_LOCALTLK : 'ARPHRD_LOCALTLK', ARPHRD_FDDI : 'ARPHRD_FDDI', ARPHRD_BIF : 'ARPHRD_BIF', ARPHRD_SIT : 'ARPHRD_SIT', ARPHRD_IPDDP : 'ARPHRD_IPDDP', ARPHRD_IPGRE : 'ARPHRD_IPGRE', ARPHRD_PIMREG : 'ARPHRD_PIMREG', ARPHRD_HIPPI : 'ARPHRD_HIPPI', ARPHRD_ASH : 'ARPHRD_ASH', ARPHRD_ECONET : 'ARPHRD_ECONET', ARPHRD_IRDA : 'ARPHRD_IRDA', ARPHRD_FCPP : 'ARPHRD_FCPP', ARPHRD_FCAL : 'ARPHRD_FCAL', ARPHRD_FCPL : 'ARPHRD_FCPL', ARPHRD_FCFABRIC : 'ARPHRD_FCFABRIC', ARPHRD_IEEE802_TR : 'ARPHRD_IEEE802_TR', ARPHRD_IEEE80211 : 'ARPHRD_IEEE80211', ARPHRD_IEEE80211_PRISM : 'ARPHRD_IEEE80211_PRISM', ARPHRD_IEEE80211_RADIOTAP : 'ARPHRD_IEEE80211_RADIOTAP', ARPHRD_IEEE802154 : 'ARPHRD_IEEE802154', ARPHRD_PHONET : 'ARPHRD_PHONET', ARPHRD_PHONET_PIPE : 'ARPHRD_PHONET_PIPE', ARPHRD_CAIF : 'ARPHRD_CAIF', ARPHRD_VOID : 'ARPHRD_VOID', ARPHRD_NONE : 'ARPHRD_NONE' } # ========================================= # IFLA_LINKINFO attributes # ========================================= IFLA_INFO_UNSPEC = 0 IFLA_INFO_KIND = 1 IFLA_INFO_DATA = 2 IFLA_INFO_XSTATS = 3 IFLA_INFO_SLAVE_KIND = 4 IFLA_INFO_SLAVE_DATA = 5 IFLA_INFO_MAX = 6 ifla_info_to_string = { IFLA_INFO_UNSPEC : 'IFLA_INFO_UNSPEC', IFLA_INFO_KIND : 'IFLA_INFO_KIND', IFLA_INFO_DATA : 'IFLA_INFO_DATA', IFLA_INFO_XSTATS : 'IFLA_INFO_XSTATS', IFLA_INFO_SLAVE_KIND : 'IFLA_INFO_SLAVE_KIND', IFLA_INFO_SLAVE_DATA : 'IFLA_INFO_SLAVE_DATA', IFLA_INFO_MAX : 'IFLA_INFO_MAX' } # ========================================= # IFLA_INFO_DATA attributes for vlan # ========================================= IFLA_VLAN_UNSPEC = 0 IFLA_VLAN_ID = 1 IFLA_VLAN_FLAGS = 2 IFLA_VLAN_EGRESS_QOS = 3 IFLA_VLAN_INGRESS_QOS = 4 IFLA_VLAN_PROTOCOL = 5 ifla_vlan_to_string = { IFLA_VLAN_UNSPEC : 'IFLA_VLAN_UNSPEC', IFLA_VLAN_ID : 'IFLA_VLAN_ID', IFLA_VLAN_FLAGS : 'IFLA_VLAN_FLAGS', IFLA_VLAN_EGRESS_QOS : 'IFLA_VLAN_EGRESS_QOS', IFLA_VLAN_INGRESS_QOS : 'IFLA_VLAN_INGRESS_QOS', IFLA_VLAN_PROTOCOL : 'IFLA_VLAN_PROTOCOL' } ifla_vlan_protocol_dict = { '802.1Q': 0x8100, '802.1q': 0x8100, '802.1ad': 0x88A8, '802.1AD': 0x88A8, '802.1Ad': 0x88A8, '802.1aD': 0x88A8, 0x8100: '802.1Q', 0x88A8: '802.1ad' } # ========================================= # IFLA_INFO_DATA attributes for macvlan # ========================================= IFLA_MACVLAN_UNSPEC = 0 IFLA_MACVLAN_MODE = 1 ifla_macvlan_to_string = { IFLA_MACVLAN_UNSPEC : 'IFLA_MACVLAN_UNSPEC', IFLA_MACVLAN_MODE : 'IFLA_MACVLAN_MODE' } # macvlan modes MACVLAN_MODE_PRIVATE = 1 MACVLAN_MODE_VEPA = 2 MACVLAN_MODE_BRIDGE = 3 MACVLAN_MODE_PASSTHRU = 4 macvlan_mode_to_string = { MACVLAN_MODE_PRIVATE : 'MACVLAN_MODE_PRIVATE', MACVLAN_MODE_VEPA : 'MACVLAN_MODE_VEPA', MACVLAN_MODE_BRIDGE : 'MACVLAN_MODE_BRIDGE', MACVLAN_MODE_PASSTHRU : 'MACVLAN_MODE_PASSTHRU' } # ========================================= # IFLA_INFO_DATA attributes for vxlan # ========================================= IFLA_VXLAN_UNSPEC = 0 IFLA_VXLAN_ID = 1 IFLA_VXLAN_GROUP = 2 IFLA_VXLAN_LINK = 3 IFLA_VXLAN_LOCAL = 4 IFLA_VXLAN_TTL = 5 IFLA_VXLAN_TOS = 6 IFLA_VXLAN_LEARNING = 7 IFLA_VXLAN_AGEING = 8 IFLA_VXLAN_LIMIT = 9 IFLA_VXLAN_PORT_RANGE = 10 IFLA_VXLAN_PROXY = 11 IFLA_VXLAN_RSC = 12 IFLA_VXLAN_L2MISS = 13 IFLA_VXLAN_L3MISS = 14 IFLA_VXLAN_PORT = 15 IFLA_VXLAN_GROUP6 = 16 IFLA_VXLAN_LOCAL6 = 17 IFLA_VXLAN_UDP_CSUM = 18 IFLA_VXLAN_UDP_ZERO_CSUM6_TX = 19 IFLA_VXLAN_UDP_ZERO_CSUM6_RX = 20 IFLA_VXLAN_REMCSUM_TX = 21 IFLA_VXLAN_REMCSUM_RX = 22 IFLA_VXLAN_GBP = 23 IFLA_VXLAN_REMCSUM_NOPARTIAL = 24 IFLA_VXLAN_COLLECT_METADATA = 25 IFLA_VXLAN_REPLICATION_NODE = 253 IFLA_VXLAN_REPLICATION_TYPE = 254 ifla_vxlan_to_string = { IFLA_VXLAN_UNSPEC : 'IFLA_VXLAN_UNSPEC', IFLA_VXLAN_ID : 'IFLA_VXLAN_ID', IFLA_VXLAN_GROUP : 'IFLA_VXLAN_GROUP', IFLA_VXLAN_LINK : 'IFLA_VXLAN_LINK', IFLA_VXLAN_LOCAL : 'IFLA_VXLAN_LOCAL', IFLA_VXLAN_TTL : 'IFLA_VXLAN_TTL', IFLA_VXLAN_TOS : 'IFLA_VXLAN_TOS', IFLA_VXLAN_LEARNING : 'IFLA_VXLAN_LEARNING', IFLA_VXLAN_AGEING : 'IFLA_VXLAN_AGEING', IFLA_VXLAN_LIMIT : 'IFLA_VXLAN_LIMIT', IFLA_VXLAN_PORT_RANGE : 'IFLA_VXLAN_PORT_RANGE', IFLA_VXLAN_PROXY : 'IFLA_VXLAN_PROXY', IFLA_VXLAN_RSC : 'IFLA_VXLAN_RSC', IFLA_VXLAN_L2MISS : 'IFLA_VXLAN_L2MISS', IFLA_VXLAN_L3MISS : 'IFLA_VXLAN_L3MISS', IFLA_VXLAN_PORT : 'IFLA_VXLAN_PORT', IFLA_VXLAN_GROUP6 : 'IFLA_VXLAN_GROUP6', IFLA_VXLAN_LOCAL6 : 'IFLA_VXLAN_LOCAL6', IFLA_VXLAN_UDP_CSUM : 'IFLA_VXLAN_UDP_CSUM', IFLA_VXLAN_UDP_ZERO_CSUM6_TX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_TX', IFLA_VXLAN_UDP_ZERO_CSUM6_RX : 'IFLA_VXLAN_UDP_ZERO_CSUM6_RX', IFLA_VXLAN_REMCSUM_TX : 'IFLA_VXLAN_REMCSUM_TX', IFLA_VXLAN_REMCSUM_RX : 'IFLA_VXLAN_REMCSUM_RX', IFLA_VXLAN_GBP : 'IFLA_VXLAN_GBP', IFLA_VXLAN_REMCSUM_NOPARTIAL : 'IFLA_VXLAN_REMCSUM_NOPARTIAL', IFLA_VXLAN_COLLECT_METADATA : 'IFLA_VXLAN_COLLECT_METADATA', IFLA_VXLAN_REPLICATION_NODE : 'IFLA_VXLAN_REPLICATION_NODE', IFLA_VXLAN_REPLICATION_TYPE : 'IFLA_VXLAN_REPLICATION_TYPE' } # ========================================= # IFLA_INFO_DATA attributes for bonds # ========================================= IFLA_BOND_UNSPEC = 0 IFLA_BOND_MODE = 1 IFLA_BOND_ACTIVE_SLAVE = 2 IFLA_BOND_MIIMON = 3 IFLA_BOND_UPDELAY = 4 IFLA_BOND_DOWNDELAY = 5 IFLA_BOND_USE_CARRIER = 6 IFLA_BOND_ARP_INTERVAL = 7 IFLA_BOND_ARP_IP_TARGET = 8 IFLA_BOND_ARP_VALIDATE = 9 IFLA_BOND_ARP_ALL_TARGETS = 10 IFLA_BOND_PRIMARY = 11 IFLA_BOND_PRIMARY_RESELECT = 12 IFLA_BOND_FAIL_OVER_MAC = 13 IFLA_BOND_XMIT_HASH_POLICY = 14 IFLA_BOND_RESEND_IGMP = 15 IFLA_BOND_NUM_PEER_NOTIF = 16 IFLA_BOND_ALL_SLAVES_ACTIVE = 17 IFLA_BOND_MIN_LINKS = 18 IFLA_BOND_LP_INTERVAL = 19 IFLA_BOND_PACKETS_PER_SLAVE = 20 IFLA_BOND_AD_LACP_RATE = 21 IFLA_BOND_AD_SELECT = 22 IFLA_BOND_AD_INFO = 23 IFLA_BOND_AD_ACTOR_SYS_PRIO = 24 IFLA_BOND_AD_USER_PORT_KEY = 25 IFLA_BOND_AD_ACTOR_SYSTEM = 26 IFLA_BOND_AD_LACP_BYPASS = 100 ifla_bond_to_string = { IFLA_BOND_UNSPEC : 'IFLA_BOND_UNSPEC', IFLA_BOND_MODE : 'IFLA_BOND_MODE', IFLA_BOND_ACTIVE_SLAVE : 'IFLA_BOND_ACTIVE_SLAVE', IFLA_BOND_MIIMON : 'IFLA_BOND_MIIMON', IFLA_BOND_UPDELAY : 'IFLA_BOND_UPDELAY', IFLA_BOND_DOWNDELAY : 'IFLA_BOND_DOWNDELAY', IFLA_BOND_USE_CARRIER : 'IFLA_BOND_USE_CARRIER', IFLA_BOND_ARP_INTERVAL : 'IFLA_BOND_ARP_INTERVAL', IFLA_BOND_ARP_IP_TARGET : 'IFLA_BOND_ARP_IP_TARGET', IFLA_BOND_ARP_VALIDATE : 'IFLA_BOND_ARP_VALIDATE', IFLA_BOND_ARP_ALL_TARGETS : 'IFLA_BOND_ARP_ALL_TARGETS', IFLA_BOND_PRIMARY : 'IFLA_BOND_PRIMARY', IFLA_BOND_PRIMARY_RESELECT : 'IFLA_BOND_PRIMARY_RESELECT', IFLA_BOND_FAIL_OVER_MAC : 'IFLA_BOND_FAIL_OVER_MAC', IFLA_BOND_XMIT_HASH_POLICY : 'IFLA_BOND_XMIT_HASH_POLICY', IFLA_BOND_RESEND_IGMP : 'IFLA_BOND_RESEND_IGMP', IFLA_BOND_NUM_PEER_NOTIF : 'IFLA_BOND_NUM_PEER_NOTIF', IFLA_BOND_ALL_SLAVES_ACTIVE : 'IFLA_BOND_ALL_SLAVES_ACTIVE', IFLA_BOND_MIN_LINKS : 'IFLA_BOND_MIN_LINKS', IFLA_BOND_LP_INTERVAL : 'IFLA_BOND_LP_INTERVAL', IFLA_BOND_PACKETS_PER_SLAVE : 'IFLA_BOND_PACKETS_PER_SLAVE', IFLA_BOND_AD_LACP_RATE : 'IFLA_BOND_AD_LACP_RATE', IFLA_BOND_AD_SELECT : 'IFLA_BOND_AD_SELECT', IFLA_BOND_AD_INFO : 'IFLA_BOND_AD_INFO', IFLA_BOND_AD_ACTOR_SYS_PRIO : 'IFLA_BOND_AD_ACTOR_SYS_PRIO', IFLA_BOND_AD_USER_PORT_KEY : 'IFLA_BOND_AD_USER_PORT_KEY', IFLA_BOND_AD_ACTOR_SYSTEM : 'IFLA_BOND_AD_ACTOR_SYSTEM', IFLA_BOND_AD_LACP_BYPASS : 'IFLA_BOND_AD_LACP_BYPASS' } IFLA_BOND_AD_INFO_UNSPEC = 0 IFLA_BOND_AD_INFO_AGGREGATOR = 1 IFLA_BOND_AD_INFO_NUM_PORTS = 2 IFLA_BOND_AD_INFO_ACTOR_KEY = 3 IFLA_BOND_AD_INFO_PARTNER_KEY = 4 IFLA_BOND_AD_INFO_PARTNER_MAC = 5 ifla_bond_ad_to_string = { IFLA_BOND_AD_INFO_UNSPEC : 'IFLA_BOND_AD_INFO_UNSPEC', IFLA_BOND_AD_INFO_AGGREGATOR : 'IFLA_BOND_AD_INFO_AGGREGATOR', IFLA_BOND_AD_INFO_NUM_PORTS : 'IFLA_BOND_AD_INFO_NUM_PORTS', IFLA_BOND_AD_INFO_ACTOR_KEY : 'IFLA_BOND_AD_INFO_ACTOR_KEY', IFLA_BOND_AD_INFO_PARTNER_KEY : 'IFLA_BOND_AD_INFO_PARTNER_KEY', IFLA_BOND_AD_INFO_PARTNER_MAC : 'IFLA_BOND_AD_INFO_PARTNER_MAC' } ifla_bond_mode_tbl = { 'balance-rr': 0, 'active-backup': 1, 'balance-xor': 2, 'broadcast': 3, '802.3ad': 4, 'balance-tlb': 5, 'balance-alb': 6, '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, 0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6 } ifla_bond_mode_pretty_tbl = { 0: 'balance-rr', 1: 'active-backup', 2: 'balance-xor', 3: 'broadcast', 4: '802.3ad', 5: 'balance-tlb', 6: 'balance-alb' } ifla_bond_xmit_hash_policy_tbl = { 'layer2': 0, 'layer3+4': 1, 'layer2+3': 2, 'encap2+3': 3, 'encap3+4': 4, '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, 0: 0, 1: 1, 2: 2, 3: 3, 4: 4 } ifla_bond_xmit_hash_policy_pretty_tbl = { 0: 'layer2', 1: 'layer3+4', 2: 'layer2+3', 3: 'encap2+3', 4: 'encap3+4', } # ========================================= # IFLA_INFO_SLAVE_DATA attributes for bonds # ========================================= IFLA_BOND_SLAVE_UNSPEC = 0 IFLA_BOND_SLAVE_STATE = 1 IFLA_BOND_SLAVE_MII_STATUS = 2 IFLA_BOND_SLAVE_LINK_FAILURE_COUNT = 3 IFLA_BOND_SLAVE_PERM_HWADDR = 4 IFLA_BOND_SLAVE_QUEUE_ID = 5 IFLA_BOND_SLAVE_AD_AGGREGATOR_ID = 6 IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE = 7 IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE = 8 IFLA_BOND_SLAVE_CL_START = 50 IFLA_BOND_SLAVE_AD_RX_BYPASS = IFLA_BOND_SLAVE_CL_START ifla_bond_slave_to_string = { IFLA_BOND_SLAVE_UNSPEC : 'IFLA_BOND_SLAVE_UNSPEC', IFLA_BOND_SLAVE_STATE : 'IFLA_BOND_SLAVE_STATE', IFLA_BOND_SLAVE_MII_STATUS : 'IFLA_BOND_SLAVE_MII_STATUS', IFLA_BOND_SLAVE_LINK_FAILURE_COUNT : 'IFLA_BOND_SLAVE_LINK_FAILURE_COUNT', IFLA_BOND_SLAVE_PERM_HWADDR : 'IFLA_BOND_SLAVE_PERM_HWADDR', IFLA_BOND_SLAVE_QUEUE_ID : 'IFLA_BOND_SLAVE_QUEUE_ID', IFLA_BOND_SLAVE_AD_AGGREGATOR_ID : 'IFLA_BOND_SLAVE_AD_AGGREGATOR_ID', IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE', IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE : 'IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE', IFLA_BOND_SLAVE_CL_START : 'IFLA_BOND_SLAVE_CL_START', IFLA_BOND_SLAVE_AD_RX_BYPASS : 'IFLA_BOND_SLAVE_AD_RX_BYPASS' } # ========================================= # IFLA_PROTINFO attributes for bridge ports # ========================================= IFLA_BRPORT_UNSPEC = 0 IFLA_BRPORT_STATE = 1 IFLA_BRPORT_PRIORITY = 2 IFLA_BRPORT_COST = 3 IFLA_BRPORT_MODE = 4 IFLA_BRPORT_GUARD = 5 IFLA_BRPORT_PROTECT = 6 IFLA_BRPORT_FAST_LEAVE = 7 IFLA_BRPORT_LEARNING = 8 IFLA_BRPORT_UNICAST_FLOOD = 9 IFLA_BRPORT_PROXYARP = 10 IFLA_BRPORT_LEARNING_SYNC = 11 IFLA_BRPORT_PROXYARP_WIFI = 12 IFLA_BRPORT_ROOT_ID = 13 IFLA_BRPORT_BRIDGE_ID = 14 IFLA_BRPORT_DESIGNATED_PORT = 15 IFLA_BRPORT_DESIGNATED_COST = 16 IFLA_BRPORT_ID = 17 IFLA_BRPORT_NO = 18 IFLA_BRPORT_TOPOLOGY_CHANGE_ACK = 19 IFLA_BRPORT_CONFIG_PENDING = 20 IFLA_BRPORT_MESSAGE_AGE_TIMER = 21 IFLA_BRPORT_FORWARD_DELAY_TIMER = 22 IFLA_BRPORT_HOLD_TIMER = 23 IFLA_BRPORT_FLUSH = 24 IFLA_BRPORT_MULTICAST_ROUTER = 25 IFLA_BRPORT_PAD = 26 IFLA_BRPORT_MCAST_FLOOD = 27 IFLA_BRPORT_MCAST_TO_UCAST = 28 IFLA_BRPORT_VLAN_TUNNEL = 29 IFLA_BRPORT_BCAST_FLOOD = 30 IFLA_BRPORT_GROUP_FWD_MASK = 31 IFLA_BRPORT_ARP_SUPPRESS = 32 IFLA_BRPORT_PEER_LINK = 150 IFLA_BRPORT_DUAL_LINK = 151 IFLA_BRPORT_GROUP_FWD_MASKHI = 153 IFLA_BRPORT_DOWN_PEERLINK_REDIRECT = 154 ifla_brport_to_string = { IFLA_BRPORT_UNSPEC : 'IFLA_BRPORT_UNSPEC', IFLA_BRPORT_STATE : 'IFLA_BRPORT_STATE', IFLA_BRPORT_PRIORITY : 'IFLA_BRPORT_PRIORITY', IFLA_BRPORT_COST : 'IFLA_BRPORT_COST', IFLA_BRPORT_MODE : 'IFLA_BRPORT_MODE', IFLA_BRPORT_GUARD : 'IFLA_BRPORT_GUARD', IFLA_BRPORT_PROTECT : 'IFLA_BRPORT_PROTECT', IFLA_BRPORT_FAST_LEAVE : 'IFLA_BRPORT_FAST_LEAVE', IFLA_BRPORT_LEARNING : 'IFLA_BRPORT_LEARNING', IFLA_BRPORT_UNICAST_FLOOD : 'IFLA_BRPORT_UNICAST_FLOOD', IFLA_BRPORT_PROXYARP : 'IFLA_BRPORT_PROXYARP', IFLA_BRPORT_LEARNING_SYNC : 'IFLA_BRPORT_LEARNING_SYNC', IFLA_BRPORT_PROXYARP_WIFI : 'IFLA_BRPORT_PROXYARP_WIFI', IFLA_BRPORT_ROOT_ID : 'IFLA_BRPORT_ROOT_ID', IFLA_BRPORT_BRIDGE_ID : 'IFLA_BRPORT_BRIDGE_ID', IFLA_BRPORT_DESIGNATED_PORT : 'IFLA_BRPORT_DESIGNATED_PORT', IFLA_BRPORT_DESIGNATED_COST : 'IFLA_BRPORT_DESIGNATED_COST', IFLA_BRPORT_ID : 'IFLA_BRPORT_ID', IFLA_BRPORT_NO : 'IFLA_BRPORT_NO', IFLA_BRPORT_TOPOLOGY_CHANGE_ACK : 'IFLA_BRPORT_TOPOLOGY_CHANGE_ACK', IFLA_BRPORT_CONFIG_PENDING : 'IFLA_BRPORT_CONFIG_PENDING', IFLA_BRPORT_MESSAGE_AGE_TIMER : 'IFLA_BRPORT_MESSAGE_AGE_TIMER', IFLA_BRPORT_FORWARD_DELAY_TIMER : 'IFLA_BRPORT_FORWARD_DELAY_TIMER', IFLA_BRPORT_HOLD_TIMER : 'IFLA_BRPORT_HOLD_TIMER', IFLA_BRPORT_FLUSH : 'IFLA_BRPORT_FLUSH', IFLA_BRPORT_MULTICAST_ROUTER : 'IFLA_BRPORT_MULTICAST_ROUTER', IFLA_BRPORT_PAD : 'IFLA_BRPORT_PAD', IFLA_BRPORT_MCAST_FLOOD : 'IFLA_BRPORT_MCAST_FLOOD', IFLA_BRPORT_MCAST_TO_UCAST : 'IFLA_BRPORT_MCAST_TO_UCAST', IFLA_BRPORT_VLAN_TUNNEL : 'IFLA_BRPORT_VLAN_TUNNEL', IFLA_BRPORT_BCAST_FLOOD : 'IFLA_BRPORT_BCAST_FLOOD', IFLA_BRPORT_GROUP_FWD_MASK : 'IFLA_BRPORT_GROUP_FWD_MASK', IFLA_BRPORT_PEER_LINK : 'IFLA_BRPORT_PEER_LINK', IFLA_BRPORT_DUAL_LINK : 'IFLA_BRPORT_DUAL_LINK', IFLA_BRPORT_ARP_SUPPRESS : 'IFLA_BRPORT_ARP_SUPPRESS', IFLA_BRPORT_GROUP_FWD_MASKHI : 'IFLA_BRPORT_GROUP_FWD_MASKHI', IFLA_BRPORT_DOWN_PEERLINK_REDIRECT : 'IFLA_BRPORT_DOWN_PEERLINK_REDIRECT' } # Subtype attributes for IFLA_AF_SPEC IFLA_INET6_UNSPEC = 0 IFLA_INET6_FLAGS = 1 # link flags IFLA_INET6_CONF = 2 # sysctl parameters IFLA_INET6_STATS = 3 # statistics IFLA_INET6_MCAST = 4 # MC things. What of them? IFLA_INET6_CACHEINFO = 5 # time values and max reasm size IFLA_INET6_ICMP6STATS = 6 # statistics (icmpv6) IFLA_INET6_TOKEN = 7 # device token IFLA_INET6_ADDR_GEN_MODE = 8 # implicit address generator mode __IFLA_INET6_MAX = 9 ifla_inet6_af_spec_to_string = { IFLA_INET6_UNSPEC : 'IFLA_INET6_UNSPEC', IFLA_INET6_FLAGS : 'IFLA_INET6_FLAGS', IFLA_INET6_CONF : 'IFLA_INET6_CONF', IFLA_INET6_STATS : 'IFLA_INET6_STATS', IFLA_INET6_MCAST : 'IFLA_INET6_MCAST', IFLA_INET6_CACHEINFO : 'IFLA_INET6_CACHEINFO', IFLA_INET6_ICMP6STATS : 'IFLA_INET6_ICMP6STATS', IFLA_INET6_TOKEN : 'IFLA_INET6_TOKEN', IFLA_INET6_ADDR_GEN_MODE : 'IFLA_INET6_ADDR_GEN_MODE', } # IFLA_INET6_ADDR_GEN_MODE values IN6_ADDR_GEN_MODE_EUI64 = 0 IN6_ADDR_GEN_MODE_NONE = 1 IN6_ADDR_GEN_MODE_STABLE_PRIVACY = 2 IN6_ADDR_GEN_MODE_RANDOM = 3 ifla_inet6_addr_gen_mode_dict = { IN6_ADDR_GEN_MODE_EUI64: "eui64", IN6_ADDR_GEN_MODE_NONE: "none", IN6_ADDR_GEN_MODE_STABLE_PRIVACY: "stable_secret", IN6_ADDR_GEN_MODE_RANDOM: "random" } # Subtype attrbutes AF_INET IFLA_INET_UNSPEC = 0 IFLA_INET_CONF = 1 __IFLA_INET_MAX = 2 ifla_inet_af_spec_to_string = { IFLA_INET_UNSPEC : 'IFLA_INET_UNSPEC', IFLA_INET_CONF : 'IFLA_INET_CONF', } # BRIDGE IFLA_AF_SPEC attributes IFLA_BRIDGE_FLAGS = 0 IFLA_BRIDGE_MODE = 1 IFLA_BRIDGE_VLAN_INFO = 2 ifla_bridge_af_spec_to_string = { IFLA_BRIDGE_FLAGS : 'IFLA_BRIDGE_FLAGS', IFLA_BRIDGE_MODE : 'IFLA_BRIDGE_MODE', IFLA_BRIDGE_VLAN_INFO : 'IFLA_BRIDGE_VLAN_INFO' } # BRIDGE_VLAN_INFO flags BRIDGE_VLAN_INFO_MASTER = 1 << 0 # Operate on Bridge device as well BRIDGE_VLAN_INFO_PVID = 1 << 1 # VLAN is PVID, ingress untagged BRIDGE_VLAN_INFO_UNTAGGED = 1 << 2 # VLAN egresses untagged BRIDGE_VLAN_INFO_RANGE_BEGIN = 1 << 3 # VLAN is start of vlan range BRIDGE_VLAN_INFO_RANGE_END = 1 << 4 # VLAN is end of vlan range BRIDGE_VLAN_INFO_BRENTRY = 1 << 5 # Global bridge VLAN entry bridge_vlan_to_string = { BRIDGE_VLAN_INFO_MASTER : 'BRIDGE_VLAN_INFO_MASTER', BRIDGE_VLAN_INFO_PVID : 'BRIDGE_VLAN_INFO_PVID', BRIDGE_VLAN_INFO_UNTAGGED : 'BRIDGE_VLAN_INFO_UNTAGGED', BRIDGE_VLAN_INFO_RANGE_BEGIN : 'BRIDGE_VLAN_INFO_RANGE_BEGIN', BRIDGE_VLAN_INFO_RANGE_END : 'BRIDGE_VLAN_INFO_RANGE_END', BRIDGE_VLAN_INFO_BRENTRY : 'BRIDGE_VLAN_INFO_BRENTRY' } # Bridge flags BRIDGE_FLAGS_MASTER = 1 BRIDGE_FLAGS_SELF = 2 bridge_flags_to_string = { BRIDGE_FLAGS_MASTER : 'BRIDGE_FLAGS_MASTER', BRIDGE_FLAGS_SELF : 'BRIDGE_FLAGS_SELF' } # filters for IFLA_EXT_MASK RTEXT_FILTER_VF = 1 << 0 RTEXT_FILTER_BRVLAN = 1 << 1 RTEXT_FILTER_BRVLAN_COMPRESSED = 1 << 2 RTEXT_FILTER_SKIP_STATS = 1 << 3 rtext_to_string = { RTEXT_FILTER_VF : 'RTEXT_FILTER_VF', RTEXT_FILTER_BRVLAN : 'RTEXT_FILTER_BRVLAN', RTEXT_FILTER_BRVLAN_COMPRESSED : 'RTEXT_FILTER_BRVLAN_COMPRESSED', RTEXT_FILTER_SKIP_STATS : 'RTEXT_FILTER_SKIP_STATS' } IFLA_BR_UNSPEC = 0 IFLA_BR_FORWARD_DELAY = 1 IFLA_BR_HELLO_TIME = 2 IFLA_BR_MAX_AGE = 3 IFLA_BR_AGEING_TIME = 4 IFLA_BR_STP_STATE = 5 IFLA_BR_PRIORITY = 6 IFLA_BR_VLAN_FILTERING = 7 IFLA_BR_VLAN_PROTOCOL = 8 IFLA_BR_GROUP_FWD_MASK = 9 IFLA_BR_ROOT_ID = 10 IFLA_BR_BRIDGE_ID = 11 IFLA_BR_ROOT_PORT = 12 IFLA_BR_ROOT_PATH_COST = 13 IFLA_BR_TOPOLOGY_CHANGE = 14 IFLA_BR_TOPOLOGY_CHANGE_DETECTED = 15 IFLA_BR_HELLO_TIMER = 16 IFLA_BR_TCN_TIMER = 17 IFLA_BR_TOPOLOGY_CHANGE_TIMER = 18 IFLA_BR_GC_TIMER = 19 IFLA_BR_GROUP_ADDR = 20 IFLA_BR_FDB_FLUSH = 21 IFLA_BR_MCAST_ROUTER = 22 IFLA_BR_MCAST_SNOOPING = 23 IFLA_BR_MCAST_QUERY_USE_IFADDR = 24 IFLA_BR_MCAST_QUERIER = 25 IFLA_BR_MCAST_HASH_ELASTICITY = 26 IFLA_BR_MCAST_HASH_MAX = 27 IFLA_BR_MCAST_LAST_MEMBER_CNT = 28 IFLA_BR_MCAST_STARTUP_QUERY_CNT = 29 IFLA_BR_MCAST_LAST_MEMBER_INTVL = 30 IFLA_BR_MCAST_MEMBERSHIP_INTVL = 31 IFLA_BR_MCAST_QUERIER_INTVL = 32 IFLA_BR_MCAST_QUERY_INTVL = 33 IFLA_BR_MCAST_QUERY_RESPONSE_INTVL = 34 IFLA_BR_MCAST_STARTUP_QUERY_INTVL = 35 IFLA_BR_NF_CALL_IPTABLES = 36 IFLA_BR_NF_CALL_IP6TABLES = 37 IFLA_BR_NF_CALL_ARPTABLES = 38 IFLA_BR_VLAN_DEFAULT_PVID = 39 IFLA_BR_PAD = 40 IFLA_BR_VLAN_STATS_ENABLED = 41 IFLA_BR_MCAST_STATS_ENABLED = 42 IFLA_BR_MCAST_IGMP_VERSION = 43 IFLA_BR_MCAST_MLD_VERSION = 44 ifla_br_to_string = { IFLA_BR_UNSPEC : 'IFLA_BR_UNSPEC', IFLA_BR_FORWARD_DELAY : 'IFLA_BR_FORWARD_DELAY', IFLA_BR_HELLO_TIME : 'IFLA_BR_HELLO_TIME', IFLA_BR_MAX_AGE : 'IFLA_BR_MAX_AGE', IFLA_BR_AGEING_TIME : 'IFLA_BR_AGEING_TIME', IFLA_BR_STP_STATE : 'IFLA_BR_STP_STATE', IFLA_BR_PRIORITY : 'IFLA_BR_PRIORITY', IFLA_BR_VLAN_FILTERING : 'IFLA_BR_VLAN_FILTERING', IFLA_BR_VLAN_PROTOCOL : 'IFLA_BR_VLAN_PROTOCOL', IFLA_BR_GROUP_FWD_MASK : 'IFLA_BR_GROUP_FWD_MASK', IFLA_BR_ROOT_ID : 'IFLA_BR_ROOT_ID', IFLA_BR_BRIDGE_ID : 'IFLA_BR_BRIDGE_ID', IFLA_BR_ROOT_PORT : 'IFLA_BR_ROOT_PORT', IFLA_BR_ROOT_PATH_COST : 'IFLA_BR_ROOT_PATH_COST', IFLA_BR_TOPOLOGY_CHANGE : 'IFLA_BR_TOPOLOGY_CHANGE', IFLA_BR_TOPOLOGY_CHANGE_DETECTED : 'IFLA_BR_TOPOLOGY_CHANGE_DETECTED', IFLA_BR_HELLO_TIMER : 'IFLA_BR_HELLO_TIMER', IFLA_BR_TCN_TIMER : 'IFLA_BR_TCN_TIMER', IFLA_BR_TOPOLOGY_CHANGE_TIMER : 'IFLA_BR_TOPOLOGY_CHANGE_TIMER', IFLA_BR_GC_TIMER : 'IFLA_BR_GC_TIMER', IFLA_BR_GROUP_ADDR : 'IFLA_BR_GROUP_ADDR', IFLA_BR_FDB_FLUSH : 'IFLA_BR_FDB_FLUSH', IFLA_BR_MCAST_ROUTER : 'IFLA_BR_MCAST_ROUTER', IFLA_BR_MCAST_SNOOPING : 'IFLA_BR_MCAST_SNOOPING', IFLA_BR_MCAST_QUERY_USE_IFADDR : 'IFLA_BR_MCAST_QUERY_USE_IFADDR', IFLA_BR_MCAST_QUERIER : 'IFLA_BR_MCAST_QUERIER', IFLA_BR_MCAST_HASH_ELASTICITY : 'IFLA_BR_MCAST_HASH_ELASTICITY', IFLA_BR_MCAST_HASH_MAX : 'IFLA_BR_MCAST_HASH_MAX', IFLA_BR_MCAST_LAST_MEMBER_CNT : 'IFLA_BR_MCAST_LAST_MEMBER_CNT', IFLA_BR_MCAST_STARTUP_QUERY_CNT : 'IFLA_BR_MCAST_STARTUP_QUERY_CNT', IFLA_BR_MCAST_LAST_MEMBER_INTVL : 'IFLA_BR_MCAST_LAST_MEMBER_INTVL', IFLA_BR_MCAST_MEMBERSHIP_INTVL : 'IFLA_BR_MCAST_MEMBERSHIP_INTVL', IFLA_BR_MCAST_QUERIER_INTVL : 'IFLA_BR_MCAST_QUERIER_INTVL', IFLA_BR_MCAST_QUERY_INTVL : 'IFLA_BR_MCAST_QUERY_INTVL', IFLA_BR_MCAST_QUERY_RESPONSE_INTVL : 'IFLA_BR_MCAST_QUERY_RESPONSE_INTVL', IFLA_BR_MCAST_STARTUP_QUERY_INTVL : 'IFLA_BR_MCAST_STARTUP_QUERY_INTVL', IFLA_BR_NF_CALL_IPTABLES : 'IFLA_BR_NF_CALL_IPTABLES', IFLA_BR_NF_CALL_IP6TABLES : 'IFLA_BR_NF_CALL_IP6TABLES', IFLA_BR_NF_CALL_ARPTABLES : 'IFLA_BR_NF_CALL_ARPTABLES', IFLA_BR_VLAN_DEFAULT_PVID : 'IFLA_BR_VLAN_DEFAULT_PVID', IFLA_BR_PAD : 'IFLA_BR_PAD', IFLA_BR_VLAN_STATS_ENABLED : 'IFLA_BR_VLAN_STATS_ENABLED', IFLA_BR_MCAST_STATS_ENABLED : 'IFLA_BR_MCAST_STATS_ENABLED', IFLA_BR_MCAST_IGMP_VERSION : 'IFLA_BR_MCAST_IGMP_VERSION', IFLA_BR_MCAST_MLD_VERSION : 'IFLA_BR_MCAST_MLD_VERSION' } # ========================================= # IFLA_INFO_DATA attributes for vrfs # ========================================= IFLA_VRF_UNSPEC = 0 IFLA_VRF_TABLE = 1 ifla_vrf_to_string = { IFLA_VRF_UNSPEC : 'IFLA_VRF_UNSPEC', IFLA_VRF_TABLE : 'IFLA_VRF_TABLE' } # ================================================================ # IFLA_INFO_DATA attributes for (ip6)gre, (ip6)gretap, (ip6)erspan # ================================================================ IFLA_GRE_UNSPEC = 0 IFLA_GRE_LINK = 1 IFLA_GRE_IFLAGS = 2 IFLA_GRE_OFLAGS = 3 IFLA_GRE_IKEY = 4 IFLA_GRE_OKEY = 5 IFLA_GRE_LOCAL = 6 IFLA_GRE_REMOTE = 7 IFLA_GRE_TTL = 8 IFLA_GRE_TOS = 9 IFLA_GRE_PMTUDISC = 10 IFLA_GRE_ENCAP_LIMIT = 11 IFLA_GRE_FLOWINFO = 12 IFLA_GRE_FLAGS = 13 IFLA_GRE_ENCAP_TYPE = 14 IFLA_GRE_ENCAP_FLAGS = 15 IFLA_GRE_ENCAP_SPORT = 16 IFLA_GRE_ENCAP_DPORT = 17 IFLA_GRE_COLLECT_METADATA = 18 IFLA_GRE_IGNORE_DF = 19 IFLA_GRE_FWMARK = 20 IFLA_GRE_ERSPAN_INDEX = 21 IFLA_GRE_ERSPAN_VER = 22 IFLA_GRE_ERSPAN_DIR = 23 IFLA_GRE_ERSPAN_HWID = 24 ifla_gre_to_string = { IFLA_GRE_UNSPEC : "IFLA_GRE_UNSPEC", IFLA_GRE_LINK : "IFLA_GRE_LINK", IFLA_GRE_IFLAGS : "IFLA_GRE_IFLAGS", IFLA_GRE_OFLAGS : "IFLA_GRE_OFLAGS", IFLA_GRE_IKEY : "IFLA_GRE_IKEY", IFLA_GRE_OKEY : "IFLA_GRE_OKEY", IFLA_GRE_LOCAL : "IFLA_GRE_LOCAL", IFLA_GRE_REMOTE : "IFLA_GRE_REMOTE", IFLA_GRE_TTL : "IFLA_GRE_TTL", IFLA_GRE_TOS : "IFLA_GRE_TOS", IFLA_GRE_PMTUDISC : "IFLA_GRE_PMTUDISC", IFLA_GRE_ENCAP_LIMIT : "IFLA_GRE_ENCAP_LIMIT", IFLA_GRE_FLOWINFO : "IFLA_GRE_FLOWINFO", IFLA_GRE_FLAGS : "IFLA_GRE_FLAGS", IFLA_GRE_ENCAP_TYPE : "IFLA_GRE_ENCAP_TYPE", IFLA_GRE_ENCAP_FLAGS : "IFLA_GRE_ENCAP_FLAGS", IFLA_GRE_ENCAP_SPORT : "IFLA_GRE_ENCAP_SPORT", IFLA_GRE_ENCAP_DPORT : "IFLA_GRE_ENCAP_DPORT", IFLA_GRE_COLLECT_METADATA : "IFLA_GRE_COLLECT_METADATA", IFLA_GRE_IGNORE_DF : "IFLA_GRE_IGNORE_DF", IFLA_GRE_FWMARK : "IFLA_GRE_FWMARK", IFLA_GRE_ERSPAN_INDEX : "IFLA_GRE_ERSPAN_INDEX", IFLA_GRE_ERSPAN_VER : "IFLA_GRE_ERSPAN_VER", IFLA_GRE_ERSPAN_DIR : "IFLA_GRE_ERSPAN_DIR", IFLA_GRE_ERSPAN_HWID : "IFLA_GRE_ERSPAN_HWID", } # =============================================== # IFLA_INFO_DATA attributes for ipip, sit, ip6tnl # =============================================== IFLA_IPTUN_UNSPEC = 0 IFLA_IPTUN_LINK = 1 IFLA_IPTUN_LOCAL = 2 IFLA_IPTUN_REMOTE = 3 IFLA_IPTUN_TTL = 4 IFLA_IPTUN_TOS = 5 IFLA_IPTUN_ENCAP_LIMIT = 6 IFLA_IPTUN_FLOWINFO = 7 IFLA_IPTUN_FLAGS = 8 IFLA_IPTUN_PROTO = 9 IFLA_IPTUN_PMTUDISC = 10 IFLA_IPTUN_6RD_PREFIX = 11 IFLA_IPTUN_6RD_RELAY_PREFIX = 12 IFLA_IPTUN_6RD_PREFIXLEN = 13 IFLA_IPTUN_6RD_RELAY_PREFIXLEN = 14 IFLA_IPTUN_ENCAP_TYPE = 15 IFLA_IPTUN_ENCAP_FLAGS = 16 IFLA_IPTUN_ENCAP_SPORT = 17 IFLA_IPTUN_ENCAP_DPORT = 18 IFLA_IPTUN_COLLECT_METADATA = 19 IFLA_IPTUN_FWMARK = 20 ifla_iptun_to_string = { IFLA_IPTUN_UNSPEC : "IFLA_IPTUN_UNSPEC", IFLA_IPTUN_LINK : "IFLA_IPTUN_LINK", IFLA_IPTUN_LOCAL : "IFLA_IPTUN_LOCAL", IFLA_IPTUN_REMOTE : "IFLA_IPTUN_REMOTE", IFLA_IPTUN_TTL : "IFLA_IPTUN_TTL", IFLA_IPTUN_TOS : "IFLA_IPTUN_TOS", IFLA_IPTUN_ENCAP_LIMIT : "IFLA_IPTUN_ENCAP_LIMIT", IFLA_IPTUN_FLOWINFO : "IFLA_IPTUN_FLOWINFO", IFLA_IPTUN_FLAGS : "IFLA_IPTUN_FLAGS", IFLA_IPTUN_PROTO : "IFLA_IPTUN_PROTO", IFLA_IPTUN_PMTUDISC : "IFLA_IPTUN_PMTUDISC", IFLA_IPTUN_6RD_PREFIX : "IFLA_IPTUN_6RD_PREFIX", IFLA_IPTUN_6RD_RELAY_PREFIX : "IFLA_IPTUN_6RD_RELAY_PREFIX", IFLA_IPTUN_6RD_PREFIXLEN : "IFLA_IPTUN_6RD_PREFIXLEN", IFLA_IPTUN_6RD_RELAY_PREFIXLEN : "IFLA_IPTUN_6RD_RELAY_PREFIXLEN", IFLA_IPTUN_ENCAP_TYPE : "IFLA_IPTUN_ENCAP_TYPE", IFLA_IPTUN_ENCAP_FLAGS : "IFLA_IPTUN_ENCAP_FLAGS", IFLA_IPTUN_ENCAP_SPORT : "IFLA_IPTUN_ENCAP_SPORT", IFLA_IPTUN_ENCAP_DPORT : "IFLA_IPTUN_ENCAP_DPORT", IFLA_IPTUN_COLLECT_METADATA : "IFLA_IPTUN_COLLECT_METADATA", IFLA_IPTUN_FWMARK : "IFLA_IPTUN_FWMARK", } # ========================================= # IFLA_INFO_DATA attributes for vti, vti6 # ========================================= IFLA_VTI_UNSPEC = 0 IFLA_VTI_LINK = 1 IFLA_VTI_IKEY = 2 IFLA_VTI_OKEY = 3 IFLA_VTI_LOCAL = 4 IFLA_VTI_REMOTE = 5 IFLA_VTI_FWMARK = 6 ifla_vti_to_string = { IFLA_VTI_UNSPEC : "IFLA_VTI_UNSPEC", IFLA_VTI_LINK : "IFLA_VTI_LINK", IFLA_VTI_IKEY : "IFLA_VTI_IKEY", IFLA_VTI_OKEY : "IFLA_VTI_OKEY", IFLA_VTI_LOCAL : "IFLA_VTI_LOCAL", IFLA_VTI_REMOTE : "IFLA_VTI_REMOTE", IFLA_VTI_FWMARK : "IFLA_VTI_FWMARK", } def __init__(self, msgtype, debug=False, logger=None, use_color=True): NetlinkPacket.__init__(self, msgtype, debug, logger, use_color) self.PACK = 'BxHiII' self.LEN = calcsize(self.PACK) def get_link_type_string(self, index): return self.get_string(self.link_type_to_string, index) def get_ifla_inet6_af_spec_to_string(self, index): return self.get_string(self.ifla_inet6_af_spec_to_string, index) def get_ifla_inet_af_spec_to_string(self, index): return self.get_string(self.ifla_inet_af_spec_to_string, index) def get_ifla_bridge_af_spec_to_string(self, index): return self.get_string(self.ifla_bridge_af_spec_to_string, index) def get_ifla_info_string(self, index): return self.get_string(self.ifla_info_to_string, index) def get_ifla_vlan_string(self, index): return self.get_string(self.ifla_vlan_to_string, index) def get_ifla_vxlan_string(self, index): return self.get_string(self.ifla_vxlan_to_string, index) def get_ifla_macvlan_string(self, index): return self.get_string(self.ifla_macvlan_to_string, index) def get_macvlan_mode_string(self, index): return self.get_string(self.macvlan_mode_to_string, index) def get_ifla_gre_string(self, index): return self.get_string(self.ifla_gre_to_string, index) def get_ifla_vti_string(self, index): return self.get_string(self.ifla_vti_to_string, index) def get_ifla_iptun_string(self, index): return self.get_string(self.ifla_iptun_to_string, index) def get_ifla_bond_string(self, index): return self.get_string(self.ifla_bond_to_string, index) def get_ifla_bond_ad_string(self, index): return self.get_string(self.ifla_bond_ad_to_string, index) def get_ifla_brport_string(self, index): return self.get_string(self.ifla_brport_to_string, index) def get_ifla_br_string(self, index): return self.get_string(self.ifla_br_to_string, index) def get_bridge_vlan_string(self, index): return self.get_string(self.bridge_vlan_to_string, index) def get_bridge_flags_string(self, index): return self.get_string(self.bridge_flags_to_string, index) def decode_service_header(self): # Nothing to do if the message did not contain a service header if self.length == self.header_LEN: return (self.family, self.device_type, self.ifindex, self.flags, self.change_mask) = \ unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: color = yellow if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sService Header%s" % (color_start, color_end)) for x in range(0, self.LEN/4): if self.line_number == 5: extra = "Family %s (%s:%d), Device Type %s (%d - %s)" % \ (zfilled_hex(self.family, 2), get_family_str(self.family), self.family, zfilled_hex(self.device_type, 4), self.device_type, self.get_link_type_string(self.device_type)) elif self.line_number == 6: extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex) elif self.line_number == 7: extra = "Device Flags %s (%s)" % (zfilled_hex(self.flags, 8), self.get_flags_string()) elif self.line_number == 8: extra = "Change Mask %s" % zfilled_hex(self.change_mask, 8) else: extra = "Unexpected line number %d" % self.line_number start = x * 4 end = start + 4 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra)) self.line_number += 1 def is_up(self): if self.flags & Link.IFF_UP: return True return False class Netconf(Link): """ RTM_NEWNETCONF - Service Header 0 1 0 1 2 3 4 5 6 7 8 +-+-+-+-+-+-+-+-+ | Family | +-+-+-+-+-+-+-+-+ RTM_GETNETCONF - Service Header 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Family | Reserved | Device Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Device Flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Change Mask | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ # Netconf attributes # /usr/include/linux/netconf.h NETCONFA_UNSPEC = 0 NETCONFA_IFINDEX = 1 NETCONFA_FORWARDING = 2 NETCONFA_RP_FILTER = 3 NETCONFA_MC_FORWARDING = 4 NETCONFA_PROXY_NEIGH = 5 NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN = 6 NETCONFA_INPUT = 7 __NETCONFA_MAX = 8 NETCONFA_MAX = (__NETCONFA_MAX - 1) NETCONFA_ALL = -1 NETCONFA_IFINDEX_ALL = -1 NETCONFA_IFINDEX_DEFAULT = -2 NETCONF_ATTR_FAMILY = 0x0001 NETCONF_ATTR_IFINDEX = 0x0002 NETCONF_ATTR_RP_FILTER = 0x0004 NETCONF_ATTR_FWDING = 0x0008 NETCONF_ATTR_MC_FWDING = 0x0010 NETCONF_ATTR_PROXY_NEIGH = 0x0020 NETCONF_ATTR_IGNORE_RT_LINKDWN = 0x0040 attribute_to_class = { NETCONFA_UNSPEC : ('NETCONFA_UNSPEC', AttributeGeneric), NETCONFA_IFINDEX : ('NETCONFA_IFINDEX', AttributeFourByteValue), NETCONFA_FORWARDING : ('NETCONFA_FORWARDING', AttributeFourByteValue), NETCONFA_RP_FILTER : ('NETCONFA_RP_FILTER', AttributeFourByteValue), NETCONFA_MC_FORWARDING : ('NETCONFA_MC_FORWARDING', AttributeFourByteValue), NETCONFA_PROXY_NEIGH : ('NETCONFA_PROXY_NEIGH', AttributeFourByteValue), NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN : ('NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN', AttributeFourByteValue), NETCONFA_INPUT : ('NETCONFA_INPUT', AttributeFourByteValue), } def __init__(self, msgtype, debug=False, logger=None, use_color=True): NetlinkPacket.__init__(self, msgtype, debug, logger, use_color) if msgtype == RTM_GETNETCONF: # same as RTM_GETLINK self.PACK = 'BxHiII' self.LEN = calcsize(self.PACK) elif msgtype == RTM_NEWNETCONF: self.PACK = 'Bxxx' self.LEN = calcsize(self.PACK) def decode_service_header(self): # Nothing to do if the message did not contain a service header if self.length == self.header_LEN: return if self.msgtype == RTM_GETNETCONF: super(Netconf, self).decode_service_header() elif self.msgtype == RTM_NEWNETCONF: (self.family,) = unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: color = yellow if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sService Header%s" % (color_start, color_end)) self.dump_buffer.append(data_to_color_text(1, color, bytearray(struct.pack('!I', self.family)), "Family %s (%s:%d)" % (zfilled_hex(self.family, 2), get_family_str(self.family), self.family))) class Neighbor(NetlinkPacket): """ Service Header 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Family | Reserved1 | Reserved2 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | State | Flags | Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ # Neighbor attributes # /usr/include/linux/neighbour.h NDA_UNSPEC = 0x00 # Unknown type NDA_DST = 0x01 # A neighbour cache network. layer destination address NDA_LLADDR = 0x02 # A neighbor cache link layer address. NDA_CACHEINFO = 0x03 # Cache statistics NDA_PROBES = 0x04 NDA_VLAN = 0x05 NDA_PORT = 0x06 NDA_VNI = 0x07 NDA_IFINDEX = 0x08 NDA_MASTER = 0x09 NDA_LINK_NETNSID = 0x0A attribute_to_class = { NDA_UNSPEC : ('NDA_UNSPEC', AttributeGeneric), NDA_DST : ('NDA_DST', AttributeIPAddress), NDA_LLADDR : ('NDA_LLADDR', AttributeMACAddress), NDA_CACHEINFO : ('NDA_CACHEINFO', AttributeFourByteList), NDA_PROBES : ('NDA_PROBES', AttributeFourByteValue), NDA_VLAN : ('NDA_VLAN', AttributeTwoByteValue), NDA_PORT : ('NDA_PORT', AttributeGeneric), NDA_VNI : ('NDA_VNI', AttributeFourByteValue), NDA_IFINDEX : ('NDA_IFINDEX', AttributeFourByteValue), NDA_MASTER : ('NDA_MASTER', AttributeFourByteValue), NDA_LINK_NETNSID : ('NDA_LINK_NETNSID', AttributeGeneric) } # Neighbor flags # /usr/include/linux/neighbour.h NTF_USE = 0x01 NTF_SELF = 0x02 NTF_MASTER = 0x04 NTF_PROXY = 0x08 # A proxy ARP entry NTF_EXT_LEARNED = 0x10 # neigh entry installed by an external APP NTF_ROUTER = 0x80 # An IPv6 router flag_to_string = { NTF_USE : 'NTF_USE', NTF_SELF : 'NTF_SELF', NTF_MASTER : 'NTF_MASTER', NTF_PROXY : 'NTF_PROXY', NTF_EXT_LEARNED : 'NTF_EXT_LEARNED', NTF_ROUTER : 'NTF_ROUTER' } # Neighbor states # /usr/include/linux/neighbour.h NUD_NONE = 0x00 NUD_INCOMPLETE = 0x01 # Still attempting to resolve NUD_REACHABLE = 0x02 # A confirmed working cache entry NUD_STALE = 0x04 # an expired cache entry NUD_DELAY = 0x08 # Neighbor no longer reachable. Traffic sent, waiting for confirmatio. NUD_PROBE = 0x10 # A cache entry that is currently being re-solicited NUD_FAILED = 0x20 # An invalid cache entry NUD_NOARP = 0x40 # A device which does not do neighbor discovery(ARP) NUD_PERMANENT = 0x80 # A static entry state_to_string = { NUD_NONE : 'NUD_NONE', NUD_INCOMPLETE : 'NUD_INCOMPLETE', NUD_REACHABLE : 'NUD_REACHABLE', NUD_STALE : 'NUD_STALE', NUD_DELAY : 'NUD_DELAY', NUD_PROBE : 'NUD_PROBE', NUD_FAILED : 'NUD_FAILED', NUD_NOARP : 'NUD_NOARP', NUD_PERMANENT : 'NUD_PERMANENT' } def __init__(self, msgtype, debug=False, logger=None, use_color=True): NetlinkPacket.__init__(self, msgtype, debug, logger, use_color) self.PACK = 'BxxxiHBB' self.LEN = calcsize(self.PACK) def get_state_string(self, index): return self.get_string(self.state_to_string, index) def get_states_string(self, states): for_string = [] if states & Neighbor.NUD_INCOMPLETE: for_string.append('NUD_INCOMPLETE') if states & Neighbor.NUD_REACHABLE: for_string.append('NUD_REACHABLE') if states & Neighbor.NUD_STALE: for_string.append('NUD_STALE') if states & Neighbor.NUD_DELAY: for_string.append('NUD_DELAY') if states & Neighbor.NUD_PROBE: for_string.append('NUD_PROBE') if states & Neighbor.NUD_FAILED: for_string.append('NUD_FAILED') if states & Neighbor.NUD_NOARP: for_string.append('NUD_NOARP') if states & Neighbor.NUD_PERMANENT: for_string.append('NUD_PERMANENT') return ', '.join(for_string) def get_flags_string(self, flags): for_string = [] if flags & Neighbor.NTF_USE: for_string.append('NTF_USE') if flags & Neighbor.NTF_SELF: for_string.append('NTF_SELF') if flags & Neighbor.NTF_MASTER: for_string.append('NTF_MASTER') if flags & Neighbor.NTF_PROXY: for_string.append('NTF_PROXY') if flags & Neighbor.NTF_ROUTER: for_string.append('NTF_ROUTER') return ', '.join(for_string) def decode_service_header(self): # Nothing to do if the message did not contain a service header if self.length == self.header_LEN: return (self.family, self.ifindex, self.state, self.flags, self.neighbor_type) = \ unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: color = yellow if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sService Header%s" % (color_start, color_end)) for x in range(0, self.LEN/4): if self.line_number == 5: extra = "Family %s (%s:%d)" % (zfilled_hex(self.family, 2), get_family_str(self.family), self.family) elif self.line_number == 6: extra = "Interface Index %s (%d)" % (zfilled_hex(self.ifindex, 8), self.ifindex) elif self.line_number == 7: extra = "State %s (%d) %s, Flags %s (%s) %s, Type %s (%d)" % \ (zfilled_hex(self.state, 4), self.state, self.get_states_string(self.state), zfilled_hex(self.flags, 2), self.flags, self.get_flags_string(self.flags), zfilled_hex(self.neighbor_type, 4), self.neighbor_type) else: extra = "Unexpected line number %d" % self.line_number start = x * 4 end = start + 4 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra)) self.line_number += 1 class Route(NetlinkPacket): """ Service Header 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Family | Dest length | Src length | TOS | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Table ID | Protocol | Scope | Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Flags | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ # Route attributes # /usr/include/linux/rtnetlink.h RTA_UNSPEC = 0x00 # Ignored. RTA_DST = 0x01 # Protocol address for route destination address. RTA_SRC = 0x02 # Protocol address for route source address. RTA_IIF = 0x03 # Input interface index. RTA_OIF = 0x04 # Output interface index. RTA_GATEWAY = 0x05 # Protocol address for the gateway of the route RTA_PRIORITY = 0x06 # Priority of broker. RTA_PREFSRC = 0x07 # Preferred source address in cases where more than one source address could be used. RTA_METRICS = 0x08 # Route metrics attributed to route and associated protocols(e.g., RTT, initial TCP window, etc.). RTA_MULTIPATH = 0x09 # Multipath route next hop's attributes. RTA_PROTOINFO = 0x0A # Firewall based policy routing attribute. RTA_FLOW = 0x0B # Route realm. RTA_CACHEINFO = 0x0C # Cached route information. RTA_SESSION = 0x0D RTA_MP_ALGO = 0x0E RTA_TABLE = 0x0F RTA_MARK = 0x10 RTA_MFC_STATS = 0x11 RTA_VIA = 0x12 RTA_NEWDST = 0x13 RTA_PREF = 0x14 RTA_ENCAP_TYPE= 0x15 RTA_ENCAP = 0x16 attribute_to_class = { RTA_UNSPEC : ('RTA_UNSPEC', AttributeGeneric), RTA_DST : ('RTA_DST', AttributeIPAddress), RTA_SRC : ('RTA_SRC', AttributeIPAddress), RTA_IIF : ('RTA_IIF', AttributeFourByteValue), RTA_OIF : ('RTA_OIF', AttributeFourByteValue), RTA_GATEWAY : ('RTA_GATEWAY', AttributeIPAddress), RTA_PRIORITY : ('RTA_PRIORITY', AttributeFourByteValue), RTA_PREFSRC : ('RTA_PREFSRC', AttributeIPAddress), RTA_METRICS : ('RTA_METRICS', AttributeGeneric), RTA_MULTIPATH : ('RTA_MULTIPATH', AttributeRTA_MULTIPATH), RTA_PROTOINFO : ('RTA_PROTOINFO', AttributeGeneric), RTA_FLOW : ('RTA_FLOW', AttributeGeneric), RTA_CACHEINFO : ('RTA_CACHEINFO', AttributeGeneric), RTA_SESSION : ('RTA_SESSION', AttributeGeneric), RTA_MP_ALGO : ('RTA_MP_ALGO', AttributeGeneric), RTA_TABLE : ('RTA_TABLE', AttributeFourByteValue), RTA_MARK : ('RTA_MARK', AttributeGeneric), RTA_MFC_STATS : ('RTA_MFC_STATS', AttributeGeneric), RTA_VIA : ('RTA_VIA', AttributeGeneric), RTA_NEWDST : ('RTA_NEWDST', AttributeGeneric), RTA_PREF : ('RTA_PREF', AttributeGeneric), RTA_ENCAP_TYPE: ('RTA_ENCAP_TYPE', AttributeGeneric), RTA_ENCAP : ('RTA_ENCAP', AttributeGeneric) } # Route tables # /usr/include/linux/rtnetlink.h RT_TABLE_UNSPEC = 0x00 # An unspecified routing table RT_TABLE_COMPAT = 0xFC RT_TABLE_DEFAULT = 0xFD # The default table RT_TABLE_MAIN = 0xFE # The main table RT_TABLE_LOCAL = 0xFF # The local table table_to_string = { RT_TABLE_UNSPEC : 'RT_TABLE_UNSPEC', RT_TABLE_COMPAT : 'RT_TABLE_COMPAT', RT_TABLE_DEFAULT : 'RT_TABLE_DEFAULT', RT_TABLE_MAIN : 'RT_TABLE_MAIN', RT_TABLE_LOCAL : 'RT_TABLE_LOCAL' } # Route scope # /usr/include/linux/rtnetlink.h RT_SCOPE_UNIVERSE = 0x00 # Global route RT_SCOPE_SITE = 0xC8 # Interior route in the local autonomous system RT_SCOPE_LINK = 0xFD # Route on this link RT_SCOPE_HOST = 0xFE # Route on the local host RT_SCOPE_NOWHERE = 0xFF # Destination does not exist scope_to_string = { RT_SCOPE_UNIVERSE : 'RT_SCOPE_UNIVERSE', RT_SCOPE_SITE : 'RT_SCOPE_SITE', RT_SCOPE_LINK : 'RT_SCOPE_LINK', RT_SCOPE_HOST : 'RT_SCOPE_HOST', RT_SCOPE_NOWHERE : 'RT_SCOPE_NOWHERE' } # Route scope to string # iproute2/lib/rt_names.c rtnl_rtscope_tab = { RT_SCOPE_UNIVERSE: 'global', RT_SCOPE_NOWHERE: 'nowhere', RT_SCOPE_HOST: 'host', RT_SCOPE_LINK: 'link', RT_SCOPE_SITE: 'site' } # Routing stack # /usr/include/linux/rtnetlink.h RT_PROT_UNSPEC = 0x00 # Identifies what/who added the route RT_PROT_REDIRECT = 0x01 # By an ICMP redirect RT_PROT_KERNEL = 0x02 # By the kernel RT_PROT_BOOT = 0x03 # During bootup RT_PROT_STATIC = 0x04 # By the administrator RT_PROT_GATED = 0x08 # GateD RT_PROT_RA = 0x09 # RDISC/ND router advertissements RT_PROT_MRT = 0x0A # Merit MRT RT_PROT_ZEBRA = 0x0B # ZEBRA RT_PROT_BIRD = 0x0C # BIRD RT_PROT_DNROUTED = 0x0D # DECnet routing daemon RT_PROT_XORP = 0x0E # XORP RT_PROT_NTK = 0x0F # Netsukuku RT_PROT_DHCP = 0x10 # DHCP client RT_PROT_EXABGP = 0x11 # Exa Networks ExaBGP prot_to_string = { RT_PROT_UNSPEC : 'RT_PROT_UNSPEC', RT_PROT_REDIRECT : 'RT_PROT_REDIRECT', RT_PROT_KERNEL : 'RT_PROT_KERNEL', RT_PROT_BOOT : 'RT_PROT_BOOT', RT_PROT_STATIC : 'RT_PROT_STATIC', RT_PROT_GATED : 'RT_PROT_GATED', RT_PROT_RA : 'RT_PROT_RA', RT_PROT_MRT : 'RT_PROT_MRT', RT_PROT_ZEBRA : 'RT_PROT_ZEBRA', RT_PROT_BIRD : 'RT_PROT_BIRD', RT_PROT_DNROUTED : 'RT_PROT_DNROUTED', RT_PROT_XORP : 'RT_PROT_XORP', RT_PROT_NTK : 'RT_PROT_NTK', RT_PROT_DHCP : 'RT_PROT_DHCP', RT_PROT_EXABGP : 'RT_PROT_EXABGP' } # Route types # /usr/include/linux/rtnetlink.h RTN_UNSPEC = 0x00 # Unknown broker. RTN_UNICAST = 0x01 # A gateway or direct broker. RTN_LOCAL = 0x02 # A local interface broker. RTN_BROADCAST = 0x03 # A local broadcast route(sent as a broadcast). RTN_ANYCAST = 0x04 # An anycast broker. RTN_MULTICAST = 0x05 # A multicast broker. RTN_BLACKHOLE = 0x06 # A silent packet dropping broker. RTN_UNREACHABLE = 0x07 # An unreachable destination. Packets dropped and # host unreachable ICMPs are sent to the originator. RTN_PROHIBIT = 0x08 # A packet rejection broker. Packets are dropped and # communication prohibited ICMPs are sent to the originator. RTN_THROW = 0x09 # When used with policy routing, continue routing lookup # in another table. Under normal routing, packets are # dropped and net unreachable ICMPs are sent to the originator. RTN_NAT = 0x0A # A network address translation rule. RTN_XRESOLVE = 0x0B # Refer to an external resolver(not implemented). rt_type_to_string = { RTN_UNSPEC : 'RTN_UNSPEC', RTN_UNICAST : 'RTN_UNICAST', RTN_LOCAL : 'RTN_LOCAL', RTN_BROADCAST : 'RTN_BROADCAST', RTN_ANYCAST : 'RTN_ANYCAST', RTN_MULTICAST : 'RTN_MULTICAST', RTN_BLACKHOLE : 'RTN_BLACKHOLE', RTN_UNREACHABLE : 'RTN_UNREACHABLE', RTN_PROHIBIT : 'RTN_PROHIBIT', RTN_THROW : 'RTN_THROW', RTN_NAT : 'RTN_NAT', RTN_XRESOLVE : 'RTN_XRESOLVE' } # Route flags # /usr/include/linux/rtnetlink.h RTM_F_NOTIFY = 0x100 # If the route changes, notify the user RTM_F_CLONED = 0x200 # Route is cloned from another route RTM_F_EQUALIZE = 0x400 # Allow randomization of next hop path in multi-path routing(currently not implemented) RTM_F_PREFIX = 0x800 # Prefix Address flag_to_string = { RTM_F_NOTIFY : 'RTM_F_NOTIFY', RTM_F_CLONED : 'RTM_F_CLONED', RTM_F_EQUALIZE : 'RTM_F_EQUALIZE', RTM_F_PREFIX : 'RTM_F_PREFIX' } def __init__(self, msgtype, debug=False, logger=None, use_color=True): NetlinkPacket.__init__(self, msgtype, debug, logger, use_color) self.PACK = '=8BI' # or is it 8Bi ? self.LEN = calcsize(self.PACK) def get_prefix_string(self): dst = self.get_attribute_value(self.RTA_DST) if dst: return "%s/%d" % (dst, self.src_len) else: if self.family == AF_INET: return "0.0.0.0/0" elif self.family == AF_INET6: return "::/0" def get_protocol_string(self, index=None): if index is None: index = self.protocol return self.get_string(self.prot_to_string, index) def get_rt_type_string(self, index=None): if index is None: index = self.route_type return self.get_string(self.rt_type_to_string, index) def get_scope_string(self, index=None): if index is None: index = self.scope return self.get_string(self.scope_to_string, index) def get_table_id_string(self, index=None): if index is None: index = self.table_id return self.get_string(self.table_to_string, index) def _get_ifname_from_index(self, ifindex, ifname_by_index): if ifindex: ifname = ifname_by_index.get(ifindex) if ifname is None: ifname = str(ifindex) else: ifname = None return ifname def get_nexthops(self, ifname_by_index={}): nexthop = self.get_attribute_value(self.RTA_GATEWAY) multipath = self.get_attribute_value(self.RTA_MULTIPATH) nexthops = [] if nexthop: rta_oif = self.get_attribute_value(self.RTA_OIF) ifname = self._get_ifname_from_index(rta_oif, ifname_by_index) nexthops.append((nexthop, ifname)) elif multipath: for (nexthop, rtnh_ifindex, rtnh_flags, rtnh_hops) in multipath: ifname = self._get_ifname_from_index(rtnh_ifindex, ifname_by_index) nexthops.append((nexthop, ifname)) return nexthops def get_nexthops_string(self, ifname_by_index={}): output = [] for (nexthop, ifname) in self.get_nexthops(ifname_by_index): output.append(" via %s on %s" % (nexthop, ifname)) return ",".join(output) def decode_service_header(self): # Nothing to do if the message did not contain a service header if self.length == self.header_LEN: return (self.family, self.src_len, self.dst_len, self.tos, self.table_id, self.protocol, self.scope, self.route_type, self.flags) = \ unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: color = yellow if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sService Header%s" % (color_start, color_end)) for x in range(0, self.LEN/4): if self.line_number == 5: extra = "Family %s (%s:%d), Source Length %s (%d), Destination Length %s (%d), TOS %s (%d)" % \ (zfilled_hex(self.family, 2), get_family_str(self.family), self.family, zfilled_hex(self.src_len, 2), self.src_len, zfilled_hex(self.dst_len, 2), self.dst_len, zfilled_hex(self.tos, 2), self.tos) elif self.line_number == 6: extra = "Table ID %s (%d - %s), Protocol %s (%d - %s), Scope %s (%d - %s), Type %s (%d - %s)" % \ (zfilled_hex(self.table_id, 2), self.table_id, self.get_table_id_string(), zfilled_hex(self.protocol, 2), self.protocol, self.get_protocol_string(), zfilled_hex(self.scope, 2), self.scope, self.get_scope_string(), zfilled_hex(self.route_type, 2), self.route_type, self.get_rt_type_string()) elif self.line_number == 7: extra = "Flags %s" % zfilled_hex(self.flags, 8) else: extra = "Unexpected line number %d" % self.line_number start = x * 4 end = start + 4 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra)) self.line_number += 1 class Done(NetlinkPacket): """ NLMSG_DONE Service Header 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | TBD | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ """ def __init__(self, msgtype, debug=False, logger=None, use_color=True): NetlinkPacket.__init__(self, msgtype, debug, logger, use_color) self.PACK = 'i' self.LEN = calcsize(self.PACK) def decode_service_header(self): foo = unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: color = yellow if self.use_color else None color_start = "\033[%dm" % color if color else "" color_end = "\033[0m" if color else "" self.dump_buffer.append(" %sService Header%s" % (color_start, color_end)) for x in range(0, self.LEN/4): extra = '' start = x * 4 end = start + 4 self.dump_buffer.append(data_to_color_text(self.line_number, color, self.msg_data[start:end], extra)) self.line_number += 1