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 |
Alex Savatieiev | 5d1eebb | 2019-01-25 18:15:36 +0100 | [diff] [blame] | 35 | # identify device type |
| 36 | _dev_link_path = shell('readlink /sys/class/net/{}'.format(_name)) |
| 37 | _type = "unknown" |
| 38 | if len(_dev_link_path) > 0: |
| 39 | _tmp = _dev_link_path.split('/') |
| 40 | _tmp = _tmp[_tmp.index("devices") + 1] |
| 41 | if _tmp.startswith("pci"): |
| 42 | _type = "physical" |
| 43 | elif _tmp.startswith("virtual"): |
| 44 | _type = "virtual" |
| 45 | |
| 46 | # get linked devices if any |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 47 | _links = shell( |
| 48 | "find /sys/class/net/{}/ -type l".format(_name) |
| 49 | ) |
| 50 | # there can be only one parent device |
| 51 | _lower = None |
| 52 | # can be more than one child device |
| 53 | _upper = None |
| 54 | for line in _links.splitlines(): |
| 55 | _line = line.rsplit('/', 1)[1] |
| 56 | if _line.startswith("upper_"): |
Alex Savatieiev | bd256e8 | 2019-01-25 18:27:01 +0100 | [diff] [blame] | 57 | if not _upper: |
| 58 | _upper = [] |
| 59 | _upper.append(_line[6:]) |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 60 | elif _line.startswith("lower_"): |
| 61 | if not _lower: |
| 62 | _lower = [] |
| 63 | _lower.append(_line[6:]) |
| 64 | |
Alex Savatieiev | 5d1eebb | 2019-01-25 18:15:36 +0100 | [diff] [blame] | 65 | return _lower, _upper, _type |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 66 | |
| 67 | |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 68 | def get_ifs_data(): |
| 69 | _ifs_raw = shell('ip a') |
| 70 | |
| 71 | if_start = re.compile("^[0-9]+: .*: \<.*\> .*$") |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 72 | if_link = re.compile("^\s{4}link\/ether\ .*$") |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 73 | if_ipv4 = re.compile("^\s{4}inet\ .*$") |
| 74 | |
| 75 | _ifs = {} |
| 76 | _if_name = None |
| 77 | for line in _ifs_raw.splitlines(): |
| 78 | _if_data = {} |
| 79 | if if_start.match(line): |
| 80 | _tmp = line.split(':') |
| 81 | _if_name = _tmp[1].strip() |
| 82 | _if_options = _tmp[2].strip().split(' ') |
Alex Savatieiev | 5d1eebb | 2019-01-25 18:15:36 +0100 | [diff] [blame] | 83 | _lower, _upper, _type = get_linked_devices(_if_name) |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 84 | _if_data['order'] = _tmp[0] |
| 85 | _if_data['mtu'], _if_options = cut_option("mtu", _if_options) |
| 86 | _if_data['qlen'], _if_options = cut_option("qlen", _if_options) |
| 87 | _if_data['state'], _if_options = cut_option("state", _if_options) |
| 88 | _if_data['other'] = _if_options |
| 89 | _if_data['ipv4'] = {} |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 90 | _if_data['mac'] = {} |
Alex Savatieiev | 5d1eebb | 2019-01-25 18:15:36 +0100 | [diff] [blame] | 91 | _if_data['type'] = _type |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 92 | _if_data['upper'] = _upper |
| 93 | _if_data['lower'] = _lower |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 94 | _ifs[_if_name] = _if_data |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 95 | elif if_link.match(line): |
| 96 | if _if_name is None: |
| 97 | continue |
| 98 | else: |
| 99 | _tmp = line.strip().split(' ', 2) |
| 100 | _mac_addr = _tmp[1] |
| 101 | _options = _tmp[2].split(' ') |
| 102 | _brd, _options = cut_option("brd", _options) |
| 103 | _ifs[_if_name]['mac'][_mac_addr] = {} |
| 104 | _ifs[_if_name]['mac'][_mac_addr]['brd'] = _brd |
| 105 | _ifs[_if_name]['mac'][_mac_addr]['other'] = _options |
Oleksandr Savatieiev | fb9f943 | 2018-11-23 17:39:12 +0100 | [diff] [blame] | 106 | elif if_ipv4.match(line): |
| 107 | if _if_name is None: |
| 108 | continue |
| 109 | else: |
| 110 | _tmp = line.strip().split(' ', 2) |
| 111 | _ip = _tmp[1] |
| 112 | _options = _tmp[2].split(' ') |
| 113 | _brd, _options = cut_option("brd", _options) |
| 114 | # TODO: Parse other options, mask, brd, etc... |
| 115 | _ifs[_if_name]['ipv4'][_ip] = {} |
| 116 | _ifs[_if_name]['ipv4'][_ip]['brd'] = _brd |
| 117 | _ifs[_if_name]['ipv4'][_ip]['other'] = _options |
| 118 | |
| 119 | return _ifs |
| 120 | |
| 121 | |
| 122 | ifs_data = get_ifs_data() |
| 123 | |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 124 | if len(sys.argv) > 1 and sys.argv[1] == 'json': |
| 125 | sys.stdout.write(json.dumps(ifs_data)) |
| 126 | else: |
| 127 | _ifs = sorted(ifs_data.keys()) |
| 128 | _ifs.remove("lo") |
| 129 | for _idx in range(len(_ifs)): |
| 130 | _linked = "" |
| 131 | if ifs_data[_ifs[_idx]]['lower']: |
Alex Savatieiev | 5d1eebb | 2019-01-25 18:15:36 +0100 | [diff] [blame] | 132 | _linked += "lower:{} ".format( |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 133 | ','.join(ifs_data[_ifs[_idx]]['lower']) |
| 134 | ) |
| 135 | if ifs_data[_ifs[_idx]]['upper']: |
Alex Savatieiev | bd256e8 | 2019-01-25 18:27:01 +0100 | [diff] [blame] | 136 | _linked += "upper:{} ".format( |
| 137 | ','.join(ifs_data[_ifs[_idx]]['upper']) |
| 138 | ) |
Alex Savatieiev | 5d1eebb | 2019-01-25 18:15:36 +0100 | [diff] [blame] | 139 | _linked = _linked.strip() |
| 140 | print("{0:8} {1:30} {2:18} {3:19} {4:5} {5:4} {6}".format( |
| 141 | ifs_data[_ifs[_idx]]['type'], |
Alex Savatieiev | 0137dad | 2019-01-25 16:18:42 +0100 | [diff] [blame] | 142 | _ifs[_idx], |
| 143 | ",".join(ifs_data[_ifs[_idx]]['mac'].keys()), |
| 144 | ",".join(ifs_data[_ifs[_idx]]['ipv4'].keys()), |
| 145 | ifs_data[_ifs[_idx]]['mtu'], |
| 146 | ifs_data[_ifs[_idx]]['state'], |
| 147 | _linked |
| 148 | )) |