diff --git a/src/confd/yang/confd.inc b/src/confd/yang/confd.inc index 02e8c4f6..f05fc1bf 100644 --- a/src/confd/yang/confd.inc +++ b/src/confd/yang/confd.inc @@ -33,7 +33,7 @@ MODULES=( "infix-dhcp-client@2025-01-20.yang" "infix-dhcp-server@2025-01-13.yang" "infix-meta@2024-10-18.yang" - "infix-system@2024-11-27.yang" + "infix-system@2025-01-25.yang" "infix-services@2024-12-03.yang" "ieee802-ethernet-interface@2019-06-21.yang" "infix-ethernet-interface@2024-02-27.yang" diff --git a/src/confd/yang/infix-system.yang b/src/confd/yang/infix-system.yang index 372606a9..dc651ca7 100644 --- a/src/confd/yang/infix-system.yang +++ b/src/confd/yang/infix-system.yang @@ -6,6 +6,12 @@ module infix-system { import ietf-system { prefix sys; } + import ietf-interfaces { + prefix if; + } + import ietf-yang-types { + prefix yang; + } import iana-timezones { prefix iana-tz; } @@ -22,8 +28,12 @@ module infix-system { contact "kernelkit@googlegroups.com"; description "Infix augments and deviations to ietf-system."; + revision 2025-01-25 { + description "Add DNS resolver status."; + reference "internal"; + } revision 2024-11-27 { - description "Add NTP status"; + description "Add NTP status."; reference "internal"; } revision 2024-09-13 { @@ -305,6 +315,8 @@ module infix-system { augment "/sys:system-state" { container ntp { description "NTP status"; + config false; + container sources { list source { key address; @@ -328,11 +340,80 @@ module infix-system { type uint8; description "Interval between transmitted NTP messages, expressed as a power of two in seconds"; } + } + } + } + container dns-resolver { + description "List of active DNS servers"; + config false; + + container options { + description "Resolver options."; + + leaf timeout { + description "Number of seconds before resolves tries another server."; + type uint8; + units "seconds"; + } + leaf attempts { + description "Number of times the resolver reties before giving up."; + type uint8; + } + } + + leaf-list search { + type inet:domain-name; + description "Ordered list of domains to search when resolving a host name."; + } + + list server { + key "address"; + + leaf address { + description "IP address of DNS server"; + type inet:ip-address; + } + + leaf origin { + description "How DNS server was acquired"; + type enumeration { + enum static { + description "Statically configured"; + } + enum dhcp { + description "Dynamically acquired via DHCP"; + } + } + } + + leaf interface { + type if:interface-ref; + description "Interface DNS server was learned from, if DHCP"; + } + } + + container statistics { + description "DNS resolver statistics"; + + leaf cache-size { + description "Current number of entries in DNS cache"; + type yang:counter32; + } + + leaf cache-hits { + description "Number of successful cache lookups"; + type yang:counter64; + } + + leaf cache-misses { + description "Number of failed cache lookups"; + type yang:counter64; } } } } + deviation "/sys:system/sys:hostname" { deviate replace { type infix-sys:hostname; diff --git a/src/confd/yang/infix-system@2024-11-27.yang b/src/confd/yang/infix-system@2025-01-25.yang similarity index 100% rename from src/confd/yang/infix-system@2024-11-27.yang rename to src/confd/yang/infix-system@2025-01-25.yang diff --git a/src/statd/python/yanger/ietf_system.py b/src/statd/python/yanger/ietf_system.py index 2f424fc5..08b76be3 100644 --- a/src/statd/python/yanger/ietf_system.py +++ b/src/statd/python/yanger/ietf_system.py @@ -1,4 +1,5 @@ import subprocess +import ipaddress from .common import insert from .host import HOST @@ -61,6 +62,65 @@ def add_ntp(out): insert(out, "infix-system:ntp", "sources", "source", source) +def add_dns(out): + options = {} + servers = [] + search = [] + + content = HOST.read_multiline("/etc/resolv.conf.head", []) + for line in content: + line = line.strip() + + if line.startswith('nameserver'): + ip = line.split()[1] + try: + ipaddress.ip_address(ip) + servers.append({ + "address": ip, + "origin": "static" + }) + except ValueError: + continue + + elif line.startswith('search'): + search.extend(line.split()[1:]) + + elif line.startswith('options'): + opts = line.split()[1:] + for opt in opts: + if opt.startswith('timeout:'): + options["timeout"] = int(opt.split(':')[1]) + elif opt.startswith('attempts:'): + options["attempts"] = int(opt.split(':')[1]) + + output = HOST.run_multiline(['/sbin/resolvconf', '-l'], []) + for line in output: + line = line.strip() + if line.startswith('nameserver'): + parts = line.split('#', 1) + ip = parts[0].split()[1] + + iface = None + if len(parts) > 1: + iface = parts[1].strip() + + try: + ipaddress.ip_address(ip) + servers.append({ + "address": ip, + "origin": "dhcp", + "interface": iface + }) + except ValueError: + continue + + elif line.startswith('search'): + search.extend(line.split()[1:]) + + insert(out, "infix-system:dns-resolver", "options", options) + insert(out, "infix-system:dns-resolver", "server", servers) + insert(out, "infix-system:dns-resolver", "search", search) + def add_software_slots(out, data): slots = [] for slot in data["slots"]: @@ -136,4 +196,6 @@ def operational(): add_software(out_state) add_ntp(out_state) + add_dns(out_state) + return out