}
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<<base<<"queries" << ' ' << state->queries.load() << " " << now << "\r\n";
{ "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" },
{ "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" },
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<ServerPolicy>(name, policy, true);});
g_lua.registerMember("name", &ServerPolicy::name);
g_lua.registerMember("policy", &ServerPolicy::policy);
g_lua.registerMember("isLua", &ServerPolicy::isLua);
[](DownstreamState& s, int newWeight) {s.setWeight(newWeight);}
);
g_lua.registerMember("order", &DownstreamState::order);
- g_lua.registerMember("name", &DownstreamState::name);
+ g_lua.registerMember<const std::string(DownstreamState::*)>("name", [](const DownstreamState& backend) -> const std::string { return backend.getName(); }, [](DownstreamState& backend, const std::string& newName) { backend.setName(newName); });
g_lua.registerFunction<std::string(DownstreamState::*)()>("getID", [](const DownstreamState& s) { return boost::uuids::to_string(s.id); });
/* dnsheader */
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;
}
}
if(vars.count("name")) {
- ret->name=boost::get<string>(vars["name"]);
+ ret->setName(boost::get<string>(vars["name"]));
}
if (vars.count("id")) {
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; });
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;
}
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();
#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();
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>(ServerPolicy{name, policy, true}));
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,
backendNameOID,
OID_LENGTH(backendNameOID),
ASN_OCTET_STR,
- dss->name.c_str(),
- dss->name.size());
+ dss->getName().c_str(),
+ dss->getName().size());
snmp_varlist_add_variable(&varList,
backendAddressOID,
for (const auto& state : *states) {
string serverName;
- if (state->name.empty())
+ if (state->getName().empty())
serverName = state->remote.toStringWithPort();
else
serverName = state->getName();
Json::object server{
{"id", num++},
- {"name", a->name},
+ {"name", a->getName()},
{"address", a->remote.toStringWithPort()},
{"state", status},
{"qps", (double)a->queryLoad},
#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"
}
}
-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();
GlobalStateHolder<ServerPolicy> g_policy;
-shared_ptr<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq)
+shared_ptr<DownstreamState> firstAvailable(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
for(auto& d : servers) {
if(d.second->isUp() && d.second->qps.check())
}
// get server with least outstanding queries, and within those, with the lowest order, and within those: the fastest
-shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq)
+shared_ptr<DownstreamState> leastOutstanding(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
if (servers.size() == 1 && servers[0].second->isUp()) {
return servers[0].second;
return poss.begin()->second;
}
-shared_ptr<DownstreamState> valrandom(unsigned int val, const NumberedServerVector& servers, const DNSQuestion* dq)
+shared_ptr<DownstreamState> valrandom(unsigned int val, const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
vector<pair<int, shared_ptr<DownstreamState>>> poss;
int sum = 0;
return p->second;
}
-shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq)
+shared_ptr<DownstreamState> wrandom(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
return valrandom(random(), servers, dq);
}
uint32_t g_hashperturb;
double g_consistentHashBalancingFactor = 0;
-shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq)
+shared_ptr<DownstreamState> whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
return valrandom(dq->qname->hash(g_hashperturb), servers, dq);
}
-shared_ptr<DownstreamState> chashed(const NumberedServerVector& servers, const DNSQuestion* dq)
+shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
unsigned int qhash = dq->qname->hash(g_hashperturb);
unsigned int sel = std::numeric_limits<unsigned int>::max();
return shared_ptr<DownstreamState>();
}
-shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq)
+shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq)
{
- NumberedServerVector poss;
+ ServerPolicy::NumberedServerVector poss;
for(auto& d : servers) {
if(d.second->isUp()) {
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<ServerPool> pool = getPool(pools, poolName);
return pool->getServers();
}
auto servers = serverPool->getServers();
if (policy.isLua) {
- std::lock_guard<std::mutex> lock(g_luamutex);
- selectedBackend = policy.policy(servers, &dq);
+ if (!policy.isFFI) {
+ std::lock_guard<std::mutex> 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<std::mutex> lock(g_luamutex);
+ selected = policy.ffipolicy(&serversList, &dnsq);
+ }
+ selectedBackend = servers.at(selected).second;
+ }
}
else {
selectedBackend = policy.policy(servers, &dq);
--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;
std::atomic<double> tcpAvgQueriesPerConnection{0.0};
/* in ms */
std::atomic<double> tcpAvgConnectionDuration{0.0};
- string name;
size_t socketsOffset{0};
double queryLoad{0.0};
double dropRate{0.0};
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;
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<std::shared_ptr<DownstreamState>>;
-template <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
-
void responderThread(std::shared_ptr<DownstreamState> state);
extern std::mutex g_luamutex;
extern LuaContext g_lua;
mutable std::atomic<uint64_t> d_matches{0};
};
-using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
-typedef std::function<shared_ptr<DownstreamState>(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 <class T> using NumberedVector = std::vector<std::pair<unsigned int, T> >;
+ using NumberedServerVector = NumberedVector<shared_ptr<DownstreamState>>;
+ typedef std::function<shared_ptr<DownstreamState>(const NumberedServerVector& servers, const DNSQuestion*)> policyfunc_t;
+ typedef std::function<unsigned int(dnsdist_ffi_servers_list_t* servers, dnsdist_ffi_dnsquestion_t* dq)> 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 + "\"";
}
return count;
}
- NumberedVector<shared_ptr<DownstreamState>> getServers()
+ ServerPolicy::NumberedServerVector getServers()
{
- NumberedVector<shared_ptr<DownstreamState>> result;
+ ServerPolicy::NumberedServerVector result;
{
ReadLock rl(&d_lock);
result = d_servers;
}
private:
- NumberedVector<shared_ptr<DownstreamState>> d_servers;
+ ServerPolicy::NumberedServerVector d_servers;
pthread_rwlock_t d_lock;
bool d_useECS{false};
};
void controlThread(int fd, ComboAddress local);
std::shared_ptr<ServerPool> getPool(const pools_t& pools, const std::string& poolName);
std::shared_ptr<ServerPool> 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<DownstreamState> firstAvailable(const NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> firstAvailable(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
-std::shared_ptr<DownstreamState> leastOutstanding(const NumberedServerVector& servers, const DNSQuestion* dq);
-std::shared_ptr<DownstreamState> wrandom(const NumberedServerVector& servers, const DNSQuestion* dq);
-std::shared_ptr<DownstreamState> whashed(const NumberedServerVector& servers, const DNSQuestion* dq);
-std::shared_ptr<DownstreamState> chashed(const NumberedServerVector& servers, const DNSQuestion* dq);
-std::shared_ptr<DownstreamState> roundrobin(const NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> leastOutstanding(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> wrandom(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> whashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> chashed(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
+std::shared_ptr<DownstreamState> roundrobin(const ServerPolicy::NumberedServerVector& servers, const DNSQuestion* dq);
struct WebserverConfig
{
* 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;
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")));
}
}
+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 =
boost::optional<std::string> httpScheme{boost::none};
};
+// dnsdist_ffi_server_t is a lightuserdata
+template<>
+struct LuaContext::Pusher<dnsdist_ffi_server_t*> {
+ 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<DownstreamState>& server_): server(server_)
+ {
+ }
+
+ const std::shared_ptr<DownstreamState>& server;
+};
+
+// dnsdist_ffi_servers_list_t is a lightuserdata
+template<>
+struct LuaContext::Pusher<dnsdist_ffi_servers_list_t*> {
+ 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<dnsdist_ffi_server_t> ffiServers;
+};
+
const std::string& getLuaFFIWrappers();
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.
: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.