Commit eb25a7da639e ("Improve debuggability of OVN to OpenFlow translations.") added cookies for Port_Binding, Mac_Binding, Multicast_Group, Chassis records to the OpenfFlow entries they generate.
Add support for parsing such cookies in ovn-detrace too. Also: - refactor ovn-detrace to allow a more generic way of defining cookie handlers. - properly handle potential collisions between cookie -> UUID mappings. - change print statements to print() calls. - add custom printing functions to simplify prefixing outputs. Signed-off-by: Dumitru Ceara <dce...@redhat.com> --- utilities/ovn-detrace.in | 197 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 135 insertions(+), 62 deletions(-) diff --git a/utilities/ovn-detrace.in b/utilities/ovn-detrace.in index 34b6b0e..00d162f 100755 --- a/utilities/ovn-detrace.in +++ b/utilities/ovn-detrace.in @@ -14,6 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import print_function + +import functools import getopt import os import re @@ -37,7 +40,7 @@ argv0 = sys.argv[0] def usage(): - print """\ + print("""\ %(argv0)s: usage: %(argv0)s < FILE where FILE is output from ovs-appctl ofproto/trace. @@ -47,9 +50,21 @@ The following options are also available: -V, --version display version information --ovnsb=DATABASE use DATABASE as southbound DB --ovnnb=DATABASE use DATABASE as northbound DB\ -""" % {'argv0': argv0} +""" % {'argv0': argv0}) sys.exit(0) +pprint = functools.partial(print, ' * ') +hprint = functools.partial(print, ' * ') + +def datapath_str(datapath): + return '"%s" (%s)' % (str(datapath.external_ids.get('name')), + datapath.uuid) + +def chassis_str(chassis): + if len(chassis) == 0: + return '' + ch = chassis[0] + return 'chassis-name "%s", chassis-str "%s"' % (ch.name, ch.hostname) class OVSDB(object): @staticmethod @@ -87,59 +102,112 @@ class OVSDB(object): def get_table(self, table_name): return self._idl_conn.tables[table_name] - def _find_row(self, table_name, find): - return next( - (row for row in self.get_table(table_name).rows.values() - if find(row)), None) + def _find_row(self, table_name, find_fn): + return filter(find_fn, self.get_table(table_name).rows.values()) - def _find_row_by_name(self, table_name, value): + def _find_rows_by_name(self, table_name, value): return self._find_row(table_name, lambda row: row.name == value) - def find_row_by_partial_uuid(self, table_name, value): - return self._find_row(table_name, lambda row: value in str(row.uuid)) - - -def get_lflow_from_cookie(ovnsb_db, cookie): - return ovnsb_db.find_row_by_partial_uuid('Logical_Flow', cookie) - - -def print_lflow(lflow, prefix): - ldp_uuid = lflow.logical_datapath.uuid - ldp_name = str(lflow.logical_datapath.external_ids.get('name')) - - print '%sLogical datapath: "%s" (%s) [%s]' % (prefix, - ldp_name, - ldp_uuid, - lflow.pipeline) - print "%sLogical flow: table=%s (%s), priority=%s, " \ - "match=(%s), actions=(%s)" % (prefix, - lflow.table_id, - lflow.external_ids.get('stage-name'), - lflow.priority, - str(lflow.match).strip('"'), - str(lflow.actions).strip('"')) - - -def print_lflow_nb_hint(lflow, prefix, ovnnb_db): - external_ids = lflow.external_ids - if external_ids.get('stage-name') in ['ls_in_acl', - 'ls_out_acl']: - acl_hint = external_ids.get('stage-hint') - if not acl_hint: - return - acl = ovnnb_db.find_row_by_partial_uuid('ACL', acl_hint) - if not acl: - return - output = "%sACL: %s, priority=%s, " \ - "match=(%s), %s" % (prefix, - acl.direction, - acl.priority, - acl.match.strip('"'), - acl.action) - if acl.log: - output += ' (log)' - print output - + def find_rows_by_partial_uuid(self, table_name, value): + return self._find_row(table_name, + lambda row: str(row.uuid).startswith(value)) + +class CookieHandler(object): + def __init__(self, db, table): + self._db = db + 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) + + def print_record(self, record): + pass + + def print_hint(self, record, db): + pass + +class LogicalFlowHandler(CookieHandler): + def __init__(self, ovnsb_db): + super(LogicalFlowHandler, self).__init__(ovnsb_db, 'Logical_Flow') + + def print_record(self, lflow): + pprint('Logical datapath: %s [%s]' % + (datapath_str(lflow.logical_datapath), lflow.pipeline)) + pprint('Logical flow: table=%s (%s), priority=%s, ' + 'match=(%s), actions=(%s)' % + (lflow.table_id, lflow.external_ids.get('stage-name'), + lflow.priority, + str(lflow.match).strip('"'), + str(lflow.actions).strip('"'))) + + def print_hint(self, lflow, ovnnb_db): + external_ids = lflow.external_ids + if external_ids.get('stage-name') in ['ls_in_acl', + 'ls_out_acl']: + acl_hint = external_ids.get('stage-hint') + if not acl_hint: + return + for i, acl in enumerate( + ovnnb_db.find_rows_by_partial_uuid('ACL', acl_hint)): + if i > 0: + hprint('[Duplicate uuid ACL hint]') + + output = 'ACL: %s, priority=%s, ' \ + 'match=(%s), %s' % (acl.direction, + acl.priority, + acl.match.strip('"'), + acl.action) + if acl.log: + output += ' (log)' + hprint(output) + +class PortBindingHandler(CookieHandler): + def __init__(self, ovnsb_db): + super(PortBindingHandler, self).__init__(ovnsb_db, 'Port_Binding') + + def print_record(self, pb): + pprint('Logical datapath: %s' % (datapath_str(pb.datapath))) + pprint('Port Binding: logical_port "%s", tunnel_key %ld, %s' % + (pb.logical_port, pb.tunnel_key, + chassis_str(pb.chassis))) + +class MacBindingHandler(CookieHandler): + def __init__(self, ovnsb_db): + super(MacBindingHandler, self).__init__(ovnsb_db, 'MAC_Binding') + + def print_record(self, mb): + pprint('Logical datapath: %s' % (datapath_str(mb.datapath))) + pprint('MAC Binding: ip "%s", logical_port "%s", mac "%s"' % + (mb.ip, mb.logical_port, mb.mac)) + +class MulticastGroupHandler(CookieHandler): + def __init__(self, ovnsb_db): + super(MulticastGroupHandler, self).__init__(ovnsb_db, + 'Multicast_Group') + + def print_record(self, mc): + mc_ports = ', '.join([pb.logical_port for pb in mc.ports]) + + pprint('Logical datapath: %s' % (datapath_str(mc.datapath))) + pprint('Multicast Group: name "%s", tunnel_key %ld ports: (%s)' % + (mc.name, mc.tunnel_key, mc_ports)) + +class ChassisHandler(CookieHandler): + def __init__(self, ovnsb_db): + super(ChassisHandler, self).__init__(ovnsb_db, 'Chassis') + + def print_record(self, chassis): + pprint('%sChassis: %s' % (chassis_str([chassis]))) + +def print_sb_record_from_cookie(ovnnb_db, ovnsb_db, cookie_handlers, cookie): + for handler in cookie_handlers: + for i, sb_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) def main(): try: @@ -156,7 +224,7 @@ def main(): if key in ['-h', '--help']: usage() elif key in ['-V', '--version']: - print "%s (Open vSwitch) @VERSION@" % argv0 + print("%s (Open vSwitch) @VERSION@" % argv0) elif key in ['--ovnsb']: ovnsb_db = value elif key in ['--ovnnb']: @@ -183,6 +251,14 @@ def main(): ovsdb_ovnsb = OVSDB(ovnsb_db, 'OVN_Southbound') ovsdb_ovnnb = OVSDB(ovnnb_db, 'OVN_Northbound') + cookie_handlers = [ + LogicalFlowHandler(ovsdb_ovnsb), + PortBindingHandler(ovsdb_ovnsb), + MacBindingHandler(ovsdb_ovnsb), + MulticastGroupHandler(ovsdb_ovnsb), + ChassisHandler(ovsdb_ovnsb) + ] + regex_cookie = re.compile(r'^.*cookie 0x([0-9a-fA-F]+)') regex_table_id = re.compile(r'^[0-9]+\.') cookie = None @@ -194,16 +270,13 @@ def main(): line = line.strip() - if cookie: - # print lflow info when the current flow block ends - if regex_table_id.match(line): - lflow = get_lflow_from_cookie(ovsdb_ovnsb, cookie) - if lflow: - print_lflow(lflow, " * ") - print_lflow_nb_hint(lflow, " * ", ovsdb_ovnnb) - cookie = None + # Print SB record info when the current flow block ends. + if cookie and regex_table_id.match(line): + print_sb_record_from_cookie(ovsdb_ovnnb, ovsdb_ovnsb, + cookie_handlers, cookie) + cookie = None - print line + print(line) m = regex_cookie.match(line) if m: _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev