use crate::config::repository::load_config_json; use crate::runtime::state::runtime_state::RuntimeInstanceState; use easytier::proto::api::manage::NetworkConfig; use ipnet::IpNet; use ohos_hilog_binding::hilog_debug; use std::collections::HashSet; use std::net::IpAddr; pub(crate) fn load_manual_routes(config_id: &str) -> Vec { load_config_json(config_id) .and_then(|raw| serde_json::from_str::(&raw).ok()) .map(|config| config.routes) .unwrap_or_default() } fn normalize_route_cidr(route: &str) -> Option { route .parse::() .ok() .map(|network| match network { IpNet::V4(net) => net.trunc().to_string(), IpNet::V6(net) => net.trunc().to_string(), }) .or_else(|| { route.parse::().ok().map(|addr| match addr { IpAddr::V4(ip) => format!("{}/32", ip), IpAddr::V6(ip) => format!("{}/128", ip), }) }) } fn simplify_routes(routes: Vec) -> Vec { let mut parsed = routes .into_iter() .filter_map(|route| normalize_route_cidr(&route)) .filter_map(|route| route.parse::().ok()) .collect::>(); parsed.sort_by(|left, right| { left.prefix_len() .cmp(&right.prefix_len()) .then_with(|| left.network().to_string().cmp(&right.network().to_string())) }); let mut simplified = Vec::::new(); 'outer: for route in parsed { for existing in &simplified { if existing.contains(&route.network()) && existing.prefix_len() <= route.prefix_len() { continue 'outer; } } simplified.retain(|existing| { !(route.contains(&existing.network()) && route.prefix_len() <= existing.prefix_len()) }); simplified.push(route); } let mut seen = HashSet::new(); simplified .into_iter() .map(|route| route.to_string()) .filter(|route| seen.insert(route.clone())) .collect() } pub(crate) fn aggregate_tun_routes(instance: &RuntimeInstanceState) -> Vec { let virtual_ipv4_cidr = instance .my_node_info .as_ref() .and_then(|info| info.virtual_ipv4_cidr.clone()); let manual_routes = load_manual_routes(&instance.config_id); let proxy_cidrs = instance .routes .iter() .flat_map(|route| route.proxy_cidrs.iter().cloned()) .collect::>(); let mut raw_routes = Vec::new(); if let Some(cidr) = virtual_ipv4_cidr.clone() { raw_routes.push(cidr); } raw_routes.extend(manual_routes.iter().cloned()); raw_routes.extend(proxy_cidrs.iter().cloned()); let aggregated_routes = simplify_routes(raw_routes); hilog_debug!( "[Rust] aggregate_tun_routes instance={} proxy_cidrs={:?} aggregated_routes={:?}", instance.instance_id, proxy_cidrs, aggregated_routes ); aggregated_routes } pub(crate) fn aggregate_requested_tun_routes(instances: &[RuntimeInstanceState]) -> Vec { let mut aggregated_routes = Vec::new(); let mut seen_routes = HashSet::new(); for instance in instances.iter().filter(|instance| instance.tun_required) { for route in aggregate_tun_routes(instance) { if seen_routes.insert(route.clone()) { aggregated_routes.push(route); } } } aggregated_routes }