def install_flow(node_id, table_id): """ This will install a flow. You should pass via POST few args. TODO: Better documentation. """ credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) try: node = odl.get_node_by_id(node_id) table = node.get_table_by_id(table_id) except (NodeNotFound, TableNotFound) as e: flask.abort(404) form = flask.request.form table.install_flow(priority = form.get('priority'), name = form.get('name'), eth_type = form.get('eth_type'), eth_source = form.get('eth_source'), eth_destination = form.get('eth_destination'), ipv4_source = form.get('ipv4_source'), ipv4_destination = form.get('ipv4_destination'), connector_id = form.get('output'), template_dir = template_dir) return flask.redirect("/")
def path_stats(node_id, table_id, clean_flow_id, diff): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) try: node = odl.get_node_by_id(node_id) table = node.get_table_by_id(table_id) flow = table.get_flow_by_clean_id(clean_flow_id) except (NodeNotFound, TableNotFound, FlowNotFound) as e: return flask.abort(404) nodes = odl.get_nodes() data = []; eth_type = flow.get_ethernet_type() eth_src = flow.get_ethernet_source() eth_dest = flow.get_ethernet_destination() ipv4_src = flow.get_ipv4_source() ipv4_dest = flow.get_ipv4_destination() if eth_type == 0x0800 and (eth_src != '*' or eth_dest != '*' or ipv4_src != '*' or ipv4_dest != '*'): path = explore_path(nodes, flow, eth_type, eth_src, eth_dest, ipv4_src, ipv4_dest) for n in path: ndata = { 'id': n['id'], 'main': get_rrd_stats(n['id'], n['main']['table_id'], n['main']['clean_flow_id'], diff) } if n.has_key('oposite'): ndata['oposite'] = get_rrd_stats(n['id'], n['oposite']['table_id'], n['oposite']['clean_flow_id'], diff) data.append(ndata) else: data.append({'id': node.id, 'main': get_rrd_stats(node.id, table.id, flow.clean_id, diff)}) return flask.jsonify(data)
def delete_flow(node_id, table_id, flow_id): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) data = json.loads(flask.request.get_data().decode('utf-8')) delete_all = data['delete_all'] try: # Get the node object node = odl.get_node_by_id(node_id) # Get the table object table = node.get_table_by_id(table_id) # Get the flow flow = table.get_all_flows()[flow_id] except (NodeNotFound, TableNotFound, FlowNotFound) as e: flask.abort(404) if delete_all: nodes = odl.get_nodes() for node in nodes.values(): node.delete_config_flows_by_name(flow.name) else: flow.delete() return flask.redirect("/")
def flow_stats(node_id, table_id, clean_flow_id): """ This endpoint returns statistics to plot. You should pass a node id, table id and a clean flow id. (removing #, $, - and * symbols from id). """ # Main flow main = get_rrd_stats(node_id, table_id, clean_flow_id) credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) try: node = odl.get_node_by_id(node_id) table = node.get_table_by_id(table_id) flow = table.get_flow_by_clean_id(clean_flow_id) except (NodeNotFound, TableNotFound, FlowNotFound) as e: return flask.abort(404) # Try to get the oposite flow (just in case of where booth are added with # same name. flows = table.get_config_flows_by_name(flow.name) for oposite in flows: if oposite.clean_id != clean_flow_id: break if flows: oposite = get_rrd_stats(node_id, table_id, oposite.clean_id) else: oposite = [] return flask.jsonify({'main': main, 'oposite': oposite})
def all_stats(): """ Get all statistics information for each node """ credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) nodes = odl.get_nodes() all_stats = {} for node in nodes.values(): ports = node.get_connectors() for port in ports.values(): connector = port.id stat = get_port_rrd_stats(node.id, port.id, 120) rates = map(lambda x: x['bytes'], stat) rate = sum(rates) / len(rates) if rates else 0 all_stats[connector] = rate # tables = node.get_tables() # for table in tables.values(): # for flow in table.get_all_flows().values(): # for action in flow.get_actions(): # if action['type'] == 'output-action': # connector = node.id + ":" + action['value'] # stat = get_rrd_stats(node.id, table.id, flow.clean_id, 120) # rates = map(lambda x: x['bytes'], stat) # rate = sum(rates) / len(rates) if rates else 0 # all_stats[connector] = all_stats.get(connector, 0) + rate return flask.jsonify(all_stats)
def install_flows_for_l3path(path_id): """ This will install a l3 full path flows (based on IP Address addresses) in all switches in a path. You should use first '/api/routes/l3' to see the uid of path. This is a necessary argument for this endpoint. """ client_ip = "%s" % flask.request.environ['REMOTE_ADDR'] try: path = session_l3paths[client_ip][path_id] except KeyError: flask.abort(404) ports = get_ports_on_path(path) source_host = path[0] target_host = path[-1] # Install a flow in each switch on the path with correct output # port. for source_port, target_port in ports: source_switch = "%s:%s" % (source_port.split(":")[0], source_port.split(":")[1]) target_switch = "%s:%s" % (target_port.split(":")[0], target_port.split(":")[1]) # Just in case check if (source_switch != target_switch): print "Error 500: Switches are different on path" flask.abort(500) # Match: source_port, source_host, target_host, eth_type = 0x806 ? # Target Action: target_port # Lookup for switch in database try: credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) node = odl.get_node_by_id(target_switch) table = node.get_table_by_id(0) # Assuming installing on table 0 except (NodeNotFound, TableNotFound) as e: print "Error: 404 - Switch or table not found in database" flask.abort(404) print "Inserting flow for %s..." % node.id # Install the flow one way table.l3output(flow_name = "L3AR%s" % path_id.split("-")[0], connector_id = target_port, source = "%s/32" % source_host, destination = "%s/32" % target_host, template_dir = template_dir) # Install the flow another way table.l3output(flow_name = "L3AR%s" % path_id.split("-")[0], connector_id = source_port, source = "%s/32" % target_host, destination = "%s/32" % source_host, template_dir = template_dir) # Update Json file return flask.redirect("/")
def get_topology(): """ This endpoint returns a big topology with nodes and links. """ credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) data = odl.to_dict() return flask.jsonify(data)
def delete_low_priority_flows(node_id, table_id): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) try: node = odl.get_node_by_id(node_id) table = node.get_table_by_id(table_id) table.delete_low_priority_flows() return flask.redirect("/") except (NodeNotFloud, TableNotFound) as e: flask.abort(404)
def __init__(self, url, user, pw): self.prompt = col.PROMPT + "odl-cli> " + col.ENDC self.config = {} self.cwc = self.config self.cwd_list = [] self.odl = ODLInstance(url, (user, pw)) self.util = Util() self.node = None self.table = None self.pp = pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None) cmd.Cmd.__init__(self)
def flow_stats_all(name, diff): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) nodes = odl.get_nodes() stats = {} for node in nodes.values(): tables = node.get_tables() node_stats = {} for table in tables.values(): flows = table.get_config_flows_by_name(name) for flow in flows: node_stats[flow.clean_id] = get_rrd_stats(node.id, table.id, flow.clean_id, diff) if node_stats: stats[node.id] = node_stats return flask.jsonify(stats)
def l2routes(): """ This returns a list of all paths available between two MAC address. Also an random ID is generated for this session for each path. So you can use this ID when creating a complete PATH l2 flow. You should pass as data to the POST request the source and destination MAC addresses. Ex: {'source': '00:00:00:00:00:01', 'destination': '00:00:00:00:00:02'} """ data = json.loads(flask.request.get_data().decode('utf-8')) source = data['source'] destination = data['destination'] credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) graph = odl.topology.get_networkx_graph() client_ip = "%s" % flask.request.environ['REMOTE_ADDR'] session_l2paths[client_ip] = {} paths = [] for path in nx.all_simple_paths(graph, source, destination): uid = "%s" % uuid.uuid1() paths.append({'uid': uid, 'path': path}) session_l2paths[client_ip][uid] = path return flask.jsonify({'paths': paths})
def flow_stats_all(name, diff): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) nodes = odl.get_nodes() stats = {} for node in nodes.values(): tables = node.get_tables() node_stats = {} for table in tables.values(): flows = table.get_config_flows_by_name(name) for flow in flows: node_stats[flow.clean_id] = get_rrd_stats( node.id, table.id, flow.clean_id, diff) if node_stats: stats[node.id] = node_stats return flask.jsonify(stats)
def spce_set_tc(): data = json.loads(flask.request.get_data().decode('utf-8')) source = data['source'] destination = data['destination'] bandwidth = data['bandwidth'] bs = data['bs'] operation = data['operation'] credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) spce = ALTOSpce(odl) try: if operation == 'create': return flask.jsonify( spce.set_tc(src=source, dst=destination, bd=bandwidth, bs=bs)) else: return flask.jsonify( spce.update_tc(src=source, dst=destination, bd=bandwidth, bs=bs)) except ODLErrorOnPOST as e: print "Error: 500 - Rate limiting setup failed" flask.abort(500)
def e2e_stats(path_id, diff): if cache_l2paths.has_key(path_id): path = cache_l2paths[path_id] flow_name = "L2AR%s" % path_id.split("-")[0] source_host = ":".join(path[0].split(":")[1::]) target_host = ":".join(path[-1].split(":")[1::]) match = {'eth_type': 0x0800, 'eth_src': source_host, 'eth_dest': target_host, 'ipv4_src': '*', 'ipv4_dest': '*'} elif cache_l3paths.has_key(path_id): path = cache_l3paths[path_id] flow_name = "L3AR%s" % path_id.split("-")[0] source_host = path[0] + '/32' target_host = path[-1] + '/32' match = {'eth_type': 0x0800, 'eth_src': '*', 'eth_dest': '*', 'ipv4_src': source_host, 'ipv4_dest': target_host} else: flask.abort(404) ports = get_ports_on_path(path) source_switch = "%s:%s" % (ports[0][1].split(":")[0], ports[0][1].split(":")[1]) target_switch = "%s:%s" % (ports[-1][0].split(":")[0], ports[-1][0].split(":")[1]) try: credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) main_node = odl.get_node_by_id(source_switch) oposite_node = odl.get_node_by_id(target_switch) # Assuming installing on table 0 main_table = main_node.get_table_by_id(0) oposite_table = oposite_node.get_table_by_id(0) except (NodeNotFound, TableNotFound) as e: print "Error: 404 - Switch or table not found in database" flask.abort(404) main = {} for flow in main_table.get_config_flows_by_name(flow_name): if check_match_flow(flow, **match): main = get_rrd_stats(main_node.id, main_table.id, flow.clean_id, diff) break oposite = {} for flow in oposite_table.get_config_flows_by_name(flow_name): if check_reverse_match_flow(flow, **match): oposite = get_rrd_stats(oposite_node.id, oposite_table.id, flow.clean_id, diff) break return flask.jsonify({'main': main, 'oposite': oposite, 'source': source_host, 'target': target_host})
def path_stats(node_id, table_id, clean_flow_id, diff): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) try: node = odl.get_node_by_id(node_id) table = node.get_table_by_id(table_id) flow = table.get_flow_by_clean_id(clean_flow_id) except (NodeNotFound, TableNotFound, FlowNotFound) as e: return flask.abort(404) nodes = odl.get_nodes() data = [] eth_type = flow.get_ethernet_type() eth_src = flow.get_ethernet_source() eth_dest = flow.get_ethernet_destination() ipv4_src = flow.get_ipv4_source() ipv4_dest = flow.get_ipv4_destination() if eth_type == 0x0800 and (eth_src != '*' or eth_dest != '*' or ipv4_src != '*' or ipv4_dest != '*'): path = explore_path(nodes, flow, eth_type, eth_src, eth_dest, ipv4_src, ipv4_dest) for n in path: ndata = { 'id': n['id'], 'main': get_rrd_stats(n['id'], n['main']['table_id'], n['main']['clean_flow_id'], diff) } if n.has_key('oposite'): ndata['oposite'] = get_rrd_stats(n['id'], n['oposite']['table_id'], n['oposite']['clean_flow_id'], diff) data.append(ndata) else: data.append({ 'id': node.id, 'main': get_rrd_stats(node.id, table.id, flow.clean_id, diff) }) return flask.jsonify(data)
def l3routes(): """ This returns a list of all paths available between two IPv4 address. Also an random ID is generated for this session for each path. So you can use this ID when creating a complete PATH l3 flow. You should pass as data to the POST request the source and destination IPv4 addresses. Ex: {'source': '192.168.1.1', 'destination': '192.168.1.2'} """ data = json.loads(flask.request.get_data().decode('utf-8')) source = data['source'] destination = data['destination'] credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) graph = odl.topology.get_networkx_graph() source_id, dest_id = None, None # Theses are topology nodes # TODO: Topology nodes should be of same type of a normal node. # EX: switch vs Host vs Port nodes = odl.topology.get_nodes() for node in nodes.values(): node_id = node['node-id'] if (node_id.split(":")[0] == "host"): ips = node['host-tracker-service:addresses'] for ip in ips: if ip['ip'] == source: source_id = "host:%s" % ip['mac'] if ip['ip'] == destination: dest_id = "host:%s" % ip['mac'] if not source_id or not dest_id: return flask.jsonify({'paths': []}) client_ip = "%s" % flask.request.environ['REMOTE_ADDR'] session_l3paths[client_ip] = {} paths = [] for path in nx.all_simple_paths(graph, source_id, dest_id): uid = "%s" % uuid.uuid1() path[0] = source path[-1] = destination paths.append({'uid': uid, 'path': path}) session_l3paths[client_ip][uid] = path return flask.jsonify({'paths': paths})
def all_stats(): """ Get all statistics information for each node """ credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) nodes = odl.get_nodes() all_stats = {} for node in nodes.values(): tables = node.get_tables() for table in tables.values(): for flow in table.get_all_flows().values(): for action in flow.get_actions(): if action['type'] == 'output-action': connector = node.id + ":" + action['value'] stat = get_rrd_stats(node.id, table.id, flow.clean_id, 120) rates = map(lambda x: x['bytes'], stat) rate = sum(rates) / len(rates) if rates else 0 all_stats[connector] = all_stats.get(connector, 0) + rate return flask.jsonify(all_stats)
def spce_remove_tc(): data = json.loads(flask.request.get_data().decode('utf-8')) path = data['path'] credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) spce = ALTOSpce(odl) try: return flask.jsonify(spce.remove_tc(path)) except ODLErrorOnPOST as e: print "Error: 500 - Rate limiting setup failed" flask.abort(500)
def l2routes(): """ This returns a list of all paths available between two MAC address. Also an random ID is generated for this session for each path. So you can use this ID when creating a complete PATH l2 flow. You should pass as data to the POST request the source and destination MAC addresses. Ex: {'source': '00:00:00:00:00:01', 'destination': '00:00:00:00:00:02'} """ data = json.loads(flask.request.get_data().decode('utf-8')) source = data['source'] destination = data['destination'] source_mac = data['source-mac'] destination_mac = data['destination-mac'] src_vlan = data['source-vlan'] if 'source-vlan' in data.keys() else '' dst_vlan = data['destination-vlan'] if 'destination-vlan' in data.keys( ) else '' if src_vlan != '' and dst_vlan != '': flask.abort(500, "Only one attachment point can have a vlan tag!") credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) graph = odl.topology.get_networkx_graph() client_ip = "%s" % flask.request.environ['REMOTE_ADDR'] session_l2paths[client_ip] = {} paths = [] for path in nx.all_simple_paths(graph, source, destination): uid = "%s" % uuid.uuid1() if source_mac: path = ['host:' + source_mac] + path if destination_mac: path.append('host:' + destination_mac) paths.append({'uid': uid, 'path': path}) session_l2paths[client_ip][uid] = { 'path': path, 'src-vlan': src_vlan, 'dst-vlan': dst_vlan } return flask.jsonify({'paths': paths})
def delete_flow(node_id, table_id, flow_id): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) delete_all = flask.request.form.get('delete_all') try: # Get the node object node = odl.get_node_by_id(node_id) # Get the table object table = node.get_table_by_id(table_id) # Get the flow flow = table.get_flow_by_id(flow_id) except (NodeNotFound, TableNotFound, FlowNotFound) as e: flask.abort(404) if delete_all: nodes = odl.get_nodes() for node in nodes.values(): node.delete_config_flows_by_name(flow.name) else: flow.delete() return flask.redirect("/")
def spce_get_paths(): credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) spce = ALTOSpce(odl) try: paths = spce.get_all_paths() alto_paths = [] for path in paths: p = {'path': path['path'].split('|')} if 'tc' in path.keys() and path['tc'] >= 0: p['tc'] = path['tc'] alto_paths.append(p) return flask.jsonify(paths=alto_paths) except ODLErrorOnPOST as e: print "Error: 500 - Get path failed" flask.abort(500)
def spce_setup_path(): data = json.loads(flask.request.get_data().decode('utf-8')) source = data['source'] destination = data['destination'] obj_metrics = data['obj_metrics'] constraints = data['constraints'] credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) spce = ALTOSpce(odl) try: return flask.jsonify( spce.path_setup(src=source, dst=destination, objective_metrics=obj_metrics, constraint_metric=constraints)) except ODLErrorOnPOST as e: print "Error: 500 - Setup path failed" flask.abort(500)
class ODLCmd(cmd.Cmd): def __init__(self, url, user, pw): self.prompt = col.PROMPT + "odl-cli> " + col.ENDC self.config = {} self.cwc = self.config self.cwd_list = [] self.odl = ODLInstance(url, (user, pw)) self.util = Util() self.node = None self.table = None self.pp = pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None) cmd.Cmd.__init__(self) def emptyline(self): pass def do_cd(self, path): '''Change the current level of view of the config to be at <key> cd <key>''' if path == "" or path[0] == "/": new_wd_list = path[1:].split("/") else: new_wd_list = self.cwd_list + path.split("/") try: cwc, new_wd_list = self._conf_for_list(new_wd_list) except ConfigurationError as e: print col.FAIL + str(e) + col.ENDC return self.cwd_list = new_wd_list self.cwc = cwc def complete_cd(self, text, l, b, e): return [ x[b - 3:] for x, y in self.cwc.iteritems() if x.startswith(l[3:]) ] def do_ls(self, key): '''Show the top level of the current working config, or top level of config under [key] ls [key]''' conf = self.cwc if key: try: conf = conf[key] except KeyError: print "No such key %s" % key return try: for k, v in conf.iteritems(): if isinstance(v, ODLNode): try: hostname = socket.gethostbyaddr(v.ip_address)[0] except: hostname = v.ip_address print col.DIR + k + col.ENDC + ": (\"%s\", \"%s\", \"%s\")" % \ (hostname, v.description, v.manufacturer) elif isinstance(v, dict) or isinstance(v, list): print col.DIR + k + col.ENDC else: print "%s: %s" % (k, v) except: print "%s" % conf def complete_ls(self, text, l, b, e): return [ x[b - 3:] for x, y in self.cwc.iteritems() if x.startswith(l[3:]) ] def do_lsd(self, key): '''Show all config from current level down... or all config under [key] lsd [key]''' conf = self.cwc if key: try: conf = conf[key] except KeyError: print "No such key %s" % key self.pp.pprint(conf) def complete_lsd(self, text, l, b, e): return [ x for x, y in self.cwc.iteritems() if isinstance(y, dict) and x.startswith(text) ] def do_pwd(self, key): '''Show current path in config separated by slashes pwd''' print "/" + "/".join(self.cwd_list) def do_get_nodes(self, args): '''Get all or a specific node from ODL get_nodes [node]''' try: nodes = self.odl.get_nodes() self.config = nodes self._set_cwc() except Exception as e: print "Error: %s" % e def do_get_topo(self, args): '''Get ODL topology''' try: t = ODLTopology(None, None, self.odl) topo = t.get_topology() self.config = topo self._set_cwc() except Exception as e: print "Error: %s" % e def do_del_flow(self, fid): try: if not self.cwd_list[-3] == "tables": raise except: print col.FAIL + "Not in a valid table leaf!" + col.ENDC return if not fid: print col.FAIL + "Must specify flow id or '*'" + col.ENDC return table = self.cwd_list[-2] if fid == "*": yn = self.util.query_yes_no("Delete ALL flows in table %s" % (table)) if yn: flows = self.tables[int(table)].get_config_flows() for f in flows.values(): try: f.delete() except Exception as e: print "Error deleting flow: %s" % e else: return else: yn = self.util.query_yes_no("Delete flow %s in table %s" % (fid, table)) if yn: try: flows = self.tables[int(table)].get_config_flows() flows[fid].delete() except Exception as e: print "Error deleting flow: %s" % e else: return self.do_update(None) self.do_get_nodes(None) def complete_del_flow(self, text, l, b, e): return [ x[b - 9:] for x, y in self.cwc.iteritems() if x.startswith(l[9:]) ] def do_add_flow(self, args): '''Add a flow, will prompt for user input''' if not self.node: print col.FAIL + "No ODL node selected!" + col.ENDC return file_path = self.util.get_string("Input file: ", None) if not file_path: print "You must include a json file containing the ODL flow(s)" return try: with open(file_path, 'r') as in_file: raw_json = in_file.read() flow_requests = json.loads(raw_json) except IOError, e: print "Could not open file %s" % file_path return except ValueError, e: print "Invalid json formatting in request" return
def e2e_stats(path_id, diff): if cache_l2paths.has_key(path_id): path = cache_l2paths[path_id] flow_name = "L2AR%s" % path_id.split("-")[0] source_host = ":".join(path[0].split(":")[1::]) target_host = ":".join(path[-1].split(":")[1::]) match = { 'eth_type': 0x0800, 'eth_src': source_host, 'eth_dest': target_host, 'ipv4_src': '*', 'ipv4_dest': '*' } elif cache_l3paths.has_key(path_id): path = cache_l3paths[path_id] flow_name = "L3AR%s" % path_id.split("-")[0] source_host = path[0] + '/32' target_host = path[-1] + '/32' match = { 'eth_type': 0x0800, 'eth_src': '*', 'eth_dest': '*', 'ipv4_src': source_host, 'ipv4_dest': target_host } else: flask.abort(404) ports = get_ports_on_path(path) source_switch = "%s:%s" % (ports[0][1].split(":")[0], ports[0][1].split(":")[1]) target_switch = "%s:%s" % (ports[-1][0].split(":")[0], ports[-1][0].split(":")[1]) try: credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) main_node = odl.get_node_by_id(source_switch) oposite_node = odl.get_node_by_id(target_switch) # Assuming installing on table 0 main_table = main_node.get_table_by_id(0) oposite_table = oposite_node.get_table_by_id(0) except (NodeNotFound, TableNotFound) as e: print "Error: 404 - Switch or table not found in database" flask.abort(404) main = {} for flow in main_table.get_config_flows_by_name(flow_name): if check_match_flow(flow, **match): main = get_rrd_stats(main_node.id, main_table.id, flow.clean_id, diff) break oposite = {} for flow in oposite_table.get_config_flows_by_name(flow_name): if check_reverse_match_flow(flow, **match): oposite = get_rrd_stats(oposite_node.id, oposite_table.id, flow.clean_id, diff) break return flask.jsonify({ 'main': main, 'oposite': oposite, 'source': source_host, 'target': target_host })
class ODLCmd(cmd.Cmd): def __init__(self, url, user, pw): self.prompt = col.PROMPT + "odl-cli> " + col.ENDC self.config = {} self.cwc = self.config self.cwd_list = [] self.odl = ODLInstance(url, (user, pw)) self.util = Util() self.node = None self.table = None self.pp = pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None) cmd.Cmd.__init__(self) def emptyline(self): pass def do_cd(self, path): '''Change the current level of view of the config to be at <key> cd <key>''' if path=="" or path[0]=="/": new_wd_list = path[1:].split("/") else: new_wd_list = self.cwd_list + path.split("/") try: cwc, new_wd_list = self._conf_for_list(new_wd_list) except ConfigurationError as e: print col.FAIL + str(e) + col.ENDC return self.cwd_list = new_wd_list self.cwc = cwc def complete_cd(self, text, l, b, e): return [ x[b-3:] for x,y in self.cwc.iteritems() if x.startswith(l[3:])] def do_ls(self, key): '''Show the top level of the current working config, or top level of config under [key] ls [key]''' conf = self.cwc if key: try: conf = conf[key] except KeyError: print "No such key %s" % key return try: for k,v in conf.iteritems(): if isinstance(v, ODLNode): try: hostname = socket.gethostbyaddr(v.ip_address)[0] except: hostname = v.ip_address print col.DIR + k + col.ENDC + ": (\"%s\", \"%s\", \"%s\")" % \ (hostname, v.description, v.manufacturer) elif isinstance(v, dict) or isinstance(v, list): print col.DIR + k + col.ENDC else: print "%s: %s" % (k, v) except: print "%s" % conf def complete_ls(self, text, l, b, e): return [ x[b-3:] for x,y in self.cwc.iteritems() if x.startswith(l[3:]) ] def do_lsd(self, key): '''Show all config from current level down... or all config under [key] lsd [key]''' conf = self.cwc if key: try: conf = conf[key] except KeyError: print "No such key %s" % key self.pp.pprint(conf) def complete_lsd(self, text, l, b, e): return [ x for x,y in self.cwc.iteritems() if isinstance(y, dict) and x.startswith(text) ] def do_pwd(self, key): '''Show current path in config separated by slashes pwd''' print "/" + "/".join(self.cwd_list) def do_get_nodes(self, args): '''Get all or a specific node from ODL get_nodes [node]''' try: nodes = self.odl.get_nodes() self.config = nodes self._set_cwc() except Exception as e: print "Error: %s" % e def do_get_topo(self, args): '''Get ODL topology''' try: t = ODLTopology(None, None, self.odl) topo = t.get_topology() self.config = topo self._set_cwc() except Exception as e: print "Error: %s" % e def do_del_flow(self, fid): try: if not self.cwd_list[-3] == "tables": raise except: print col.FAIL + "Not in a valid table leaf!" + col.ENDC return if not fid: print col.FAIL + "Must specify flow id or '*'" + col.ENDC return table = self.cwd_list[-2] if fid == "*": yn = self.util.query_yes_no("Delete ALL flows in table %s" % (table)) if yn: flows = self.tables[int(table)].get_config_flows() for f in flows.values(): try: f.delete() except Exception as e: print "Error deleting flow: %s" % e else: return else: yn = self.util.query_yes_no("Delete flow %s in table %s" % (fid, table)) if yn: try: flows = self.tables[int(table)].get_config_flows() flows[fid].delete() except Exception as e: print "Error deleting flow: %s" % e else: return self.do_update(None) self.do_get_nodes(None) def complete_del_flow(self, text, l, b, e): return [ x[b-9:] for x,y in self.cwc.iteritems() if x.startswith(l[9:]) ] def do_add_flow(self, args): '''Add a flow, will prompt for user input''' if not self.node: print col.FAIL + "No ODL node selected!" + col.ENDC return file_path = self.util.get_string("Input file: ", None) if not file_path: print "You must include a json file containing the ODL flow(s)" return try: with open(file_path, 'r') as in_file: raw_json = in_file.read() flow_requests = json.loads(raw_json) except IOError, e: print "Could not open file %s" % file_path return except ValueError, e: print "Invalid json formatting in request" return
def install_flows_for_l2path(path_id): """ This will install a l2 full path flows (based on MAC addresses) in all switches in a path. You should use first '/api/routes/l2' to see the uid of path. This is a necessary argument for this endpoint. """ client_ip = "%s" % flask.request.environ['REMOTE_ADDR'] try: path = session_l2paths[client_ip][path_id] path, src_vlan, dst_vlan = path['path'], path['src-vlan'], path[ 'dst-vlan'] src_vlan = src_vlan if src_vlan != '' else None dst_vlan = dst_vlan if dst_vlan != '' else None except KeyError: flask.abort(404) ports = get_ports_on_path(path) # [(u'openflow:562958149829575:2', u'openflow:562958149829575:21'), # (u'openflow:440565346114459:257', u'openflow:440565346114459:217')] data = json.loads(flask.request.get_data().decode('utf-8')) source_host = data['source'] target_host = data['destination'] # source_host = ":".join(path[0].split(":")[1::]) # target_host = ":".join(path[-1].split(":")[1::]) # Install a flow in each switch on the path with correct output # port. if dst_vlan: source_host, target_host = target_host, source_host src_vlan, dst_vlan = dst_vlan, src_vlan ports.reverse() first = src_vlan for source_port, target_port in ports: source_switch = "%s:%s" % (source_port.split(":")[0], source_port.split(":")[1]) target_switch = "%s:%s" % (target_port.split(":")[0], target_port.split(":")[1]) # Just in case check if (source_switch != target_switch): print "Error 500: Switches are different on path" flask.abort(500) # Match: source_port, source_host, target_host, eth_type = 0x806 ? # Target Action: target_port # Lookup for switch in database try: credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) node = odl.get_node_by_id(target_switch) table = node.get_table_by_id(0) # Assuming installing on table 0 except (NodeNotFound, TableNotFound) as e: print "Error: 404 - Switch or table not found in database" flask.abort(404) print "Inserting flow for %s..." % node.id flow_name = "L2AR%s" % path_id.split('-')[0] if first: table.l2output(flow_name=flow_name, in_port=source_port, connector_id=target_port, source=source_host, destination=target_host, template_dir=template_dir, ingress_vlan=src_vlan) table.l2output(flow_name=flow_name, in_port=target_port, connector_id=source_port, source=target_host, destination=source_host, template_dir=template_dir, egress_vlan=src_vlan) first = False continue # Install the flow one way table.l2output(flow_name=flow_name, in_port=source_port, connector_id=target_port, source=source_host, destination=target_host, template_dir=template_dir) # Install the flow another way table.l2output(flow_name=flow_name, in_port=target_port, connector_id=source_port, source=target_host, destination=source_host, template_dir=template_dir) cache_l2paths[path_id] = path # Update Json file return flask.redirect("/")
pw = args.get("<password>") if not pw: pw = "admin" ffile = args.get("<flow_file>") info =\ """File : %s Server: %s User : %s Passwd: %s\n""" % (ffile, url, user, "*****" if pw != "admin" else pw) print info try: f = open(ffile, 'r') fstr = f.read() flows = json.loads(fstr) except Exception, e: print "Error: %s" % e odl = ODLInstance(url, (user, pw)) nodes = odl.get_nodes() for flow in flows: sw = flow['switch'] tid = flow['flow']['table_id'] tables = nodes[sw].get_tables() tables[tid].put_flow_from_data_json(json.dumps({"flow": flow['flow']}), flow['id']) f.close()
def install_flows_for_l2path(path_id): """ This will install a l2 full path flows (based on MAC addresses) in all switches in a path. You should use first '/api/routes/l2' to see the uid of path. This is a necessary argument for this endpoint. """ client_ip = "%s" % flask.request.environ['REMOTE_ADDR'] try: path = session_l2paths[client_ip][path_id] path, src_vlan, dst_vlan = path['path'], path['src-vlan'], path['dst-vlan'] src_vlan = src_vlan if src_vlan != '' else None dst_vlan = dst_vlan if dst_vlan != '' else None except KeyError: flask.abort(404) ports = get_ports_on_path(path) # [(u'openflow:562958149829575:2', u'openflow:562958149829575:21'), # (u'openflow:440565346114459:257', u'openflow:440565346114459:217')] data = json.loads(flask.request.get_data().decode('utf-8')) source_host = data['source'] target_host = data['destination'] # source_host = ":".join(path[0].split(":")[1::]) # target_host = ":".join(path[-1].split(":")[1::]) # Install a flow in each switch on the path with correct output # port. if dst_vlan: source_host, target_host = target_host, source_host src_vlan, dst_vlan = dst_vlan, src_vlan ports.reverse() first = src_vlan for source_port, target_port in ports: source_switch = "%s:%s" % (source_port.split(":")[0], source_port.split(":")[1]) target_switch = "%s:%s" % (target_port.split(":")[0], target_port.split(":")[1]) # Just in case check if (source_switch != target_switch): print "Error 500: Switches are different on path" flask.abort(500) # Match: source_port, source_host, target_host, eth_type = 0x806 ? # Target Action: target_port # Lookup for switch in database try: credentials = (odl_user, odl_pass) odl = ODLInstance(odl_server, credentials) node = odl.get_node_by_id(target_switch) table = node.get_table_by_id(0) # Assuming installing on table 0 except (NodeNotFound, TableNotFound) as e: print "Error: 404 - Switch or table not found in database" flask.abort(404) print "Inserting flow for %s..." % node.id flow_name = "L2AR%s" % path_id.split('-')[0] if first: table.l2output(flow_name = flow_name, in_port = source_port, connector_id = target_port, source = source_host, destination = target_host, template_dir = template_dir, ingress_vlan = src_vlan) table.l2output(flow_name = flow_name, in_port = target_port, connector_id = source_port, source = target_host, destination = source_host, template_dir = template_dir, egress_vlan = src_vlan) first = False continue # Install the flow one way table.l2output(flow_name = flow_name, in_port = source_port, connector_id = target_port, source = source_host, destination = target_host, template_dir = template_dir) # Install the flow another way table.l2output(flow_name = flow_name, in_port = target_port, connector_id = source_port, source = target_host, destination = source_host, template_dir = template_dir) cache_l2paths[path_id] = path # Update Json file return flask.redirect("/")