master
go 156 lines 2.95 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package ntpd
4
5 import (
6 "fmt"
7 "net/netip"
8 "strconv"
9 "time"
10 )
11
12 const (
13 precision = 1000000
14 )
15
16 func (c *Collector) collect() (map[string]int64, error) {
17 if c.client == nil {
18 client, err := c.newClient(c.Config)
19 if err != nil {
20 return nil, fmt.Errorf("creating NTP client: %v", err)
21 }
22 c.client = client
23 }
24
25 mx := make(map[string]int64)
26
27 if err := c.collectInfo(mx); err != nil {
28 return nil, err
29 }
30
31 if c.CollectPeers {
32 if now := time.Now(); now.Sub(c.findPeersTime) > c.findPeersEvery {
33 c.findPeersTime = now
34 if err := c.findPeers(); err != nil {
35 c.Warning(err)
36 }
37 }
38 c.collectPeersInfo(mx)
39 }
40
41 return mx, nil
42 }
43
44 func (c *Collector) collectInfo(mx map[string]int64) error {
45 info, err := c.client.systemInfo()
46 if err != nil {
47 return fmt.Errorf("error on querying system info: %v", err)
48 }
49
50 for k, v := range info {
51 switch k {
52 case
53 "offset",
54 "sys_jitter",
55 "clk_jitter",
56 "frequency",
57 "clk_wander",
58 "rootdelay",
59 "rootdisp",
60 "stratum",
61 "tc",
62 "mintc",
63 "precision":
64 if val, err := strconv.ParseFloat(v, 64); err == nil {
65 mx[k] = int64(val * precision)
66 }
67 }
68 }
69 return nil
70 }
71
72 func (c *Collector) collectPeersInfo(mx map[string]int64) {
73 for _, id := range c.peerIDs {
74 info, err := c.client.peerInfo(id)
75 if err != nil {
76 c.Warningf("error on querying NTP peer info id='%d': %v", id, err)
77 continue
78 }
79
80 addr, ok := info["srcadr"]
81 if !ok {
82 continue
83 }
84
85 for k, v := range info {
86 switch k {
87 case
88 "offset",
89 "delay",
90 "dispersion",
91 "jitter",
92 "xleave",
93 "rootdelay",
94 "rootdisp",
95 "stratum",
96 "hmode",
97 "pmode",
98 "hpoll",
99 "ppoll",
100 "precision":
101 if val, err := strconv.ParseFloat(v, 64); err == nil {
102 mx["peer_"+addr+"_"+k] = int64(val * precision)
103 }
104 }
105 }
106 }
107 }
108
109 func (c *Collector) findPeers() error {
110 c.peerIDs = c.peerIDs[:0]
111
112 c.Debug("querying NTP peers")
113 peers, err := c.client.peerIDs()
114 if err != nil {
115 return fmt.Errorf("querying NTP peers: %v", err)
116 }
117
118 c.Debugf("found %d NTP peers (ids: %v)", len(peers), peers)
119 seen := make(map[string]bool)
120
121 for _, id := range peers {
122 info, err := c.client.peerInfo(id)
123 if err != nil {
124 c.Debugf("error on querying NTP peer info id='%d': %v", id, err)
125 continue
126 }
127
128 srcAddr, ok := info["srcadr"]
129 addr, err := netip.ParseAddr(srcAddr)
130
131 if !ok || err != nil || !addr.IsValid() || c.peerIPAddrFilter.Contains(addr) {
132 c.Debugf("skipping NTP peer id='%d', srcadr='%s'", id, addr)
133 continue
134 }
135
136 seen[addr.String()] = true
137
138 if !c.peerAddr[addr.String()] {
139 c.peerAddr[addr.String()] = true
140 c.Debugf("new NTP peer id='%d', srcadr='%s': creating charts", id, addr)
141 c.addPeerCharts(addr.String())
142 }
143
144 c.peerIDs = append(c.peerIDs, id)
145 }
146
147 for addr := range c.peerAddr {
148 if !seen[addr] {
149 delete(c.peerAddr, addr)
150 c.Debugf("stale NTP peer srcadr='%s': removing charts", addr)
151 c.removePeerCharts(addr)
152 }
153 }
154
155 return nil
156 }