diff options
| -rw-r--r-- | op-mode-definitions/show-ip-multicast.xml.in | 6 | ||||
| -rwxr-xr-x | src/op_mode/igmp-proxy.py | 167 | 
2 files changed, 24 insertions, 149 deletions
| diff --git a/op-mode-definitions/show-ip-multicast.xml.in b/op-mode-definitions/show-ip-multicast.xml.in index d8f16d997..605d61e8d 100644 --- a/op-mode-definitions/show-ip-multicast.xml.in +++ b/op-mode-definitions/show-ip-multicast.xml.in @@ -15,12 +15,6 @@                  </properties>                  <command>${vyos_op_scripts_dir}/igmp-proxy.py show_interface</command>                </leafNode> -              <leafNode name="mfc"> -                <properties> -                  <help>Show multicast fowarding cache</help> -                </properties> -                <command>${vyos_op_scripts_dir}/igmp-proxy.py show_mfc</command> -              </leafNode>                <leafNode name="summary">                  <properties>                    <help>IP multicast information</help> diff --git a/src/op_mode/igmp-proxy.py b/src/op_mode/igmp-proxy.py index 2a8f284bc..0086c9aa6 100755 --- a/src/op_mode/igmp-proxy.py +++ b/src/op_mode/igmp-proxy.py @@ -21,9 +21,9 @@  import ipaddress  import json -import jinja2  import socket  import sys +import tabulate  import vyos.config  import vyos.opmode @@ -43,161 +43,42 @@ def _kernel_to_ip(addr):      Convert any given address from Linux kernel to a proper, IPv4 address      using the correct host byte order.      """ -      # Convert from hex 'FE000A0A' to decimal '4261415434'      addr = int(addr, 16) -    # Kernel ABI _always_ uses network byte order +    # Kernel ABI _always_ uses network byte order.      addr = socket.ntohl(addr) -      return str(ipaddress.IPv4Address(addr))  def _process_mr_vif(): -    """ -    Read contents of file /proc/net/ip_mr_vif and print a more human -    friendly version to the command line. IPv4 addresses presented as -    32-bit integers in hex format are converted to IPv4 notation too. -    """ - -    with open('/proc/net/ip_mr_vif', 'r') as f: -        lines = len(f.readlines()) -        if lines < 2: -            return None - -    result = { -        'data': [] -    } - -    # Build up table format string -    table_format = { -        'interface': 'Interface', -        'pkts_in'  : 'PktsIn', -        'pkts_out' : 'PktsOut', -        'bytes_in' : 'BytesIn', -        'bytes_out': 'BytesOut', -        'loc'      : 'Local' -    } -    result['data'].append(table_format) - -    # read and parse information from /proc filesystema +    """Read rows from /proc/net/ip_mr_vif into dicts.""" +    result = []      with open('/proc/net/ip_mr_vif', 'r') as f: -        header_line = next(f) +        next(f)          for line in f: -            data = { -                'interface': line.split()[1], -                'pkts_in'  : line.split()[3], -                'pkts_out' : line.split()[5], - -                # convert raw byte number to something more human readable -                'bytes_in' : bytes_to_human(int(line.split()[2])), -                'bytes_out': bytes_to_human(int(line.split()[4])), - -                # convert IP address from hex 'FE000A0A' to decimal '4261415434' -                'loc'      : _kernel_to_ip(line.split()[7]), -            } -            result['data'].append(data) - +            result.append({ +                'Interface': line.split()[1], +                'PktsIn'   : int(line.split()[3]), +                'PktsOut'  : int(line.split()[5]), +                'BytesIn'  : int(line.split()[2]), +                'BytesOut' : int(line.split()[4]), +                'Local'    : _kernel_to_ip(line.split()[7]), +            })      return result -def _process_mr_mfc(): -    """ -    Read contents of file /proc/net/ip_mr_cache and print a more human -    friendly version to the command line. IPv4 addresses presented as -    32-bit integers in hex format are converted to IPv4 notation too. -    """ - -    with open('/proc/net/ip_mr_cache', 'r') as f: -        lines = len(f.readlines()) -        if lines < 2: -            return None - -    # We need this to convert from interface index to a real interface name -    # Thus we also skip the format identifier on list index 0 -    vif = do_mr_vif()['data'][1:] - -    result = { -        'data': [] -    } - -    # Build up table format string -    table_format = { -        'group' : 'Group', -        'origin': 'Origin', -        'iif'   : 'In', -        'oifs'  : ['Out'], -        'pkts'  : 'Pkts', -        'bytes' : 'Bytes', -        'wrong' : 'Wrong' -    } -    result['data'].append(table_format) - -    # read and parse information from /proc filesystem -    with open('/proc/net/ip_mr_cache', 'r') as f: -        header_line = next(f) -        for line in f: -            data = { -                # convert IP address from hex 'FE000A0A' to decimal '4261415434' -                'group' : _kernel_to_ip(line.split()[0]), -                'origin': _kernel_to_ip(line.split()[1]), - -                'iif'   : '--', -                'pkts'  : '', -                'bytes' : '', -                'wrong' : '', -                'oifs'  : [] -            } - -            iif = int(line.split()[2]) -            if not ((iif == -1) or (iif == 65535)): -                data['pkts']  = line.split()[3] -                data['bytes'] = bytes_to_human(int(line.split()[4])) -                data['wrong'] = line.split()[5] - -                # convert index to real interface name -                data['iif']  = vif[iif]['interface'] - -                # convert each output interface index to a real interface name -                for oif in line.split()[6:]: -                    idx = int(oif.split(':')[0]) -                    data['oifs'].append(vif[idx]['interface']) - -            result['data'].append(data) - -    return result - - -# Output template for "show ip multicast interface" command -# -# Example: -# Interface  BytesIn      PktsIn       BytesOut     PktsOut      Local -# eth0       0.0 B        0            0.0 B        0            xxx.xxx.xxx.65 -# eth1       0.0 B        0            0.0 B        0            xxx.xxx.xx.201 -# eth0.3     0.0 B        0            0.0 B        0            xxx.xxx.x.7 -# tun1       0.0 B        0            0.0 B        0            xxx.xxx.xxx.2  def show_interface(raw: bool): -    vif_out_template = """{%- for r in data -%} -{{ "%-10s"|format(r.interface) }} {{ "%-12s"|format(r.bytes_in) }} {{ "%-12s"|format(r.pkts_in) }} {{ "%-12s"|format(r.bytes_out) }} {{ "%-12s"|format(r.pkts_out) }} {{ "%-15s"|format(r.loc) }} -{% endfor %}"""      if data := _process_mr_vif():          if raw: -            return json.loads(json.dumps(data)) -        else: -            return jinja2.Template(vif_out_template).render(data) - -# Output template for "show ip multicast mfc" command -# -# Example: -# Group             Origin            In    Out           Pkts        Bytes        Wrong -# xxx.xxx.xxx.250   xxx.xx.xxx.75     -- -# xxx.xxx.xx.124    xx.xxx.xxx.26     -- -def show_mfc(raw: bool): -    mfc_out_template = """{%- for r in data -%} -{{ "%-15s"|format(r.group) }} {{ "%-15s"|format(r.origin) }} {{ "%-12s"|format(r.pkts) }} {{ "%-12s"|format(r.bytes) }} {{ "%-12s"|format(r.wrong) }} {{ "%-10s"|format(r.iif) }} {{ "%-20s"|format(r.oifs|join(', ')) }} -{% endfor %}""" -    if data := _process_mr_mfc(): -        if raw: -            return json.loads(json.dumps(data)) -        else: -            return jinja2.Template(mfc_out_template).render(data) +            # Make the interface name the key for each row. +            table = {} +            for v in data: +                table[v.pop('Interface')] = v +            return json.loads(json.dumps(table)) +        # Make byte values human-readable for the table. +        arr = [] +        for x in data: +            arr.append({k: bytes_to_human(v) if k.startswith('Bytes') \ +                        else v for k, v in x.items()}) +        return tabulate.tabulate(arr, headers='keys')  if not _is_configured(): | 
