def capture_packets(params, tag='src', src_tag=None): if tag == 'src': port_info = src_info elif tag == 'dst': port_info = dst_info else: error('tag has to be one of [src, dst]!') return # XXX TODO # If src_tag and dst_tag are the same, then we need to monitor on just # br-int. Else, we will need to monitor on qr- ports (router ports) port_info['pids'] = [] for port in port_info['ports'].keys(): intf = port_info['ports'][port] filename = '%s.tcpdump.%s.txt' % (tag, intf) if os.path.isfile(filename): os.remove(filename) cmd = 'sudo tcpdump -v icmp -i %s -c %d -l > %s 2>&1' % ( intf, params['count'], filename) pid = subprocess.Popen(cmd, shell=True).pid port_info['pids'].append(pid) status_update('%s: tcpdump launched with pid %d for interface %s' % (tag, pid, intf))
def process_captures(tag='src'): if tag == 'src': port_info = src_info elif tag == 'dst': port_info = dst_info else: error('tag has to be one of [src, dst]!') return port_info['counts'] = {} port_info['pass'] = [] port_info['fail'] = [] for key in port_info['ports'].keys(): intf = port_info['ports'][key] # Assume tcpdump did not capture anything port_info['counts'][key] = 0 port_info['fail'].append(intf) filename = '%s.tcpdump.%s.txt' % (tag, intf) if not os.path.isfile(filename): continue with open(filename) as f: lines = f.readlines() for line in lines: m = re.search('(\d+)\s+packets captured', line) if m: port_info['counts'][key] = int(m.group(1)) port_info['pass'].append(intf) break
def ovs_ofctl_show_br_parser(bridge, parse_this): bridge_dict = info['bridges'] if not bridge_dict.has_key(bridge): common.error('Skipping bridge [' + bridge + ']! Supported bridges: ' + str(bridge_dict.keys())) return bridge_entry = bridge_dict.get(bridge) pprint.pprint(bridge_entry) for line in parse_this: m = re.search('(\d+)\((\S+)\):\s+addr:(\S+)', line) if m: port_id = m.group(1) port = m.group(2) port_mac = m.group(3) if not bridge_entry['ports'].has_key(port): bridge_entry['ports'][port] = {} port_entry = bridge_entry['ports'][port] port_entry['id'] = port_id port_entry['mac'] = port_mac continue m = re.search('(\w+)\((\S+)\):\s+addr:(\S+)', line) if m: port_id = m.group(1) port = m.group(2) port_mac = m.group(3) if not bridge_entry['ports'].has_key(port): bridge_entry['ports'][port] = {} port_entry = bridge_entry['ports'][port] port_entry['id'] = port_id port_entry['mac'] = port_mac
def record_linuxbridge(bridges, bridge, interface_list): """Add given bridge and its interfaces to the bridges dictionary. The bridge is coming from brctl command. :param bridge: the name of the bridge. :param interface_list: the interfaces of the bridge. """ if bridges.has_key(bridge): common.error('Bridge ' + bridge + ' repeated! Overwriting!') bridges[bridge] = {'interfaces': interface_list}
def add_new_command(cmds, cmd_key, cmd): """Add given command to the commands dictionary. :param cmds: the commands dictionary. :param cmd_key: the key of the dictionary where to add the command. :param cmd: the dictionary of the command. """ if cmds.has_key(cmd_key): common.error(cmd_key + ' already exists in command dictionary') else: cmds[cmd_key] = cmd
def get_bridge_entry(bridge): """Returns given bridge dictionary. :param bridge: the name of the bridge. """ bridges = info['bridges'] if not bridges.has_key(bridge): common.error('Bridge ' + bridge + ' does not exist! Supported bridges: ' + str(bridges.keys())) return None else: return bridges.get(bridge)
def ovs_vsctl_show_parser(parse_this): bridge = None bridge_dict = info['bridges'] for line in parse_this: m = re.search('Bridge\s+(br-\S+)', line) if m: bridge = str(m.group(1)) if not bridge_dict.has_key(bridge): common.error('Skipping bridge [' + bridge + ']! Supported bridges: ' + str(bridge_dict.keys())) bridge = None continue bridge_entry = bridge_dict.get(bridge) if bridge: m = re.search('fail_mode: (\S+)', line) if m: bridge_entry['fail_mode'] = m.group(1) continue m = re.search('Port (\S+)', line) if m: # the port names seem to have double quotes around them! port = m.group(1).replace('"', '') if not bridge_entry['ports'].has_key(port): bridge_entry['ports'][port] = {} port_entry = bridge_entry['ports'][port] continue m = re.search('tag: (\d+)', line) if m: port_entry['tag'] = m.group(1) continue m = re.search('Interface (\S+)', line) if m: # the interface names seem to have double quotes around them! interface = m.group(1).replace('"', '') if not port_entry.has_key('interfaces'): port_entry['interfaces'] = {} port_entry['interfaces'][interface] = {} interface_entry = port_entry['interfaces'][interface] continue m = re.search('type: (\S+)', line) if m: interface_entry['type'] = m.group(1) continue m = re.search('options: {(\S+)}', line) if m: options = m.group(1) interface_entry['options'] = options continue
def path(params): global src_info global dst_info global net_info src_info = None dst_info = None net_info = None settings['debug'] = True BASE_DIR = os.path.dirname(os.path.dirname(__file__)) CUR_DIR = os.getcwd() if not re.search('/openstack_dashboard/don/', CUR_DIR): os.chdir(BASE_DIR + '/ovs') NEW_DIR = os.getcwd() debug(BASE_DIR + ':' + CUR_DIR + ':' + NEW_DIR) src_ip = params['src_ip'] dst_ip = params['dst_ip'] json_file = params['json_file'] router = params['router'] debug('Json_file: ' + json_file) info = load_json(json_file) qrouter = router_to_namespace(info, router) params['qrouter'] = qrouter src_info = get_port_info(info, src_ip) dst_info = get_port_info(info, dst_ip) if src_info is None: return "Source ip not found on the network" if dst_info is None: return "Destination ip not found on the network" if qrouter is None: return "No such router information found on the network" # src and dst are in the same network if src_info['tag'] == dst_info['tag']: path_same_network(params) else: status_update('The source and destination are in different networks') next_hop_list = get_next_hop(src_info, dst_info, qrouter, params) if len(next_hop_list) == 0: error('Could not find next hop list from %s to %s' % (src_ip, dst_ip)) path_same_network(params, next_hop_list)
def qrouter_usable(qrouter, src_ip, dst_ip, username, passwd): status_update('Testing whether %s is reachable via qrouter %s (dst %s)' % (src_ip, qrouter, dst_ip)) outfile = 'path.testping.txt' ping_process = launch_ping(src_ip, dst_ip, username, passwd, 2, 2, qrouter, outfile) status_update("Ping process %s" % (ping_process)) time.sleep(5) ping_pass = process_ping(outfile, src_ip, check_ssh_connectivity_only=True) if ping_pass: status_update('IP %s is reachable via qrouter: %s' % (src_ip, qrouter)) return True else: error('IP %s is reachable via qrouter: %s' % (src_ip, qrouter)) return False
def get_port_info(info, port_ip): port_info = None for tap, ip in info['tap_to_ip'].iteritems(): if ip == port_ip: port_info = {} port_info['ip'] = ip port_info['ports'] = {} port_info['ports']['tap'] = 'tap' + tap port_info['ports']['brctl'] = 'qbr' + tap port_info['ports']['qvb'] = 'qvb' + tap port_info['ports']['qvo'] = 'qvo' + tap # also get the tag (used later to figure out where to run tcpdump) br_int = info['bridges'].get('br-int', None) if not br_int: error('No OVS integration bridge (br-int)! Cannot proceed') return None tag = br_int['ports'][port_info['ports']['qvo']]['tag'] port_info['tag'] = tag break return port_info
def path_same_network(params, nms_hops=None): src_ip = params['src_ip'] dst_ip = params['dst_ip'] json_file = params['json_file'] username = params['username'] passwd = params['passwd'] count = params['count'] timeout = params['timeout'] qrouter = params['qrouter'] router = params['router'] if qrouter_usable(qrouter, src_ip, dst_ip, username, passwd): outfile = 'path.ping.txt' ping_process = launch_ping(src_ip, dst_ip, username, passwd, count, timeout, qrouter, outfile) debug('Ping started with pid: %d' % ping_process.pid) capture_packets(params, 'src') capture_packets(params, 'dst', src_tag=src_info['tag']) if src_info['tag'] != dst_info['tag']: capture_network_packets(params, nms_hops) status_update( 'Waiting %s sec for tcpdump and ping processes to complete' % (params['count'] + 2)) time.sleep(params['count'] + 4) status_update('if processes have not stopped, lets kill them') cleanup_processes([ping_process.pid] + src_info['pids'] + dst_info['pids']) if net_info: cleanup_processes(net_info['pids']) process_captures('src') process_captures('dst') if src_info['tag'] != dst_info['tag']: process_network_captures() ping_pass = process_ping(outfile) debug(pprint.pformat(src_info)) debug(pprint.pformat(dst_info)) debug(pprint.pformat(net_info)) info = { 'src': src_ip, 'dst': dst_ip, 'src_info': src_info, 'dst_info': dst_info, 'net_info': net_info, 'ping_pass': ping_pass, 'error': '', } status_update('Dumping results into %s in JSON format' % params['path_file']) dump_json(info, params['path_file']) if params['plot']: cmd = 'python plot.py --info_file %s --highlight_file %s --combined_file static/ping' % ( json_file, params['path_file']) status_update('Running ' + cmd) output = execute_cmd(cmd, shell=True).split('\n') debug(pprint.pformat(output)) status_update('Done') else: err_msg = 'Cannot reach %s via router %s' % (src_ip, router) info = { 'src': src_ip, 'dst': dst_ip, 'src_info': src_info, 'dst_info': dst_info, 'ping_pass': False, 'error': err_msg } error(err_msg) status_update('Dumping results into %s in JSON format' % params['path_file']) dump_json(info, params['path_file']) status_update('Done')