Skip to content

Commit

Permalink
cable-guy: update interface metrics live on dhcpcd
Browse files Browse the repository at this point in the history
  • Loading branch information
Williangalvani committed Feb 3, 2025
1 parent b2331fc commit b6f4352
Showing 1 changed file with 81 additions and 66 deletions.
147 changes: 81 additions & 66 deletions core/services/cable_guy/networksetup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import re
import socket
from typing import Dict, List
from typing import Any, Dict, List

import sdbus
from loguru import logger
Expand Down Expand Up @@ -49,6 +49,83 @@ def trigger_dynamic_ip_acquisition(self, interface_name: str) -> None:
def cleanup_interface_connections(self, interface_name: str) -> None:
pass

def set_interfaces_priority_on_ipr(self, interfaces: List[NetworkInterfaceMetricApi]) -> None:
if not interfaces:
logger.info("No interfaces to set priority for")
return

# If there's only one interface and no priority specified, set it to highest priority (0)
if len(interfaces) == 1 and interfaces[0].priority is None:
interfaces[0].priority = 0

current_priority = 1000
for interface in interfaces:
current_priority = self._update_interface_routes(interface, current_priority)

def _update_single_route(self, interface_index: int, route: Any, priority: int) -> None:
# Delete the existing route first
self._delete_route(interface_index, route)
# Add the new route with updated priority
self._add_route(interface_index, route, priority)
logger.info(f"Updated route for interface index {interface_index} with priority {priority}")

def _delete_route(self, interface_index: int, route: Any) -> None:
self.ipr.route(
"del",
oif=interface_index,
family=socket.AF_INET,
dst=route.get_attr("RTA_DST") if route.get_attr("RTA_DST") else "0.0.0.0/0",
gateway=route.get_attr("RTA_GATEWAY"),
table=route.get_attr("RTA_TABLE", 254), # Default to main table if not specified
scope=route["scope"],
proto=route["proto"],
type=route["type"],
)

def _add_route(self, interface_index: int, route: Any, priority: int) -> None:
route_data = {
"priority": priority,
"oif": interface_index,
"family": socket.AF_INET,
"scope": route["scope"],
"proto": route["proto"],
"type": route["type"],
}

# Copy existing route attributes
for attr in ["RTA_DST", "RTA_GATEWAY", "RTA_TABLE", "RTA_PREFSRC"]:
value = route.get_attr(attr)
if value:
# Convert attribute name to lowercase and remove RTA_ prefix
key = attr.lower().replace("rta_", "")
route_data[key] = value

# Add the new route
self.ipr.route("add", **route_data)

def _update_interface_routes(self, interface: NetworkInterfaceMetricApi, current_priority: int) -> int:
try:
# Use specified priority or increment current_priority
priority = interface.priority if interface.priority is not None else current_priority

# Get interface index
interface_index = self.ipr.link_lookup(ifname=interface.name)[0]

# Get all routes for this interface
routes = self.ipr.get_routes(oif=interface_index, family=socket.AF_INET)

# Update existing routes
for route in routes:
try:
self._update_single_route(interface_index, route, priority)
except Exception as e:
logger.error(f"Failed to update route for {interface.name}: {e}")

return current_priority + 1000
except Exception as e:
logger.error(f"Failed to set priority for interface {interface.name}: {e}")
return current_priority


class BookwormHandler(AbstractNetworkHandler):
"""
Expand Down Expand Up @@ -148,71 +225,7 @@ def set_interfaces_priority(self, interfaces: List[NetworkInterfaceMetricApi]) -
interfaces (List[NetworkInterfaceMetricApi]): A list of interfaces and their priority metrics,
sorted by priority to set.
"""
if not interfaces:
logger.info("No interfaces to set priority for")
return

# If there's only one interface and no priority specified, set it to highest priority (0)
if len(interfaces) == 1 and interfaces[0].priority is None:
interfaces[0].priority = 0

current_priority = 1000
for interface in interfaces:
try:
# Use specified priority or increment current_priority
priority = interface.priority if interface.priority is not None else current_priority

# Get interface index
interface_index = self.ipr.link_lookup(ifname=interface.name)[0]

# Get all routes for this interface
routes = self.ipr.get_routes(oif=interface_index, family=socket.AF_INET)

# Update existing routes
for route in routes:
try:
# Delete the existing route first
self.ipr.route(
"del",
oif=interface_index,
family=socket.AF_INET,
dst=route.get_attr("RTA_DST") if route.get_attr("RTA_DST") else "0.0.0.0/0",
gateway=route.get_attr("RTA_GATEWAY"),
table=route.get_attr("RTA_TABLE", 254), # Default to main table if not specified
scope=route["scope"],
proto=route["proto"],
type=route["type"],
)

# Add the new route with updated priority
route_data = {
"priority": priority,
"oif": interface_index,
"family": socket.AF_INET,
"scope": route["scope"],
"proto": route["proto"],
"type": route["type"],
}

# Copy existing route attributes
for attr in ["RTA_DST", "RTA_GATEWAY", "RTA_TABLE", "RTA_PREFSRC"]:
value = route.get_attr(attr)
if value:
# Convert attribute name to lowercase and remove RTA_ prefix
key = attr.lower().replace("rta_", "")
route_data[key] = value

# Add the new route
self.ipr.route("add", **route_data)
logger.info(f"Updated route for {interface.name} with priority {priority}")
except Exception as e:
logger.error(f"Failed to update route for {interface.name}: {e}")
continue

current_priority += 1000
except Exception as e:
logger.error(f"Failed to set priority for interface {interface.name}: {e}")
continue
self.set_interfaces_priority_on_ipr(interfaces)

def _get_dhcp_address_using_dhclient(self, interface_name: str) -> str | None:
"""Run dhclient to get a new IP address and return it.
Expand Down Expand Up @@ -402,6 +415,8 @@ def set_interfaces_priority(self, interfaces: List[NetworkInterfaceMetricApi]) -
interfaces (List[NetworkInterfaceMetricApi]): A list of interfaces and their priority metrics.
"""

# first let's apply them live, then we can save
self.set_interfaces_priority_on_ipr(interfaces)
# Note: With DHCPCD, lower priority wins!
self._remove_dhcpcd_configuration()

Expand Down

0 comments on commit b6f4352

Please sign in to comment.