[ovs-dev] [PATCH ovn] ovn-detrace: Decode OVS Interfaces from ofproto/trace dumps.

Mark Michelson mmichels at redhat.com
Sat Nov 16 01:39:33 UTC 2019


Acked-by: Mark Michelson <mmichels at redhat.com>

On 11/15/19 2:24 PM, Dumitru Ceara wrote:
> Two new command line arguments are added to ovn-detrace:
> - "--ovs": which will instruct ovn-detrace to connect to the local OVS
>    db.sock and try to decode input/output ofport values and pretty print
>    the corresponding OVS interfaces.
> - "--ovsdb": which allows the user to point ovn-detrace to other OVS DB
>    remotes (useful when ovn-trace is not run on the hypervisor where
>    ofproto-trace was run.
> 
> Signed-off-by: Dumitru Ceara <dceara at redhat.com>
> ---
>   utilities/ovn-detrace.1.in |  11 +++++
>   utilities/ovn-detrace.in   | 105 +++++++++++++++++++++++++++++++++------------
>   2 files changed, 88 insertions(+), 28 deletions(-)
> 
> diff --git a/utilities/ovn-detrace.1.in b/utilities/ovn-detrace.1.in
> index 2f662d4..b899b63 100644
> --- a/utilities/ovn-detrace.1.in
> +++ b/utilities/ovn-detrace.1.in
> @@ -33,6 +33,17 @@ Otherwise, the default is \fBunix:@RUNDIR@/ovnnb_db.sock\fR, but this
>   default is unlikely to be useful outside of single-machine OVN test
>   environments.
>   .
> +.IP "\fB\-\-ovs=\fR"
> +Also decode flow information (like OVS ofport) from the flows by connecting
> +to the OVS DB.
> +.
> +.IP "\fB\-\-ovsdb=\fIserver\fR"
> +The OVS DB remote to contact if \fB\-\-ovs\f is present.  If the
> +\fBOVS_RUNDIR\fR environment variable is set, its value is used as the
> +default. Otherwise, the default is \fBunix:@RUNDIR@/db.sock\fR, but this
> +default is unlikely to be useful outside of single-machine OVN test
> +environments.
> +.
>   .SH "SEE ALSO"
>   .
>   .BR ovs\-appctl (8), ovn\-sbctl (8), ovn-\-nbctl (8), ovn\-trace (8)
> diff --git a/utilities/ovn-detrace.in b/utilities/ovn-detrace.in
> index c645658..52f6f4f 100755
> --- a/utilities/ovn-detrace.in
> +++ b/utilities/ovn-detrace.in
> @@ -28,6 +28,7 @@ try:
>       from ovs import jsonrpc
>       from ovs.poller import Poller
>       from ovs.stream import Stream
> +    from ovs import dirs
>   except Exception:
>       print("ERROR: Please install the correct Open vSwitch python support")
>       print("       libraries (@VERSION@).")
> @@ -49,7 +50,8 @@ The following options are also available:
>     -h, --help                  display this help message
>     -V, --version               display version information
>     --ovnsb=DATABASE            use DATABASE as southbound DB
> -  --ovnnb=DATABASE            use DATABASE as northbound DB\
> +  --ovnnb=DATABASE            use DATABASE as northbound DB
> +  --ovsdb=DATABASE            use DATABASE as OVS DB\
>   """ % {'argv0': argv0})
>       sys.exit(0)
>   
> @@ -102,15 +104,15 @@ class OVSDB(object):
>       def get_table(self, table_name):
>           return self._idl_conn.tables[table_name]
>   
> -    def _find_row(self, table_name, find_fn):
> +    def _find_rows(self, table_name, find_fn):
>           return filter(find_fn, self.get_table(table_name).rows.values())
>   
>       def _find_rows_by_name(self, table_name, value):
> -        return self._find_row(table_name, lambda row: row.name == value)
> +        return self._find_rows(table_name, lambda row: row.name == value)
>   
>       def find_rows_by_partial_uuid(self, table_name, value):
> -        return self._find_row(table_name,
> -                              lambda row: str(row.uuid).startswith(value))
> +        return self._find_rows(table_name,
> +                               lambda row: str(row.uuid).startswith(value))
>   
>   class CookieHandler(object):
>       def __init__(self, db, table):
> @@ -118,9 +120,7 @@ class CookieHandler(object):
>           self._table = table
>   
>       def get_records(self, cookie):
> -        # Adjust cookie to include leading zeroes if needed.
> -        cookie = cookie.zfill(8)
> -        return self._db.find_rows_by_partial_uuid(self._table, cookie)
> +        return []
>   
>       def print_record(self, record):
>           pass
> @@ -128,7 +128,16 @@ class CookieHandler(object):
>       def print_hint(self, record, db):
>           pass
>   
> -class LogicalFlowHandler(CookieHandler):
> +class CookieHandlerByUUUID(CookieHandler):
> +    def __init__(self, db, table):
> +        super(CookieHandlerByUUUID, self).__init__(db, table)
> +
> +    def get_records(self, cookie):
> +        # Adjust cookie to include leading zeroes if needed.
> +        cookie = cookie.zfill(8)
> +        return self._db.find_rows_by_partial_uuid(self._table, cookie)
> +
> +class LogicalFlowHandler(CookieHandlerByUUUID):
>       def __init__(self, ovnsb_db):
>           super(LogicalFlowHandler, self).__init__(ovnsb_db, 'Logical_Flow')
>   
> @@ -163,7 +172,7 @@ class LogicalFlowHandler(CookieHandler):
>                       output += ' (log)'
>                   print_h(output)
>   
> -class PortBindingHandler(CookieHandler):
> +class PortBindingHandler(CookieHandlerByUUUID):
>       def __init__(self, ovnsb_db):
>           super(PortBindingHandler, self).__init__(ovnsb_db, 'Port_Binding')
>   
> @@ -173,7 +182,7 @@ class PortBindingHandler(CookieHandler):
>                       (pb.logical_port, pb.tunnel_key,
>                        chassis_str(pb.chassis)))
>   
> -class MacBindingHandler(CookieHandler):
> +class MacBindingHandler(CookieHandlerByUUUID):
>       def __init__(self, ovnsb_db):
>           super(MacBindingHandler, self).__init__(ovnsb_db, 'MAC_Binding')
>   
> @@ -182,7 +191,7 @@ class MacBindingHandler(CookieHandler):
>           print_p('MAC Binding: ip "%s", logical_port "%s", mac "%s"' %
>                       (mb.ip, mb.logical_port, mb.mac))
>   
> -class MulticastGroupHandler(CookieHandler):
> +class MulticastGroupHandler(CookieHandlerByUUUID):
>       def __init__(self, ovnsb_db):
>           super(MulticastGroupHandler, self).__init__(ovnsb_db,
>                                                       'Multicast_Group')
> @@ -194,31 +203,47 @@ class MulticastGroupHandler(CookieHandler):
>           print_p('Multicast Group: name "%s", tunnel_key %ld ports: (%s)' %
>                       (mc.name, mc.tunnel_key, mc_ports))
>   
> -class ChassisHandler(CookieHandler):
> +class ChassisHandler(CookieHandlerByUUUID):
>       def __init__(self, ovnsb_db):
>           super(ChassisHandler, self).__init__(ovnsb_db, 'Chassis')
>   
>       def print_record(self, chassis):
>           print_p('Chassis: %s' % (chassis_str([chassis])))
>   
> -def print_sb_record_from_cookie(ovnnb_db, ovnsb_db, cookie_handlers, cookie):
> +class OvsInterfaceHandler(CookieHandler):
> +    def __init__(self, ovs_db):
> +        super(OvsInterfaceHandler, self).__init__(ovs_db, 'Interface')
> +
> +    def get_records(self, ofport):
> +        return self._db._find_rows(self._table,
> +                                   lambda intf: len(intf.ofport) > 0 and
> +                                        str(intf.ofport[0]) == ofport)
> +
> +    def print_record(self, intf):
> +        print_p('OVS Interface: %s (%s)' %
> +            (intf.name, intf.external_ids.get('iface-id')))
> +
> +def print_record_from_cookie(ovnnb_db, cookie_handlers, cookie):
>       for handler in cookie_handlers:
> -        for i, sb_record in enumerate(handler.get_records(cookie)):
> +        for i, record in enumerate(handler.get_records(cookie)):
>               if i > 0:
>                   handler.print('[Duplicate uuid cookie]')
> -            handler.print_record(sb_record)
> -            handler.print_hint(sb_record, ovnnb_db)
> +            handler.print_record(record)
> +            handler.print_hint(record, ovnnb_db)
>   
>   def main():
>       try:
>           options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
> -                                          ['help', 'version', 'ovnsb=', 'ovnnb='])
> +                                          ['help', 'version', 'ovs',
> +                                           'ovnsb=', 'ovnnb=', 'ovsdb='])
>       except getopt.GetoptError, geo:
>           sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
>           sys.exit(1)
>   
>       ovnsb_db = None
>       ovnnb_db = None
> +    ovs_db   = None
> +    ovs      = False
>   
>       for key, value in options:
>           if key in ['-h', '--help']:
> @@ -229,6 +254,10 @@ def main():
>               ovnsb_db = value
>           elif key in ['--ovnnb']:
>               ovnnb_db = value
> +        elif key in ['--ovsdb']:
> +            ovs_db = value
> +        elif key in ['--ovs']:
> +            ovs = True
>           else:
>               sys.exit(0)
>   
> @@ -238,6 +267,8 @@ def main():
>           sys.exit(1)
>   
>       ovn_rundir = os.getenv('OVN_RUNDIR', '@OVN_RUNDIR@')
> +    ovs_rundir = os.getenv('OVS_RUNDIR', dirs.RUNDIR)
> +
>       if not ovnsb_db:
>           ovnsb_db = os.getenv('OVN_SB_DB')
>           if not ovnsb_db:
> @@ -247,6 +278,8 @@ def main():
>           ovnnb_db = os.getenv('OVN_NB_DB')
>           if not ovnnb_db:
>               ovnnb_db = 'unix:%s/ovnnb_db.sock' % ovn_rundir
> +    if ovs and not ovs_db:
> +        ovs_db = 'unix:%s/db.sock' % ovs_rundir
>   
>       ovsdb_ovnsb = OVSDB(ovnsb_db, 'OVN_Southbound')
>       ovsdb_ovnnb = OVSDB(ovnnb_db, 'OVN_Northbound')
> @@ -260,25 +293,41 @@ def main():
>       ]
>   
>       regex_cookie = re.compile(r'^.*cookie 0x([0-9a-fA-F]+)')
> +    regex_handlers = [
> +        (regex_cookie, cookie_handlers)
> +    ]
> +
> +    if ovs:
> +        ovsdb_ovs = OVSDB(ovs_db, 'Open_vSwitch')
> +        regex_inport = re.compile(r'^ *[0-9]+\. *in_port=([0-9])+')
> +        regex_outport = re.compile(r'^ *output:([0-9]+)')
> +        ofport_handlers = [
> +            OvsInterfaceHandler(ovsdb_ovs)
> +        ]
> +        regex_handlers += [
> +            (regex_outport, ofport_handlers),
> +            (regex_inport, ofport_handlers)
> +        ]
> +
>       regex_table_id = re.compile(r'^ *[0-9]+\.')
> -    cookie = None
> +    cookies = []
>       while True:
>           line = sys.stdin.readline()
> -        if cookie:
> -            # Print SB record info when the current flow block ends.
> +        if len(cookies) > 0:
> +            # Print record info when the current flow block ends.
>               if regex_table_id.match(line) or line.strip() == '':
> -                print_sb_record_from_cookie(ovsdb_ovnnb, ovsdb_ovnsb,
> -                                            cookie_handlers, cookie)
> -                cookie = None
> +                for cookie, handlers in cookies:
> +                    print_record_from_cookie(ovsdb_ovnnb, handlers, cookie)
> +                cookies = []
>   
>           print(line.strip())
>           if line == '':
>               break
>   
> -        m = regex_cookie.match(line)
> -        if not m:
> -            continue
> -        cookie = m.group(1)
> +        for regex, handlers in regex_handlers:
> +            m = regex.match(line)
> +            if m:
> +                cookies.append((m.group(1), handlers))
>   
>   
>   if __name__ == "__main__":
> 



More information about the dev mailing list