From a61d1777cddbe5302d8b090ade6edbf92ef03a82 Mon Sep 17 00:00:00 2001 From: Scott Emery Date: Mon, 29 Aug 2016 11:28:52 -0700 Subject: [PATCH] nlmanager: Provide option to prevent color output Ticket: CM-7361 Reviewed By: CCR- Testing Done: Tested with clag Certain loggers, most notably the syslog, don't allow non-printable characters in their output, and so they convert them to a string of printable characters. For example, the newline character is converted to #012. This results in output that looks like this: 2016-08-29T18:50:46.263178+00:00 act-5712-08 clagd[21539]: RXed RTM_NEWNEIGH, length 68, seq 0, pid 0, flags 0x0#012#012 #033[91mNetlink Header#033[0m#012 1: #033[91m0x44000000#033[0m D... Length 0x00000044 (68)#012 2: #033[91m0x1c000000#033[0m .... Type 0x001c (28 - RTM_NEWNEIGH), Flags 0x0000 ()#012 3: #033[91m0x00000000#033[0m .... Sequence Number 0x00000000 (0)#012 4: #033[91m0x00000000#033[0m .... Process ID 0x00000000 (0)#012 #033[93mService Header#033[0m#012 5: #033[93m0x07000000#033[0m .... Family 0x07 (7)#012 6: #033[93m0x29010000#033[0m )... Interface Index 0x00000129 (297)#012 7: #033[93m0x02000000#033[0m .... State 0x0002 (2), Flags 0x00, Type 0x0000 (0)#012 Attributes#012 8: #033[92m0x0a000200#033[0m .... Length 0x000a (10) padded to 12, Type 0x0002 (2) NDA_LLADDR#012 9: #033[92m0x00020000#033[0m .... 00:02:00:00:00:09#012 10: #033[92m0x00090000#033[0m .... #012 11: #033[94m0x08000900#033[0m .... Length 0x0008 (8), Type 0x0009 (9) NDA_MASTER#012 12: #033[94m0x2b010000#033[0m +... 299#012 13: #033[92m0x14000300#033[0m .... Length 0x0014 (20), Type 0x0003 (3) NDA_CACHEINFO#012 14: #033[92m0x00000000#033[0m .... 0#012 15: #033[92m0x00000000#033[0m .... 0#012 16: #033[92m0x00000000#033[0m .... 0#012 17: #033[92m0x00000000#033[0m .... 0#012#012Attributes Summary#012{'( 2) NDA_LLADDR': '00:02:00:00:00:09',#012 '( 3) NDA_CACHEINFO': (0, 0, 0, 0),#012 '( 9) NDA_MASTER': 299} which is rather hard to interpret. So this patch modifes the nlpacket debug output so that the user can specify whether or not color output should be used by including an extra, optional parameter when instantiating a NetlinkPacket object. The default is for color output, just like before this patch. But if color output is not desired, then no VT100 control sequences will be output. Nor will there be any newline characters embedded in the output. The NetlinkManagerWithListener and NetlinkManager classes were also modified to add the same optional use_color attribute, which defaults to True. Thus when class members which instantiate NetlinkPacket objects are created the appropriate value for the use_color attribute will be applied. I also noticed that the default pid_offset of the NetlinkListener class was 2, when it should have been 1. So I fixed that too. --- nlmanager/nllistener.py | 22 ++++----- nlmanager/nlmanager.py | 43 +++++++++--------- nlmanager/nlpacket.py | 98 ++++++++++++++++++++++++++++------------- 3 files changed, 100 insertions(+), 63 deletions(-) diff --git a/nlmanager/nllistener.py b/nlmanager/nllistener.py index 99033ac..46ffe7c 100644 --- a/nlmanager/nllistener.py +++ b/nlmanager/nllistener.py @@ -14,7 +14,7 @@ log = logging.getLogger(__name__) class NetlinkListener(Thread): - def __init__(self, manager, groups, pid_offset=2): + def __init__(self, manager, groups, pid_offset=1): """ groups controls what types of messages we are interested in hearing To get everything pass: @@ -173,8 +173,8 @@ class NetlinkListener(Thread): class NetlinkManagerWithListener(NetlinkManager): - def __init__(self, groups, start_listener=True): - NetlinkManager.__init__(self) + def __init__(self, groups, start_listener=True, use_color=True): + NetlinkManager.__init__(self, use_color=use_color) self.groups = groups self.workq = Queue() self.netlinkq = [] @@ -289,7 +289,7 @@ class NetlinkManagerWithListener(NetlinkManager): family = socket.AF_UNSPEC debug = RTM_GETADDR in self.debug - addr = Address(RTM_GETADDR, debug) + addr = Address(RTM_GETADDR, debug, use_color=self.use_color) addr.flags = NLM_F_REQUEST | NLM_F_DUMP addr.body = pack('Bxxxi', family, 0) addr.build_message(self.sequence.next(), self.pid) @@ -303,7 +303,7 @@ class NetlinkManagerWithListener(NetlinkManager): family = socket.AF_UNSPEC debug = RTM_GETLINK in self.debug - link = Link(RTM_GETLINK, debug) + link = Link(RTM_GETLINK, debug, use_color=self.use_color) link.flags = NLM_F_REQUEST | NLM_F_DUMP link.body = pack('Bxxxiii', family, 0, 0, 0) link.build_message(self.sequence.next(), self.pid) @@ -317,7 +317,7 @@ class NetlinkManagerWithListener(NetlinkManager): family = socket.AF_UNSPEC debug = RTM_GETNEIGH in self.debug - neighbor = Neighbor(RTM_GETNEIGH, debug) + neighbor = Neighbor(RTM_GETNEIGH, debug, use_color=self.use_color) neighbor.flags = NLM_F_REQUEST | NLM_F_DUMP neighbor.body = pack('Bxxxii', family, 0, 0) neighbor.build_message(self.sequence.next(), self.pid) @@ -331,7 +331,7 @@ class NetlinkManagerWithListener(NetlinkManager): family = socket.AF_UNSPEC debug = RTM_GETROUTE in self.debug - route = Route(RTM_GETROUTE, debug) + route = Route(RTM_GETROUTE, debug, use_color=self.use_color) route.flags = NLM_F_REQUEST | NLM_F_DUMP route.body = pack('Bxxxii', family, 0, 0) route.build_message(self.sequence.next(), self.pid) @@ -479,16 +479,16 @@ class NetlinkManagerWithListener(NetlinkManager): debug = self.debug_this_packet(msgtype) if msgtype == RTM_NEWLINK or msgtype == RTM_DELLINK: - msg = Link(msgtype, debug) + msg = Link(msgtype, debug, use_color=self.use_color) elif msgtype == RTM_NEWADDR or msgtype == RTM_DELADDR: - msg = Address(msgtype, debug) + msg = Address(msgtype, debug, use_color=self.use_color) elif msgtype == RTM_NEWNEIGH or msgtype == RTM_DELNEIGH: - msg = Neighbor(msgtype, debug) + msg = Neighbor(msgtype, debug, use_color=self.use_color) elif msgtype == RTM_NEWROUTE or msgtype == RTM_DELROUTE: - msg = Route(msgtype, debug) + msg = Route(msgtype, debug, use_color=self.use_color) else: log.warning('RXed unknown netlink message type %s' % msgtype) diff --git a/nlmanager/nlmanager.py b/nlmanager/nlmanager.py index c9aaa86..daad410 100644 --- a/nlmanager/nlmanager.py +++ b/nlmanager/nlmanager.py @@ -40,7 +40,7 @@ class Sequence(object): class NetlinkManager(object): - def __init__(self, pid_offset=0): + def __init__(self, pid_offset=0, use_color=True): # PID_MAX_LIMIT is 2^22 allowing 1024 sockets per-pid. We default to 0 # in the upper space (top 10 bits), which will simply be the PID. Other # NetlinkManager instantiations in the same process can choose other @@ -50,6 +50,7 @@ class NetlinkManager(object): self.shutdown_flag = False self.ifindexmap = {} self.tx_socket = None + self.use_color = use_color # debugs self.debug = {} @@ -287,16 +288,16 @@ class NetlinkManager(object): nle_intr_count = 0 if msgtype == RTM_NEWLINK or msgtype == RTM_DELLINK: - msg = Link(msgtype, nlpacket.debug) + msg = Link(msgtype, nlpacket.debug, use_color=self.use_color) elif msgtype == RTM_NEWADDR or msgtype == RTM_DELADDR: - msg = Address(msgtype, nlpacket.debug) + msg = Address(msgtype, nlpacket.debug, use_color=self.use_color) elif msgtype == RTM_NEWNEIGH or msgtype == RTM_DELNEIGH: - msg = Neighbor(msgtype, nlpacket.debug) + msg = Neighbor(msgtype, nlpacket.debug, use_color=self.use_color) elif msgtype == RTM_NEWROUTE or msgtype == RTM_DELROUTE: - msg = Route(msgtype, nlpacket.debug) + msg = Route(msgtype, nlpacket.debug, use_color=self.use_color) else: raise Exception("RXed unknown netlink message type %s" % msgtype) @@ -326,19 +327,19 @@ class NetlinkManager(object): """ if rtm_type == RTM_GETADDR: - msg = Address(rtm_type, debug) + msg = Address(rtm_type, debug, use_color=self.use_color) msg.body = pack('Bxxxi', family, 0) elif rtm_type == RTM_GETLINK: - msg = Link(rtm_type, debug) + msg = Link(rtm_type, debug, use_color=self.use_color) msg.body = pack('Bxxxiii', family, 0, 0, 0) elif rtm_type == RTM_GETNEIGH: - msg = Neighbor(rtm_type, debug) + msg = Neighbor(rtm_type, debug, use_color=self.use_color) msg.body = pack('Bxxxii', family, 0, 0) elif rtm_type == RTM_GETROUTE: - msg = Route(rtm_type, debug) + msg = Route(rtm_type, debug, use_color=self.use_color) msg.body = pack('Bxxxii', family, 0, 0) else: @@ -384,7 +385,7 @@ class NetlinkManager(object): if routes: for (afi, ip, mask, nexthop, interface_index) in routes: - route = Route(rtm_command, debug) + route = Route(rtm_command, debug, use_color=self.use_color) route.flags = NLM_F_REQUEST | NLM_F_CREATE route.body = pack('BBBBBBBBi', afi, mask, 0, 0, table, protocol, route_scope, route_type, 0) @@ -404,7 +405,7 @@ class NetlinkManager(object): for (route_key, value) in ecmp_routes.iteritems(): (afi, ip, mask) = route_key - route = Route(rtm_command, debug) + route = Route(rtm_command, debug, use_color=self.use_color) route.flags = NLM_F_REQUEST | NLM_F_CREATE route.body = pack('BBBBBBBBi', afi, mask, 0, 0, table, protocol, route_scope, route_type, 0) @@ -438,7 +439,7 @@ class NetlinkManager(object): - IPv6Address """ # Transmit a RTM_GETROUTE to query for the route we want - route = Route(RTM_GETROUTE, debug) + route = Route(RTM_GETROUTE, debug, use_color=self.use_color) route.flags = NLM_F_REQUEST | NLM_F_ACK # Set everything in the service header as 0 other than the afi @@ -478,7 +479,7 @@ class NetlinkManager(object): """ debug = RTM_GETLINK in self.debug - link = Link(RTM_GETLINK, debug) + link = Link(RTM_GETLINK, debug, use_color=self.use_color) link.flags = NLM_F_REQUEST | NLM_F_ACK link.body = pack('=Bxxxiii', socket.AF_UNSPEC, 0, 0, 0) link.add_attribute(Link.IFLA_IFNAME, ifname) @@ -507,7 +508,7 @@ class NetlinkManager(object): """ debug = RTM_NEWLINK in self.debug - link = Link(RTM_NEWLINK, debug) + link = Link(RTM_NEWLINK, debug, use_color=self.use_color) link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK link.body = pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0) link.add_attribute(Link.IFLA_IFNAME, ifname) @@ -556,7 +557,7 @@ class NetlinkManager(object): """ debug = RTM_GETLINK in self.debug - link = Link(RTM_GETLINK, debug) + link = Link(RTM_GETLINK, debug, use_color=self.use_color) link.flags = NLM_F_DUMP | NLM_F_REQUEST link.body = pack('Bxxxiii', socket.AF_BRIDGE, 0, 0, 0) @@ -672,7 +673,7 @@ class NetlinkManager(object): bridge_flags = 0 vlan_info_flags = 0 - link = Link(msgtype, debug) + link = Link(msgtype, debug, use_color=self.use_color) link.flags = NLM_F_REQUEST | NLM_F_ACK link.body = pack('Bxxxiii', socket.AF_BRIDGE, ifindex, 0, 0) @@ -737,7 +738,7 @@ class NetlinkManager(object): debug = RTM_NEWLINK in self.debug if_change = Link.IFF_UP - link = Link(RTM_NEWLINK, debug) + link = Link(RTM_NEWLINK, debug, use_color=self.use_color) link.flags = NLM_F_REQUEST | NLM_F_ACK link.body = pack('=BxxxiLL', socket.AF_UNSPEC, 0, if_flags, if_change) link.add_attribute(Link.IFLA_IFNAME, ifname) @@ -753,7 +754,7 @@ class NetlinkManager(object): debug = RTM_NEWLINK in self.debug - link = Link(RTM_NEWLINK, debug) + link = Link(RTM_NEWLINK, debug, use_color=self.use_color) link.flags = NLM_F_REQUEST | NLM_F_ACK link.body = pack('=BxxxiLL', socket.AF_UNSPEC, 0, 0, 0) link.add_attribute(Link.IFLA_IFNAME, ifname) @@ -768,7 +769,7 @@ class NetlinkManager(object): debug = RTM_NEWNEIGH in self.debug service_hdr_flags = 0 - nbr = Neighbor(RTM_NEWNEIGH, debug) + nbr = Neighbor(RTM_NEWNEIGH, debug, use_color=self.use_color) nbr.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK nbr.family = afi nbr.body = pack('=BxxxiHBB', afi, ifindex, Neighbor.NUD_REACHABLE, service_hdr_flags, Route.RTN_UNICAST) @@ -781,7 +782,7 @@ class NetlinkManager(object): debug = RTM_DELNEIGH in self.debug service_hdr_flags = 0 - nbr = Neighbor(RTM_DELNEIGH, debug) + nbr = Neighbor(RTM_DELNEIGH, debug, use_color=self.use_color) nbr.flags = NLM_F_REQUEST | NLM_F_ACK nbr.family = afi nbr.body = pack('=BxxxiHBB', afi, ifindex, Neighbor.NUD_REACHABLE, service_hdr_flags, Route.RTN_UNICAST) @@ -809,7 +810,7 @@ class NetlinkManager(object): if ageing: info_data[Link.IFLA_VXLAN_AGEING] = int(ageing) - link = Link(RTM_NEWLINK, debug) + link = Link(RTM_NEWLINK, debug, use_color=self.use_color) link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK link.body = pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0) link.add_attribute(Link.IFLA_IFNAME, ifname) diff --git a/nlmanager/nlpacket.py b/nlmanager/nlpacket.py index 30ff449..fa801db 100644 --- a/nlmanager/nlpacket.py +++ b/nlmanager/nlpacket.py @@ -164,7 +164,10 @@ def data_to_color_text(line_number, color, data, extra=''): else: in_ascii.append('.') - return ' %2d: \033[%dm0x%02x%02x%02x%02x\033[0m %s %s' % (line_number, color, c1, c2, c3, c4, ''.join(in_ascii), extra) + 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): @@ -1235,13 +1238,14 @@ class NetlinkPacket(object): RTM_GETQDISC : 'RTM_GETQDISC' } - def __init__(self, msgtype, debug, owner_logger=None): + 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 if owner_logger: self.log = owner_logger @@ -1346,9 +1350,11 @@ class NetlinkPacket(object): header_data = self.header_data # Print the netlink header in red - color = red netlink_header_length = 16 - self.dump_buffer.append(" \033[%dmNetlink Header\033[0m" % color) + 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 @@ -1384,7 +1390,7 @@ class NetlinkPacket(object): if self.debug: self.dump_buffer.append(" Attributes") - color = green + color = green if self.use_color else None data = self.msg_data[self.LEN:] @@ -1413,10 +1419,11 @@ class NetlinkPacket(object): self.line_number = attr.dump_lines(self.dump_buffer, self.line_number, color) # Alternate back and forth between green and blue - if color == green: - color = blue - else: - color = green + if self.use_color: + if color == green: + color = blue + else: + color = green data = data[attr_end:] @@ -1484,6 +1491,14 @@ class NetlinkPacket(object): (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+1) + 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 = {} @@ -1495,8 +1510,18 @@ class NetlinkPacket(object): key_string = "(%2d) %s" % (attr_type, self.get_attr_string(attr_type)) attr_string[key_string] = attr_obj.get_pretty_value() - self.log.debug("%s\n%s\n\nAttributes Summary\n%s\n" % - (desc, '\n'.join(self.dump_buffer), pformat(attr_string))) + 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): @@ -1557,8 +1582,8 @@ class Address(NetlinkPacket): IFA_F_PERMANENT : 'IFA_F_PERMANENT' } - def __init__(self, msgtype, debug=False, logger=None): - NetlinkPacket.__init__(self, msgtype, debug, logger) + 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) @@ -1573,8 +1598,10 @@ class Address(NetlinkPacket): unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: - color = yellow - self.dump_buffer.append(" \033[%dmService Header\033[0m" % color) + 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: @@ -1670,8 +1697,8 @@ class Error(NetlinkPacket): NLE_DUMP_INTR : 'NLE_DUMP_INTR' } - def __init__(self, msgtype, debug=False, logger=None): - NetlinkPacket.__init__(self, msgtype, debug, logger) + 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) @@ -1686,8 +1713,10 @@ class Error(NetlinkPacket): unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: - color = yellow - self.dump_buffer.append(" \033[%dmService Header\033[0m" % color) + 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): @@ -2328,8 +2357,8 @@ class Link(NetlinkPacket): RTEXT_FILTER_SKIP_STATS : 'RTEXT_FILTER_SKIP_STATS' } - def __init__(self, msgtype, debug=False, logger=None): - NetlinkPacket.__init__(self, msgtype, debug, logger) + 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) @@ -2379,8 +2408,11 @@ class Link(NetlinkPacket): unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: - color = yellow - self.dump_buffer.append(" \033[%dmService Header\033[0m" % color) + 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 (%d), Device Type %s (%d - %s)" % \ @@ -2489,8 +2521,8 @@ class Neighbor(NetlinkPacket): NUD_PERMANENT : 'NUD_PERMANENT' } - def __init__(self, msgtype, debug=False, logger=None): - NetlinkPacket.__init__(self, msgtype, debug, logger) + 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) @@ -2509,8 +2541,10 @@ class Neighbor(NetlinkPacket): unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: - color = yellow - self.dump_buffer.append(" \033[%dmService Header\033[0m" % color) + 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: @@ -2714,8 +2748,8 @@ class Route(NetlinkPacket): RTM_F_PREFIX : 'RTM_F_PREFIX' } - def __init__(self, msgtype, debug=False, logger=None): - NetlinkPacket.__init__(self, msgtype, debug, logger) + 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) self.family = None @@ -2799,8 +2833,10 @@ class Route(NetlinkPacket): unpack(self.PACK, self.msg_data[:self.LEN]) if self.debug: - color = yellow - self.dump_buffer.append(" \033[%dmService Header\033[0m" % color) + 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: