use serde::{Deserialize, Serialize};
use crate::ir::NetworkConfig;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DeviceProfile {
L2Switch,
L3Router,
}
impl DeviceProfile {
pub fn label(&self) -> &'static str {
match self {
DeviceProfile::L2Switch => "L2 (switching)",
DeviceProfile::L3Router => "L3 (routing)",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DomainMismatch {
pub domain: String,
pub detail: String,
}
pub fn detect_domain_mismatches(
config: &NetworkConfig,
profile: DeviceProfile,
) -> Vec<DomainMismatch> {
let mut out = Vec::new();
match profile {
DeviceProfile::L2Switch => {
if !config.routing.static_routes.is_empty() {
out.push(DomainMismatch {
domain: "L3/static".to_string(),
detail: format!(
"{} статических маршрутов — не относится к L2-профилю",
config.routing.static_routes.len()
),
});
}
if !config.routing.ospf.is_empty() {
out.push(DomainMismatch {
domain: "L3/ospf".to_string(),
detail: format!("{} процессов OSPF", config.routing.ospf.len()),
});
}
if config.routing.bgp.is_some() {
out.push(DomainMismatch {
domain: "L3/bgp".to_string(),
detail: "конфигурация BGP".to_string(),
});
}
if !config.routing.eigrp.is_empty() {
out.push(DomainMismatch {
domain: "L3/eigrp".to_string(),
detail: format!("{} процессов EIGRP", config.routing.eigrp.len()),
});
}
if !config.acls.is_empty() {
out.push(DomainMismatch {
domain: "L3/acl".to_string(),
detail: format!("{} ACL", config.acls.len()),
});
}
if !config.nat.is_empty() {
out.push(DomainMismatch {
domain: "L3/nat".to_string(),
detail: format!("{} правил NAT", config.nat.len()),
});
}
let hsrp_count: usize = config.interfaces.iter().map(|i| i.hsrp.len()).sum();
if hsrp_count > 0 {
out.push(DomainMismatch {
domain: "L3/hsrp".to_string(),
detail: format!("{} групп HSRP", hsrp_count),
});
}
}
DeviceProfile::L3Router => {
if !config.vlans.is_empty() {
out.push(DomainMismatch {
domain: "L2/vlan".to_string(),
detail: format!("{} VLAN в базе", config.vlans.len()),
});
}
if config.stp.is_some() {
out.push(DomainMismatch {
domain: "L2/stp".to_string(),
detail: "глобальная конфигурация STP".to_string(),
});
}
let l2_iface_count = config.interfaces.iter().filter(|i| i.l2.is_some()).count();
if l2_iface_count > 0 {
out.push(DomainMismatch {
domain: "L2/switchport".to_string(),
detail: format!(
"{} интерфейсов в режиме switchport (access/trunk)",
l2_iface_count
),
});
}
let voice_vlan_count = config
.interfaces
.iter()
.filter(|i| i.voice_vlan.is_some())
.count();
if voice_vlan_count > 0 {
out.push(DomainMismatch {
domain: "L2/voice-vlan".to_string(),
detail: format!("{} интерфейсов с voice VLAN", voice_vlan_count),
});
}
}
}
out
}