]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/test-dnsdistpacketcache_cc.cc
Merge pull request #6220 from pieterlexis/ddist-xpf
[thirdparty/pdns.git] / pdns / test-dnsdistpacketcache_cc.cc
CommitLineData
886e2cf2
RG
1#define BOOST_TEST_DYN_LINK
2#define BOOST_TEST_NO_MAIN
3
4#include <boost/test/unit_test.hpp>
5
1ea747c0 6#include "dnsdist.hh"
886e2cf2 7#include "iputils.hh"
886e2cf2 8#include "dnswriter.hh"
1ea747c0 9#include "dnsdist-cache.hh"
886e2cf2
RG
10
11BOOST_AUTO_TEST_SUITE(dnsdistpacketcache_cc)
12
13BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
14 const size_t maxEntries = 150000;
15 DNSDistPacketCache PC(maxEntries, 86400, 1);
16 BOOST_CHECK_EQUAL(PC.getSize(), 0);
17
18 size_t counter=0;
19 size_t skipped=0;
1ea747c0 20 ComboAddress remote;
886e2cf2
RG
21 try {
22 for(counter = 0; counter < 100000; ++counter) {
490dc586 23 DNSName a=DNSName(std::to_string(counter))+DNSName(" hello");
886e2cf2
RG
24 BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
25
26 vector<uint8_t> query;
27 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
28 pwQ.getHeader()->rd = 1;
29
30 vector<uint8_t> response;
31 DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
32 pwR.getHeader()->rd = 1;
33 pwR.getHeader()->ra = 1;
34 pwR.getHeader()->qr = 1;
35 pwR.getHeader()->id = pwQ.getHeader()->id;
36 pwR.startRecord(a, QType::A, 100, QClass::IN, DNSResourceRecord::ANSWER);
37 pwR.xfr32BitInt(0x01020304);
38 pwR.commit();
39 uint16_t responseLen = response.size();
40
41 char responseBuf[4096];
42 uint16_t responseBufSize = sizeof(responseBuf);
43 uint32_t key = 0;
1ea747c0
RG
44 DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false);
45 bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key);
886e2cf2
RG
46 BOOST_CHECK_EQUAL(found, false);
47
acb8f5d5 48 PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
886e2cf2 49
1ea747c0 50 found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true);
886e2cf2
RG
51 if (found == true) {
52 BOOST_CHECK_EQUAL(responseBufSize, responseLen);
53 int match = memcmp(responseBuf, response.data(), responseLen);
54 BOOST_CHECK_EQUAL(match, 0);
55 }
56 else {
57 skipped++;
58 }
59 }
60
61 BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions());
62 BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped);
63
64 size_t deleted=0;
65 size_t delcounter=0;
66 for(delcounter=0; delcounter < counter/1000; ++delcounter) {
490dc586 67 DNSName a=DNSName(std::to_string(delcounter))+DNSName(" hello");
886e2cf2
RG
68 vector<uint8_t> query;
69 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
70 pwQ.getHeader()->rd = 1;
71 char responseBuf[4096];
72 uint16_t responseBufSize = sizeof(responseBuf);
73 uint32_t key = 0;
1ea747c0
RG
74 DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false);
75 bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key);
886e2cf2 76 if (found == true) {
4275aaba 77 PC.expungeByName(a);
886e2cf2
RG
78 deleted++;
79 }
80 }
81 BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted);
82
490dc586 83
886e2cf2
RG
84 size_t matches=0;
85 vector<DNSResourceRecord> entry;
86 size_t expected=counter-skipped-deleted;
87 for(; delcounter < counter; ++delcounter) {
490dc586 88 DNSName a(DNSName(std::to_string(delcounter))+DNSName(" hello"));
886e2cf2
RG
89 vector<uint8_t> query;
90 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
91 pwQ.getHeader()->rd = 1;
92 uint16_t len = query.size();
93 uint32_t key = 0;
94 char response[4096];
95 uint16_t responseSize = sizeof(response);
1ea747c0
RG
96 DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), len, query.size(), false);
97 if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key)) {
490dc586 98 matches++;
886e2cf2
RG
99 }
100 }
101 BOOST_CHECK_EQUAL(matches, expected);
490dc586
RG
102
103 PC.expungeByName(DNSName(" hello"), QType::ANY, true);
104 BOOST_CHECK_EQUAL(PC.getSize(), 0);
886e2cf2
RG
105 }
106 catch(PDNSException& e) {
107 cerr<<"Had error: "<<e.reason<<endl;
108 throw;
109 }
110}
111
acb8f5d5
CH
112BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) {
113 const size_t maxEntries = 150000;
114 DNSDistPacketCache PC(maxEntries, 86400, 1);
115
116 ComboAddress remote;
117 try {
118 DNSName a = DNSName("servfail");
119 BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
120
121 vector<uint8_t> query;
122 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
123 pwQ.getHeader()->rd = 1;
124
125 vector<uint8_t> response;
126 DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
127 pwR.getHeader()->rd = 1;
128 pwR.getHeader()->ra = 0;
129 pwR.getHeader()->qr = 1;
130 pwR.getHeader()->rcode = RCode::ServFail;
131 pwR.getHeader()->id = pwQ.getHeader()->id;
132 pwR.commit();
133 uint16_t responseLen = response.size();
134
135 char responseBuf[4096];
136 uint16_t responseBufSize = sizeof(responseBuf);
137 uint32_t key = 0;
138 DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false);
139 bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key);
140 BOOST_CHECK_EQUAL(found, false);
141
142 // Insert with failure-TTL of 0 (-> should not enter cache).
143 PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(0));
144 found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true);
145 BOOST_CHECK_EQUAL(found, false);
146
56459632 147 // Insert with failure-TTL non-zero (-> should enter cache).
acb8f5d5
CH
148 PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(300));
149 found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true);
150 BOOST_CHECK_EQUAL(found, true);
151 }
152 catch(PDNSException& e) {
153 cerr<<"Had error: "<<e.reason<<endl;
154 throw;
155 }
156}
157
886e2cf2
RG
158static DNSDistPacketCache PC(500000);
159
af619119 160static void *threadMangler(void* off)
886e2cf2
RG
161{
162 try {
1ea747c0 163 ComboAddress remote;
af619119 164 unsigned int offset=(unsigned int)(unsigned long)off;
886e2cf2
RG
165 for(unsigned int counter=0; counter < 100000; ++counter) {
166 DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
167 vector<uint8_t> query;
168 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
169 pwQ.getHeader()->rd = 1;
170
171 vector<uint8_t> response;
172 DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0);
173 pwR.getHeader()->rd = 1;
174 pwR.getHeader()->ra = 1;
175 pwR.getHeader()->qr = 1;
176 pwR.getHeader()->id = pwQ.getHeader()->id;
177 pwR.startRecord(a, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER);
178 pwR.xfr32BitInt(0x01020304);
179 pwR.commit();
180 uint16_t responseLen = response.size();
181
182 char responseBuf[4096];
183 uint16_t responseBufSize = sizeof(responseBuf);
184 uint32_t key = 0;
1ea747c0
RG
185 DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false);
186 PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key);
886e2cf2 187
acb8f5d5 188 PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none);
886e2cf2
RG
189 }
190 }
191 catch(PDNSException& e) {
192 cerr<<"Had error: "<<e.reason<<endl;
193 throw;
194 }
195 return 0;
196}
197
198AtomicCounter g_missing;
199
af619119 200static void *threadReader(void* off)
886e2cf2
RG
201{
202 try
203 {
af619119 204 unsigned int offset=(unsigned int)(unsigned long)off;
886e2cf2 205 vector<DNSResourceRecord> entry;
1ea747c0 206 ComboAddress remote;
886e2cf2
RG
207 for(unsigned int counter=0; counter < 100000; ++counter) {
208 DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset));
209 vector<uint8_t> query;
210 DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0);
211 pwQ.getHeader()->rd = 1;
212
213 char responseBuf[4096];
214 uint16_t responseBufSize = sizeof(responseBuf);
215 uint32_t key = 0;
1ea747c0
RG
216 DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false);
217 bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key);
886e2cf2
RG
218 if (!found) {
219 g_missing++;
220 }
221 }
222 }
223 catch(PDNSException& e) {
224 cerr<<"Had error in threadReader: "<<e.reason<<endl;
225 throw;
226 }
227 return 0;
228}
229
230BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) {
231 try {
232 pthread_t tid[4];
233 for(int i=0; i < 4; ++i)
234 pthread_create(&tid[i], 0, threadMangler, (void*)(i*1000000UL));
235 void* res;
236 for(int i=0; i < 4 ; ++i)
237 pthread_join(tid[i], &res);
238
239 BOOST_CHECK_EQUAL(PC.getSize() + PC.getDeferredInserts() + PC.getInsertCollisions(), 400000);
240 BOOST_CHECK_SMALL(1.0*PC.getInsertCollisions(), 10000.0);
241
242 for(int i=0; i < 4; ++i)
243 pthread_create(&tid[i], 0, threadReader, (void*)(i*1000000UL));
244 for(int i=0; i < 4 ; ++i)
245 pthread_join(tid[i], &res);
246
247 BOOST_CHECK((PC.getDeferredInserts() + PC.getDeferredLookups() + PC.getInsertCollisions()) >= g_missing);
248 }
249 catch(PDNSException& e) {
250 cerr<<"Had error: "<<e.reason<<endl;
251 throw;
252 }
253
254}
255
256BOOST_AUTO_TEST_SUITE_END()