From 3479a0c3bba7d549499efd577ecd629c5048680f Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Wed, 29 Aug 2018 17:21:54 +0200 Subject: [PATCH] nlpacket:: add netconf support (RTM_GETNETCONF/RTM_NEWNETCONF) $ cd python-nlmanager/examples $ ./netconf_show.py 2018-06-01 16:59:02,398 DEBUG: TXed RTM_GETNETCONF, length 32, seq 1, pid 14202, flags 0x0 () Netlink Header 1: 0x20000000 ... Length 0x00000020 (32) 2: 0x52000503 R... Type 0x0052 (82 - RTM_GETNETCONF), Flags 0x0305 (NLM_F_REQUEST, NLM_F_ACK, NLM_F_DUMP) 3: 0x01000000 .... Sequence Number 0x00000001 (1) 4: 0x7a370000 z7.. Process ID 0x0000377a (14202) Service Header 5: 0x00000000 .... Family 0x00 (0), Device Type 0x0000 (0 - ARPHRD_NETROM) 6: 0x00000000 .... Interface Index 0x00000000 (0) 7: 0x00000000 .... Device Flags 0x00000000 () 8: 0x00000000 .... Change Mask 0x00000000 Attributes Attributes Summary {} 2018-06-01 16:59:02,401 DEBUG: RXed RTM_NEWNETCONF, length 68, seq 1, pid 14202, flags 0x2 Netlink Header 1: 0x44000000 D... Length 0x00000044 (68) 2: 0x50000200 P... Type 0x0050 (80 - RTM_NEWNETCONF), Flags 0x0002 (NLM_F_MULTI) 3: 0x01000000 .... Sequence Number 0x00000001 (1) 4: 0x7a370000 z7.. Process ID 0x0000377a (14202) Service Header 1: 0x00000002 .... Family 0x02 (2) Attributes 5: 0x08000100 .... Length 0x0008 (8), Type 0x0001 (1) NETCONFA_IFINDEX 6: 0x01000000 .... 1 7: 0x08000200 .... Length 0x0008 (8), Type 0x0002 (2) NETCONFA_FORWARDING 8: 0x01000000 .... 1 9: 0x08000300 .... Length 0x0008 (8), Type 0x0003 (3) NETCONFA_RP_FILTER 10: 0x00000000 .... 0 11: 0x08000400 .... Length 0x0008 (8), Type 0x0004 (4) NETCONFA_MC_FORWARDING 12: 0x00000000 .... 0 13: 0x08000500 .... Length 0x0008 (8), Type 0x0005 (5) NETCONFA_PROXY_NEIGH 14: 0x00000000 .... 0 15: 0x08000600 .... Length 0x0008 (8), Type 0x0006 (6) NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN 16: 0x01000000 .... 1 Attributes Summary {'( 1) NETCONFA_IFINDEX': 1, '( 2) NETCONFA_FORWARDING': 1, '( 3) NETCONFA_RP_FILTER': 0, '( 4) NETCONFA_MC_FORWARDING': 0, '( 5) NETCONFA_PROXY_NEIGH': 0, '( 6) NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN': 1} Signed-off-by: Julien Fortin --- ifupdown2/nlmanager/nlmanager.py | 23 +++++++ ifupdown2/nlmanager/nlpacket.py | 100 ++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 3 deletions(-) diff --git a/ifupdown2/nlmanager/nlmanager.py b/ifupdown2/nlmanager/nlmanager.py index 9110a0b..baa0023 100644 --- a/ifupdown2/nlmanager/nlmanager.py +++ b/ifupdown2/nlmanager/nlmanager.py @@ -129,6 +129,9 @@ class NetlinkManager(object): def debug_route(self, enabled): self._debug_set_clear((RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE), enabled) + def debug_netconf(self, enabled): + self._debug_set_clear((RTM_GETNETCONF, RTM_NEWNETCONF), enabled) + def debug_this_packet(self, mtype): if mtype in self.debug: return True @@ -328,6 +331,9 @@ class NetlinkManager(object): elif msgtype == RTM_NEWROUTE or msgtype == RTM_DELROUTE: msg = Route(msgtype, nlpacket.debug, use_color=self.use_color) + elif msgtype in (RTM_GETNETCONF, RTM_NEWNETCONF): + msg = Netconf(msgtype, nlpacket.debug, use_color=self.use_color) + else: raise Exception("RXed unknown netlink message type %s" % msgtype) @@ -1019,3 +1025,20 @@ class NetlinkManager(object): msg.build_message(self.sequence.next(), self.pid) return self.tx_nlpacket_get_response(msg) + + # ======= + # Netconf + # ======= + def netconf_dump(self): + """ + The attribute Netconf.NETCONFA_IFINDEX is available but don't let it fool you + it seems like the kernel doesn't really care about this attribute and will dump + everything according of the requested family (AF_UNSPEC for everything). + Device filtering needs to be done afterwards by the user. + """ + debug = RTM_GETNETCONF in self.debug + msg = Netconf(RTM_GETNETCONF, debug, use_color=self.use_color) + msg.body = pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0) + msg.flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ACK + msg.build_message(self.sequence.next(), self.pid) + return self.tx_nlpacket_get_response(msg) diff --git a/ifupdown2/nlmanager/nlpacket.py b/ifupdown2/nlmanager/nlpacket.py index 470ec88..6515b78 100644 --- a/ifupdown2/nlmanager/nlpacket.py +++ b/ifupdown2/nlmanager/nlpacket.py @@ -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 @@ -2219,7 +2222,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 = { @@ -2299,7 +2304,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: @@ -2433,7 +2438,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 @@ -3721,6 +3726,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 (%d)" % (zfilled_hex(self.family, 2), self.family))) + + class Neighbor(NetlinkPacket): """ Service Header -- 2.39.2