*.iml
*.iws
.idea
+.pydevproject
*.pyc
log.html
output.xml
--- /dev/null
+VIF_TYPE_TO_PREFIX = {
+ 'ovs':'tap',
+ 'vhost_user':'vhu'
+ }
+
+VIF_TYPE = 'neutron-binding:vif-type'
+IFACE_PARENT = 'odl-interface:parent-interface'
+VIF_TYPE = 'neutron-binding:vif-type'
+IFTYPE_VLAN = 'iana-if-type:l2vlan'
+IFTYPE_TUNNEL = 'iana-if-type:tunnel'
+
+NODE_GROUP = 'flow-node-inventory:group'
+NODE_TABLE = 'flow-node-inventory:table'
+
+DSM_FILE = 0
+DSM_DSTYPE = 1
+DSM_PATH = 2
+DSM_ROOT1 = 3
+DSM_ROOT2 = 4
+"""
+ source map to fetch data from data store.
+ Format is:
+ resource-key-name:[filename,datastore_type,resource-url,container-name,list-title]
+"""
+DSMAP = {
+ 'bindings': ['service-bindings.log', 'config',
+ 'interface-service-bindings:service-bindings',
+ 'service-bindings', 'services-info'],
+ 'dpnendpoints': ['dpn-endpoints.log', 'config', 'itm-state:dpn-endpoints',
+ 'dpn-endpoints', 'DPN-TEPs-info'],
+ 'elaninstances': ['elan-instances.log', 'config', 'elan:elan-instances',
+ 'elan-instances', 'elan-instance'],
+ 'elaninterfaces': ['elan-interfaces.log', 'config', 'elan:elan-interfaces',
+ 'elan-interfaces', 'elan-interface'],
+ 'fibentries': ['fibentries.log', 'config', 'odl-fib:fibEntries',
+ 'fibEntries', 'vrfTables'],
+ 'ifconfig': ['iface-config.log', 'config', 'ietf-interfaces:interfaces',
+ 'interfaces', 'interface'],
+ 'ifindexes': ['ifindexes.log', 'operational',
+ 'odl-interface-meta:if-indexes-interface-map',
+ 'if-indexes-interface-map', 'if-index-interface'],
+ 'ifstate': ['ifstate.log', 'operational',
+ 'ietf-interfaces:interfaces-state',
+ 'interfaces-state', 'interface'],
+ 'inventory': ['inventory-config.log', 'config',
+ 'opendaylight-inventory:nodes', 'nodes', 'node'],
+ 'l3vpn': ['l3vpn-config.log', 'config', 'l3vpn:vpn-interfaces',
+ 'vpn-interfaces', 'vpn-interface'],
+ 'neutronports': ['neutron-ports.log', 'config', 'neutron:neutron/ports',
+ 'ports', 'port'],
+ 'neutronvpn-portip': ['neutronvpn-portip-port.log', 'config',
+ 'neutronvpn:neutron-vpn-portip-port-data',
+ 'neutron-vpn-portip-port-data',
+ 'vpn-portip-to-port'],
+ 'tunconfig': ['tunnel-config.log', 'config', 'itm-state:tunnel-list',
+ 'tunnel-list', 'internal-tunnel'],
+ 'tunconfig-external': ['tunnel-config-external.log', 'config',
+ 'itm-state:external-tunnel-list',
+ 'external-tunnel-list', 'external-tunnel'],
+ 'tunstate': ['tunnel-state.log', 'operational', 'itm-state:tunnels_state',
+ 'tunnels_state', 'state-tunnel-list'],
+ 'vpninstance-to-vpnid': ['vpninstance-to-vpnid.log', 'config',
+ 'odl-l3vpn:vpn-instance-to-vpn-id',
+ 'vpn-instance-to-vpn-id', 'vpn-instance'],
+ 'vpninterfaces': ['vpn-interfaces.log', 'config', 'l3vpn:vpn-interfaces',
+ 'vpn-interfaces', 'vpn-interface']
+}
+
+TABLE_MAP = {
+ 'ifm': [0, 17, 220],
+ 'l3vpn': [19, 20, 21, 22, 36, 81],
+ 'elan': [50, 51, 52, 55],
+ 'acl': [211, 212, 213, 214, 215, 241, 242, 243, 244, 245]
+}
--- /dev/null
+import collections
+import constants as const
+import ds_get_data as dsg
+import flow_parser as fp
+import json
+import netvirt_utils as utils
+import ovs_get_data as og
+
+
+# Required
+ifaces = None
+ifstates = None
+
+#Optional
+ports = {}
+tunnels = {}
+confNodes = {}
+operNodes = {}
+
+
+def by_ifname(ifname):
+ print ifname
+ ifstate = ifstates.get(ifname)
+ iface = ifaces.get(ifname)
+ port = None
+ tunnel = None
+ tunState = None
+ if iface.get('type') == const.IFTYPE_VLAN:
+ ports = dsg.get_neutron_ports()
+ port = ports.get(ifname)
+ elif iface.get('type') == const.IFTYPE_TUNNEL:
+ tunnels = dsg.get_config_tunnels()
+ tunnel = tunnels.get(ifname)
+ tunStates = dsg.get_tunnel_states()
+ tunState = tunStates.get(ifname)
+ else:
+ print "UNSUPPORTED IfType"
+ return iface,ifstate,port,tunnel,tunState
+
+
+def print_keys():
+ print "InterfaceNames: ", ifaces.keys()
+ print
+ print "IfStateNames: ", ifstates.keys()
+
+
+def analyze_interface(ifname=None):
+ global ifaces,ifstates
+ ifaces = dsg.get_config_interfaces()
+ ifstates = dsg.get_interface_states()
+ if not ifname:
+ print_keys()
+ exit(1)
+ ifname = ifname[1]
+ iface,ifstate,port,tunnel,tunState = by_ifname(ifname)
+ print "InterfaceConfig: "
+ utils.pretty_print(iface)
+ print "InterfaceState: "
+ utils.pretty_print(ifstate)
+ if port:
+ print "NeutronPort: "
+ utils.pretty_print(port)
+ analyze_neutron_port(port, iface, ifstate)
+ return
+ if tunnel:
+ print "Tunnel: "
+ utils.pretty_print(tunnel)
+ if tunState:
+ print "TunState: "
+ utils.pretty_print(tunState)
+ if ifstate:
+ ncId = ifstate.get('lower-layer-if')[0]
+ nodeId = ncId[:ncId.rindex(':')]
+ analyze_inventory(nodeId, True, ncId, ifname)
+ #analyze_inventory(nodeId, False, ncId, ifname)
+
+def analyze_neutron_port(port, iface, ifstate):
+ for flow in utils.sort(get_all_flows(['all']), 'table'):
+ if ((flow.get('ifname') == port['uuid']) or
+ (flow.get('lport') and flow['lport'] == ifstate.get('if-index')) or
+ (iface['name'] == flow.get('ifname'))):
+ result = 'Table:{},FlowId:{}{}'.format(
+ flow['table'], flow['id'],
+ utils.show_optionals(flow))
+ print result
+ print 'Flow:', json.dumps(parse_flow(flow.get('flow')))
+
+
+def analyze_inventory(nodeId, isConfig=True, ncId=None, ifName=None):
+ if isConfig:
+ nodes = dsg.get_inventory_config()
+ print "Inventory Config:"
+ else:
+ print "Inventory Operational:"
+ nodes = dsg.get_inventory_oper()
+ node = nodes.get(nodeId)
+ tables = node.get(const.NODE_TABLE)
+ groups = node.get(const.NODE_GROUP)
+ flow_list = []
+ print "Flows:"
+ for table in tables:
+ for flow in table.get('flow'):
+ if not ifName or ifName in utils.nstr(flow.get('flow-name')):
+ flow_dict = {}
+ flow_dict['table'] = table['id']
+ flow_dict['id'] = flow['id']
+ flow_dict['name'] = flow.get('flow-name')
+ flow_dict['flow'] = flow
+ flow_list.append(flow_dict)
+ flows = sorted(flow_list, key=lambda x: x['table'])
+ for flow in flows:
+ print 'Table:', flow['table']
+ print 'FlowId:', flow['id'], 'FlowName:', flow.get('name')
+
+
+def get_dpn_host_mapping(oper_nodes=None):
+ nodes_dict = {}
+ nodes = oper_nodes or dsg.get_inventory_oper()
+ for node in nodes.itervalues():
+ dpnid = utils.get_dpn_from_ofnodeid(node['id'])
+ nodes_dict[dpnid] = node.get('flow-node-inventory:description', '')
+ return nodes_dict
+
+
+def get_groups(ofnodes=None):
+ of_nodes = ofnodes or dsg.get_inventory_config()
+ key ='group-id'
+ group_dict = collections.defaultdict(dict)
+ for node in of_nodes.itervalues():
+ dpnid = utils.get_dpn_from_ofnodeid(node['id'])
+ for group in node[const.NODE_GROUP]:
+ if group_dict.get(dpnid) and group_dict.get(dpnid).get(group[key]):
+ print 'Duplicate:', dpnid, group[key]
+ group_dict[dpnid][group[key]] = group
+ return dict(group_dict)
+
+
+def get_stale_flows(modules=['ifm']):
+ if not modules:
+ return 'No modules specified'
+ ifaces = {}
+ ifstates = {}
+ ifindexes = {}
+ bindings = {}
+ einsts = {}
+ eifaces = {}
+ fibentries = {}
+ vpnids = {}
+ vpninterfaces = {}
+ groups = {}
+ table_list = list(set([table for module in modules for table in const.TABLE_MAP[module]]))
+ ##table_list = [214, 244]
+ of_nodes = dsg.get_inventory_config()
+ if 'ifm' in modules:
+ ifaces = dsg.get_config_interfaces()
+ ifstates = dsg.get_interface_states()
+ if 'l3vpn' in modules:
+ ifaces = ifaces or dsg.get_config_interfaces()
+ ifindexes = ifindexes or dsg.get_ifindexes()
+ fibentries = fibentries or dsg.get_fibentries_by_label()
+ vpnids = vpnids or dsg.get_vpnids()
+ vpninterfaces = vpninterfaces or dsg.get_vpninterfaces()
+ groups = groups or get_groups(of_nodes)
+ if 'acl' in modules:
+ ifaces = ifaces or dsg.get_config_interfaces()
+ ifindexes = ifindexes or dsg.get_ifindexes()
+ einsts = einsts or dsg.get_elan_instances()
+ eifaces = eifaces or dsg.get_elan_interfaces()
+ if 'elan' in modules:
+ ifaces = ifaces or dsg.get_config_interfaces()
+ einsts = einsts or dsg.get_elan_instances()
+ eifaces = eifaces or dsg.get_elan_interfaces()
+ ifindexes = ifindexes or dsg.get_ifindexes()
+ stale_flows = []
+ for node in of_nodes.itervalues():
+ tables = [x for x in node[const.NODE_TABLE] if x['id'] in table_list]
+ for table in tables:
+ for flow in table.get('flow', []):
+ flow_dict = None
+ flow_info = {}
+ flow_info['dpnid'] = utils.get_dpn_from_ofnodeid(node['id'])
+ if 'ifm' in modules and table['id'] in const.TABLE_MAP['ifm']:
+ flow_dict = fp.stale_ifm_flow(flow, flow_info, ifaces, ifstates)
+ if 'l3vpn' in modules and table['id'] in const.TABLE_MAP['l3vpn']:
+ flow_dict = fp.stale_l3vpn_flow(flow, flow_info, groups, ifaces, ifindexes, vpnids, vpninterfaces, fibentries)
+ if 'elan' in modules and table['id'] in const.TABLE_MAP['elan']:
+ flow_dict = fp.stale_elan_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces)
+ if 'acl' in modules and table['id'] in const.TABLE_MAP['acl']:
+ flow_dict = fp.stale_acl_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces)
+ if flow_dict is not None:
+ stale_flows.append(flow_dict)
+
+ return stale_flows
+
+
+def show_stale_bindings():
+ stale_ids, bindings = get_stale_bindings()
+ for iface_id in sorted(stale_ids):
+ for binding in bindings[iface_id].itervalues():
+ #if binding.get('bound-services'):
+ path = get_data_path('bindings', binding)
+ print json.dumps(bindings[iface_id])
+ print('http://192.168.2.32:8383/restconf/config/{}'.format(path))
+
+
+def get_stale_bindings():
+ ifaces = dsg.get_config_interfaces()
+ bindings, orphans = dsg.get_service_bindings()
+ return set(bindings.keys()) - set(ifaces.keys()), bindings
+
+
+def get_ips_for_iface(nports, ifname):
+ ips = []
+ port = nports.get(ifname) if ifname else None
+ fixed_ips = port.get('fixed-ips', []) if port else []
+ for fixed_ip in fixed_ips:
+ ips.append(fixed_ip['ip-address'])
+ return ips
+
+
+def show_link_flow_binding():
+ stale_ids, bindings = get_stale_bindings()
+ flows = get_stale_flows()
+ print len(stale_ids), len(flows)
+ for flow in flows:
+ if flow['ifname'] in stale_ids and 'bound-services' in bindings[flow['ifname']]:
+ print 'Flow with binding: ', flow['ifname']
+ else:
+ print 'Flow without binding: ', flow['ifname']
+
+
+def show_stale_flows(sort_by='table'):
+ compute_map = get_dpn_host_mapping()
+ nports = dsg.get_neutron_ports()
+ for flow in utils.sort(get_stale_flows(['acl']), sort_by):
+ host = compute_map.get(flow.get('dpnid'), flow.get('dpnid'))
+ ip_list = get_ips_for_iface(nports, flow.get('ifname'))
+ if ip_list:
+ flow['iface-ips'] = ip_list
+ result = 'Table:{},Host:{},FlowId:{}{}'.format(
+ flow['table'], host, flow['id'],
+ utils.show_optionals(flow))
+ print result
+ ##path = get_data_path('flows', flow)
+ #print('http://192.168.2.32:8383/restconf/config/{}'.format(path))
+ #print 'Flow:', json.dumps(parse_flow(flow['flow']))
+
+
+def get_all_flows(modules=['ifm']):
+ if not modules:
+ return 'No modules specified'
+ ifaces = {}
+ ifstates = {}
+ ifindexes = {}
+ bindings = {}
+ einsts = {}
+ eifaces = {}
+ fibentries = {}
+ vpnids = {}
+ vpninterfaces = {}
+ groups = {}
+ if 'all' in modules:
+ table_list = list(range(0, 255))
+ else:
+ table_list = list(set([table for module in modules for table in const.TABLE_MAP[module]]))
+ ##table_list = [214, 244]
+ of_nodes = dsg.get_inventory_config()
+ if 'ifm' in modules:
+ ifaces = dsg.get_config_interfaces()
+ ifstates = dsg.get_interface_states()
+ if 'l3vpn' in modules:
+ ifaces = ifaces or dsg.get_config_interfaces()
+ ifindexes = ifindexes or dsg.get_ifindexes()
+ fibentries = fibentries or dsg.get_fibentries_by_label()
+ vpnids = vpnids or dsg.get_vpnids()
+ vpninterfaces = vpninterfaces or dsg.get_vpninterfaces()
+ groups = groups or get_groups(of_nodes)
+ if 'acl' in modules:
+ ifaces = ifaces or dsg.get_config_interfaces()
+ ifindexes = ifindexes or dsg.get_ifindexes()
+ einsts = einsts or dsg.get_elan_instances()
+ eifaces = eifaces or dsg.get_elan_interfaces()
+ if 'elan' in modules:
+ ifaces = ifaces or dsg.get_config_interfaces()
+ einsts = einsts or dsg.get_elan_instances()
+ eifaces = eifaces or dsg.get_elan_interfaces()
+ ifindexes = ifindexes or dsg.get_ifindexes()
+ if 'all' in modules:
+ groups = groups or get_groups(of_nodes)
+ ifaces = ifaces or dsg.get_config_interfaces()
+ ifstates = ifstates or dsg.get_interface_states()
+ ifindexes = ifindexes or dsg.get_ifindexes()
+ fibentries = fibentries or dsg.get_fibentries_by_label()
+ vpnids = vpnids or dsg.get_vpnids()
+ vpninterfaces = vpninterfaces or dsg.get_vpninterfaces()
+ einsts = einsts or dsg.get_elan_instances()
+ eifaces = eifaces or dsg.get_elan_interfaces()
+ flows = []
+ for node in of_nodes.itervalues():
+ tables = [x for x in node[const.NODE_TABLE] if x['id'] in table_list]
+ for table in tables:
+ for flow in table.get('flow', []):
+ flow_dict = None
+ flow_info = {}
+ flow_info['dpnid'] = utils.get_dpn_from_ofnodeid(node['id'])
+ flow_dict = fp.get_any_flow(flow, flow_info, groups,
+ ifaces, ifstates, ifindexes,
+ fibentries, vpnids, vpninterfaces,
+ einsts, eifaces)
+ if flow_dict is not None:
+ flows.append(flow_dict)
+ return flows
+
+
+def show_all_flows():
+ compute_map = get_dpn_host_mapping()
+ nports = dsg.get_neutron_ports()
+ for flow in utils.sort(get_all_flows(['all']), 'table'):
+ host = compute_map.get(flow.get('dpnid'), flow.get('dpnid'))
+ ip_list = get_ips_for_iface(nports, flow.get('ifname'))
+ if ip_list:
+ flow['iface-ips'] = ip_list
+ result = 'Table:{},Host:{},FlowId:{}{}'.format(
+ flow['table'], host, flow['id'],
+ utils.show_optionals(flow))
+ print result
+ print 'Flow:', json.dumps(parse_flow(flow['flow']))
+
+
+def show_elan_flows():
+ for flow in utils.sort(get_stale_flows(['elan']), 'table'):
+ print 'Table:', flow['table'], 'FlowId:', flow['id'], utils.show_optionals(flow)
+ print 'Flow:', json.dumps(parse_flow(flow['flow']))
+
+
+def show_elan_instances():
+ insts = dsg.get_elan_instances()
+ json.dumps(insts)
+
+
+def parse_flow(flow):
+ #parse flow fields
+ #hex(int(mask, 16) & int(data, 16))
+ if flow['cookie']:
+ utils.to_hex(flow, 'cookie')
+ # parse instructions
+ for instruction in flow['instructions'].get('instruction', []):
+ if 'write-metadata' in instruction:
+ utils.to_hex(instruction['write-metadata'],'metadata')
+ utils.to_hex(instruction['write-metadata'],'metadata-mask')
+ if 'apply-actions' in instruction:
+ for action in instruction['apply-actions'].get('action', []):
+ if 'openflowplugin-extension-nicira-action:nx-reg-load' in action:
+ utils.to_hex(action['openflowplugin-extension-nicira-action:nx-reg-load'], 'value')
+ # parse matches
+ if 'metadata' in flow['match']:
+ metadata = flow['match']['metadata']
+ utils.to_hex(metadata,'metadata')
+ utils.to_hex(metadata,'metadata-mask')
+
+ for ofex in flow['match'].get('openflowplugin-extension-general:extension-list', []):
+ if ofex['extension-key'] == 'openflowplugin-extension-nicira-match:nxm-nx-reg6-key':
+ utils.to_hex(ofex['extension']['openflowplugin-extension-nicira-match:nxm-nx-reg'], 'value')
+
+ return flow
+
+
+def get_data_path(res_type, data):
+ if res_type == 'bindings':
+ return 'interface-service-bindings:service-bindings/services-info/{}/{}'.format(data['interface-name'],data['service-mode'])
+ elif res_type == 'flows':
+ return 'opendaylight-inventory:nodes/node/openflow:{}/flow-node-inventory:table/{}/flow/{}'.format(data['dpnid'],data['table'],data['id'])
+
+
+# Sample method that shows how to use
+def show_all_tables():
+ of_nodes = dsg.get_inventory_config()
+ tables = set()
+ for node in of_nodes.itervalues():
+ for table in node[const.NODE_TABLE]:
+ if table.get('flow'):
+ tables.add(table['id'])
+ print list(tables)
+
+
+def show_all_groups():
+ of_nodes = dsg.get_inventory_config()
+ groups = get_groups(of_nodes)
+ for dpn in groups:
+ for group_key in groups[dpn]:
+ print 'Dpn:', dpn, 'ID:', group_key, 'Group:', json.dumps(groups[dpn][group_key])
+
+
+def main(args=None):
+ options, args = utils.parse_args()
+ if options.callMethod:
+ if args[1:]:
+ eval(options.callMethod)(args[1:])
+ return
+ else:
+ eval(options.callMethod)()
+ return
+ #print json.dumps(dsg.get_vpninterfaces())
+ #show_all_tables()
+ #analyze_inventory('openflow:165862438671169',ifName='tunf94333cc491')
+ #show_stale_flows()
+ #show_stale_bindings()
+ analyze_interface(args)
+ #og.print_flow_dict(og.get_ofctl_flows())
+
+
+if __name__ == '__main__':
+ import sys
+ main()
--- /dev/null
+import collections
+import json
+import netvirt_utils as utils
+import constants as const
+
+
+def get_ds_data(name, file_name=None, ds_type=None):
+ res = const.DSMAP[name]
+ filename = file_name or res[const.DSM_FILE]
+ dstype = ds_type or res[const.DSM_DSTYPE]
+ path = res[const.DSM_PATH]
+ root1 = res[const.DSM_ROOT1]
+ root2 = res[const.DSM_ROOT2]
+ data = {}
+ try:
+ with open(filename) as data_file:
+ data = json.load(data_file)[root1][root2]
+ except IOError:
+ url = utils.create_url(dstype, path)
+ result = utils.grabJson(url)
+ if result:
+ data = result[root1][root2]
+ return data
+
+
+def get_config_interfaces(file_name=None):
+ # Returns dict of ifaces, key is iface name
+ if_dict = {}
+ ifaces = get_ds_data('ifconfig',file_name)
+ for iface in ifaces:
+ if_dict[iface['name']] = iface
+ return if_dict
+
+
+def get_neutron_ports(file_name=None):
+ port_dict = {}
+ ports = get_ds_data('neutronports',file_name)
+ for port in ports:
+ port_dict[port['uuid']] = port
+ return port_dict
+
+
+def get_interface_states(file_name=None):
+ ifs_dict = {}
+ ifstates = get_ds_data('ifstate',file_name)
+ for ifstate in ifstates:
+ ifs_dict[ifstate['name']] = ifstate
+ return ifs_dict
+
+
+def get_config_tunnels(file_name='tunnel-config.log'):
+ tun_dict = {}
+ tunnels = {}
+ try:
+ with open(file_name) as tunconfig_file:
+ tunnels = json.load(tunconfig_file)['tunnel-list']['internal-tunnel']
+ except Exception:
+ pass
+ for tunnel in tunnels:
+ for tun_name in tunnel['tunnel-interface-name']:
+ tun_dict[tun_name] = tunnel
+ return tun_dict
+
+
+def get_tunnel_states(file_name=None):
+ tun_dict = {}
+ tunnels = get_ds_data('tunstate',file_name)
+ for tunnel in tunnels:
+ tun_dict[tunnel['tunnel-interface-name']] = tunnel
+ return tun_dict
+
+
+def get_topology_nodes(file_name, type = 'ovsdb:1', dsType = 'config'):
+ nodes_dict = {}
+ topologies = {}
+ nodes = {}
+ try:
+ with open(file_name) as topology_file:
+ topologies = json.load(topology_file)['topology']
+ nodes = [topology['node'] for topology in topologies if topology['topology-id'] == type][0]
+ except IOError:
+ url = utils.create_url(dsType, "network-topology:network-topology/{}".format(type))
+ result = utils.grabJson(url)
+ if result:
+ nodes = result['node']
+ for node in nodes:
+ nodes_dict[node['node-id']] = node
+ return nodes_dict
+
+
+def get_topology_config(file_name='topology-config.log', type = 'ovsdb:1'):
+ return get_topology_nodes(file_name)
+
+
+def get_topology_oper(file_name='topology-oper.log', type = 'ovsdb:1', dsType = 'operational'):
+ return get_topology_nodes(file_name, type)
+
+
+def get_inventory_nodes(file_name, dsType = 'config'):
+ nodes_dict = {}
+ nodes = get_ds_data('inventory', file_name, dsType)
+ for node in nodes:
+ nodes_dict[node['id']] = node
+ return nodes_dict
+
+
+def get_inventory_config(file_name=None):
+ return get_inventory_nodes(file_name)
+
+
+def get_inventory_oper(file_name='inventory-oper.log'):
+ return get_inventory_nodes(file_name, 'operational')
+
+
+def get_service_bindings(file_name=None):
+ sb_dict = collections.defaultdict(dict)
+ orphans_dict = collections.defaultdict(dict)
+ sb_infos = get_ds_data('bindings')
+ for sb_info in sb_infos:
+ service_mode = sb_info['service-mode'][len('interface-service-bindings:'):]
+ if sb_info.get('bound-services'):
+ sb_dict[sb_info['interface-name']][service_mode] = sb_info
+ else:
+ orphans_dict[sb_info['interface-name']][service_mode] = sb_info
+ return dict(sb_dict), dict(orphans_dict)
+
+
+def get_elan_instances(file_name=None):
+ einstances_dict = {}
+ einstances = get_ds_data('elaninstances')
+ for einstance in einstances:
+ einstances_dict[einstance['elan-instance-name']] = einstance
+ return einstances_dict
+
+
+def get_elan_interfaces(file_name=None):
+ eifaces_dict = {}
+ eifaces = get_ds_data('elaninterfaces')
+ for eiface in eifaces:
+ eifaces_dict[eiface['name']] = eiface
+ return eifaces_dict
+
+
+def get_ifindexes(file_name=None):
+ ifindexes_dict = {}
+ ifindexes = get_ds_data('ifindexes')
+ for ifindex in ifindexes:
+ ifindexes_dict[ifindex['if-index']] = ifindex
+ return ifindexes_dict
+
+
+def get_fibentries_by_label(file_name=None):
+ fibs_dict = {}
+ fibs = get_ds_data('fibentries')
+ for vrftable in fibs:
+ for vrfEntry in vrftable.get('vrfentry', []):
+ if vrfEntry.get('label'):
+ vrfEntry['rd'] = vrftable['routeDistinguisher']
+ fibs_dict[vrfEntry['label']] = vrfEntry
+ return fibs_dict
+
+
+def get_vpnids(filename=None):
+ vpnids_dict = {}
+ vpninstances = get_ds_data('vpninstance-to-vpnid')
+ for vpninstance in vpninstances:
+ vpnids_dict[vpninstance['vpn-id']] = vpninstance
+ return vpnids_dict
+
+
+def get_vpninterfaces(filename=None):
+ vpninterfaces_dict = {}
+ vpninterfaces = get_ds_data('vpninterfaces')
+ for vpninterface in vpninterfaces:
+ vpninterfaces_dict[vpninterface['name']] = vpninterface
+ return vpninterfaces_dict
--- /dev/null
+import netvirt_utils as utils
+import constants as const
+
+
+OPTIONALS = ['ifname', 'lport', 'elan-tag', 'mpls', 'vpnid', 'reason']
+MAC_LEN = 17
+
+# Flow table constants
+
+PREFIX_211_GOTO = 'Egress_Fixed_Goto_Classifier_'
+PREFIX_211_DHCPSv4 = 'Egress_DHCP_Server_v4'
+PREFIX_211_DHCPSv6 = 'Egress_DHCP_Server_v6_'
+PREFIX_211_DHCPCv4 = 'Egress_DHCP_Client_v4'
+PREFIX_211_DHCPCv6 = 'Egress_DHCP_Client_v6_'
+PREFIX_211_ARP = 'Egress_ARP_'
+PREFIX_211_L2BCAST = 'Egress_L2Broadcast_'
+PREFIX_211_ICMPv6 = 'Egress_ICMPv6_'
+
+PREFIX_213 = 'Egress_Fixed_Conntrk_'
+PREFIX_214 = 'Egress_Fixed_Conntrk_Drop'
+PREFIX_215 = 'Egress_Fixed_NonConntrk_Drop'
+PREFIX_241_DHCPv4 = 'Ingress_DHCP_Server_v4'
+PREFIX_241_DHCPv6 = 'Ingress_DHCP_Server_v6_'
+PREFIX_241_ICMPv6 = 'Ingress_ICMPv6_'
+PREFIX_241_ARP = 'Ingress_ARP_'
+PREFIX_241_BCASTv4 = 'Ingress_v4_Broadcast_'
+PREFIX_241_GOTO = 'Ingress_Fixed_Goto_Classifier_'
+PREFIX_243 = 'Ingress_Fixed_Conntrk_'
+PREFIX_244 = 'Ingress_Fixed_Conntrk_Drop'
+PREFIX_245 = 'Ingress_Fixed_NonConntrk_Drop'
+
+
+PREFIX_FOR_LPORT = {211: [PREFIX_211_GOTO, PREFIX_211_DHCPSv4,
+ PREFIX_211_DHCPSv6, PREFIX_211_DHCPCv4,
+ PREFIX_211_DHCPCv6, PREFIX_211_ARP,
+ PREFIX_211_L2BCAST, PREFIX_211_ICMPv6],
+ 212: [],
+ 213: [PREFIX_213],
+ 214: [PREFIX_214],
+ 215: [PREFIX_215],
+ 241: [PREFIX_241_DHCPv4, PREFIX_241_DHCPv6,
+ PREFIX_241_ICMPv6, PREFIX_241_ARP,
+ PREFIX_241_BCASTv4, PREFIX_241_GOTO],
+ 242: [],
+ 243: [PREFIX_243],
+ 244: [PREFIX_244],
+ 245: [PREFIX_245]}
+
+PREFIX_SGR_ETHER = 'ETHERnull_'
+PREFIX_SGR_ICMP = 'ICMP_'
+PREFIX_SGR_TCP = 'TCP_'
+PREFIX_SGR_UDP = 'UDP_'
+PREFIX_SGR_OTHER = 'OTHER_PROTO'
+
+PREFIX_LPORT_SGR = {211: [], 212: [], 213: [],
+ 214: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
+ PREFIX_SGR_UDP, PREFIX_SGR_OTHER],
+ 215: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
+ PREFIX_SGR_UDP, PREFIX_SGR_OTHER],
+ 241: [], 242: [], 243: [],
+ 244: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
+ PREFIX_SGR_UDP, PREFIX_SGR_OTHER],
+ 245: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
+ PREFIX_SGR_UDP, PREFIX_SGR_OTHER]
+ }
+
+# Metadata consts
+LPORT_MASK = 0x1fffff0000000000
+LPORT_MASK_ZLEN = 10 # no. of trailing 0s in lport mask
+ELAN_TAG_MASK = 0x000000ffff000000
+ELAN_HEX_LEN = 4
+LPORT_REG6_MASK = 0x1fffff00
+LPORT_REG6_MASK_ZLEN = 2
+VRFID_MASK = 0x00000000fffffffe
+
+
+def create_flow_dict(flow_info, flow):
+ flow_dict = {}
+ flow_dict['table'] = flow['table_id']
+ flow_dict['id'] = flow['id']
+ flow_dict['name'] = flow.get('flow-name')
+ flow_dict['flow'] = flow
+ flow_dict['dpnid'] = flow_info['dpnid']
+ for opt in OPTIONALS:
+ if flow_info.get(opt):
+ flow_dict[opt] = flow_info.get(opt)
+ return flow_dict
+
+
+def get_any_flow(flow, flow_info, groups, ifaces, ifstates, ifindexes,
+ fibentries, vpnids, vpninterfaces, einsts, eifaces):
+ table = flow['table_id']
+ if table in const.TABLE_MAP['ifm']:
+ stale_ifm = stale_ifm_flow(flow, flow_info, ifaces, ifstates)
+ flow_info = stale_ifm if stale_ifm else get_flow_info_from_ifm_table(flow_info, flow)
+ elif table in const.TABLE_MAP['acl']:
+ stale_acl = stale_acl_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces)
+ flow_info = stale_acl if stale_acl else get_flow_info_from_acl_table(flow_info, flow)
+ elif table in const.TABLE_MAP['elan']:
+ stale_elan = stale_elan_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces)
+ flow_info = stale_elan if stale_elan else get_flow_info_from_elan_table(flow_info, flow)
+ elif table in const.TABLE_MAP['l3vpn']:
+ stale_l3vpn = stale_l3vpn_flow(flow, flow_info, groups, ifaces, ifindexes, vpnids, vpninterfaces, fibentries)
+ flow_info = stale_l3vpn if stale_l3vpn else get_flow_info_from_l3vpn_table(flow_info, flow)
+ else:
+ flow_info = get_flow_info_from_any(flow_info, flow)
+ iface = (get_iface_for_lport(ifaces, ifindexes, flow_info.get('lport'))
+ if flow_info.get('lport') else None)
+ if iface and iface.get('name'):
+ flow_info['ifname'] = iface['name']
+ return create_flow_dict(flow_info, flow)
+
+
+def stale_ifm_flow(flow, flow_info, ifaces, ifstates):
+ get_flow_info_from_ifm_table(flow_info, flow)
+ flow_ifname = flow_info['ifname']
+ if flow_ifname is not None and not ifaces.get(flow_ifname):
+ flow_info['reason'] = 'Interface doesnt exist'
+ return create_flow_dict(flow_info, flow)
+ elif flow_ifname and ifstates.get(flow_ifname):
+ ifstate = ifstates.get(flow_ifname)
+ ncid_list = ifstate.get('lower-layer-if')
+ ncid = ncid_list[0] if ncid_list else None
+ dpn = utils.get_dpn_from_ofnodeid(ncid)
+ if dpn and dpn != flow_info['dpnid']:
+ flow_info['reason'] = 'DpnId mismatch for flow and Interface'
+ return create_flow_dict(flow_info, flow)
+ if (flow_info.get('lport') and ifstate.get('if-index')
+ and flow_info['lport'] != ifstate['if-index']):
+ flow_info['reason'] = 'Lport and IfIndex mismatch'
+ return create_flow_dict(flow_info, flow)
+ return None
+ # return create_flow_dict(flow_info, flow)
+
+
+def stale_l3vpn_flow(flow, flow_info, groups, ifaces, ifindexes,
+ vpnids, vpninterfaces, fibentries):
+ get_flow_info_from_l3vpn_table(flow_info, flow)
+ lport = flow_info.get('lport')
+ iface = get_iface_for_lport(ifaces, ifindexes, lport)
+ if lport and not iface:
+ flow_info['reason'] = 'Interface for lport not found'
+ return create_flow_dict(flow_info, flow)
+ if iface:
+ flow_info['ifname'] = iface['name']
+ vpninterface = vpninterfaces.get(iface.get('name')) if iface else None
+ if not vpninterfaces:
+ flow_info['reason'] = 'VpnInterface for Lport not found'
+ return create_flow_dict(flow_info, flow)
+ vpnid = flow_info.get('vpnid')
+ if vpnid and not vpnids.get(vpnid):
+ flow_info['reason'] = 'VpnInstance for VpnId not found'
+ return create_flow_dict(flow_info, flow)
+ if vpnid and vpninterface and vpnids.get(vpnid):
+ if (vpninterface.get('vpn-instance-name') !=
+ vpnids[vpnid]['vpn-instance-name']):
+ flow_info['reason'] = 'Lport VpnId mismatch'
+ return create_flow_dict(flow_info, flow)
+ label = flow_info.get('label')
+ fibentry = fibentries.get(label) if label else None
+ if label and not fibentry:
+ flow_info['reason'] = 'Fibentry for MplsLabel not found'
+ return create_flow_dict(flow_info, flow)
+ # Label check for group
+ prefix = fibentry.get('destPrefix') if fibentry else None
+ if prefix and flow_info.get('group-id'):
+ gid = flow_info.get('group-id')
+ if groups.get(gid) and (
+ groups.get(gid).get('group-name', '') != prefix):
+ flow_info['reason'] = 'DestPrefix mismatch for label and group'
+ return create_flow_dict(flow_info, flow)
+ return None
+
+
+def stale_elan_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces):
+ # hex(int(mask, 16) & int(hexa, 16))
+ get_flow_info_from_elan_table(flow_info, flow)
+ lport = flow_info.get('lport')
+ eltag = flow_info.get('elan-tag')
+ iface = get_iface_for_lport(ifaces, ifindexes, lport)
+ if lport and not iface:
+ flow_info['reason'] = 'Interface for lport not found'
+ return create_flow_dict(flow_info, flow)
+ if iface:
+ flow_info['ifname'] = iface['name']
+ if not is_elantag_valid(eltag, eifaces, einsts, iface):
+ flow_info['reason'] = 'Lport Elantag mismatch'
+ return create_flow_dict(flow_info, flow)
+ return None
+
+
+def stale_acl_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces):
+ get_flow_info_from_acl_table(flow_info, flow)
+ lport = flow_info.get('lport')
+ eltag = flow_info.get('elan-tag')
+ iface = get_iface_for_lport(ifaces, ifindexes, lport)
+ if lport and not iface:
+ flow_info['reason'] = 'Interface for lport not found'
+ #return create_flow_dict(flow_info, flow)
+ if iface:
+ flow_info['ifname'] = iface['name']
+ if not is_elantag_valid(eltag, eifaces, einsts, iface):
+ flow_info['reason'] = 'Lport Elantag mismatch'
+ #return create_flow_dict(flow_info, flow)
+ return create_flow_dict(flow_info, flow)
+ #return None
+
+
+def is_elantag_valid(eltag, eifaces, einsts, iface):
+ if (iface and eltag
+ and eltag != get_eltag_for_iface(eifaces, einsts, iface)):
+ return False
+ return True
+
+
+def get_iface_for_lport(ifaces, ifindexes, lport):
+ if lport:
+ if ifindexes.get(lport):
+ ifname = ifindexes.get(lport).get('interface-name')
+ if ifname and ifaces.get(ifname):
+ return ifaces.get(ifname)
+ return None
+
+
+def get_eltag_for_iface(eifaces, einsts, iface):
+ ifname = iface.get('name') if iface else None
+ eiface = eifaces.get(ifname) if ifname else None
+ einst_name = eiface.get('elan-instance-name') if eiface else None
+ einst = einsts.get(einst_name) if einst_name else None
+ return einst.get('elan-tag') if einst else None
+
+
+# Methods to extract flow fields
+def get_instruction_writemeta(flow):
+ for instruction in flow['instructions'].get('instruction', []):
+ if 'write-metadata' in instruction:
+ return instruction['write-metadata']
+ return None
+
+
+def get_act_reg6load(flow):
+ for instruction in flow['instructions'].get('instruction', []):
+ if 'apply-actions' in instruction:
+ for action in instruction['apply-actions'].get('action', []):
+ if ('openflowplugin-extension-nicira-action:nx-reg-load'
+ in action):
+ return action[
+ 'openflowplugin-extension-nicira-action:nx-reg-load']
+ return None
+
+
+def get_act_conntrack(flow):
+ for instruction in flow['instructions'].get('instruction', []):
+ if 'apply-actions' in instruction:
+ for action in instruction['apply-actions'].get('action', []):
+ if ('openflowplugin-extension-nicira-action:nx-conntrack'
+ in action):
+ return action[
+ 'openflowplugin-extension-nicira-action:nx-conntrack']
+
+
+def get_act_group(flow):
+ for instruction in flow['instructions'].get('instruction', []):
+ if 'apply-actions' in instruction:
+ for action in instruction['apply-actions'].get('action', []):
+ if 'group-action' in action:
+ return action['group-action']
+
+
+def get_match_metadata(flow):
+ return flow['match'].get('metadata')
+
+
+def get_match_reg6(flow):
+ for ofex in (
+ flow['match'].get(
+ 'openflowplugin-extension-general:extension-list', [])):
+ if (ofex['extension-key']
+ == 'openflowplugin-extension-nicira-match:nxm-nx-reg6-key'):
+ return (
+ ofex['extension']
+ ['openflowplugin-extension-nicira-match:nxm-nx-reg'])
+ return None
+
+
+def get_match_mpls(flow):
+ if flow['match'].get('protocol-match-fields'):
+ return flow['match'].get('protocol-match-fields').get('mpls-label')
+ return None
+
+
+def get_match_tunnelid(flow):
+ if flow['match'].get('tunnel'):
+ return flow['match'].get('tunnel').get('tunnel-id')
+ return None
+
+
+def get_flow_info_from_any(flow_info, flow):
+ w_mdata = get_instruction_writemeta(flow)
+ if w_mdata:
+ metadata = w_mdata['metadata']
+ mask = w_mdata['metadata-mask']
+ if (mask & LPORT_MASK):
+ lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
+ if lport:
+ flow_info['lport'] = int(lport, 16)
+ m_metadata = get_match_metadata(flow)
+ if m_metadata:
+ metadata = m_metadata['metadata']
+ mask = m_metadata['metadata-mask']
+ if (mask & ELAN_TAG_MASK):
+ elan = ('%x' % (metadata & ELAN_TAG_MASK))[:ELAN_HEX_LEN]
+ if elan:
+ flow_info['elan-tag'] = int(elan, 16)
+ if not lport and (mask & LPORT_MASK):
+ lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
+ if lport:
+ flow_info['lport'] = int(lport, 16)
+ return flow_info
+
+# Table specific parsing
+
+def get_ifname_from_flowid(flow_id, table):
+ splitter = ':' if table == 0 else '.'
+ i = 2 if table == 0 else 1
+ # i = 2
+ ifname = None
+ try:
+ ifname = flow_id.split(splitter)[i]
+ except IndexError:
+ tun_index = flow_id.find('tun')
+ if tun_index > -1:
+ ifname = flow_id[tun_index:]
+ return ifname
+
+
+def get_flow_info_from_ifm_table(flow_info, flow):
+ flow_info['ifname'] = get_ifname_from_flowid(flow['id'], flow['table_id'])
+ w_mdata = get_instruction_writemeta(flow)
+ if w_mdata:
+ metadata = w_mdata['metadata']
+ mask = w_mdata['metadata-mask']
+ if (mask & LPORT_MASK):
+ lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
+ flow_info['lport'] = int(lport, 16)
+ return flow_info
+ m_reg6 = get_match_reg6(flow)
+ if m_reg6 and m_reg6.get('value'):
+ lport = (('%x' % (m_reg6.get('value') & LPORT_REG6_MASK))
+ [:-LPORT_REG6_MASK_ZLEN])
+ flow_info['lport'] = int(lport, 16)
+ return flow_info
+
+
+def get_flow_info_from_l3vpn_table(flow_info, flow):
+ label = get_match_mpls(flow)
+ if not label and flow['table_id'] == 36:
+ label = get_match_tunnelid(flow)
+ if label:
+ flow_info['mpls'] = label
+ a_group = get_act_group(flow)
+ if a_group and a_group.get('group-id'):
+ flow_info['group-id'] = a_group.get('group-id')
+ m_metadata = get_match_metadata(flow)
+ if m_metadata:
+ metadata = m_metadata['metadata']
+ mask = m_metadata['metadata-mask']
+ if (mask & LPORT_MASK):
+ lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
+ flow_info['lport'] = int(lport, 16)
+ if (mask & VRFID_MASK):
+ flow_info['vpnid'] = (metadata & VRFID_MASK) / 2
+ return flow_info
+
+
+def get_lport_elan_tags_from_flowid(flowid, dpnid):
+ res = flowid[:-MAC_LEN].split(dpnid)
+ lport = res[1]
+ elan = res[0][2:]
+ return lport, elan
+
+
+def get_flow_info_from_elan_table(flow_info, flow):
+ m_metadata = get_match_metadata(flow)
+ if m_metadata:
+ metadata = m_metadata['metadata']
+ mask = m_metadata['metadata-mask']
+ if (mask & ELAN_TAG_MASK):
+ elan = ('%x' % (metadata & ELAN_TAG_MASK))[:ELAN_HEX_LEN]
+ flow_info['elan-tag'] = int(elan, 16)
+ if (mask & LPORT_MASK):
+ lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
+ flow_info['lport'] = int(lport, 16)
+
+ if not flow_info.get('lport'):
+ reg6_load = get_act_reg6load(flow)
+ if reg6_load and reg6_load.get('value'):
+ # reg6load value is lport lft-shit by 8 bits.
+ lport = ('%x' % reg6_load.get('value'))[:-2]
+ flow_info['lport'] = int(lport, 16)
+ return flow_info
+
+
+def get_flow_info_from_acl_table(flow_info, flow):
+ m_metadata = get_match_metadata(flow)
+ if m_metadata:
+ metadata = m_metadata['metadata']
+ mask = m_metadata['metadata-mask']
+ if (mask & LPORT_MASK):
+ lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
+ flow_info['lport'] = int(lport, 16)
+ a_conntrk = get_act_conntrack(flow)
+ if a_conntrk and a_conntrk.get('conntrack-zone'):
+ flow_info['elan-tag'] = a_conntrk.get('conntrack-zone')
+ return flow_info
+
+
+def get_flow_info_from_acl_table_flowid(flow_info, flow):
+ """
+ Format for ACL flow ids is as follows:
+ 211:Egress_Fixed_Goto_Classifier_<dpId>_<lportTag>_<attachMac>_<attachIp>,
+ Egress_DHCP_Server_v4<dpId>_<lportTag>__Drop_,
+ Egress_DHCP_Server_v6_<dpId>_<lportTag>__Drop_,
+ Egress_DHCP_Client_v4<dpId>_<lportTag>_<macAddress>_Permit_,
+ Egress_DHCP_Client_v6_<dpId>_<lportTag>_<macAddress>_Permit_,
+ Egress_ARP_<dpId>_<lportTag>_<allowedAddressMac><allowedAddressIp>,
+ Egress_L2Broadcast_<dpId>_<lportTag>_<attachMac>,
+ Egress_ICMPv6_<dpId>_<lportTag>_134_Drop_,
+ Egress_ICMPv6_<dpId>_<lportTag>_<icmpv6Type>_<allowedAddressMac>_Permit_,
+ Egress_Fixed_Goto_Classifier_<dpId>_<lportTag>_<attachMac>_<attachIp>
+
+ 212:Fixed_Conntrk_Classifier_<dpId>_212_<etherType>_<protocol>
+ 213:Egress_Fixed_Conntrk_<dpId>_<lportTag>_<etherType>_Recirc
+ 214:Fixed_Conntrk_Trk_<dpId>_Tracked_Established17,
+ Fixed_Conntrk_Trk_<dpId>_Tracked_Related17,
+ Egress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_New,
+ Egress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_Invalid,
+ ETHERnull_Egress_<lportTag>_<sgRuleId>,
+ ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP__Egress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
+ ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_Egress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+
+ 215:Egress_Fixed_NonConntrk_Drop<dpId>_<lportTag>_ACL_Rule_Miss,
+ ETHERnull_Egress_<lportTag>_<sgRuleId>,
+ ETHERnull_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP__Egress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
+ ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_Egress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>
+
+ 241:Ingress_v4_Broadcast_<dpId>_Permit,
+ Ingress_L2_Broadcast_<dpId>_Permit,
+ Ingress_DHCP_Server_v4<dpId>_<lportTag>__Permit_,
+ Ingress_DHCP_Server_v6_<dpId>_<lportTag>___Permit_,
+ Ingress_ICMPv6_<dpId>_<lportTag>_130_Permit_,
+ Ingress_ICMPv6_<dpId>_<lportTag>_134_LinkLocal_Permit_,
+ Ingress_ICMPv6_<dpId>_<lportTag>_135_Permit_,
+ Ingress_ICMPv6_<dpId>_<lportTag>_136_Permit_,
+ Ingress_ARP_<dpId>_<lportTag>,
+ Ingress_v4_Broadcast_<dpId>_<lportTag>_<broadcastAddress>_Permit,
+ Ingress_Fixed_Goto_Classifier_<dpId>_<lportTag>_<attachMac>_<attachIp>
+
+ 242:Fixed_Conntrk_Classifier_<dpId>_242_<etherType>_<protocol>
+
+ 243:Ingress_Fixed_Conntrk_<dpId>_<lportTag>_<etherType>_Recirc
+
+ 244:Fixed_Conntrk_Trk_<dpId>_Tracked_Established220
+ Fixed_Conntrk_Trk_<dpId>_Tracked_Related220,
+ Ingress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_New,
+ Ingress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_Invalid,
+ ETHERnull_Ingress_<lportTag>_<sgRuleId>,
+ ETHERnull_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP__Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
+ ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_Ingress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>
+
+ 245:Ingress_Fixed_NonConntrk_Drop<dpId>_<lportTag>_ACL_Rule_Miss,
+ ETHERnull_Ingress_<lportTag>_<sgRuleId>,
+ ETHERnull_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP__Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
+ ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_Ingress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
+ OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>
+
+ """
+ flowid = flow['id']
+ """
+ This captures flows with following format:
+ *_<dpnid>_<lport>_*
+ """
+ for prefix in PREFIX_FOR_LPORT[flow['table_id']]:
+ if flowid.startswith(prefix):
+ res = flowid[len(prefix):].split('_')
+ try:
+ flow_info['lport'] = int(res[1])
+ return flow_info
+ except ValueError:
+ """ Possible cases, ignore:
+ 241:Ingress_v4_Broadcast_<dpId>_Permit
+ """
+ pass
+ """
+ This captures flows with following format:
+ *_<lport>_<sgRuleId>
+ """
+ for prefix in PREFIX_LPORT_SGR[flow['table_id']]:
+ if flowid.startswith(prefix):
+ res = flowid[len(prefix):].split('_')
+ try:
+ flow_info['lport'] = int(res[-2])
+ return flow_info
+ except ValueError:
+ """ Possible cases, ignore:
+ Unexpected, log?
+ """
+ pass
+ except IndexError:
+ # Unknown flow type. Log???
+ pass
+ return flow_info
--- /dev/null
+import constants as const
+import json, pprint, urllib2, base64, sys
+import optparse
+
+
+options = None
+args = None
+
+def parse_args():
+ global options, args
+ parser = optparse.OptionParser(version="0.1")
+ parser.add_option("-i", "--ip", action="store", type="string", dest="odlIp", default="localhost",
+ help="opendaylights ip address")
+ parser.add_option("-t", "--port", action="store", type="string", dest="odlPort", default="8080",
+ help="opendaylights listening tcp port on restconf northbound")
+ parser.add_option("-u", "--user", action="store", type="string", dest="odlUsername", default="admin",
+ help="opendaylight restconf username")
+ parser.add_option("-p", "--password", action="store", type="string", dest="odlPassword", default="admin",
+ help="opendaylight restconf password")
+ parser.add_option("-m", "--method", action="store", type="string", dest="callMethod", default=None,
+ help="method to call")
+ (options, args) = parser.parse_args(sys.argv)
+ return options, args
+
+
+def get_options():
+ return options
+
+
+def get_args():
+ return args
+
+
+def create_url(dsType, path):
+ return 'http://{}:{}/restconf/{}/{}/'.format(options.odlIp, options.odlPort, dsType, path)
+
+
+def grabJson(url):
+ data = None
+ try:
+ request = urllib2.Request(url)
+ # You need the replace to handle encodestring adding a trailing newline
+ # (https://docs.python.org/2/library/base64.html#base64.encodestring)
+ base64string = base64.encodestring('{}:{}'.format(options.odlUsername, options.odlPassword)).replace('\n', '')
+ request.add_header('Authorization', 'Basic {}'.format(base64string))
+ result = urllib2.urlopen(request)
+ except urllib2.URLError, e:
+ printError('Unable to send request: {}\n'.format(e))
+ return data
+
+ if (result.code != 200):
+ printError( '{}\n{}\n\nError: unexpected code: {}\n'.format(result.info(), result.read(), result.code) )
+ return data
+
+ data = json.load(result)
+ return data
+
+
+def nstr(s):
+ if not s:
+ return ''
+ return str(s)
+
+
+def pretty_print(arg):
+ pp = pprint.PrettyPrinter(indent=2)
+ pp.pprint(arg)
+ print
+
+
+def printError(msg):
+ sys.stderr.write(msg)
+
+
+def get_port_name(port):
+ prefix = const.VIF_TYPE_TO_PREFIX.get(port[const.VIF_TYPE])
+ if prefix is None:
+ return None
+ else:
+ return prefix + port['uuid'][:11]
+
+
+def get_dpn_from_ofnodeid(node_id):
+ return node_id.split(':')[1]
+
+
+def to_hex(data, ele=None):
+ if not ele:
+ data = ("0x%x" % data) if data else None
+ return data
+ elif data.get(ele):
+ data[ele] = "0x%x" % data[ele]
+ return data[ele]
+ else:
+ return data
+
+
+def sort(data, field):
+ return sorted(data, key=lambda x: x[field])
+
+
+
+def show_optionals(flow):
+ result = ''
+ lport = flow.get('lport')
+ elantag = flow.get('elan-tag')
+ label = flow.get('mpls')
+ vpnid = flow.get('vpnid')
+ ip = flow.get('iface-ips')
+ if lport:
+ result = '{},LportTag:{}/{}'.format(result, lport, to_hex(lport))
+ if vpnid:
+ result = '{},VpnId:{}/{}'.format(result, vpnid, to_hex(vpnid*2))
+ if label:
+ result = '{},MplsLabel:{}'.format(result, label)
+ if elantag:
+ result = '{},ElanTag:{}/{}'.format(result, elantag, to_hex(elantag))
+ if ip:
+ result = '{},LportIp:{}'.format(result, json.dumps(ip))
+ result = '{},Reason:{}'.format(result, flow.get('reason'))
+ return result
+
--- /dev/null
+import sys
+import re
+
+from datetime import datetime as dt
+from datetime import timedelta as td
+
+base_time = '2017-07-31 20:19:00,698'
+#base_time = None
+TIME_FORMAT = '%Y-%m-%d %H:%M:%S,%f'
+
+def get_ofctl_flows(file_name='ofctl-flows.log'):
+ flow_list = []
+ with open(file_name, 'rb') as f:
+ data = f.read().splitlines()
+ for row in data:
+ meta = row.split(', ')
+ matches, actions = meta.pop().split()
+ flow_list.append(get_flow_dict(meta, matches, actions))
+ return flow_list
+
+
+def get_flow_dict(meta, matches, actions):
+ actions = actions.strip('actions=')
+ flow_dict = {}
+ flow_dict['meta'] = get_meta_dict(meta)
+ flow_dict['matches'] = get_matches_dict(matches)
+ flow_dict['actions'] = get_actions_dict(actions)
+ return flow_dict
+
+
+def get_meta_dict(meta_str):
+ meta = {}
+ for field in meta_str:
+ k, v = field.split('=')
+ if base_time and k == 'duration':
+ v = get_flow_time(v)
+ k = 'installed'
+ meta[k] = v
+ return meta
+
+
+def get_matches_dict(matches_str):
+ return matches_str
+''' Note: This mostly works requires bit of rework for matches like:
+ arp,arp_sa=abc etc.
+ matches = {}
+ for match in matches_str.split(','):
+ if '=' in match:
+ k, v = match.split('=')
+ else:
+ k, v = match, ""
+ matches[k] = v
+ return matches
+'''
+
+
+def get_flow_time(duration):
+ duration = duration.strip('s')
+ time = dt.strptime(base_time, TIME_FORMAT) + td(0, float(duration))
+ time_str = time.strftime(TIME_FORMAT)
+ return time_str
+
+
+def get_actions_dict(action_str):
+ return action_str
+''' todo: Action parsing is WiP and requires much complex logic
+ actions_dict = {}
+ actions = action_str.split(',')
+ actions = iter(actions)
+ for action in actions:
+ if ':' in action:
+ k, v = action.split(':')
+ actions_dict[k] = v
+ elif action.startswith('resubmit'):
+ k = 'resubmit'
+ port = action.strip('resubmit(')
+ try:
+ next_action = next(actions)
+ if next_action.endswith(')'):
+ table = next_action.strip(')')
+ else:
+ table = action
+ except StopIteration:
+ break;
+ actions_dict[k] = '('+port+','+table+')'
+ return actions_dict
+'''
+
+
+def print_flow_dict(flows):
+ for flow in flows:
+ print flow['meta'], flow['matches'], flow['actions']
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env python
+
+import urllib2, base64, json, sys, optparse
+
+# globals
+CONST_DEFAULT_DEBUG=0
+options = None
+state = None
+jsonTopologyNodes = []
+jsonInventoryNodes = []
+flowInfoNodes = {}
+nodeIdToDpidCache = {}
+
+CONST_OPERATIONAL = 'operational'
+CONST_CONFIG = 'config'
+CONST_NET_TOPOLOGY = 'network-topology'
+CONST_TOPOLOGY = 'topology'
+CONST_TP_OF_INTERNAL = 65534
+CONST_ALIASES = ['alpha', 'bravo', 'charlie', 'delta', 'echo', 'foxtrot', 'golf', 'hotel', 'india', 'juliet',
+ 'kilo', 'lima', 'mike', 'november', 'oscar', 'papa', 'quebec', 'romeo', 'sierra', 'tango',
+ 'uniform', 'victor', 'whiskey', 'xray', 'yankee', 'zulu']
+
+
+class State:
+ def __init__(self):
+ self.nextAliasIndex = 0
+ self.nextAliasWrap = 0
+ self.nodeIdToAlias = {}
+
+ self.bridgeNodes = {}
+ self.ovsdbNodes = {}
+ self.ofLinks = {}
+
+ def __repr__(self):
+ return 'State {}:{} {}:{} {}:{} {}:{} {}:{}'.format(
+ 'nextAliasIndex', self.nextAliasIndex,
+ 'nextAliasWrap', self.nextAliasWrap,
+ 'bridgeNodes_ids', self.bridgeNodes.keys(),
+ 'ovsdbNodes_ids', self.ovsdbNodes.keys(),
+ 'nodeIdToAlias', self.nodeIdToAlias)
+
+ def registerBridgeNode(self, bridgeNode):
+ self.bridgeNodes[bridgeNode.nodeId] = bridgeNode
+
+ def registerOvsdbNode(self, ovsdbNode):
+ self.ovsdbNodes[ovsdbNode.nodeId] = ovsdbNode
+
+ def getNextAlias(self, nodeId):
+ result = CONST_ALIASES[ self.nextAliasIndex ]
+ if self.nextAliasWrap > 0:
+ result += '_' + str(self.nextAliasWrap)
+
+ if CONST_ALIASES[ self.nextAliasIndex ] == CONST_ALIASES[-1]:
+ self.nextAliasIndex = 0
+ self.nextAliasWrap += 1
+ else:
+ self.nextAliasIndex += 1
+
+ self.nodeIdToAlias[ nodeId ] = result
+ return result
+
+# --
+
+class TerminationPoint:
+ def __init__(self, name, ofPort, tpType, mac='', ifaceId=''):
+ self.name = name
+ self.ofPort = ofPort
+ self.tpType = tpType
+ self.mac = mac
+ self.ifaceId = ifaceId
+
+ def __repr__(self):
+ result = '{} {}:{}'.format(self.name, 'of', self.ofPort)
+
+ if self.tpType != '':
+ result += ' {}:{}'.format('type', self.tpType)
+ if self.mac != '':
+ result += ' {}:{}'.format('mac', self.mac)
+ if self.ifaceId != '':
+ result += ' {}:{}'.format('ifaceId', self.ifaceId)
+
+ return '{' + result + '}'
+
+# --
+
+class BridgeNode:
+ def __init__(self, nodeId, dpId, name, controllerTarget, controllerConnected):
+ global state
+ self.alias = state.getNextAlias(nodeId)
+ self.nodeId = nodeId
+ self.dpId = dpId
+ self.name = name
+ self.controllerTarget = controllerTarget
+ self.controllerConnected = controllerConnected
+ self.tps = []
+
+ def getOpenflowName(self):
+ if self.dpId is None:
+ return self.nodeId
+ return dataPathIdToOfFormat(self.dpId)
+
+ def addTerminationPoint(self, terminationPoint):
+ self.tps.append(terminationPoint)
+
+ def __repr__(self):
+ return 'BridgeNode {}:{} {}:{} {}:{} {}:{} {}:{} {}:{} {}:{} {}:{}'.format(
+ 'alias', self.alias,
+ 'nodeId', self.nodeId,
+ 'dpId', self.dpId,
+ 'openflowName', self.getOpenflowName(),
+ 'name', self.name,
+ 'controllerTarget', self.controllerTarget,
+ 'controllerConnected', self.controllerConnected,
+ 'tps', self.tps)
+
+# --
+
+class OvsdbNode:
+ def __init__(self, nodeId, inetMgr, inetNode, otherLocalIp, ovsVersion):
+ global state
+ if inetNode != '':
+ self.alias = inetNode
+ else:
+ self.alias = nodeId
+ self.nodeId = nodeId
+ self.inetMgr = inetMgr
+ self.inetNode = inetNode
+ self.otherLocalIp = otherLocalIp
+ self.ovsVersion = ovsVersion
+
+ def __repr__(self):
+ return 'OvsdbNode {}:{} {}:{} {}:{} {}:{} {}:{} {}:{}'.format(
+ 'alias', self.alias,
+ 'nodeId', self.nodeId,
+ 'inetMgr', self.inetMgr,
+ 'inetNode', self.inetNode,
+ 'otherLocalIp', self.otherLocalIp,
+ 'ovsVersion', self.ovsVersion)
+
+# ======================================================================
+
+def make_it_a_string(param):
+ result = ""
+ try:
+ result = str( param )
+ except:
+ pass
+ return result
+
+# ======================================================================
+
+def printError(msg):
+ sys.stderr.write(msg)
+
+# ======================================================================
+
+def prt(msg, logLevel=0):
+ prtCommon(msg, logLevel)
+def prtLn(msg, logLevel=0):
+ prtCommon('{}\n'.format(msg), logLevel)
+def prtCommon(msg, logLevel):
+ if options.debug >= logLevel:
+ sys.stdout.write(msg)
+
+# ======================================================================
+
+def getMdsalTreeType():
+ if options.useConfigTree:
+ return CONST_CONFIG
+ return CONST_OPERATIONAL
+
+# --
+
+def grabJson(url):
+
+ try:
+ request = urllib2.Request(url)
+ # You need the replace to handle encodestring adding a trailing newline
+ # (https://docs.python.org/2/library/base64.html#base64.encodestring)
+ base64string = base64.encodestring('{}:{}'.format(options.odlUsername, options.odlPassword)).replace('\n', '')
+ request.add_header('Authorization', 'Basic {}'.format(base64string))
+ result = urllib2.urlopen(request)
+ except urllib2.URLError, e:
+ printError('Unable to send request: {}\n'.format(e))
+ sys.exit(1)
+
+ if (result.code != 200):
+ printError( '{}\n{}\n\nError: unexpected code: {}\n'.format(result.info(), result.read(), result.code) )
+ sys.exit(1)
+
+ data = json.load(result)
+ prtLn(data, 4)
+ return data
+
+# --
+
+def grabInventoryJson(mdsalTreeType):
+ global jsonInventoryNodes
+
+ url = 'http://{}:{}/restconf/{}/opendaylight-inventory:nodes/'.format(options.odlIp, options.odlPort, mdsalTreeType)
+ data = grabJson(url)
+
+ if not 'nodes' in data:
+ printError( '{}\n\nError: did not find nodes in {}'.format(data, url) )
+ sys.exit(1)
+
+ data2 = data['nodes']
+ if not 'node' in data2:
+ printError( '{}\n\nError: did not find node in {}'.format(data2, url) )
+ sys.exit(1)
+
+ jsonInventoryNodes = data2['node']
+
+# --
+
+def parseInventoryJson(mdsalTreeType):
+ global jsonInventoryNodes
+ global flowInfoNodes
+
+ for nodeDict in jsonInventoryNodes:
+ if not 'id' in nodeDict:
+ continue
+
+ bridgeOfId = nodeDict.get('id')
+ prtLn('inventory node {} has keys {}'.format(bridgeOfId, nodeDict.keys()), 3)
+
+ # locate bridge Node
+ bridgeNodeId = None
+ bridgeNode = None
+ for currNodeId in state.bridgeNodes.keys():
+ if state.bridgeNodes[currNodeId].getOpenflowName() == bridgeOfId:
+ bridgeNodeId = currNodeId
+ bridgeNode = state.bridgeNodes[currNodeId]
+ break
+
+ if bridgeNodeId is None:
+ prtLn('inventory node {}'.format(bridgeOfId), 1)
+ else:
+ prtLn('inventory node {}, aka {}, aka {}'.format(bridgeOfId, bridgeNodeId, showPrettyName(bridgeNodeId)), 1)
+
+ flowInfoNode = {}
+
+ indent = ' ' * 2
+ prtLn('{}features: {}'.format(indent, nodeDict.get('flow-node-inventory:switch-features', {})), 2)
+ prt('{}sw: {}'.format(indent, nodeDict.get('flow-node-inventory:software')), 2)
+ prt('{}hw: {}'.format(indent, nodeDict.get('flow-node-inventory:hardware')), 2)
+ prt('{}manuf: {}'.format(indent, nodeDict.get('flow-node-inventory:manufacturer')), 2)
+ prtLn('{}ip: {}'.format(indent, nodeDict.get('flow-node-inventory:ip-address')), 2)
+
+
+ for inventoryEntry in nodeDict.get('flow-node-inventory:table', []):
+ if 'id' in inventoryEntry:
+ currTableId = inventoryEntry.get('id')
+ for currFlow in inventoryEntry.get('flow', []):
+ prtLn('{}table {}: {}'.format(indent, currTableId, currFlow.get('id')), 1)
+ prtLn('{}{}'.format(indent * 2, currFlow), 2)
+
+ if currTableId in flowInfoNode:
+ flowInfoNode[ currTableId ].append( currFlow.get('id') )
+ else:
+ flowInfoNode[ currTableId ] = [ currFlow.get('id') ]
+
+ prtLn('', 1)
+
+ for currTableId in flowInfoNode.keys():
+ flowInfoNode[currTableId].sort()
+
+ # store info collected in flowInfoNodes
+ flowInfoNodes[bridgeOfId] = flowInfoNode
+
+# --
+
+def grabTopologyJson(mdsalTreeType):
+ global jsonTopologyNodes
+
+ url = 'http://{}:{}/restconf/{}/network-topology:network-topology/'.format(options.odlIp, options.odlPort, mdsalTreeType)
+ data = grabJson(url)
+
+ if not CONST_NET_TOPOLOGY in data:
+ printError( '{}\n\nError: did not find {} in data'.format(data, CONST_NET_TOPOLOGY) )
+ sys.exit(1)
+
+ data2 = data[CONST_NET_TOPOLOGY]
+ if not CONST_TOPOLOGY in data2:
+ printError( '{}\n\nError: did not find {} in data2'.format(data2, CONST_TOPOLOGY) )
+ sys.exit(1)
+
+ jsonTopologyNodes = data2[CONST_TOPOLOGY]
+
+# --
+
+def buildDpidCache():
+ global jsonTopologyNodes
+ global nodeIdToDpidCache
+
+ # only needed if not parsing operational tree
+ if getMdsalTreeType() == CONST_OPERATIONAL:
+ return
+
+ jsonTopologyNodesSave = jsonTopologyNodes
+ grabTopologyJson(CONST_OPERATIONAL)
+ jsonTopologyNodesLocal = jsonTopologyNodes
+ jsonTopologyNodes = jsonTopologyNodesSave
+
+ for nodeDict in jsonTopologyNodesLocal:
+ if nodeDict.get('topology-id') != 'ovsdb:1':
+ continue
+ for node in nodeDict.get('node', []):
+ if node.get('node-id') is None or node.get('ovsdb:datapath-id') is None:
+ continue
+ nodeIdToDpidCache[ node.get('node-id') ] = node.get('ovsdb:datapath-id')
+
+# --
+
+def parseTopologyJson(mdsalTreeType):
+ for nodeDict in jsonTopologyNodes:
+ if not 'topology-id' in nodeDict:
+ continue
+ prtLn('{} {} keys are: {}'.format(mdsalTreeType, nodeDict['topology-id'], nodeDict.keys()), 3)
+ if 'node' in nodeDict:
+ nodeIndex = 0
+ for currNode in nodeDict['node']:
+ parseTopologyJsonNode('', mdsalTreeType, nodeDict['topology-id'], nodeIndex, currNode)
+ nodeIndex += 1
+ prtLn('', 2)
+ if (mdsalTreeType == CONST_OPERATIONAL) and (nodeDict['topology-id'] == 'flow:1') and ('link' in nodeDict):
+ parseTopologyJsonFlowLink(nodeDict['link'])
+
+ prtLn('', 1)
+
+# --
+
+def parseTopologyJsonNode(indent, mdsalTreeType, topologyId, nodeIndex, node):
+ if node.get('node-id') is None:
+ printError( 'Warning: unexpected node: {}\n'.format(node) )
+ return
+ prt('{} {} node[{}] {} '.format(indent + mdsalTreeType, topologyId, nodeIndex, node.get('node-id')), 2)
+ if 'ovsdb:bridge-name' in node:
+ prtLn('', 2)
+ parseTopologyJsonNodeBridge(indent + ' ', mdsalTreeType, topologyId, nodeIndex, node)
+ elif 'ovsdb:connection-info' in node:
+ prtLn('', 2)
+ parseTopologyJsonNodeOvsdb(indent + ' ', mdsalTreeType, topologyId, nodeIndex, node)
+ else:
+ prtLn('keys: {}'.format(node.keys()), 2)
+
+# --
+
+def parseTopologyJsonNodeOvsdb(indent, mdsalTreeType, topologyId, nodeIndex, node):
+ keys = node.keys()
+ keys.sort()
+ for k in keys:
+ prtLn('{}{} : {}'.format(indent, k, node[k]), 2)
+
+ connectionInfoRaw = node.get('ovsdb:connection-info')
+ connectionInfo = {}
+ if type(connectionInfoRaw) is dict:
+ connectionInfo['inetMgr'] = make_it_a_string(connectionInfoRaw.get('local-ip')) + ':' + make_it_a_string(connectionInfoRaw.get('local-port'))
+ connectionInfo['inetNode'] = make_it_a_string(connectionInfoRaw.get('remote-ip')) + ':' + make_it_a_string(connectionInfoRaw.get('remote-port'))
+ otherConfigsRaw = node.get('ovsdb:openvswitch-other-configs')
+ otherLocalIp = ''
+ if type(otherConfigsRaw) is list:
+ for currOtherConfig in otherConfigsRaw:
+ if type(currOtherConfig) is dict and \
+ currOtherConfig.get('other-config-key') == 'local_ip':
+ otherLocalIp = currOtherConfig.get('other-config-value')
+ break
+
+ ovsdbNode = OvsdbNode(node.get('node-id'), connectionInfo.get('inetMgr'), connectionInfo.get('inetNode'), otherLocalIp, node.get('ovsdb:ovs-version'))
+ state.registerOvsdbNode(ovsdbNode)
+ prtLn('Added {}'.format(ovsdbNode), 1)
+
+# --
+
+def parseTopologyJsonNodeBridge(indent, mdsalTreeType, topologyId, nodeIndex, node):
+
+ controllerTarget = None
+ controllerConnected = None
+ controllerEntries = node.get('ovsdb:controller-entry')
+ if type(controllerEntries) is list:
+ for currControllerEntry in controllerEntries:
+ if type(currControllerEntry) is dict:
+ controllerTarget = currControllerEntry.get('target')
+ controllerConnected = currControllerEntry.get('is-connected')
+ break
+
+ nodeId = node.get('node-id')
+ dpId = node.get('ovsdb:datapath-id', nodeIdToDpidCache.get(nodeId))
+ bridgeNode = BridgeNode(nodeId, dpId, node.get('ovsdb:bridge-name'), controllerTarget, controllerConnected)
+
+ keys = node.keys()
+ keys.sort()
+ for k in keys:
+ if k == 'termination-point' and len(node[k]) > 0:
+ tpIndex = 0
+ for tp in node[k]:
+ terminationPoint = parseTopologyJsonNodeBridgeTerminationPoint('%stermination-point[%d] :' % (indent, tpIndex), mdsalTreeType, topologyId, nodeIndex, node, tp)
+
+ # skip boring tps
+ if terminationPoint.ofPort == CONST_TP_OF_INTERNAL and \
+ (terminationPoint.name == 'br-ex' or terminationPoint.name == 'br-int'):
+ pass
+ else:
+ bridgeNode.addTerminationPoint(terminationPoint)
+
+ tpIndex += 1
+ else:
+ prtLn('{}{} : {}'.format(indent, k, node[k]), 2)
+
+ state.registerBridgeNode(bridgeNode)
+ prtLn('Added {}'.format(bridgeNode), 1)
+
+
+# --
+
+def parseTopologyJsonNodeBridgeTerminationPoint(indent, mdsalTreeType, topologyId, nodeIndex, node, tp):
+ attachedMac = ''
+ ifaceId = ''
+
+ keys = tp.keys()
+ keys.sort()
+ for k in keys:
+ if (k == 'ovsdb:port-external-ids' or k == 'ovsdb:interface-external-ids') and len(tp[k]) > 0:
+ extIdIndex = 0
+ for extId in tp[k]:
+ prtLn('{} {}[{}] {} : {}'.format(indent, k, extIdIndex, extId.get('external-id-key'), extId.get('external-id-value')), 2)
+ extIdIndex += 1
+
+ if extId.get('external-id-key') == 'attached-mac':
+ attachedMac = extId.get('external-id-value')
+ if extId.get('external-id-key') == 'iface-id':
+ ifaceId = extId.get('external-id-value')
+ else:
+ prtLn('{} {} : {}'.format(indent, k, tp[k]), 2)
+
+ return TerminationPoint(tp.get('ovsdb:name'),
+ tp.get('ovsdb:ofport'),
+ tp.get('ovsdb:interface-type', '').split('-')[-1],
+ attachedMac, ifaceId)
+
+# --
+
+def parseTopologyJsonFlowLink(link):
+ linkCount = 0
+ spc = ' ' * 2
+ for currLinkDict in link:
+ linkCount += 1
+ linkId = currLinkDict.get('link-id')
+ linkDest = currLinkDict.get('destination', {}).get('dest-tp')
+ linkSrc = currLinkDict.get('source', {}).get('source-tp')
+
+ linkDestNode = currLinkDict.get('destination', {}).get('dest-node')
+ linkSrcNode = currLinkDict.get('source', {}).get('source-node')
+ prtLn('{} {} {} => {}:{} -> {}:{}'.format(spc, linkCount, linkId, linkSrcNode, linkSrc.split(':')[-1], linkDestNode, linkDest.split(':')[-1]), 3)
+
+ if linkId != linkSrc:
+ printError('Warning: ignoring link with unexpected id: %s != %s\n' % (linkId, linkSrc))
+ continue
+ else:
+ state.ofLinks[linkSrc] = linkDest
+
+# --
+
+def showPrettyNamesMap():
+ spc = ' ' * 2
+ if not options.useAlias or len(state.bridgeNodes) == 0:
+ return
+
+ prtLn('aliasMap:', 0)
+ resultMap = {}
+ for bridge in state.bridgeNodes.values():
+ resultMap[ bridge.alias ] = '{0: <25} {1: <7} {2}'.format(bridge.getOpenflowName(), bridge.name, bridge.dpId)
+
+ for resultMapKey in sorted(resultMap):
+ prtLn('{0}{1: <10} -> {2}'.format(spc, resultMapKey, resultMap[resultMapKey]), 0)
+ prtLn('', 0)
+
+# --
+
+def showNodesPretty():
+ if len(state.ovsdbNodes) == 0:
+ showBridgeOnlyNodes()
+ return
+
+ aliasDict = { state.ovsdbNodes[nodeId].alias : nodeId for nodeId in state.ovsdbNodes.keys() }
+ aliasDictKeys = aliasDict.keys()
+ aliasDictKeys.sort()
+ for ovsAlias in aliasDictKeys:
+ ovsdbNode = state.ovsdbNodes[ aliasDict[ovsAlias] ]
+
+ prt('ovsdbNode:{} mgr:{} version:{}'.format(ovsAlias, ovsdbNode.inetMgr, ovsdbNode.ovsVersion), 0)
+ if ovsdbNode.inetNode.split(':')[0] != ovsdbNode.otherLocalIp:
+ prt(' **localIp:{}'.format(ovsdbNode.otherLocalIp), 0)
+ prtLn('', 0)
+ showPrettyBridgeNodes(' ', getNodeBridgeIds(ovsdbNode.nodeId), ovsdbNode)
+ showBridgeOnlyNodes(True)
+ prtLn('', 0)
+
+# --
+
+def showFlowInfoPretty():
+ global flowInfoNodes
+ spc = ' ' * 2
+
+ if not options.showFlows:
+ return
+
+ if len(flowInfoNodes) == 0:
+ prtLn('no flowInfo found\n', 0)
+ return
+
+ # translate flowKeys (openflow:123124) into their alias format
+ # then sort it and translate back, so we list them in the order
+ flowInfoNodeKeysDict = {}
+ for flowInfoNodeKey in flowInfoNodes.keys():
+ flowInfoNodeKeysDict[ showPrettyName(flowInfoNodeKey) ] = flowInfoNodeKey
+ flowInfoNodeKeysKeys = flowInfoNodeKeysDict.keys()
+ flowInfoNodeKeysKeys.sort()
+
+ flowInfoNodesKeys = [ flowInfoNodeKeysDict[ x ] for x in flowInfoNodeKeysKeys ]
+
+ nodeIdToDpidCacheReverse = {dataPathIdToOfFormat(v): k for k, v in nodeIdToDpidCache.items()}
+ nodesVisited = 0
+ for flowInfoNodeKey in flowInfoNodesKeys:
+ if nodesVisited > 0: prtLn('', 0)
+
+ nodeName = showPrettyName(flowInfoNodeKey)
+ if nodeName == flowInfoNodeKey:
+ nodeName += ' ( {} )'.format( nodeIdToDpidCacheReverse.get(flowInfoNodeKey, 'node_not_in_topology') )
+
+ prtLn('{} tree flows at {}'.format(getMdsalTreeType(), nodeName), 0)
+ flowInfoNode = flowInfoNodes[flowInfoNodeKey]
+ flowInfoTables = flowInfoNode.keys()
+ flowInfoTables.sort()
+ for flowInfoTable in flowInfoTables:
+ for rule in flowInfoNode[flowInfoTable]:
+ prtLn('{}table {}: {}'.format(spc, flowInfoTable, rule), 0)
+ nodesVisited += 1
+
+ prtLn('', 0)
+
+# --
+
+def getNodeBridgeIds(nodeIdFilter = None):
+ resultMap = {}
+ for bridge in state.bridgeNodes.values():
+ if nodeIdFilter is None or nodeIdFilter in bridge.nodeId:
+ resultMap[ bridge.alias ] = bridge.nodeId
+ resultMapKeys = resultMap.keys()
+ resultMapKeys.sort()
+ return [ resultMap[x] for x in resultMapKeys ]
+
+# --
+
+def showPrettyBridgeNodes(indent, bridgeNodeIds, ovsdbNode = None):
+ if bridgeNodeIds is None:
+ return
+
+ for nodeId in bridgeNodeIds:
+ bridgeNode = state.bridgeNodes[nodeId]
+ prt('{}{}:{}'.format(indent, showPrettyName(nodeId), bridgeNode.name), 0)
+
+ if ovsdbNode is None or \
+ bridgeNode.controllerTarget is None or \
+ bridgeNode.controllerTarget == '' or \
+ ovsdbNode.inetMgr.split(':')[0] != bridgeNode.controllerTarget.split(':')[-2] or \
+ bridgeNode.controllerConnected != True:
+ prt(' controller:{}'.format(bridgeNode.controllerTarget), 0)
+ prt(' connected:{}'.format(bridgeNode.controllerConnected), 0)
+ prtLn('', 0)
+ showPrettyTerminationPoints(indent + ' ', bridgeNode.tps)
+
+# --
+
+def showBridgeOnlyNodes(showOrphansOnly = False):
+ if len(state.bridgeNodes) == 0:
+ return
+
+ # group bridges by nodeId prefix
+ resultMap = {}
+ for bridge in state.bridgeNodes.values():
+ nodePrefix = bridge.nodeId.split('/bridge/')[0]
+
+ if showOrphansOnly and nodePrefix in state.ovsdbNodes:
+ continue
+
+ if nodePrefix in resultMap:
+ resultMap[nodePrefix][bridge.alias] = bridge.nodeId
+ else:
+ resultMap[nodePrefix] = { bridge.alias: bridge.nodeId }
+ resultMapKeys = resultMap.keys()
+ resultMapKeys.sort()
+
+ if len(resultMapKeys) == 0:
+ return #noop
+
+ for nodePrefix in resultMapKeys:
+ nodePrefixEntriesKeys = resultMap[nodePrefix].keys()
+ nodePrefixEntriesKeys.sort()
+ # prtLn('Bridges in {}: {}'.format(nodePrefix, nodePrefixEntriesKeys), 0)
+ prtLn('Bridges in {}'.format(nodePrefix), 0)
+ nodeIds = [ resultMap[nodePrefix][nodePrefixEntry] for nodePrefixEntry in nodePrefixEntriesKeys ]
+ showPrettyBridgeNodes(' ', nodeIds)
+
+ prtLn('', 0)
+
+# --
+
+def showPrettyTerminationPoints(indent, tps):
+
+ tpsDict = {}
+ for tp in tps:
+ tpsDict[ tp.ofPort ] = tp
+
+ tpDictKeys = tpsDict.keys()
+ tpDictKeys.sort()
+ for tpKey in tpDictKeys:
+ tp = tpsDict[tpKey]
+ prt('{}of:{} {}'.format(indent, tp.ofPort, tp.name), 0)
+ if tp.mac != '':
+ prt(' {}:{}'.format('mac', tp.mac), 0)
+ if tp.ifaceId != '':
+ prt(' {}:{}'.format('ifaceId', tp.ifaceId), 0)
+
+ prtLn('', 0)
+
+# --
+
+def dataPathIdToOfFormat(dpId):
+ return 'openflow:' + str( int('0x' + dpId.replace(':',''), 16) )
+
+# --
+
+def showPrettyName(name):
+ if not options.useAlias:
+ return name
+
+ # handle both openflow:138604958315853:2 and openflow:138604958315853 (aka dpid)
+ # also handle ovsdb://uuid/5c72ec51-1e71-4a04-ab0b-b044fb5f4dc0/bridge/br-int (aka nodeId)
+ #
+ nameSplit = name.split(':')
+ ofName = ':'.join(nameSplit[:2])
+ ofPart = ''
+ if len(nameSplit) > 2:
+ ofPart = ':' + ':'.join(nameSplit[2:])
+
+ for bridge in state.bridgeNodes.values():
+ if bridge.getOpenflowName() == ofName or bridge.nodeId == name:
+ return '{}{}'.format(bridge.alias, ofPart)
+
+ # not found, return paramIn
+ return name
+
+# --
+
+def showOfLinks():
+ spc = ' ' * 2
+ ofLinksKeys = state.ofLinks.keys()
+ ofLinksKeys.sort()
+ ofLinksKeysVisited = set()
+
+ if len(ofLinksKeys) == 0:
+ # prtLn('no ofLinks found\n', 0)
+ return
+
+ prtLn('ofLinks (discover via lldp):', 0)
+ for ofLinkKey in ofLinksKeys:
+ if ofLinkKey in ofLinksKeysVisited:
+ continue
+ if state.ofLinks.get( state.ofLinks[ofLinkKey] ) == ofLinkKey:
+ prtLn('{}{} <-> {}'.format(spc, showPrettyName(ofLinkKey), showPrettyName(state.ofLinks[ofLinkKey])), 0)
+ ofLinksKeysVisited.add(state.ofLinks[ofLinkKey])
+ else:
+ prtLn('{}{} -> {}'.format(spc, showPrettyName(ofLinkKey), showPrettyName(state.ofLinks[ofLinkKey])), 0)
+ ofLinksKeysVisited.add(ofLinkKey)
+ prtLn('', 0)
+
+# --
+
+def parseArgv():
+ global options
+
+ parser = optparse.OptionParser(version="0.1")
+ parser.add_option("-d", "--debug", action="count", dest="debug", default=CONST_DEFAULT_DEBUG,
+ help="Verbosity. Can be provided multiple times for more debug.")
+ parser.add_option("-n", "--noalias", action="store_false", dest="useAlias", default=True,
+ help="Do not map nodeId of bridges to an alias")
+ parser.add_option("-i", "--ip", action="store", type="string", dest="odlIp", default="localhost",
+ help="opendaylights ip address")
+ parser.add_option("-t", "--port", action="store", type="string", dest="odlPort", default="8080",
+ help="opendaylights listening tcp port on restconf northbound")
+ parser.add_option("-u", "--user", action="store", type="string", dest="odlUsername", default="admin",
+ help="opendaylight restconf username")
+ parser.add_option("-p", "--password", action="store", type="string", dest="odlPassword", default="admin",
+ help="opendaylight restconf password")
+ parser.add_option("-c", "--config", action="store_true", dest="useConfigTree", default=False,
+ help="parse mdsal restconf config tree instead of operational tree")
+ parser.add_option("-f", "--hide-flows", action="store_false", dest="showFlows", default=True,
+ help="hide flows")
+
+ (options, args) = parser.parse_args(sys.argv)
+ prtLn('argv options:{} args:{}'.format(options, args), 2)
+
+# --
+
+def doMain():
+ global state
+
+ state = State()
+ parseArgv()
+ buildDpidCache()
+ grabTopologyJson(getMdsalTreeType())
+ grabInventoryJson(getMdsalTreeType())
+ parseTopologyJson(getMdsalTreeType())
+ parseInventoryJson(getMdsalTreeType())
+ showPrettyNamesMap()
+ showNodesPretty()
+ showFlowInfoPretty()
+ showOfLinks()
+
+# --
+
+if __name__ == "__main__":
+ doMain()
+ sys.exit(0)