mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-01 21:33:02 +02:00
statd: add support for ip forwarding operational state
This patch unlocks "routing interfaces" support in the ietf-routing yang model. An array of interface with IP forwarding enabled. Note, because of #515 we skip IPv6 forwarding for now. This will in the near future be handled by a per-interface force_forwarding sysctl flag. The 'show interface [ifname]' admin-exec command has been extended with a Flags field for a quick overview of which interfaces have forwarding currently enabled. Fixes #647 Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -98,6 +98,7 @@ def compress_interface_list(interfaces):
|
||||
|
||||
|
||||
class Pad:
|
||||
flags = 2
|
||||
iface = 16
|
||||
proto = 11
|
||||
state = 12
|
||||
@@ -803,6 +804,9 @@ class DhcpServer:
|
||||
|
||||
|
||||
class Iface:
|
||||
# Class variable to hold routing-enabled interfaces for the current display session
|
||||
_routing_ifaces = set()
|
||||
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.name = data.get('name', '')
|
||||
@@ -915,13 +919,16 @@ class Iface:
|
||||
return self.oper_status
|
||||
|
||||
def pr_name(self, pipe=""):
|
||||
flag = "⇅" if self.name in Iface._routing_ifaces else " "
|
||||
print(f"{flag:<{Pad.flags}}", end="")
|
||||
print(f"{pipe}{self.name:<{Pad.iface - len(pipe)}}", end="")
|
||||
|
||||
def pr_proto_ipv4(self, pipe=''):
|
||||
for addr in self.ipv4_addr:
|
||||
origin = f"({addr['origin']})" if addr.get('origin') else ""
|
||||
|
||||
row = f"{pipe:<{Pad.iface}}"
|
||||
row = f"{'':<{Pad.flags}}"
|
||||
row += f"{pipe:<{Pad.iface}}"
|
||||
row += f"{'ipv4':<{Pad.proto}}"
|
||||
row += f"{'':<{Pad.state}}{addr['ip']}/{addr['prefix-length']} {origin}"
|
||||
print(row)
|
||||
@@ -930,7 +937,8 @@ class Iface:
|
||||
for addr in self.ipv6_addr:
|
||||
origin = f"({addr['origin']})" if addr.get('origin') else ""
|
||||
|
||||
row = f"{pipe:<{Pad.iface}}"
|
||||
row = f"{'':<{Pad.flags}}"
|
||||
row += f"{pipe:<{Pad.iface}}"
|
||||
row += f"{'ipv6':<{Pad.proto}}"
|
||||
row += f"{'':<{Pad.state}}{addr['ip']}/{addr['prefix-length']} {origin}"
|
||||
print(row)
|
||||
@@ -938,7 +946,8 @@ class Iface:
|
||||
def _pr_proto_common(self, name, phys_address, pipe=''):
|
||||
row = ""
|
||||
if len(pipe) > 0:
|
||||
row = f"{pipe:<{Pad.iface}}"
|
||||
row = f"{'':<{Pad.flags}}"
|
||||
row += f"{pipe:<{Pad.iface}}"
|
||||
|
||||
row += f"{name:<{Pad.proto}}"
|
||||
dec = Decore.green if self.oper() == "up" else Decore.red
|
||||
@@ -1184,6 +1193,11 @@ class Iface:
|
||||
parent.pr_proto_eth()
|
||||
|
||||
def pr_container(self):
|
||||
# Add ⇅ flag for interfaces with IP forwarding enabled
|
||||
flag = "⇅" if self.name in Iface._routing_ifaces else " "
|
||||
# Flag column is outside the gray background
|
||||
print(f"{flag:<{Pad.flags}}", end="")
|
||||
|
||||
row = f"{self.name:<{Pad.iface}}"
|
||||
row += f"{'container':<{Pad.proto}}"
|
||||
row += f"{'':<{Pad.state}}"
|
||||
@@ -1204,6 +1218,9 @@ class Iface:
|
||||
if self.oper():
|
||||
print(f"{'operational status':<{20}}: {self.oper(detail=True)}")
|
||||
|
||||
forwarding = "enabled" if self.name in Iface._routing_ifaces else "disabled"
|
||||
print(f"{'ip forwarding':<{20}}: {forwarding}")
|
||||
|
||||
if self.lower_if:
|
||||
print(f"{'lower-layer-if':<{20}}: {self.lower_if}")
|
||||
|
||||
@@ -1407,13 +1424,21 @@ def print_interface(iface):
|
||||
|
||||
|
||||
def pr_interface_list(json):
|
||||
hdr = (f"{'INTERFACE':<{Pad.iface}}"
|
||||
hdr = (f"{'⚑':<{Pad.flags}}"
|
||||
f"{'INTERFACE':<{Pad.iface}}"
|
||||
f"{'PROTOCOL':<{Pad.proto}}"
|
||||
f"{'STATE':<{Pad.state}}"
|
||||
f"{'DATA':<{Pad.data}}")
|
||||
|
||||
print(Decore.invert(hdr))
|
||||
|
||||
# Set class variable with routing-enabled interfaces (with IP forwarding)
|
||||
if "ietf-routing:routing" in json:
|
||||
routing_data = json["ietf-routing:routing"].get("interfaces", {})
|
||||
Iface._routing_ifaces = set(routing_data.get("interface", []))
|
||||
else:
|
||||
Iface._routing_ifaces = set()
|
||||
|
||||
ifaces = sorted(json["ietf-interfaces:interfaces"]["interface"],
|
||||
key=ifname_sort)
|
||||
iface = find_iface(ifaces, "lo")
|
||||
@@ -1472,6 +1497,13 @@ def pr_interface_list(json):
|
||||
|
||||
|
||||
def show_interfaces(json, name):
|
||||
# Set class variable with routing-enabled interfaces (with IP forwarding)
|
||||
if "ietf-routing:routing" in json:
|
||||
routing_data = json["ietf-routing:routing"].get("interfaces", {})
|
||||
Iface._routing_ifaces = set(routing_data.get("interface", []))
|
||||
else:
|
||||
Iface._routing_ifaces = set()
|
||||
|
||||
if name:
|
||||
if not json.get("ietf-interfaces:interfaces"):
|
||||
print(f"No interface data found for \"{name}\"")
|
||||
|
||||
@@ -124,9 +124,37 @@ def add_protocol(routes, proto):
|
||||
insert(routes, 'routes', out)
|
||||
|
||||
|
||||
def get_routing_interfaces():
|
||||
"""Get list of interfaces with IPv4 forwarding enabled"""
|
||||
import json
|
||||
|
||||
# Get all interfaces
|
||||
links_json = HOST.run(tuple(['ip', '-j', 'link', 'show']), default="[]")
|
||||
links = json.loads(links_json)
|
||||
|
||||
routing_ifaces = []
|
||||
for link in links:
|
||||
ifname = link.get('ifname')
|
||||
if not ifname:
|
||||
continue
|
||||
|
||||
# Check if IPv4 forwarding is enabled
|
||||
# Note: We only check IPv4 forwarding. IPv6 forwarding behaves differently
|
||||
# and will be handled separately when Linux 6.17+ force_forwarding is available.
|
||||
ipv4_fwd = HOST.run(tuple(['sysctl', '-n', f'net.ipv4.conf.{ifname}.forwarding']), default="0").strip()
|
||||
|
||||
if ipv4_fwd == "1":
|
||||
routing_ifaces.append(ifname)
|
||||
|
||||
return routing_ifaces
|
||||
|
||||
|
||||
def operational():
|
||||
out = {
|
||||
"ietf-routing:routing": {
|
||||
"interfaces": {
|
||||
"interface": get_routing_interfaces()
|
||||
},
|
||||
"ribs": {
|
||||
"rib": [{
|
||||
"name": "ipv4",
|
||||
|
||||
Reference in New Issue
Block a user