Skip to content

Commit 8f0bf1c

Browse files
committed
dnsdist: Add unit tests for the AF_XDP/XSK code
Signed-off-by: Remi Gacogne <[email protected]>
1 parent fd76105 commit 8f0bf1c

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed

pdns/dnsdistdist/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ testrunner_SOURCES = \
409409
test-dnsdist-ipcrypt2_cc.cc \
410410
test-dnsdist-lua-ffi.cc \
411411
test-dnsdist-opentelemetry_cc.cc \
412+
test-dnsdist-xsk.cc \
412413
test-dnsdist_cc.cc \
413414
test-dnsdistasync.cc \
414415
test-dnsdistbackend_cc.cc \

pdns/dnsdistdist/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ test_sources += files(
546546
src_dir / 'test-dnsdistsvc_cc.cc',
547547
src_dir / 'test-dnsdistserverpool.cc',
548548
src_dir / 'test-dnsdisttcp_cc.cc',
549+
src_dir / 'test-dnsdist-xsk.cc',
549550
src_dir / 'test-dnsparser_cc.cc',
550551
src_dir / 'test-iputils_hh.cc',
551552
src_dir / 'test-luawrapper.cc',
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
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+
#ifndef BOOST_TEST_DYN_LINK
23+
#define BOOST_TEST_DYN_LINK
24+
#endif
25+
26+
#define BOOST_TEST_NO_MAIN
27+
28+
#include <boost/test/unit_test.hpp>
29+
30+
#include "config.h"
31+
#include "dnsdist-mac-address.hh"
32+
#include "iputils.hh"
33+
#include "xsk.hh"
34+
35+
BOOST_AUTO_TEST_SUITE(test_dnsdist_xsk)
36+
37+
#if defined(HAVE_XSK)
38+
39+
BOOST_AUTO_TEST_CASE(test_XskSocket)
40+
{
41+
auto itfs = getListOfNetworkInterfaces();
42+
if (itfs.empty()) {
43+
/* we won't be able to create a XskSocket without a valid interface name */
44+
return;
45+
}
46+
const auto& itfName = *itfs.begin();
47+
const uint32_t queueId = 0;
48+
const std::string path = "/tmp/xsk-test";
49+
50+
{
51+
/* not a power of two, should throw */
52+
BOOST_CHECK_THROW(XskSocket(1000U, itfName, queueId, path), std::runtime_error);
53+
}
54+
55+
{
56+
/* not a valid interface name, should throw */
57+
BOOST_CHECK_THROW(XskSocket(1024U, "not-an-interface-name", queueId, path), std::runtime_error);
58+
}
59+
60+
{
61+
/* not enough privileges, should throw */
62+
const size_t numberOfFrames = 1024U;
63+
BOOST_CHECK_THROW(XskSocket(numberOfFrames, itfName, queueId, path), std::runtime_error);
64+
}
65+
}
66+
67+
BOOST_AUTO_TEST_CASE(test_XskPacket)
68+
{
69+
const dnsdist::MacAddress fromMAC{};
70+
const dnsdist::MacAddress toMAC{0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
71+
72+
{
73+
/* empty packet with no room! */
74+
auto packet = XskPacket(nullptr, 0U, 0U);
75+
BOOST_CHECK(!packet.parse(false));
76+
BOOST_CHECK(packet.getFrameOffsetFrom(nullptr) == 0);
77+
}
78+
79+
{
80+
/* IPv4 */
81+
const ComboAddress fromAddr("192.0.2.1:42");
82+
const ComboAddress toAddr("192.0.2.2:53");
83+
84+
/* empty packet but with decent room to grow */
85+
PacketBuffer payload(XskSocket::getFrameSize());
86+
auto packet = XskPacket(payload.data(), 0U, payload.size());
87+
BOOST_CHECK_EQUAL(packet.getFlags(), 0U);
88+
BOOST_CHECK(packet.getFrameOffsetFrom(payload.data()) == 0);
89+
BOOST_CHECK(!packet.parse(false));
90+
BOOST_CHECK_EQUAL(packet.getFrameLen(), 0U);
91+
BOOST_CHECK_EQUAL(packet.getFlags(), 0U);
92+
packet.setAddr(fromAddr, fromMAC, toAddr, toMAC);
93+
BOOST_CHECK_EQUAL(packet.getFlags(), XskPacket::UPDATED);
94+
BOOST_CHECK_EQUAL(packet.getFromAddr().toStringWithPort(), fromAddr.toStringWithPort());
95+
BOOST_CHECK_EQUAL(packet.getToAddr().toStringWithPort(), toAddr.toStringWithPort());
96+
BOOST_CHECK_EQUAL(packet.isIPV6(), fromAddr.isIPv6());
97+
packet.setPayload(PacketBuffer());
98+
packet.rewrite();
99+
BOOST_CHECK_EQUAL(packet.getFlags(), XskPacket::REWRITTEN | XskPacket::UPDATED);
100+
101+
BOOST_CHECK(packet.parse(false));
102+
BOOST_CHECK_EQUAL(packet.isIPV6(), fromAddr.isIPv6());
103+
BOOST_CHECK_EQUAL(packet.getFrameLen(), 42U);
104+
BOOST_CHECK_EQUAL(packet.getCapacity(), (XskSocket::getFrameSize() - XDP_PACKET_HEADROOM - packet.getFrameLen()));
105+
BOOST_CHECK_EQUAL(packet.getDataLen(), 0U);
106+
BOOST_CHECK(packet.getPayloadData() == payload.data() + packet.getFrameLen());
107+
{
108+
auto cloned = packet.clonePacketBuffer();
109+
BOOST_CHECK(cloned.empty());
110+
auto header = packet.cloneHeaderToPacketBuffer();
111+
BOOST_CHECK_EQUAL(header.size(), 42U);
112+
auto newPacket = XskPacket(payload.data(), 0U, payload.size());
113+
newPacket.setHeader(header);
114+
BOOST_CHECK_EQUAL(newPacket.getFrameLen(), 42U);
115+
}
116+
117+
{
118+
auto smallPayload = PacketBuffer(packet.getCapacity() - 1U);
119+
BOOST_CHECK(packet.setPayload(smallPayload));
120+
BOOST_CHECK_EQUAL(packet.getFlags(), XskPacket::REWRITTEN | XskPacket::UPDATED);
121+
}
122+
123+
{
124+
auto newPacket = XskPacket(payload.data(), 0U, payload.size());
125+
auto bigPayload = PacketBuffer(newPacket.getCapacity() + 1U);
126+
BOOST_CHECK_EQUAL(newPacket.getFlags(), 0U);
127+
/* try to add a payload that is too big for the frame */
128+
BOOST_CHECK(!newPacket.setPayload(bigPayload));
129+
BOOST_CHECK_EQUAL(newPacket.getFlags(), 0U);
130+
}
131+
132+
{
133+
auto sendTime = packet.getSendTime();
134+
BOOST_CHECK_EQUAL(sendTime.tv_sec, 0);
135+
BOOST_CHECK_EQUAL(sendTime.tv_nsec, 0);
136+
BOOST_CHECK_EQUAL(packet.getFlags() & XskPacket::Flags::DELAY, 0U);
137+
/* adding 100 ms */
138+
packet.addDelay(100U);
139+
auto newSendTime = packet.getSendTime();
140+
BOOST_CHECK(sendTime < newSendTime);
141+
BOOST_CHECK_EQUAL(packet.getFlags() & XskPacket::Flags::DELAY, XskPacket::Flags::DELAY);
142+
}
143+
}
144+
145+
{
146+
/* IPv6 */
147+
const ComboAddress fromAddr("[2001:db8::1]:42");
148+
const ComboAddress toAddr("[2001:db8::2]:53");
149+
150+
/* empty packet but with decent room to grow */
151+
PacketBuffer payload(XskSocket::getFrameSize());
152+
auto packet = XskPacket(payload.data(), 0U, payload.size());
153+
BOOST_CHECK_EQUAL(packet.getFlags(), 0U);
154+
BOOST_CHECK(packet.getFrameOffsetFrom(payload.data()) == 0);
155+
BOOST_CHECK(!packet.parse(false));
156+
BOOST_CHECK_EQUAL(packet.getFrameLen(), 0U);
157+
packet.setAddr(fromAddr, fromMAC, toAddr, toMAC);
158+
BOOST_CHECK_EQUAL(packet.getFromAddr().toStringWithPort(), fromAddr.toStringWithPort());
159+
BOOST_CHECK_EQUAL(packet.getToAddr().toStringWithPort(), toAddr.toStringWithPort());
160+
BOOST_CHECK_EQUAL(packet.isIPV6(), fromAddr.isIPv6());
161+
packet.setPayload(PacketBuffer());
162+
packet.rewrite();
163+
164+
BOOST_CHECK(packet.parse(false));
165+
BOOST_CHECK_EQUAL(packet.isIPV6(), fromAddr.isIPv6());
166+
BOOST_CHECK_EQUAL(packet.getFrameLen(), 62U);
167+
BOOST_CHECK_EQUAL(packet.getCapacity(), (XskSocket::getFrameSize() - XDP_PACKET_HEADROOM - packet.getFrameLen()));
168+
BOOST_CHECK_EQUAL(packet.getDataLen(), 0U);
169+
BOOST_CHECK(packet.getPayloadData() == payload.data() + packet.getFrameLen());
170+
{
171+
auto cloned = packet.clonePacketBuffer();
172+
BOOST_CHECK(cloned.empty());
173+
auto header = packet.cloneHeaderToPacketBuffer();
174+
BOOST_CHECK_EQUAL(header.size(), 62U);
175+
auto newPacket = XskPacket(payload.data(), 0U, payload.size());
176+
newPacket.setHeader(header);
177+
BOOST_CHECK_EQUAL(newPacket.getFrameLen(), 62U);
178+
}
179+
}
180+
}
181+
182+
#endif /* HAVE_XSK */
183+
184+
BOOST_AUTO_TEST_SUITE_END();

0 commit comments

Comments
 (0)