From: Remi Gacogne Date: Mon, 16 Dec 2019 17:57:31 +0000 (+0100) Subject: dnsdist: Add unit tests for Lua LB policies as well X-Git-Tag: auth-4.3.0-beta2~1^2~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a9599e73035409a59c86c1f836787b8a6c8ea6e9;p=thirdparty%2Fpdns.git dnsdist: Add unit tests for Lua LB policies as well --- diff --git a/pdns/dnsdist-lbpolicies.hh b/pdns/dnsdist-lbpolicies.hh index ce763860ad..90c208da37 100644 --- a/pdns/dnsdist-lbpolicies.hh +++ b/pdns/dnsdist-lbpolicies.hh @@ -73,3 +73,4 @@ std::shared_ptr wrandom(const ServerPolicy::NumberedServerVecto std::shared_ptr whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq); std::shared_ptr chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq); std::shared_ptr roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq); +std::shared_ptr getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq); diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index cef2742d45..8adbb810cd 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -210,7 +210,7 @@ static void parseTLSConfig(TLSConfig& config, const std::string& context, boost: #endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS) -void setupLuaConfig(bool client, bool configCheck) +static void setupLuaConfig(bool client, bool configCheck) { typedef std::unordered_map >, DownstreamState::checkfunc_t > > newserver_t; g_lua.writeFunction("inClientStartup", [client]() { diff --git a/pdns/dnsdist-snmp.cc b/pdns/dnsdist-snmp.cc index c2d0a86fcd..eefa558b7b 100644 --- a/pdns/dnsdist-snmp.cc +++ b/pdns/dnsdist-snmp.cc @@ -52,6 +52,10 @@ static const oid specialMemoryUsageOID[] = { DNSDIST_STATS_OID, 39 }; static std::unordered_map s_statsMap; +bool g_snmpEnabled{false}; +bool g_snmpTrapsEnabled{false}; +DNSDistSNMPAgent* g_snmpAgent{nullptr}; + /* We are never called for a GETNEXT if it's registered as a "instance", as it's "magically" handled for us. */ /* a instance handler also only hands us one request at a time, so diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index c27c132dec..5c5803b1c7 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -48,7 +48,6 @@ #include "dnsdist-ecs.hh" #include "dnsdist-healthchecks.hh" #include "dnsdist-lua.hh" -#include "dnsdist-lua-ffi.hh" #include "dnsdist-rings.hh" #include "dnsdist-secpoll.hh" #include "dnsdist-xpf.hh" @@ -103,10 +102,6 @@ std::vector> g_frontends; GlobalStateHolder g_pools; size_t g_udpVectorSize{1}; -bool g_snmpEnabled{false}; -bool g_snmpTrapsEnabled{false}; -DNSDistSNMPAgent* g_snmpAgent{nullptr}; - /* UDP: the grand design. Per socket we listen on for incoming queries there is one thread. Then we have a bunch of connected sockets for talking to downstream servers. We send directly to those sockets. @@ -1181,25 +1176,7 @@ ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders& policy = *(serverPool->policy); } auto servers = serverPool->getServers(); - if (policy.isLua) { - if (!policy.isFFI) { - std::lock_guard lock(g_luamutex); - selectedBackend = policy.policy(servers, &dq); - } - else { - dnsdist_ffi_dnsquestion_t dnsq(&dq); - dnsdist_ffi_servers_list_t serversList(servers); - unsigned int selected = 0; - { - std::lock_guard lock(g_luamutex); - selected = policy.ffipolicy(&serversList, &dnsq); - } - selectedBackend = servers.at(selected).second; - } - } - else { - selectedBackend = policy.policy(servers, &dq); - } + selectedBackend = getSelectedBackendFromPolicy(policy, servers, dq); uint16_t cachedResponseSize = dq.size; uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL; diff --git a/pdns/dnsdistdist/Makefile.am b/pdns/dnsdistdist/Makefile.am index 1a48b590ad..2e0d9f9afe 100644 --- a/pdns/dnsdistdist/Makefile.am +++ b/pdns/dnsdistdist/Makefile.am @@ -224,6 +224,8 @@ testrunner_SOURCES = \ dnsdist-ecs.cc dnsdist-ecs.hh \ dnsdist-kvs.cc dnsdist-kvs.hh \ dnsdist-lbpolicies.cc dnsdist-lbpolicies.hh \ + dnsdist-lua-ffi.cc dnsdist-lua-ffi.hh \ + dnsdist-lua-ffi-interface.h dnsdist-lua-ffi-interface.inc \ dnsdist-rings.hh \ dnsdist-xpf.cc dnsdist-xpf.hh \ dnscrypt.cc dnscrypt.hh \ @@ -249,7 +251,8 @@ testrunner_SOURCES = \ threadname.hh threadname.cc \ testrunner.cc \ uuid-utils.hh uuid-utils.cc \ - xpf.cc xpf.hh + xpf.cc xpf.hh \ + ext/luawrapper/include/LuaContext.hpp dnsdist_LDFLAGS = \ $(AM_LDFLAGS) \ @@ -277,8 +280,9 @@ testrunner_LDFLAGS = \ testrunner_LDADD = \ $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \ - $(LIBSODIUM_LIBS) \ $(FSTRM_LIBS) \ + $(LIBSODIUM_LIBS) \ + $(LUA_LIBS) \ $(RT_LIBS) \ $(SANITIZER_FLAGS) \ $(LIBCAP_LIBS) diff --git a/pdns/dnsdistdist/dnsdist-lbpolicies.cc b/pdns/dnsdistdist/dnsdist-lbpolicies.cc index acb8f27780..4b707dcaa2 100644 --- a/pdns/dnsdistdist/dnsdist-lbpolicies.cc +++ b/pdns/dnsdistdist/dnsdist-lbpolicies.cc @@ -22,6 +22,7 @@ #include "dnsdist.hh" #include "dnsdist-lbpolicies.hh" +#include "dnsdist-lua-ffi.hh" #include "dolog.hh" GlobalStateHolder g_policy; @@ -241,3 +242,30 @@ std::shared_ptr getPool(const pools_t& pools, const std::string& poo return it->second; } + +std::shared_ptr getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq) +{ + std::shared_ptr selectedBackend{nullptr}; + + if (policy.isLua) { + if (!policy.isFFI) { + std::lock_guard lock(g_luamutex); + selectedBackend = policy.policy(servers, &dq); + } + else { + dnsdist_ffi_dnsquestion_t dnsq(&dq); + dnsdist_ffi_servers_list_t serversList(servers); + unsigned int selected = 0; + { + std::lock_guard lock(g_luamutex); + selected = policy.ffipolicy(&serversList, &dnsq); + } + selectedBackend = servers.at(selected).second; + } + } + else { + selectedBackend = policy.policy(servers, &dq); + } + + return selectedBackend; +} diff --git a/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc b/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc index 1e8418c70f..90a8ece93d 100644 --- a/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc +++ b/pdns/dnsdistdist/test-dnsdistlbpolicies_cc.cc @@ -10,33 +10,62 @@ #include "dolog.hh" uint16_t g_maxOutstanding{std::numeric_limits::max()}; + std::mutex g_luamutex; +#include "ext/luawrapper/include/LuaContext.hpp" +LuaContext g_lua; + +bool g_snmpEnabled{false}; +bool g_snmpTrapsEnabled{false}; +DNSDistSNMPAgent* g_snmpAgent{nullptr}; + +/* add stub implementations, we don't want to include the corresponding object files + and their dependencies */ -static std::shared_ptr getSelectedBackendFromPolicy(const ServerPolicy& policy, const ServerPolicy::NumberedServerVector& servers, DNSQuestion& dq) +#ifdef HAVE_DNS_OVER_HTTPS +std::unordered_map DOHUnit::getHTTPHeaders() const { - std::shared_ptr selectedBackend{nullptr}; + return {}; +} - if (policy.isLua) { - if (!policy.isFFI) { - std::lock_guard lock(g_luamutex); - selectedBackend = policy.policy(servers, &dq); - } - else { - dnsdist_ffi_dnsquestion_t dnsq(&dq); - dnsdist_ffi_servers_list_t serversList(servers); - unsigned int selected = 0; - { - std::lock_guard lock(g_luamutex); - selected = policy.ffipolicy(&serversList, &dnsq); - } - selectedBackend = servers.at(selected).second; - } - } - else { - selectedBackend = policy.policy(servers, &dq); - } +std::string DOHUnit::getHTTPPath() const +{ + return ""; +} + +std::string DOHUnit::getHTTPHost() const +{ + return ""; +} + +std::string DOHUnit::getHTTPScheme() const +{ + return ""; +} + +std::string DOHUnit::getHTTPQueryString() const +{ + return ""; +} + +void DOHUnit::setHTTPResponse(uint16_t statusCode, const std::string& body_, const std::string& contentType_) +{ +} +#endif /* HAVE_DNS_OVER_HTTPS */ - return selectedBackend; +std::string DNSQuestion::getTrailingData() const +{ + return ""; +} + +bool DNSQuestion::setTrailingData(const std::string& tail) +{ + return false; +} + +bool DNSDistSNMPAgent::sendDNSTrap(const DNSQuestion& dq, const std::string& reason) +{ + return false; } static DNSQuestion getDQ(const DNSName* providedName = nullptr) @@ -136,7 +165,7 @@ BOOST_AUTO_TEST_CASE(test_wrandom) { ServerPolicy::NumberedServerVector servers; std::map, uint64_t> serversMap; for (size_t idx = 1; idx <= 10; idx++) { - servers.push_back({ idx + 1, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); + servers.push_back({ idx, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); serversMap[servers.at(idx - 1).second] = 0; servers.at(idx - 1).second->setUp(); } @@ -200,7 +229,7 @@ BOOST_AUTO_TEST_CASE(test_whashed) { ServerPolicy::NumberedServerVector servers; std::map, uint64_t> serversMap; for (size_t idx = 1; idx <= 10; idx++) { - servers.push_back({ idx + 1, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); + servers.push_back({ idx, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); serversMap[servers.at(idx - 1).second] = 0; servers.at(idx - 1).second->setUp(); } @@ -264,6 +293,7 @@ BOOST_AUTO_TEST_CASE(test_whashed) { BOOST_CHECK_LT(got, expected * 2); } + BOOST_AUTO_TEST_CASE(test_chashed) { bool existingVerboseValue = g_verbose; g_verbose = false; @@ -278,7 +308,7 @@ BOOST_AUTO_TEST_CASE(test_chashed) { ServerPolicy::NumberedServerVector servers; std::map, uint64_t> serversMap; for (size_t idx = 1; idx <= 10; idx++) { - servers.push_back({ idx + 1, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); + servers.push_back({ idx, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); serversMap[servers.at(idx - 1).second] = 0; servers.at(idx - 1).second->setUp(); /* we need to have a weight of at least 1000 to get an optimal repartition with the consistent hashing algo */ @@ -348,4 +378,105 @@ BOOST_AUTO_TEST_CASE(test_chashed) { g_verbose = existingVerboseValue; } +BOOST_AUTO_TEST_CASE(test_lua) { + std::vector names; + names.reserve(1000); + for (size_t idx = 0; idx < 1000; idx++) { + names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com.")); + } + + static const std::string policySetupStr = R"foo( + local counter = 0 + function luaroundrobin(servers, dq) + counter = counter + 1 + return servers[1 + (counter % #servers)] + end + + setServerPolicyLua("luaroundrobin", luaroundrobin) + )foo"; + g_lua.writeFunction("setServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy) { + g_policy.setState(ServerPolicy{name, policy, true}); + }); + g_lua.executeCode(policySetupStr); + + ServerPolicy pol = g_policy.getCopy(); + ServerPolicy::NumberedServerVector servers; + std::map, uint64_t> serversMap; + for (size_t idx = 1; idx <= 10; idx++) { + servers.push_back({ idx, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); + serversMap[servers.at(idx - 1).second] = 0; + servers.at(idx - 1).second->setUp(); + } + BOOST_REQUIRE_EQUAL(servers.size(), 10); + + for (const auto& name : names) { + auto dq = getDQ(&name); + auto server = getSelectedBackendFromPolicy(pol, servers, dq); + BOOST_REQUIRE(serversMap.count(server) == 1); + ++serversMap[server]; + } + uint64_t total = 0; + for (const auto& entry : serversMap) { + BOOST_CHECK_GT(entry.second, 0); + BOOST_CHECK_GT(entry.second, (names.size() / servers.size() / 2)); + BOOST_CHECK_LT(entry.second, (names.size() / servers.size() * 2)); + total += entry.second; + } + BOOST_CHECK_EQUAL(total, names.size()); +} + +#ifdef LUAJIT_VERSION +BOOST_AUTO_TEST_CASE(test_lua_ffi) { + std::vector names; + names.reserve(1000); + for (size_t idx = 0; idx < 1000; idx++) { + names.push_back(DNSName("powerdns-" + std::to_string(idx) + ".com.")); + } + + static const std::string policySetupStr = R"foo( + local ffi = require("ffi") + local C = ffi.C + local counter = 0 + function ffilb(servers_list, dq) + local serversCount = tonumber(C.dnsdist_ffi_servers_list_get_count(servers_list)) + counter = counter + 1 + return counter % serversCount + end + + setServerPolicyLuaFFI("FFI", ffilb) + )foo"; + g_lua.executeCode(getLuaFFIWrappers()); + g_lua.writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) { + auto pol = ServerPolicy(name, policy); + g_policy.setState(std::move(pol)); + }); + g_lua.executeCode(policySetupStr); + + ServerPolicy pol = g_policy.getCopy(); + ServerPolicy::NumberedServerVector servers; + std::map, uint64_t> serversMap; + for (size_t idx = 1; idx <= 10; idx++) { + servers.push_back({ idx, std::make_shared(ComboAddress("192.0.2." + std::to_string(idx) + ":53")) }); + serversMap[servers.at(idx - 1).second] = 0; + servers.at(idx - 1).second->setUp(); + } + BOOST_REQUIRE_EQUAL(servers.size(), 10); + + for (const auto& name : names) { + auto dq = getDQ(&name); + auto server = getSelectedBackendFromPolicy(pol, servers, dq); + BOOST_REQUIRE(serversMap.count(server) == 1); + ++serversMap[server]; + } + uint64_t total = 0; + for (const auto& entry : serversMap) { + BOOST_CHECK_GT(entry.second, 0); + BOOST_CHECK_GT(entry.second, (names.size() / servers.size() / 2)); + BOOST_CHECK_LT(entry.second, (names.size() / servers.size() * 2)); + total += entry.second; + } + BOOST_CHECK_EQUAL(total, names.size()); +} +#endif /* LUAJIT_VERSION */ + BOOST_AUTO_TEST_SUITE_END()