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
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
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:
- if self.length == 10:
+ # 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)
- elif self.length == 8:
- self.value = IPv4Address(unpack('>L', self.data[4:])[0])
+ # 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:
self.decode_length_type(data)
self.value = {}
- # opti for now, since we only support AF_BRIDGE
- if self.family != AF_BRIDGE:
- return
-
data = self.data[4:]
while data:
sub_attr_type, sub_attr_length, sub_attr_end))
elif self.family == AF_UNSPEC:
- self.log.log(SYSLOG_EXTRA_DEBUG, 'Add support for decoding IFLA_AF_SPEC sub-attribute '
- 'type AF_UNSPEC (0), length %d, padded to %d'
- % (sub_attr_length, sub_attr_end))
+ 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'
next_sub_attr_line = line_number + (sub_attr_end/4)
if sub_attr_end == sub_attr_length:
- padded_to = ', '
+ padded_to = ','
else:
- padded_to = ' padded to %d, ' % sub_attr_end
+ padded_to = ' padded to %d,' % sub_attr_end
if self.family == AF_BRIDGE:
extra = 'Nested Attribute - Length %s (%d)%s Type %s (%d) %s' % \
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 = ''
# with the names of the nested keys instead of their numbers
value_pretty = {}
- 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
+ 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
RTM_GETROUTE : 'RTM_GETROUTE',
RTM_NEWQDISC : 'RTM_NEWQDISC',
RTM_DELQDISC : 'RTM_DELQDISC',
- RTM_GETQDISC : 'RTM_GETQDISC'
+ RTM_GETQDISC : 'RTM_GETQDISC',
+ RTM_NEWNETCONF: 'RTM_NEWNETCONF',
+ RTM_GETNETCONF: 'RTM_GETNETCONF'
}
af_family_to_string = {
foo.append('NLM_F_ECHO')
# Modifiers to GET query
- if msg_type in (RTM_GETLINK, RTM_GETADDR, RTM_GETNEIGH, RTM_GETROUTE, RTM_GETQDISC):
+ 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:
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 attr_type == Route.RTA_DST and self.family == AF_MPLS:
+ 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
for x in range(0, self.LEN/4):
if self.line_number == 5:
- extra = "Family %s (%d), Length %s (%d), Flags %s, Scope %s (%d)" % \
- (zfilled_hex(self.family, 2), self.family,
+ 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)
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',
+ }
+
+ # 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
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)
for x in range(0, self.LEN/4):
if self.line_number == 5:
- extra = "Family %s (%d), Device Type %s (%d - %s)" % \
- (zfilled_hex(self.family, 2), self.family,
+ 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)
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
for x in range(0, self.LEN/4):
if self.line_number == 5:
- extra = "Family %s (%d)" % (zfilled_hex(self.family, 2), self.family)
+ 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:
for x in range(0, self.LEN/4):
if self.line_number == 5:
- extra = "Family %s (%d), Source Length %s (%d), Destination Length %s (%d), TOS %s (%d)" % \
- (zfilled_hex(self.family, 2), self.family,
+ 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)