]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsdist.hh
Add per-frontend stats to dnsdist
[thirdparty/pdns.git] / pdns / dnsdist.hh
CommitLineData
df111b53 1#pragma once
2#include "ext/luawrapper/include/LuaContext.hpp"
3#include <time.h>
4#include "misc.hh"
5#include "iputils.hh"
6#include "dnsname.hh"
7#include <atomic>
8#include <boost/circular_buffer.hpp>
e16fd59c 9#include <boost/variant.hpp>
df111b53 10#include <mutex>
11#include <thread>
ecbe9133 12#include "sholder.hh"
42fae326 13void* carbonDumpThread();
61d1b966 14uint64_t uptimeOfProcess(const std::string& str);
bd1c631b 15
6da5d988 16extern GlobalStateHolder<NetmaskTree<string>> g_dynblockNMG;
e48090d1 17struct DNSDistStats
18{
6ad8b29a 19 using stat_t=std::atomic<uint64_t>; // aww yiss ;-)
e48090d1 20 stat_t responses{0};
21 stat_t servfailResponses{0};
22 stat_t queries{0};
e73ec7d3 23 stat_t nonCompliantQueries{0};
e48090d1 24 stat_t aclDrops{0};
25 stat_t blockFilter{0};
bd1c631b 26 stat_t dynBlocked{0};
e48090d1 27 stat_t ruleDrop{0};
28 stat_t ruleNXDomain{0};
29 stat_t selfAnswered{0};
30 stat_t downstreamTimeouts{0};
31 stat_t downstreamSendErrors{0};
6ad8b29a 32 stat_t truncFail{0};
b8bc7e61 33 stat_t noPolicy{0};
42fae326 34 stat_t latency0_1{0}, latency1_10{0}, latency10_50{0}, latency50_100{0}, latency100_1000{0}, latencySlow{0};
e48090d1 35
e16fd59c 36 double latencyAvg100{0}, latencyAvg1000{0}, latencyAvg10000{0}, latencyAvg1000000{0};
a1a787dc 37 typedef std::function<uint64_t(const std::string&)> statfunction_t;
38 typedef boost::variant<stat_t*, double*, statfunction_t> entry_t;
e16fd59c 39 std::vector<std::pair<std::string, entry_t>> entries{
42fae326 40 {"responses", &responses}, {"servfail-responses", &servfailResponses},
41 {"queries", &queries}, {"acl-drops", &aclDrops},
42 {"block-filter", &blockFilter}, {"rule-drop", &ruleDrop},
43 {"rule-nxdomain", &ruleNXDomain}, {"self-answered", &selfAnswered},
44 {"downstream-timeouts", &downstreamTimeouts}, {"downstream-send-errors", &downstreamSendErrors},
45 {"trunc-failures", &truncFail}, {"no-policy", &noPolicy},
46 {"latency0-1", &latency0_1}, {"latency1-10", &latency1_10},
47 {"latency10-50", &latency10_50}, {"latency50-100", &latency50_100},
e16fd59c 48 {"latency100-1000", &latency100_1000}, {"latency-slow", &latencySlow},
49 {"latency-avg100", &latencyAvg100}, {"latency-avg1000", &latencyAvg1000},
a1a787dc 50 {"latency-avg10000", &latencyAvg10000}, {"latency-avg1000000", &latencyAvg1000000},
61d1b966 51 {"uptime", uptimeOfProcess},
a9b6db56 52 {"real-memory-usage", getRealMemoryUsage},
a2aa00ed 53 {"noncompliant-queries", &nonCompliantQueries},
4f99f3d3
RG
54 {"cpu-user-msec", getCPUTimeUser},
55 {"cpu-sys-msec", getCPUTimeSystem},
bd1c631b 56 {"fd-usage", getOpenFileDescriptors}, {"dyn-blocked", &dynBlocked},
57 {"dyn-block-nmg-size", [](const std::string&) { return g_dynblockNMG.getLocal()->size(); }}
42fae326 58 };
e48090d1 59};
60
e16fd59c 61
e48090d1 62extern struct DNSDistStats g_stats;
63
638184e9 64
df111b53 65struct StopWatch
66{
67#ifndef CLOCK_MONOTONIC_RAW
68#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
69#endif
70 struct timespec d_start{0,0};
71 void start() {
72 if(clock_gettime(CLOCK_MONOTONIC_RAW, &d_start) < 0)
73 unixDie("Getting timestamp");
74
75 }
76
77 double udiff() const {
78 struct timespec now;
79 if(clock_gettime(CLOCK_MONOTONIC_RAW, &now) < 0)
80 unixDie("Getting timestamp");
81
82 return 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
83 }
84
85 double udiffAndSet() {
86 struct timespec now;
87 if(clock_gettime(CLOCK_MONOTONIC_RAW, &now) < 0)
88 unixDie("Getting timestamp");
89
90 auto ret= 1000000.0*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec)/1000.0;
91 d_start = now;
92 return ret;
93 }
94
95};
96
97class QPSLimiter
98{
99public:
100 QPSLimiter()
101 {
102 }
103
104 QPSLimiter(unsigned int rate, unsigned int burst) : d_rate(rate), d_burst(burst), d_tokens(burst)
105 {
106 d_passthrough=false;
107 d_prev.start();
108 }
109
110 unsigned int getRate() const
111 {
112 return d_passthrough? 0 : d_rate;
113 }
114
115 int getPassed() const
116 {
117 return d_passed;
118 }
119 int getBlocked() const
120 {
121 return d_blocked;
122 }
123
ecbe9133 124 bool check() const // this is not quite fair
df111b53 125 {
126 if(d_passthrough)
127 return true;
128 auto delta = d_prev.udiffAndSet();
129
130 d_tokens += 1.0*d_rate * (delta/1000000.0);
131
132 if(d_tokens > d_burst)
133 d_tokens = d_burst;
134
135 bool ret=false;
136 if(d_tokens >= 1.0) { // we need this because burst=1 is weird otherwise
137 ret=true;
138 --d_tokens;
139 d_passed++;
140 }
141 else
142 d_blocked++;
143
144 return ret;
145 }
146private:
147 bool d_passthrough{true};
148 unsigned int d_rate;
149 unsigned int d_burst;
ecbe9133 150 mutable double d_tokens;
151 mutable StopWatch d_prev;
152 mutable unsigned int d_passed{0};
153 mutable unsigned int d_blocked{0};
df111b53 154};
155
156
157struct IDState
158{
0e41337b 159 IDState() : origFD(-1), delayMsec(0) { origDest.sin4.sin_family = 0; pthread_rwlock_init(&lock, 0);}
df111b53 160 IDState(const IDState& orig)
161 {
162 origFD = orig.origFD;
163 origID = orig.origID;
164 origRemote = orig.origRemote;
549d63c9 165 origDest = orig.origDest;
7b3865cd 166 delayMsec = orig.delayMsec;
df111b53 167 age.store(orig.age.load());
0e41337b 168 pthread_rwlock_init(&lock, 0);
df111b53 169 }
170
2bf26975 171 int origFD; // set to <0 to indicate this state is empty // 4
172
173 ComboAddress origRemote; // 28
549d63c9 174 ComboAddress origDest; // 28
2bf26975 175 StopWatch sentTime; // 16
176 DNSName qname; // 80
0e41337b 177 pthread_rwlock_t lock;
2bf26975 178 std::atomic<uint16_t> age; // 4
179 uint16_t qtype; // 2
180 uint16_t origID; // 2
aeb36780 181 uint16_t origFlags; // 2
7b3865cd 182 int delayMsec;
df111b53 183};
184
185struct Rings {
186 Rings()
187 {
df111b53 188 queryRing.set_capacity(10000);
189 respRing.set_capacity(10000);
0e41337b 190 pthread_rwlock_init(&queryLock, 0);
df111b53 191 }
0ba5eecf 192 struct Query
193 {
194 struct timespec when;
195 ComboAddress requestor;
196 DNSName name;
197 uint16_t qtype;
198 };
199 boost::circular_buffer<Query> queryRing;
df111b53 200 struct Response
201 {
80a216c9 202 struct timespec when;
203 ComboAddress requestor;
df111b53 204 DNSName name;
205 uint16_t qtype;
206 uint8_t rcode;
207 unsigned int usec;
80a216c9 208 unsigned int size;
df111b53 209 };
210 boost::circular_buffer<Response> respRing;
211 std::mutex respMutex;
0e41337b 212 pthread_rwlock_t queryLock;
df111b53 213};
214
0e41337b 215extern Rings g_rings;
df111b53 216
8a5d5053 217struct ClientState
218{
219 ComboAddress local;
963bef8d 220 std::atomic<uint64_t> queries{0};
a36ce055
RG
221 int udpFD{-1};
222 int tcpFD{-1};
8a5d5053 223};
224
225class TCPClientCollection {
226 std::vector<int> d_tcpclientthreads;
227 std::atomic<uint64_t> d_pos;
228public:
229 std::atomic<uint64_t> d_queued, d_numthreads;
230
231 TCPClientCollection()
232 {
233 d_tcpclientthreads.reserve(1024);
234 }
235
236 int getThread()
237 {
238 int pos = d_pos++;
239 ++d_queued;
240 return d_tcpclientthreads[pos % d_numthreads];
241 }
242 void addTCPClientThread();
243};
244
245extern TCPClientCollection g_tcpclientthreads;
246
df111b53 247struct DownstreamState
248{
249 DownstreamState(const ComboAddress& remote_);
250
251 int fd;
252 std::thread tid;
253 ComboAddress remote;
254 QPSLimiter qps;
255 vector<IDState> idStates;
ad485896
RG
256 DNSName checkName;
257 QType checkType;
df111b53 258 std::atomic<uint64_t> idOffset{0};
259 std::atomic<uint64_t> sendErrors{0};
260 std::atomic<uint64_t> outstanding{0};
261 std::atomic<uint64_t> reuseds{0};
262 std::atomic<uint64_t> queries{0};
263 struct {
264 std::atomic<uint64_t> sendErrors{0};
265 std::atomic<uint64_t> reuseds{0};
266 std::atomic<uint64_t> queries{0};
267 } prev;
18eeccc9 268 string name;
df111b53 269 double queryLoad{0.0};
270 double dropRate{0.0};
271 double latencyUsec{0.0};
272 int order{1};
273 int weight{1};
3f6d07a4
RG
274 int tcpRecvTimeout{30};
275 int tcpSendTimeout{30};
276 uint16_t retries{5};
df111b53 277 StopWatch sw;
278 set<string> pools;
279 enum class Availability { Up, Down, Auto} availability{Availability::Auto};
a6e02424 280 bool mustResolve;
df111b53 281 bool upStatus{false};
282 bool isUp() const
283 {
284 if(availability == Availability::Down)
285 return false;
286 if(availability == Availability::Up)
287 return true;
288 return upStatus;
289 }
290 void setUp() { availability = Availability::Up; }
291 void setDown() { availability = Availability::Down; }
292 void setAuto() { availability = Availability::Auto; }
18eeccc9
RG
293 string getName() const {
294 if (name.empty()) {
295 return remote.toStringWithPort();
296 }
297 return name;
298 }
df111b53 299};
300using servers_t =vector<std::shared_ptr<DownstreamState>>;
df111b53 301
da4e7813 302template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
303
304void* responderThread(std::shared_ptr<DownstreamState> state);
305extern std::mutex g_luamutex;
306extern LuaContext g_lua;
307extern std::string g_outputBuffer; // locking for this is ok, as locked by g_luamutex
308
0940e4eb 309class DNSRule
310{
311public:
520eb5a0 312 virtual bool matches(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len) const =0;
0940e4eb 313 virtual string toString() const = 0;
314 mutable std::atomic<uint64_t> d_matches{0};
315};
316
317/* so what could you do:
318 drop,
319 fake up nxdomain,
320 provide actual answer,
321 allow & and stop processing,
322 continue processing,
323 modify header: (servfail|refused|notimp), set TC=1,
324 send to pool */
325
326class DNSAction
327{
328public:
7b3865cd 329 enum class Action { Drop, Nxdomain, Spoof, Allow, HeaderModify, Pool, Delay, None};
520eb5a0 330 virtual Action operator()(const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh, int len, string* ruleresult) const =0;
0940e4eb 331 virtual string toString() const = 0;
332};
333
da4e7813 334using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
335typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh)> policy_t;
df111b53 336
337struct ServerPolicy
338{
339 string name;
340 policy_t policy;
341};
342
42fae326 343struct CarbonConfig
344{
345 ComboAddress server{"0.0.0.0", 0};
346 std::string ourname;
347 unsigned int interval{30};
348};
349
350extern GlobalStateHolder<CarbonConfig> g_carbon;
ecbe9133 351extern GlobalStateHolder<ServerPolicy> g_policy;
352extern GlobalStateHolder<servers_t> g_dstates;
0940e4eb 353extern GlobalStateHolder<vector<pair<std::shared_ptr<DNSRule>, std::shared_ptr<DNSAction> > > > g_rulactions;
638184e9 354extern GlobalStateHolder<NetmaskGroup> g_ACL;
2e72cc0e 355
ecbe9133 356extern ComboAddress g_serverControl; // not changed during runtime
357
652a7355 358extern std::vector<std::pair<ComboAddress, bool>> g_locals; // not changed at runtime (we hope XXX)
963bef8d 359extern vector<ClientState*> g_frontends;
ecbe9133 360extern std::string g_key; // in theory needs locking
6ad8b29a 361extern bool g_truncateTC;
3f6d07a4
RG
362extern int g_tcpRecvTimeout;
363extern int g_tcpSendTimeout;
ecbe9133 364struct dnsheader;
365
366void controlThread(int fd, ComboAddress local);
839f3021 367vector<std::function<void(void)>> setupLua(bool client, const std::string& config);
da4e7813 368NumberedServerVector getDownstreamCandidates(const servers_t& servers, const std::string& pool);
369
370std::shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
ecbe9133 371
da4e7813 372std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
373std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
a7f3108c 374std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
da4e7813 375std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const ComboAddress& remote, const DNSName& qname, uint16_t qtype, dnsheader* dh);
520eb5a0 376int getEDNSZ(const char* packet, unsigned int len);
50bed881 377void dnsdistWebserverThread(int sock, const ComboAddress& local, const string& password);
8a5d5053 378bool getMsgLen(int fd, uint16_t* len);
379bool putMsgLen(int fd, uint16_t len);
d8d85a30 380void* tcpAcceptorThread(void* p);
80a216c9 381
382void moreLua();