summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerkin <me@erkin.party>2023-01-19 18:05:41 +0300
committererkin <me@erkin.party>2023-01-19 18:05:41 +0300
commitaac0a47b6f4556c96744ce8a73c14819494a7cf7 (patch)
tree5ef81d0fbe09a0a77a73258524a7fe98779653b9
parent06302555cd504ea1884c156ecb64dc6808256551 (diff)
downloadvyos-1x-aac0a47b6f4556c96744ce8a73c14819494a7cf7.tar.gz
vyos-1x-aac0a47b6f4556c96744ce8a73c14819494a7cf7.zip
igmp-proxy: T4912: Switch away from Jinja2 to Tabulate, remove undocumented "show MFC" command
-rw-r--r--op-mode-definitions/show-ip-multicast.xml.in6
-rwxr-xr-xsrc/op_mode/igmp-proxy.py167
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():