]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-rings.cc
updated KSK and ZSK Rollover procedures, small fixes in Algorithm Rollover procedure
[thirdparty/pdns.git] / pdns / dnsdist-rings.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include <fstream>
24
25 #include "dnsdist-rings.hh"
26
27 void Rings::setCapacity(size_t newCapacity, size_t numberOfShards)
28 {
29 if (d_initialized) {
30 throw std::runtime_error("Rings::setCapacity() should not be called once the rings have been initialized");
31 }
32 d_capacity = newCapacity;
33 d_numberOfShards = numberOfShards;
34 }
35
36 void Rings::init()
37 {
38 if (d_initialized.exchange(true)) {
39 throw std::runtime_error("Rings::init() should only be called once");
40 }
41
42 if (d_numberOfShards <= 1) {
43 d_nbLockTries = 0;
44 }
45
46 d_shards.resize(d_numberOfShards);
47
48 /* resize all the rings */
49 for (auto& shard : d_shards) {
50 shard = std::make_unique<Shard>();
51 shard->queryRing.lock()->set_capacity(d_capacity / d_numberOfShards);
52 shard->respRing.lock()->set_capacity(d_capacity / d_numberOfShards);
53 }
54
55 /* we just recreated the shards so they are now empty */
56 d_nbQueryEntries = 0;
57 d_nbResponseEntries = 0;
58 }
59
60 void Rings::setNumberOfLockRetries(size_t retries)
61 {
62 if (d_numberOfShards <= 1) {
63 d_nbLockTries = 0;
64 } else {
65 d_nbLockTries = retries;
66 }
67 }
68
69 size_t Rings::numDistinctRequestors()
70 {
71 std::set<ComboAddress, ComboAddress::addressOnlyLessThan> s;
72 for (const auto& shard : d_shards) {
73 auto rl = shard->queryRing.lock();
74 for (const auto& q : *rl) {
75 s.insert(q.requestor);
76 }
77 }
78 return s.size();
79 }
80
81 std::unordered_map<int, vector<boost::variant<string,double>>> Rings::getTopBandwidth(unsigned int numentries)
82 {
83 map<ComboAddress, unsigned int, ComboAddress::addressOnlyLessThan> counts;
84 uint64_t total=0;
85 for (const auto& shard : d_shards) {
86 {
87 auto rl = shard->queryRing.lock();
88 for(const auto& q : *rl) {
89 counts[q.requestor] += q.size;
90 total+=q.size;
91 }
92 }
93 {
94 auto rl = shard->respRing.lock();
95 for(const auto& r : *rl) {
96 counts[r.requestor] += r.size;
97 total+=r.size;
98 }
99 }
100 }
101
102 typedef vector<pair<unsigned int, ComboAddress>> ret_t;
103 ret_t rcounts;
104 rcounts.reserve(counts.size());
105 for(const auto& p : counts)
106 rcounts.push_back({p.second, p.first});
107 numentries = rcounts.size() < numentries ? rcounts.size() : numentries;
108 partial_sort(rcounts.begin(), rcounts.begin()+numentries, rcounts.end(), [](const ret_t::value_type&a, const ret_t::value_type&b)
109 {
110 return(b.first < a.first);
111 });
112 std::unordered_map<int, vector<boost::variant<string,double>>> ret;
113 uint64_t rest = 0;
114 unsigned int count = 1;
115 for(const auto& rc : rcounts) {
116 if(count==numentries+1) {
117 rest+=rc.first;
118 }
119 else {
120 ret.insert({count++, {rc.second.toString(), rc.first, 100.0*rc.first/total}});
121 }
122 }
123
124 if (total > 0) {
125 ret.insert({count, {"Rest", rest, 100.0*rest/total}});
126 }
127 else {
128 ret.insert({count, {"Rest", rest, 100.0 }});
129 }
130
131 return ret;
132 }
133
134 size_t Rings::loadFromFile(const std::string& filepath, const struct timespec& now)
135 {
136 ifstream ifs(filepath);
137 if (!ifs) {
138 throw std::runtime_error("unable to open the file at " + filepath);
139 }
140
141 size_t inserted = 0;
142 string line;
143 dnsheader dh;
144 memset(&dh, 0, sizeof(dh));
145
146 while (std::getline(ifs, line)) {
147 boost::trim_right_if(line, boost::is_any_of(" \r\n\x1a"));
148 boost::trim_left(line);
149 bool isResponse = false;
150 vector<string> parts;
151 stringtok(parts, line, " \t,");
152
153 if (parts.size() == 8) {
154 }
155 else if (parts.size() >= 11 && parts.size() <= 13) {
156 isResponse = true;
157 }
158 else {
159 cerr<<"skipping line with "<<parts.size()<<"parts: "<<line<<endl;
160 continue;
161 }
162
163 size_t idx = 0;
164 vector<string> timeStr;
165 stringtok(timeStr, parts.at(idx++), ".");
166 if (timeStr.size() != 2) {
167 cerr<<"skipping invalid time "<<parts.at(0)<<endl;
168 continue;
169 }
170
171 struct timespec when;
172 try {
173 when.tv_sec = now.tv_sec + std::stoi(timeStr.at(0));
174 when.tv_nsec = now.tv_nsec + std::stoi(timeStr.at(1)) * 100 * 1000 * 1000;
175 }
176 catch (const std::exception& e) {
177 cerr<<"error parsing time "<<parts.at(idx-1)<<" from line "<<line<<endl;
178 continue;
179 }
180
181 ComboAddress from(parts.at(idx++));
182 ComboAddress to;
183 dnsdist::Protocol protocol(parts.at(idx++));
184 if (isResponse) {
185 to = ComboAddress(parts.at(idx++));
186 }
187 /* skip ID */
188 idx++;
189 DNSName qname(parts.at(idx++));
190 QType qtype(QType::chartocode(parts.at(idx++).c_str()));
191
192 if (isResponse) {
193 insertResponse(when, from, qname, qtype.getCode(), 0, 0, dh, to, protocol);
194 }
195 else {
196 insertQuery(when, from, qname, qtype.getCode(), 0, dh, protocol);
197 }
198 ++inserted;
199 }
200
201 return inserted;
202 }