pub fn parse(input: &str) -> Result<NetworkConfig, ParseError>Expand description
Parse a Cisco IOS show running-config string into a NetworkConfig.
The parser is lenient: unrecognized commands are preserved in
NetworkConfig::unknown_blocks rather than causing an error.
§Errors
Returns ParseError::EmptyInput if the input contains no non-whitespace,
non-comment lines.
Examples found in repository?
examples/parse.rs (line 24)
12fn main() {
13 let raw = match env::args().nth(1) {
14 Some(path) => fs::read_to_string(&path)
15 .unwrap_or_else(|e| { eprintln!("Cannot read {path}: {e}"); std::process::exit(1) }),
16 None => {
17 let mut buf = String::new();
18 io::stdin().read_to_string(&mut buf)
19 .unwrap_or_else(|e| { eprintln!("Cannot read stdin: {e}"); std::process::exit(1) });
20 buf
21 }
22 };
23
24 let cfg = match parse(&raw) {
25 Ok(c) => c,
26 Err(e) => { eprintln!("Parse error: {e}"); std::process::exit(1) }
27 };
28
29 // ── Header ────────────────────────────────────────────────────────────────
30 println!("=== ios-config summary ===\n");
31 if let Some(h) = &cfg.hostname { println!("Hostname : {h}"); }
32 if let Some(d) = &cfg.domain_name { println!("Domain : {d}"); }
33
34 // ── Interfaces ────────────────────────────────────────────────────────────
35 println!("\n── Interfaces ({}) ──", cfg.interfaces.len());
36 for iface in &cfg.interfaces {
37 let state = if iface.shutdown { "shutdown" } else { "up" };
38 let addrs: Vec<_> = iface.addresses.iter()
39 .map(|a| a.prefix.to_string())
40 .collect();
41 let addr_str = if addrs.is_empty() {
42 "no ip address".to_string()
43 } else {
44 addrs.join(", ")
45 };
46 let desc = iface.description.as_deref().unwrap_or("-");
47 println!(" {:<32} [{state:^8}] {addr_str} \"{desc}\"",
48 iface.name.original);
49 }
50
51 // ── Routing ───────────────────────────────────────────────────────────────
52 if !cfg.routing.static_routes.is_empty() {
53 println!("\n── Static routes ({}) ──", cfg.routing.static_routes.len());
54 for r in &cfg.routing.static_routes {
55 print!(" {}", r.prefix);
56 match &r.next_hop {
57 ios_config::NextHop::Ip(ip) => print!(" via {ip}"),
58 ios_config::NextHop::Interface(i) => print!(" dev {i}"),
59 ios_config::NextHop::IpAndInterface(ip, i) => print!(" via {ip} dev {i}"),
60 ios_config::NextHop::Null0 => print!(" Null0"),
61 }
62 if let Some(name) = &r.name { print!(" ({name})"); }
63 println!();
64 }
65 }
66
67 for ospf in &cfg.routing.ospf {
68 println!("\n── OSPF process {} ──", ospf.process_id);
69 if let Some(rid) = &ospf.router_id { println!(" router-id {rid}"); }
70 let net_count: usize = ospf.areas.iter().map(|a| a.networks.len()).sum();
71 println!(" networks : {net_count} across {} area(s)", ospf.areas.len());
72 println!(" passive : {}", ospf.passive_interfaces.join(", "));
73 }
74
75 if let Some(bgp) = &cfg.routing.bgp {
76 println!("\n── BGP AS{} ──", bgp.asn);
77 println!(" neighbors : {}", bgp.neighbors.len());
78 println!(" peer-groups: {}", bgp.peer_groups.len());
79 println!(" address-families: {}", bgp.address_families.len());
80 }
81
82 // ── Security ──────────────────────────────────────────────────────────────
83 if !cfg.acls.is_empty() {
84 println!("\n── ACLs ({}) ──", cfg.acls.len());
85 for acl in &cfg.acls {
86 println!(" {:?} ({} entries)", acl.name, acl.entries.len());
87 }
88 }
89
90 if !cfg.nat.is_empty() {
91 println!("\n── NAT ({} rules) ──", cfg.nat.len());
92 }
93
94 // ── Management ────────────────────────────────────────────────────────────
95 if !cfg.ntp.is_empty() {
96 let servers: Vec<_> = cfg.ntp.iter().map(|n| {
97 if n.prefer { format!("{} (prefer)", n.address) } else { n.address.to_string() }
98 }).collect();
99 println!("\n── NTP: {} ──", servers.join(", "));
100 }
101
102 if let Some(snmp) = &cfg.snmp {
103 println!("\n── SNMP ──");
104 if let Some(loc) = &snmp.location { println!(" location: {loc}"); }
105 println!(" communities: {}", snmp.communities.len());
106 }
107
108 // ── Unknowns ─────────────────────────────────────────────────────────────
109 if !cfg.unknown_blocks.is_empty() {
110 println!("\n── Unrecognized commands ({}) ──", cfg.unknown_blocks.len());
111 for u in cfg.unknown_blocks.iter().take(10) {
112 println!(" [{}] {}", u.context, u.raw.trim());
113 }
114 if cfg.unknown_blocks.len() > 10 {
115 println!(" … and {} more", cfg.unknown_blocks.len() - 10);
116 }
117 }
118
119 println!("\nDone.");
120}