summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/dnsmasq_dhcp/collect.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/dnsmasq_dhcp/collect.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/dnsmasq_dhcp/collect.go b/src/go/collectors/go.d.plugin/modules/dnsmasq_dhcp/collect.go
new file mode 100644
index 000000000..4d3e3ac5e
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/dnsmasq_dhcp/collect.go
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package dnsmasq_dhcp
+
+import (
+ "bufio"
+ "io"
+ "math"
+ "math/big"
+ "net"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/iprange"
+)
+
+func (d *DnsmasqDHCP) collect() (map[string]int64, error) {
+ now := time.Now()
+ var updated bool
+
+ if now.Sub(d.parseConfigTime) > d.parseConfigEvery {
+ d.parseConfigTime = now
+
+ dhcpRanges, dhcpHosts := d.parseDnsmasqDHCPConfiguration()
+ d.dhcpRanges, d.dhcpHosts = dhcpRanges, dhcpHosts
+ updated = d.updateCharts()
+
+ d.collectV4V6Stats()
+ }
+
+ f, err := os.Open(d.LeasesPath)
+ if err != nil {
+ return nil, err
+ }
+ defer func() { _ = f.Close() }()
+
+ if !updated {
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+
+ if d.leasesModTime.Equal(fi.ModTime()) {
+ d.Debug("lease database file modification time has not changed, old data is returned")
+ return d.mx, nil
+ }
+
+ d.Debug("leases db file modification time has changed, reading it")
+ d.leasesModTime = fi.ModTime()
+ }
+
+ leases := findLeases(f)
+ d.collectRangesStats(leases)
+
+ return d.mx, nil
+}
+
+func (d *DnsmasqDHCP) collectV4V6Stats() {
+ d.mx["ipv4_dhcp_ranges"], d.mx["ipv6_dhcp_ranges"] = 0, 0
+ for _, r := range d.dhcpRanges {
+ if r.Family() == iprange.V6Family {
+ d.mx["ipv6_dhcp_ranges"]++
+ } else {
+ d.mx["ipv4_dhcp_ranges"]++
+ }
+ }
+
+ d.mx["ipv4_dhcp_hosts"], d.mx["ipv6_dhcp_hosts"] = 0, 0
+ for _, ip := range d.dhcpHosts {
+ if ip.To4() == nil {
+ d.mx["ipv6_dhcp_hosts"]++
+ } else {
+ d.mx["ipv4_dhcp_hosts"]++
+ }
+ }
+}
+
+func (d *DnsmasqDHCP) collectRangesStats(leases []net.IP) {
+ for _, r := range d.dhcpRanges {
+ d.mx["dhcp_range_"+r.String()+"_allocated_leases"] = 0
+ d.mx["dhcp_range_"+r.String()+"_utilization"] = 0
+ }
+
+ for _, ip := range leases {
+ for _, r := range d.dhcpRanges {
+ if r.Contains(ip) {
+ d.mx["dhcp_range_"+r.String()+"_allocated_leases"]++
+ break
+ }
+ }
+ }
+
+ for _, ip := range d.dhcpHosts {
+ for _, r := range d.dhcpRanges {
+ if r.Contains(ip) {
+ d.mx["dhcp_range_"+r.String()+"_allocated_leases"]++
+ break
+ }
+ }
+ }
+
+ for _, r := range d.dhcpRanges {
+ name := "dhcp_range_" + r.String() + "_allocated_leases"
+ numOfIps, ok := d.mx[name]
+ if !ok {
+ d.mx[name] = 0
+ }
+ d.mx["dhcp_range_"+r.String()+"_utilization"] = int64(math.Round(calcPercent(numOfIps, r.Size())))
+ }
+}
+
+func (d *DnsmasqDHCP) updateCharts() bool {
+ var updated bool
+ seen := make(map[string]bool)
+ for _, r := range d.dhcpRanges {
+ seen[r.String()] = true
+ if !d.cacheDHCPRanges[r.String()] {
+ d.cacheDHCPRanges[r.String()] = true
+ d.addDHCPRangeCharts(r.String())
+ updated = true
+ }
+ }
+
+ for v := range d.cacheDHCPRanges {
+ if !seen[v] {
+ delete(d.cacheDHCPRanges, v)
+ d.removeDHCPRangeCharts(v)
+ updated = true
+ }
+ }
+ return updated
+}
+
+func findLeases(r io.Reader) []net.IP {
+ /*
+ 1560300536 08:00:27:61:3c:ee 2.2.2.3 debian8 *
+ duid 00:01:00:01:24:90:cf:5b:08:00:27:61:2e:2c
+ 1560300414 660684014 1234::20b * 00:01:00:01:24:90:cf:a3:08:00:27:61:3c:ee
+ */
+ var ips []net.IP
+ s := bufio.NewScanner(r)
+
+ for s.Scan() {
+ parts := strings.Fields(s.Text())
+ if len(parts) != 5 {
+ continue
+ }
+
+ ip := net.ParseIP(parts[2])
+ if ip == nil {
+ continue
+ }
+ ips = append(ips, ip)
+ }
+
+ return ips
+}
+
+func calcPercent(ips int64, hosts *big.Int) float64 {
+ h := hosts.Int64()
+ if ips == 0 || h == 0 || !hosts.IsInt64() {
+ return 0
+ }
+ return float64(ips) * 100 / float64(h)
+}