#! @PYTHON@ # # Copyright (c) 2017 eBay Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import getopt import os import re import sys import time try: from ovs.db import idl from ovs import jsonrpc from ovs.poller import Poller from ovs.stream import Stream except Exception: print("ERROR: Please install the correct Open vSwitch python support") print(" libraries (@VERSION@).") print(" Alternatively, check that your PYTHONPATH is pointing to") print(" the correct location.") sys.exit(1) argv0 = sys.argv[0] def usage(): print """\ %(argv0)s: usage: %(argv0)s < FILE where FILE is output from ovs-appctl ofproto/trace. 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\ """ % {'argv0': argv0} sys.exit(0) class OVSDB(object): @staticmethod def wait_for_db_change(idl): seq = idl.change_seqno stop = time.time() + 10 while idl.change_seqno == seq and not idl.run(): poller = Poller() idl.wait(poller) poller.block() if time.time() >= stop: raise Exception('Retry Timeout') def __init__(self, db_sock, schema_name): self._db_sock = db_sock self._txn = None schema = self._get_schema(schema_name) schema.register_all() self._idl_conn = idl.Idl(db_sock, schema) OVSDB.wait_for_db_change(self._idl_conn) # Initial Sync with DB def _get_schema(self, schema_name): error, strm = Stream.open_block(Stream.open(self._db_sock)) if error: raise Exception("Unable to connect to %s" % self._db_sock) rpc = jsonrpc.Connection(strm) req = jsonrpc.Message.create_request('get_schema', [schema_name]) error, resp = rpc.transact_block(req) rpc.close() if error or resp.error: raise Exception('Unable to retrieve schema.') return idl.SchemaHelper(None, resp.result) 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_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 main(): try: options, args = getopt.gnu_getopt(sys.argv[1:], 'hV', ['help', 'version', 'ovnsb=', 'ovnnb=']) except getopt.GetoptError, geo: sys.stderr.write("%s: %s\n" % (argv0, geo.msg)) sys.exit(1) ovnsb_db = None ovnnb_db = None for key, value in options: if key in ['-h', '--help']: usage() elif key in ['-V', '--version']: print "%s (Open vSwitch) @VERSION@" % argv0 elif key in ['--ovnsb']: ovnsb_db = value elif key in ['--ovnnb']: ovnnb_db = value else: sys.exit(0) if len(args) != 0: sys.stderr.write("%s: non-option argument not supported " "(use --help for help)\n" % argv0) sys.exit(1) ovs_rundir = os.getenv('OVS_RUNDIR', '@RUNDIR@') if not ovnsb_db: ovnsb_db = os.getenv('OVN_SB_DB') if not ovnsb_db: ovnsb_db = 'unix:%s/ovnsb_db.sock' % ovs_rundir if not ovnnb_db: ovnnb_db = os.getenv('OVN_NB_DB') if not ovnnb_db: ovnnb_db = 'unix:%s/ovnnb_db.sock' % ovs_rundir ovsdb_ovnsb = OVSDB(ovnsb_db, 'OVN_Southbound') ovsdb_ovnnb = OVSDB(ovnnb_db, 'OVN_Northbound') regex_cookie = re.compile(r'^.*cookie 0x([0-9a-fA-F]+)') regex_table_id = re.compile(r'^[0-9]+\.') cookie = None while True: line = sys.stdin.readline() if cookie: # print lflow info when the current flow block ends if regex_table_id.match(line) or line.strip() == '': lflow = get_lflow_from_cookie(ovsdb_ovnsb, cookie) print_lflow(lflow, "\t* ") print_lflow_nb_hint(lflow, "\t\t* ", ovsdb_ovnnb) cookie = None print line.strip() if line == "": break m = regex_cookie.match(line) if not m: continue cookie = m.group(1) if __name__ == "__main__": main() # Local variables: # mode: python # End: