From be05aa918b1f48e20c1d11cf7bc5a3448285a60a Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 11 Dec 2019 18:12:32 +0100 Subject: [PATCH] dnsdist: Implement FFI LB policies --- pdns/dnsdist-carbon.cc | 2 +- pdns/dnsdist-console.cc | 2 + pdns/dnsdist-lua-bindings.cc | 4 +- pdns/dnsdist-lua-inspection.cc | 2 +- pdns/dnsdist-lua.cc | 47 ++++++++------ pdns/dnsdist-snmp.cc | 8 +-- pdns/dnsdist-web.cc | 4 +- pdns/dnsdist.cc | 39 +++++++---- pdns/dnsdist.hh | 65 ++++++++++++------- pdns/dnsdistdist/dnsdist-lua-ffi-interface.h | 15 +++++ pdns/dnsdistdist/dnsdist-lua-ffi.cc | 40 ++++++++++++ pdns/dnsdistdist/dnsdist-lua-ffi.hh | 46 +++++++++++++ pdns/dnsdistdist/docs/advanced/tuning.rst | 2 +- .../docs/guides/serverselection.rst | 9 +++ 14 files changed, 219 insertions(+), 66 deletions(-) diff --git a/pdns/dnsdist-carbon.cc b/pdns/dnsdist-carbon.cc index 72473ca00d..26702dcb65 100644 --- a/pdns/dnsdist-carbon.cc +++ b/pdns/dnsdist-carbon.cc @@ -87,7 +87,7 @@ try } auto states = g_dstates.getLocal(); for(const auto& state : *states) { - string serverName = state->name.empty() ? (state->remote.toString() + ":" + std::to_string(state->remote.getPort())) : state->getName(); + string serverName = state->getName().empty() ? (state->remote.toString() + ":" + std::to_string(state->remote.getPort())) : state->getName(); boost::replace_all(serverName, ".", "_"); const string base = namespace_name + "." + hostname + "." + instance_name + ".servers." + serverName + "."; str<queries.load() << " " << now << "\r\n"; diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index deec2fc98d..61193e7432 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -426,6 +426,7 @@ const std::vector g_consoleKeywords{ { "LuaAction", true, "function", "Invoke a Lua function that accepts a DNSQuestion" }, { "LuaFFIAction", true, "function", "Invoke a Lua FFI function that accepts a DNSQuestion" }, { "LuaFFIResponseAction", true, "function", "Invoke a Lua FFI function that accepts a DNSResponse" }, + { "LuaFFIRule", true, "function", "Invoke a Lua FFI function that filters DNS questions" }, { "LuaResponseAction", true, "function", "Invoke a Lua function that accepts a DNSResponse" }, { "MacAddrAction", true, "option", "Add the source MAC address to the query as EDNS0 option option. This action is currently only supported on Linux. Subsequent rules are processed after this action" }, { "makeIPCipherKey", true, "password", "generates a 16-byte key that can be used to pseudonymize IP addresses with IP cipher" }, @@ -532,6 +533,7 @@ const std::vector g_consoleKeywords{ { "setSecurityPollSuffix", true, "suffix", "set the security polling suffix to the specified value" }, { "setServerPolicy", true, "policy", "set server selection policy to that policy" }, { "setServerPolicyLua", true, "name, function", "set server selection policy to one named 'name' and provided by 'function'" }, + { "setServerPolicyLuaFFI", true, "name, function", "set server selection policy to one named 'name' and provided by the Lua FFI 'function'" }, { "setServFailWhenNoServer", true, "bool", "if set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query" }, { "setStaleCacheEntriesTTL", true, "n", "allows using cache entries expired for at most n seconds when there is no backend available to answer for a query" }, { "setSyslogFacility", true, "facility", "set the syslog logging facility to 'facility'. Defaults to LOG_DAEMON" }, diff --git a/pdns/dnsdist-lua-bindings.cc b/pdns/dnsdist-lua-bindings.cc index fc25caddf3..a57c620254 100644 --- a/pdns/dnsdist-lua-bindings.cc +++ b/pdns/dnsdist-lua-bindings.cc @@ -57,7 +57,7 @@ void setupLuaBindings(bool client) return string("No exception"); }); /* ServerPolicy */ - g_lua.writeFunction("newServerPolicy", [](string name, policyfunc_t policy) { return ServerPolicy{name, policy, true};}); + g_lua.writeFunction("newServerPolicy", [](string name, ServerPolicy::policyfunc_t policy) { return std::make_shared(name, policy, true);}); g_lua.registerMember("name", &ServerPolicy::name); g_lua.registerMember("policy", &ServerPolicy::policy); g_lua.registerMember("isLua", &ServerPolicy::isLua); @@ -117,7 +117,7 @@ void setupLuaBindings(bool client) [](DownstreamState& s, int newWeight) {s.setWeight(newWeight);} ); g_lua.registerMember("order", &DownstreamState::order); - g_lua.registerMember("name", &DownstreamState::name); + g_lua.registerMember("name", [](const DownstreamState& backend) -> const std::string { return backend.getName(); }, [](DownstreamState& backend, const std::string& newName) { backend.setName(newName); }); g_lua.registerFunction("getID", [](const DownstreamState& s) { return boost::uuids::to_string(s.id); }); /* dnsheader */ diff --git a/pdns/dnsdist-lua-inspection.cc b/pdns/dnsdist-lua-inspection.cc index 0d37ff320c..d01a007b11 100644 --- a/pdns/dnsdist-lua-inspection.cc +++ b/pdns/dnsdist-lua-inspection.cc @@ -583,7 +583,7 @@ void setupLuaInspection() auto states = g_dstates.getLocal(); counter = 0; for(const auto& s : *states) { - ret << (fmt % counter % s->name % s->remote.toStringWithPort() % s->tcpCurrentConnections % s->tcpDiedSendingQuery % s->tcpDiedReadingResponse % s->tcpGaveUp % s->tcpReadTimeouts % s->tcpWriteTimeouts % s->tcpAvgQueriesPerConnection % s->tcpAvgConnectionDuration) << endl; + ret << (fmt % counter % s->getName() % s->remote.toStringWithPort() % s->tcpCurrentConnections % s->tcpDiedSendingQuery % s->tcpDiedReadingResponse % s->tcpGaveUp % s->tcpReadTimeouts % s->tcpWriteTimeouts % s->tcpAvgQueriesPerConnection % s->tcpAvgConnectionDuration) << endl; ++counter; } diff --git a/pdns/dnsdist-lua.cc b/pdns/dnsdist-lua.cc index 0cb77d6064..63972b50f2 100644 --- a/pdns/dnsdist-lua.cc +++ b/pdns/dnsdist-lua.cc @@ -386,7 +386,7 @@ void setupLuaConfig(bool client, bool configCheck) } if(vars.count("name")) { - ret->name=boost::get(vars["name"]); + ret->setName(boost::get(vars["name"])); } if (vars.count("id")) { @@ -536,20 +536,6 @@ void setupLuaConfig(bool client, bool configCheck) g_dstates.setState(states); } ); - g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) { - setLuaSideEffect(); - g_policy.setState(policy); - }); - g_lua.writeFunction("setServerPolicyLua", [](string name, policyfunc_t policy) { - setLuaSideEffect(); - g_policy.setState(ServerPolicy{name, policy, true}); - }); - - g_lua.writeFunction("showServerPolicy", []() { - setLuaSideEffect(); - g_outputBuffer=g_policy.getLocal()->name+"\n"; - }); - g_lua.writeFunction("truncateTC", [](bool tc) { setLuaSideEffect(); g_truncateTC=tc; }); g_lua.writeFunction("fixupCase", [](bool fu) { setLuaSideEffect(); g_fixupCase=fu; }); @@ -696,11 +682,11 @@ void setupLuaConfig(bool client, bool configCheck) pools+=p; } if (showUUIDs) { - ret << (fmt % counter % s->name % s->remote.toStringWithPort() % + ret << (fmt % counter % s->getName() % s->remote.toStringWithPort() % status % s->queryLoad % s->qps.getRate() % s->order % s->weight % s->queries.load() % s->reuseds.load() % (s->dropRate) % (s->latencyUsec/1000.0) % s->outstanding.load() % pools % s->id) << endl; } else { - ret << (fmt % counter % s->name % s->remote.toStringWithPort() % + ret << (fmt % counter % s->getName() % s->remote.toStringWithPort() % status % s->queryLoad % s->qps.getRate() % s->order % s->weight % s->queries.load() % s->reuseds.load() % (s->dropRate) % (s->latencyUsec/1000.0) % s->outstanding.load() % pools) << endl; } @@ -1402,8 +1388,8 @@ void setupLuaConfig(bool client, bool configCheck) if (!servers.empty()) { servers += ", "; } - if (!server.second->name.empty()) { - servers += server.second->name; + if (!server.second->getName().empty()) { + servers += server.second->getName(); servers += " "; } servers += server.second->remote.toStringWithPort(); @@ -1701,6 +1687,27 @@ void setupLuaConfig(bool client, bool configCheck) #endif /* HAVE_NET_SNMP */ }); + g_lua.writeFunction("setServerPolicy", [](ServerPolicy policy) { + setLuaSideEffect(); + g_policy.setState(policy); + }); + + g_lua.writeFunction("setServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy) { + setLuaSideEffect(); + g_policy.setState(ServerPolicy{name, policy, true}); + }); + + g_lua.writeFunction("setServerPolicyLuaFFI", [](string name, ServerPolicy::ffipolicyfunc_t policy) { + setLuaSideEffect(); + auto pol = ServerPolicy(name, policy); + g_policy.setState(std::move(pol)); + }); + + g_lua.writeFunction("showServerPolicy", []() { + setLuaSideEffect(); + g_outputBuffer=g_policy.getLocal()->name+"\n"; + }); + g_lua.writeFunction("setPoolServerPolicy", [](ServerPolicy policy, string pool) { setLuaSideEffect(); auto localPools = g_pools.getCopy(); @@ -1708,7 +1715,7 @@ void setupLuaConfig(bool client, bool configCheck) g_pools.setState(localPools); }); - g_lua.writeFunction("setPoolServerPolicyLua", [](string name, policyfunc_t policy, string pool) { + g_lua.writeFunction("setPoolServerPolicyLua", [](string name, ServerPolicy::policyfunc_t policy, string pool) { setLuaSideEffect(); auto localPools = g_pools.getCopy(); setPoolPolicy(localPools, pool, std::make_shared(ServerPolicy{name, policy, true})); diff --git a/pdns/dnsdist-snmp.cc b/pdns/dnsdist-snmp.cc index c0957d4e6f..c2d0a86fcd 100644 --- a/pdns/dnsdist-snmp.cc +++ b/pdns/dnsdist-snmp.cc @@ -293,8 +293,8 @@ static int backendStatTable_handler(netsnmp_mib_handler* handler, case COLUMN_BACKENDNAME: snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR, - server->name.c_str(), - server->name.size()); + server->getName().c_str(), + server->getName().size()); break; case COLUMN_BACKENDLATENCY: DNSDistSNMPAgent::setCounter64Value(request, @@ -388,8 +388,8 @@ bool DNSDistSNMPAgent::sendBackendStatusChangeTrap(const std::shared_ptrname.c_str(), - dss->name.size()); + dss->getName().c_str(), + dss->getName().size()); snmp_varlist_add_variable(&varList, backendAddressOID, diff --git a/pdns/dnsdist-web.cc b/pdns/dnsdist-web.cc index a089a9f6c3..8afe5560bd 100644 --- a/pdns/dnsdist-web.cc +++ b/pdns/dnsdist-web.cc @@ -558,7 +558,7 @@ static void connectionThread(int sock, ComboAddress remote) for (const auto& state : *states) { string serverName; - if (state->name.empty()) + if (state->getName().empty()) serverName = state->remote.toStringWithPort(); else serverName = state->getName(); @@ -821,7 +821,7 @@ static void connectionThread(int sock, ComboAddress remote) Json::object server{ {"id", num++}, - {"name", a->name}, + {"name", a->getName()}, {"address", a->remote.toStringWithPort()}, {"state", status}, {"qps", (double)a->queryLoad}, diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index 75d7c56ea2..95cd7ef10d 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -48,6 +48,7 @@ #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" @@ -811,7 +812,7 @@ void DownstreamState::setWeight(int newWeight) } } -DownstreamState::DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf_, const std::string& sourceItfName_, size_t numberOfSockets, bool connect=true): sourceItfName(sourceItfName_), remote(remote_), sourceAddr(sourceAddr_), sourceItf(sourceItf_) +DownstreamState::DownstreamState(const ComboAddress& remote_, const ComboAddress& sourceAddr_, unsigned int sourceItf_, const std::string& sourceItfName_, size_t numberOfSockets, bool connect=true): sourceItfName(sourceItfName_), remote(remote_), sourceAddr(sourceAddr_), sourceItf(sourceItf_), name(remote_.toStringWithPort()), nameWithAddr(remote_.toStringWithPort()) { pthread_rwlock_init(&d_lock, nullptr); id = getUniqueID(); @@ -838,7 +839,7 @@ LuaContext g_lua; GlobalStateHolder g_policy; -shared_ptr firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq) +shared_ptr firstAvailable(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq) { for(auto& d : servers) { if(d.second->isUp() && d.second->qps.check()) @@ -848,7 +849,7 @@ shared_ptr firstAvailable(const NumberedServerVector& servers, } // get server with least outstanding queries, and within those, with the lowest order, and within those: the fastest -shared_ptr leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq) +shared_ptr leastOutstanding(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq) { if (servers.size() == 1 && servers[0].second->isUp()) { return servers[0].second; @@ -869,7 +870,7 @@ shared_ptr leastOutstanding(const NumberedServerVector& servers return poss.begin()->second; } -shared_ptr valrandom(unsigned int val, const NumberedServerVector& servers, const DNSQuestion* dq) +shared_ptr valrandom(unsigned int val, const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq) { vector>> poss; int sum = 0; @@ -899,19 +900,19 @@ shared_ptr valrandom(unsigned int val, const NumberedServerVect return p->second; } -shared_ptr wrandom(const NumberedServerVector& servers, const DNSQuestion* dq) +shared_ptr wrandom(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq) { return valrandom(random(), servers, dq); } uint32_t g_hashperturb; double g_consistentHashBalancingFactor = 0; -shared_ptr whashed(const NumberedServerVector& servers, const DNSQuestion* dq) +shared_ptr whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq) { return valrandom(dq->qname->hash(g_hashperturb), servers, dq); } -shared_ptr chashed(const NumberedServerVector& servers, const DNSQuestion* dq) +shared_ptr chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq) { unsigned int qhash = dq->qname->hash(g_hashperturb); unsigned int sel = std::numeric_limits::max(); @@ -962,9 +963,9 @@ shared_ptr chashed(const NumberedServerVector& servers, const D return shared_ptr(); } -shared_ptr roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq) +shared_ptr roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq) { - NumberedServerVector poss; + ServerPolicy::NumberedServerVector poss; for(auto& d : servers) { if(d.second->isUp()) { @@ -1049,7 +1050,7 @@ std::shared_ptr getPool(const pools_t& pools, const std::string& poo return it->second; } -NumberedServerVector getDownstreamCandidates(const pools_t& pools, const std::string& poolName) +ServerPolicy::NumberedServerVector getDownstreamCandidates(const pools_t& pools, const std::string& poolName) { std::shared_ptr pool = getPool(pools, poolName); return pool->getServers(); @@ -1525,8 +1526,20 @@ ProcessQueryResult processQuery(DNSQuestion& dq, ClientState& cs, LocalHolders& } auto servers = serverPool->getServers(); if (policy.isLua) { - std::lock_guard lock(g_luamutex); - selectedBackend = policy.policy(servers, &dq); + 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); @@ -2030,7 +2043,7 @@ static void healthChecksThread() --dss->outstanding; ++g_stats.downstreamTimeouts; // this is an 'actively' discovered timeout vinfolog("Had a downstream timeout from %s (%s) for query for %s|%s from %s", - dss->remote.toStringWithPort(), dss->name, + dss->remote.toStringWithPort(), dss->getName(), ids.qname.toLogString(), QType(ids.qtype).getName(), ids.origRemote.toStringWithPort()); struct timespec ts; diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 44c992d01b..7b469983dc 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -807,7 +807,6 @@ struct DownstreamState std::atomic tcpAvgQueriesPerConnection{0.0}; /* in ms */ std::atomic tcpAvgConnectionDuration{0.0}; - string name; size_t socketsOffset{0}; double queryLoad{0.0}; double dropRate{0.0}; @@ -852,17 +851,19 @@ struct DownstreamState void setDown() { availability = Availability::Down; } void setAuto() { availability = Availability::Auto; } string getName() const { - if (name.empty()) { - return remote.toStringWithPort(); - } return name; } string getNameWithAddr() const { - if (name.empty()) { - return remote.toStringWithPort(); + return nameWithAddr; + } + void setName(const std::string& newName) + { + name = newName; + if (newName.empty()) { + nameWithAddr = newName.empty() ? remote.toStringWithPort() : (name + " (" + remote.toStringWithPort()+ ")"); } - return name + " (" + remote.toStringWithPort()+ ")"; } + string getStatus() const { string status; @@ -884,11 +885,12 @@ struct DownstreamState tcpAvgQueriesPerConnection = (99.0 * tcpAvgQueriesPerConnection / 100.0) + (nbQueries / 100.0); tcpAvgConnectionDuration = (99.0 * tcpAvgConnectionDuration / 100.0) + (durationMs / 100.0); } +private: + std::string name; + std::string nameWithAddr; }; using servers_t =vector>; -template using NumberedVector = std::vector >; - void responderThread(std::shared_ptr state); extern std::mutex g_luamutex; extern LuaContext g_lua; @@ -905,14 +907,33 @@ public: mutable std::atomic d_matches{0}; }; -using NumberedServerVector = NumberedVector>; -typedef std::function(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t; +struct dnsdist_ffi_servers_list_t; +struct dnsdist_ffi_server_t; +struct dnsdist_ffi_dnsquestion_t; struct ServerPolicy { + template using NumberedVector = std::vector >; + using NumberedServerVector = NumberedVector>; + typedef std::function(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t; + typedef std::function ffipolicyfunc_t; + + ServerPolicy(const std::string& name_, policyfunc_t policy_, bool isLua_): name(name_), policy(policy_), isLua(isLua_) + { + } + ServerPolicy(const std::string& name_, ffipolicyfunc_t policy_): name(name_), ffipolicy(policy_), isLua(true), isFFI(true) + { + } + ServerPolicy() + { + } + string name; policyfunc_t policy; - bool isLua; + ffipolicyfunc_t ffipolicy; + bool isLua{false}; + bool isFFI{false}; + std::string toString() const { return string("ServerPolicy") + (isLua ? " (Lua)" : "") + " \"" + name + "\""; } @@ -956,9 +977,9 @@ struct ServerPool return count; } - NumberedVector> getServers() + ServerPolicy::NumberedServerVector getServers() { - NumberedVector> result; + ServerPolicy::NumberedServerVector result; { ReadLock rl(&d_lock); result = d_servers; @@ -1005,7 +1026,7 @@ struct ServerPool } private: - NumberedVector> d_servers; + ServerPolicy::NumberedServerVector d_servers; pthread_rwlock_t d_lock; bool d_useECS{false}; }; @@ -1117,15 +1138,15 @@ struct dnsheader; void controlThread(int fd, ComboAddress local); std::shared_ptr getPool(const pools_t& pools, const std::string& poolName); std::shared_ptr createPoolIfNotExists(pools_t& pools, const string& poolName); -NumberedServerVector getDownstreamCandidates(const pools_t& pools, const std::string& poolName); +ServerPolicy::NumberedServerVector getDownstreamCandidates(const pools_t& pools, const std::string& poolName); -std::shared_ptr firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq); +std::shared_ptr firstAvailable(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq); -std::shared_ptr leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq); -std::shared_ptr wrandom(const NumberedServerVector& servers, const DNSQuestion* dq); -std::shared_ptr whashed(const NumberedServerVector& servers, const DNSQuestion* dq); -std::shared_ptr chashed(const NumberedServerVector& servers, const DNSQuestion* dq); -std::shared_ptr roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq); +std::shared_ptr leastOutstanding(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq); +std::shared_ptr wrandom(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq); +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); struct WebserverConfig { diff --git a/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h b/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h index fa8841d0b8..d513407511 100644 --- a/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h +++ b/pdns/dnsdistdist/dnsdist-lua-ffi-interface.h @@ -20,6 +20,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ typedef struct dnsdist_ffi_dnsquestion_t dnsdist_ffi_dnsquestion_t; +typedef struct dnsdist_ffi_servers_list_t dnsdist_ffi_servers_list_t; +typedef struct dnsdist_ffi_server_t dnsdist_ffi_server_t; typedef struct dnsdist_ednsoption { uint16_t optionCode; @@ -88,3 +90,16 @@ size_t dnsdist_ffi_dnsquestion_get_trailing_data(dnsdist_ffi_dnsquestion_t* dq, bool dnsdist_ffi_dnsquestion_set_trailing_data(dnsdist_ffi_dnsquestion_t* dq, const char* data, size_t dataLen) __attribute__ ((visibility ("default"))); void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char* reason, size_t reasonLen) __attribute__ ((visibility ("default"))); + +typedef struct dnsdist_ffi_servers_list_t dnsdist_ffi_servers_list_t; +typedef struct dnsdist_ffi_server_t dnsdist_ffi_server_t; + +size_t dnsdist_ffi_servers_list_get_count(const dnsdist_ffi_servers_list_t* list) __attribute__ ((visibility ("default"))); +void dnsdist_ffi_servers_list_get_server(const dnsdist_ffi_servers_list_t* list, size_t idx, const dnsdist_ffi_server_t** out) __attribute__ ((visibility ("default"))); + +uint64_t dnsdist_ffi_server_get_outstanding(const dnsdist_ffi_server_t* server) __attribute__ ((visibility ("default"))); +bool dnsdist_ffi_server_is_up(const dnsdist_ffi_server_t* server) __attribute__ ((visibility ("default"))); +const char* dnsdist_ffi_server_get_name(const dnsdist_ffi_server_t* server) __attribute__ ((visibility ("default"))); +const char* dnsdist_ffi_server_get_name_with_addr(const dnsdist_ffi_server_t* server) __attribute__ ((visibility ("default"))); +int dnsdist_ffi_server_get_weight(const dnsdist_ffi_server_t* server) __attribute__ ((visibility ("default"))); +int dnsdist_ffi_server_get_order(const dnsdist_ffi_server_t* server) __attribute__ ((visibility ("default"))); diff --git a/pdns/dnsdistdist/dnsdist-lua-ffi.cc b/pdns/dnsdistdist/dnsdist-lua-ffi.cc index cfffc2c1e3..67466e2631 100644 --- a/pdns/dnsdistdist/dnsdist-lua-ffi.cc +++ b/pdns/dnsdistdist/dnsdist-lua-ffi.cc @@ -410,6 +410,46 @@ void dnsdist_ffi_dnsquestion_send_trap(dnsdist_ffi_dnsquestion_t* dq, const char } } +size_t dnsdist_ffi_servers_list_get_count(const dnsdist_ffi_servers_list_t* list) +{ + return list->ffiServers.size(); +} + +void dnsdist_ffi_servers_list_get_server(const dnsdist_ffi_servers_list_t* list, size_t idx, const dnsdist_ffi_server_t** out) +{ + *out = &list->ffiServers.at(idx); +} + +uint64_t dnsdist_ffi_server_get_outstanding(const dnsdist_ffi_server_t* server) +{ + return server->server->outstanding; +} + +int dnsdist_ffi_server_get_weight(const dnsdist_ffi_server_t* server) +{ + return server->server->weight; +} + +int dnsdist_ffi_server_get_order(const dnsdist_ffi_server_t* server) +{ + return server->server->order; +} + +bool dnsdist_ffi_server_is_up(const dnsdist_ffi_server_t* server) +{ + return server->server->isUp(); +} + +const char* dnsdist_ffi_server_get_name(const dnsdist_ffi_server_t* server) +{ + return server->server->getName().c_str(); +} + +const char* dnsdist_ffi_server_get_name_with_addr(const dnsdist_ffi_server_t* server) +{ + return server->server->getNameWithAddr().c_str(); +} + const std::string& getLuaFFIWrappers() { static const std::string interface = diff --git a/pdns/dnsdistdist/dnsdist-lua-ffi.hh b/pdns/dnsdistdist/dnsdist-lua-ffi.hh index 913c759474..811a7f777e 100644 --- a/pdns/dnsdistdist/dnsdist-lua-ffi.hh +++ b/pdns/dnsdistdist/dnsdist-lua-ffi.hh @@ -58,4 +58,50 @@ struct dnsdist_ffi_dnsquestion_t boost::optional httpScheme{boost::none}; }; +// dnsdist_ffi_server_t is a lightuserdata +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, dnsdist_ffi_server_t* ptr) noexcept { + lua_pushlightuserdata(state, ptr); + return PushedObject{state, 1}; + } +}; + +struct dnsdist_ffi_server_t +{ + dnsdist_ffi_server_t(const std::shared_ptr& server_): server(server_) + { + } + + const std::shared_ptr& server; +}; + +// dnsdist_ffi_servers_list_t is a lightuserdata +template<> +struct LuaContext::Pusher { + static const int minSize = 1; + static const int maxSize = 1; + + static PushedObject push(lua_State* state, dnsdist_ffi_servers_list_t* ptr) noexcept { + lua_pushlightuserdata(state, ptr); + return PushedObject{state, 1}; + } +}; + +struct dnsdist_ffi_servers_list_t +{ + dnsdist_ffi_servers_list_t(const ServerPolicy::NumberedServerVector& servers) + { + ffiServers.reserve(servers.size()); + for (const auto& server: servers) { + ffiServers.push_back(dnsdist_ffi_server_t(server.second)); + } + } + + std::vector ffiServers; +}; + const std::string& getLuaFFIWrappers(); diff --git a/pdns/dnsdistdist/docs/advanced/tuning.rst b/pdns/dnsdistdist/docs/advanced/tuning.rst index 4fbbd171b7..46f846c68c 100644 --- a/pdns/dnsdistdist/docs/advanced/tuning.rst +++ b/pdns/dnsdistdist/docs/advanced/tuning.rst @@ -31,7 +31,7 @@ Large installations are advised to increase the default value at the cost of a s Most of the query processing is done in C++ for maximum performance, but some operations are executed in Lua for maximum flexibility: * Rules added by :func:`addLuaAction` - * Server selection policies defined via :func:`setServerPolicyLua` or :func:`newServerPolicy` + * Server selection policies defined via :func:`setServerPolicyLua`, :func:`setServerPolicyLuaFFI` or :func:`newServerPolicy` While Lua is fast, its use should be restricted to the strict necessary in order to achieve maximum performance, it might be worth considering using LuaJIT instead of Lua. When Lua inspection is needed, the best course of action is to restrict the queries sent to Lua inspection by using :func:`addLuaAction` with a selector. diff --git a/pdns/dnsdistdist/docs/guides/serverselection.rst b/pdns/dnsdistdist/docs/guides/serverselection.rst index f86dc6d852..53286c346e 100644 --- a/pdns/dnsdistdist/docs/guides/serverselection.rst +++ b/pdns/dnsdistdist/docs/guides/serverselection.rst @@ -146,6 +146,15 @@ Functions :param string name: name for this policy :param string function: name of the function +.. function:: setServerPolicyLuaFFI(name, function) + + .. versionadded:: 1.5.0 + + Set server selection policy to one named `name`` and provided by the FFI function ``function``. + + :param string name: name for this policy + :param string function: name of the FFI function + .. function:: setServFailWhenNoServer(value) If set, return a ServFail when no servers are available, instead of the default behaviour of dropping the query. -- 2.47.2