]> git.proxmox.com Git - mirror_ifupdown2.git/blobdiff - ifupdown2/nlmanager/nlpacket.py
nlpacket:: add family string (AF_*) to debug dump
[mirror_ifupdown2.git] / ifupdown2 / nlmanager / nlpacket.py
index f2cf6002c9bf1678d5f6bc649d982a19977aa787..285481ba52671a3065fe1f8b1ba7ddcfe4880f50 100644 (file)
@@ -71,6 +71,9 @@ 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
@@ -118,6 +121,20 @@ RTMGRP_ALL = (RTMGRP_LINK | RTMGRP_NOTIFY | RTMGRP_NEIGH | RTMGRP_TC |
 
 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
@@ -796,10 +813,6 @@ class AttributeIFLA_AF_SPEC(Attribute):
         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:
@@ -828,10 +841,63 @@ class AttributeIFLA_AF_SPEC(Attribute):
                                   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'
@@ -862,9 +928,9 @@ class AttributeIFLA_AF_SPEC(Attribute):
                 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' % \
@@ -872,6 +938,18 @@ class AttributeIFLA_AF_SPEC(Attribute):
                              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 = ''
 
@@ -889,9 +967,25 @@ class AttributeIFLA_AF_SPEC(Attribute):
         # 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
 
@@ -2142,7 +2236,9 @@ class NetlinkPacket(object):
         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 = {
@@ -2222,7 +2318,7 @@ class NetlinkPacket(object):
             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:
@@ -2356,7 +2452,7 @@ class NetlinkPacket(object):
             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
 
@@ -2528,8 +2624,8 @@ class Address(NetlinkPacket):
 
             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)
@@ -3362,6 +3458,40 @@ class Link(NetlinkPacket):
         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
@@ -3525,6 +3655,12 @@ class Link(NetlinkPacket):
     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)
 
@@ -3581,8 +3717,8 @@ class Link(NetlinkPacket):
 
             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)
@@ -3604,6 +3740,95 @@ class Link(NetlinkPacket):
         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
@@ -3765,7 +3990,7 @@ class Neighbor(NetlinkPacket):
 
             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:
@@ -4066,8 +4291,8 @@ class Route(NetlinkPacket):
 
             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)