Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 1 | import re |
| 2 | import sys |
| 3 | import subprocess |
| 4 | import json |
| 5 | |
| 6 | |
| 7 | def shell(command): |
| 8 | _ps = subprocess.Popen( |
| 9 | command.split(), |
| 10 | stdout=subprocess.PIPE |
| 11 | ).communicate()[0].decode() |
| 12 | |
| 13 | return _ps |
| 14 | |
| 15 | |
| 16 | def cut_option(_param, _options_list): |
| 17 | _option = "n/a" |
| 18 | _result_list = [] |
| 19 | if _param in _options_list: |
| 20 | _index = _options_list.index(_param) |
| 21 | _option = _options_list[_index+1] |
| 22 | _l1 = _options_list[:_index] |
| 23 | _l2 = _options_list[_index+2:] |
| 24 | _result_list = _l1 + _l2 |
| 25 | else: |
| 26 | _result_list = _options_list |
| 27 | return _option, _result_list |
| 28 | |
| 29 | |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame^] | 30 | def get_linked_devices(if_name): |
| 31 | if '@' in if_name: |
| 32 | _name = if_name[:if_name.index('@')] |
| 33 | else: |
| 34 | _name = if_name |
| 35 | _links = shell( |
| 36 | "find /sys/class/net/{}/ -type l".format(_name) |
| 37 | ) |
| 38 | # there can be only one parent device |
| 39 | _lower = None |
| 40 | # can be more than one child device |
| 41 | _upper = None |
| 42 | for line in _links.splitlines(): |
| 43 | _line = line.rsplit('/', 1)[1] |
| 44 | if _line.startswith("upper_"): |
| 45 | _upper = _line[6:] |
| 46 | elif _line.startswith("lower_"): |
| 47 | if not _lower: |
| 48 | _lower = [] |
| 49 | _lower.append(_line[6:]) |
| 50 | |
| 51 | return _lower, _upper |
| 52 | |
| 53 | |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 54 | def get_ifs_data(): |
| 55 | _ifs_raw = shell('ip a') |
| 56 | |
| 57 | if_start = re.compile("^[0-9]+: .*: \<.*\> .*$") |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame^] | 58 | if_link = re.compile("^\s{4}link\/ether\ .*$") |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 59 | if_ipv4 = re.compile("^\s{4}inet\ .*$") |
| 60 | |
| 61 | _ifs = {} |
| 62 | _if_name = None |
| 63 | for line in _ifs_raw.splitlines(): |
| 64 | _if_data = {} |
| 65 | if if_start.match(line): |
| 66 | _tmp = line.split(':') |
| 67 | _if_name = _tmp[1].strip() |
| 68 | _if_options = _tmp[2].strip().split(' ') |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame^] | 69 | _lower, _upper = get_linked_devices(_if_name) |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 70 | _if_data['order'] = _tmp[0] |
| 71 | _if_data['mtu'], _if_options = cut_option("mtu", _if_options) |
| 72 | _if_data['qlen'], _if_options = cut_option("qlen", _if_options) |
| 73 | _if_data['state'], _if_options = cut_option("state", _if_options) |
| 74 | _if_data['other'] = _if_options |
| 75 | _if_data['ipv4'] = {} |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame^] | 76 | _if_data['mac'] = {} |
| 77 | _if_data['upper'] = _upper |
| 78 | _if_data['lower'] = _lower |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 79 | _ifs[_if_name] = _if_data |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame^] | 80 | elif if_link.match(line): |
| 81 | if _if_name is None: |
| 82 | continue |
| 83 | else: |
| 84 | _tmp = line.strip().split(' ', 2) |
| 85 | _mac_addr = _tmp[1] |
| 86 | _options = _tmp[2].split(' ') |
| 87 | _brd, _options = cut_option("brd", _options) |
| 88 | _ifs[_if_name]['mac'][_mac_addr] = {} |
| 89 | _ifs[_if_name]['mac'][_mac_addr]['brd'] = _brd |
| 90 | _ifs[_if_name]['mac'][_mac_addr]['other'] = _options |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 91 | elif if_ipv4.match(line): |
| 92 | if _if_name is None: |
| 93 | continue |
| 94 | else: |
| 95 | _tmp = line.strip().split(' ', 2) |
| 96 | _ip = _tmp[1] |
| 97 | _options = _tmp[2].split(' ') |
| 98 | _brd, _options = cut_option("brd", _options) |
| 99 | # TODO: Parse other options, mask, brd, etc... |
| 100 | _ifs[_if_name]['ipv4'][_ip] = {} |
| 101 | _ifs[_if_name]['ipv4'][_ip]['brd'] = _brd |
| 102 | _ifs[_if_name]['ipv4'][_ip]['other'] = _options |
| 103 | |
| 104 | return _ifs |
| 105 | |
| 106 | |
| 107 | ifs_data = get_ifs_data() |
| 108 | |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame^] | 109 | if len(sys.argv) > 1 and sys.argv[1] == 'json': |
| 110 | sys.stdout.write(json.dumps(ifs_data)) |
| 111 | else: |
| 112 | _ifs = sorted(ifs_data.keys()) |
| 113 | _ifs.remove("lo") |
| 114 | for _idx in range(len(_ifs)): |
| 115 | _linked = "" |
| 116 | if ifs_data[_ifs[_idx]]['lower']: |
| 117 | _linked += "lower:{}".format( |
| 118 | ','.join(ifs_data[_ifs[_idx]]['lower']) |
| 119 | ) |
| 120 | if ifs_data[_ifs[_idx]]['upper']: |
| 121 | _linked += "upper:{}".format(ifs_data[_ifs[_idx]]['upper']) |
| 122 | print("{0:30} {1:18} {2:19} {3:5} {4:4} {5}".format( |
| 123 | _ifs[_idx], |
| 124 | ",".join(ifs_data[_ifs[_idx]]['mac'].keys()), |
| 125 | ",".join(ifs_data[_ifs[_idx]]['ipv4'].keys()), |
| 126 | ifs_data[_ifs[_idx]]['mtu'], |
| 127 | ifs_data[_ifs[_idx]]['state'], |
| 128 | _linked |
| 129 | )) |