|  | import re | 
|  | import sys | 
|  | import subprocess | 
|  | import json | 
|  |  | 
|  |  | 
|  | def shell(command): | 
|  | _ps = subprocess.Popen( | 
|  | command.split(), | 
|  | stdout=subprocess.PIPE | 
|  | ).communicate()[0].decode() | 
|  |  | 
|  | return _ps | 
|  |  | 
|  |  | 
|  | def cut_option(_param, _options_list): | 
|  | _option = "n/a" | 
|  | _result_list = [] | 
|  | if _param in _options_list: | 
|  | _index = _options_list.index(_param) | 
|  | _option = _options_list[_index+1] | 
|  | _l1 = _options_list[:_index] | 
|  | _l2 = _options_list[_index+2:] | 
|  | _result_list = _l1 + _l2 | 
|  | else: | 
|  | _result_list = _options_list | 
|  | return _option, _result_list | 
|  |  | 
|  |  | 
|  | def get_linked_devices(if_name): | 
|  | if '@' in if_name: | 
|  | _name = if_name[:if_name.index('@')] | 
|  | else: | 
|  | _name = if_name | 
|  | # identify device type | 
|  | _dev_link_path = shell('readlink /sys/class/net/{}'.format(_name)) | 
|  | _type = "unknown" | 
|  | if len(_dev_link_path) > 0: | 
|  | _tmp = _dev_link_path.split('/') | 
|  | _tmp = _tmp[_tmp.index("devices") + 1] | 
|  | if _tmp.startswith("pci"): | 
|  | _type = "physical" | 
|  | elif _tmp.startswith("virtual"): | 
|  | _type = "virtual" | 
|  |  | 
|  | # get linked devices if any | 
|  | _links = shell( | 
|  | "find /sys/class/net/{}/ -type l".format(_name) | 
|  | ) | 
|  | # there can be only one parent device | 
|  | _lower = None | 
|  | # can be more than one child device | 
|  | _upper = None | 
|  | for line in _links.splitlines(): | 
|  | _line = line.rsplit('/', 1)[1] | 
|  | if _line.startswith("upper_"): | 
|  | if not _upper: | 
|  | _upper = [] | 
|  | _upper.append(_line[6:]) | 
|  | elif _line.startswith("lower_"): | 
|  | if not _lower: | 
|  | _lower = [] | 
|  | _lower.append(_line[6:]) | 
|  |  | 
|  | return _lower, _upper, _type | 
|  |  | 
|  |  | 
|  | def get_ifs_data(): | 
|  | _ifs_raw = shell('ip a') | 
|  |  | 
|  | if_start = re.compile("^[0-9]+: .*: \<.*\> .*$") | 
|  | if_link = re.compile("^\s{4}link\/ether\ .*$") | 
|  | if_ipv4 = re.compile("^\s{4}inet\ .*$") | 
|  |  | 
|  | _ifs = {} | 
|  | _if_name = None | 
|  | for line in _ifs_raw.splitlines(): | 
|  | _if_data = {} | 
|  | if if_start.match(line): | 
|  | _tmp = line.split(':') | 
|  | _if_name = _tmp[1].strip() | 
|  | _if_options = _tmp[2].strip().split(' ') | 
|  | _lower, _upper, _type = get_linked_devices(_if_name) | 
|  | _if_data['order'] = _tmp[0] | 
|  | _if_data['mtu'], _if_options = cut_option("mtu", _if_options) | 
|  | _if_data['qlen'], _if_options = cut_option("qlen", _if_options) | 
|  | _if_data['state'], _if_options = cut_option("state", _if_options) | 
|  | _if_data['other'] = _if_options | 
|  | _if_data['ipv4'] = {} | 
|  | _if_data['mac'] = {} | 
|  | _if_data['type'] = _type | 
|  | _if_data['upper'] = _upper | 
|  | _if_data['lower'] = _lower | 
|  | _ifs[_if_name] = _if_data | 
|  | elif if_link.match(line): | 
|  | if _if_name is None: | 
|  | continue | 
|  | else: | 
|  | _tmp = line.strip().split(' ', 2) | 
|  | _mac_addr = _tmp[1] | 
|  | _options = _tmp[2].split(' ') | 
|  | _brd, _options = cut_option("brd", _options) | 
|  | _ifs[_if_name]['mac'][_mac_addr] = {} | 
|  | _ifs[_if_name]['mac'][_mac_addr]['brd'] = _brd | 
|  | _ifs[_if_name]['mac'][_mac_addr]['other'] = _options | 
|  | elif if_ipv4.match(line): | 
|  | if _if_name is None: | 
|  | continue | 
|  | else: | 
|  | _tmp = line.strip().split(' ', 2) | 
|  | _ip = _tmp[1] | 
|  | _options = _tmp[2].split(' ') | 
|  | _brd, _options = cut_option("brd", _options) | 
|  | # TODO: Parse other options, mask, brd, etc... | 
|  | _ifs[_if_name]['ipv4'][_ip] = {} | 
|  | _ifs[_if_name]['ipv4'][_ip]['brd'] = _brd | 
|  | _ifs[_if_name]['ipv4'][_ip]['other'] = _options | 
|  |  | 
|  | return _ifs | 
|  |  | 
|  |  | 
|  | ifs_data = get_ifs_data() | 
|  |  | 
|  | if len(sys.argv) > 1 and sys.argv[1] == 'json': | 
|  | sys.stdout.write(json.dumps(ifs_data)) | 
|  | else: | 
|  | _ifs = sorted(ifs_data.keys()) | 
|  | _ifs.remove("lo") | 
|  | for _idx in range(len(_ifs)): | 
|  | _linked = "" | 
|  | if ifs_data[_ifs[_idx]]['lower']: | 
|  | _linked += "lower:{} ".format( | 
|  | ','.join(ifs_data[_ifs[_idx]]['lower']) | 
|  | ) | 
|  | if ifs_data[_ifs[_idx]]['upper']: | 
|  | _linked += "upper:{} ".format( | 
|  | ','.join(ifs_data[_ifs[_idx]]['upper']) | 
|  | ) | 
|  | _linked = _linked.strip() | 
|  | print("{0:8} {1:30} {2:18} {3:19} {4:5} {5:4} {6}".format( | 
|  | ifs_data[_ifs[_idx]]['type'], | 
|  | _ifs[_idx], | 
|  | ",".join(ifs_data[_ifs[_idx]]['mac'].keys()), | 
|  | ",".join(ifs_data[_ifs[_idx]]['ipv4'].keys()), | 
|  | ifs_data[_ifs[_idx]]['mtu'], | 
|  | ifs_data[_ifs[_idx]]['state'], | 
|  | _linked | 
|  | )) |