Commit 28565f82 authored by Marek Vavruša's avatar Marek Vavruša

daemon/bindings: replaced old Lua/C bindings with LuaJIT FFI

this is a first step of leaning towards LuaJIT.
the FFI bindings are much faster, simpler and don’t abort traces

daemon core scripting engine is still going to support interpreted Lua, but modules requiring library bindings (such as ‘block’) will require LuaJIT for FFI
parent 5bec676d
This diff is collapsed.
/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Lua-friendly bindings to resolver library parts,
* notably packet parsing and interpretation and operation on primitives like domain names.
*/
#pragma once
#include "daemon/bindings.h"
/* Metatable list */
#define META_PKT "kres.meta_pkt"
/**
* Load libkres library.
* @param L scriptable
* @return number of packages to load
*/
int lib_kres(lua_State *L);
\ No newline at end of file
......@@ -9,13 +9,15 @@ kresd_SOURCES := \
daemon/worker.c \
daemon/bindings.c \
daemon/ffimodule.c \
daemon/bindings/kres.c \
daemon/main.c
# Embed resources
daemon/engine.o: daemon/lua/sandbox.inc daemon/lua/config.inc
%.inc: %.lua
@$(call quiet,XXD,$<) $< > $@
# Installed FFI bindings
bindings-install: daemon/lua/kres.lua
$(INSTALL) $< $(PREFIX)/$(MODULEDIR)
# Dependencies
kresd_DEPEND := $(libkres)
......@@ -28,7 +30,7 @@ endif
# Targets
daemon: $(kresd)
daemon-install: kresd-install
daemon-install: kresd-install bindings-install
daemon-clean: kresd-clean
@$(RM) daemon/lua/*.inc
......
......@@ -19,7 +19,6 @@
#include "daemon/engine.h"
#include "daemon/ffimodule.h"
#include "daemon/bindings.h"
#include "daemon/bindings/kres.h"
#include "lib/module.h"
#include "lib/layer.h"
......@@ -41,13 +40,6 @@ enum {
};
#define SLOT_size sizeof(int)
/** @internal Set metatable on the object on stack. */
static void set_metatable(lua_State *L, const char *tname)
{
luaL_getmetatable(L, tname);
lua_setmetatable(L, -2);
}
/** @internal Helper for retrieving the right function entrypoint. */
static inline lua_State *l_ffi_preface(struct kr_module *module, const char *call) {
lua_State *L = module->lib;
......@@ -95,10 +87,10 @@ static inline int l_ffi_call(lua_State *L, int argc)
lua_pop(L, 1);
return kr_error(EIO);
}
if (lua_isthread(L, -1)) { /* Continuations */
status = l_ffi_defer(lua_tothread(L, -1));
} else if (lua_isnumber(L, -1)) { /* Return code */
if (lua_isnumber(L, -1)) { /* Return code */
status = lua_tonumber(L, -1);
} else if (lua_isthread(L, -1)) { /* Continuations */
status = l_ffi_defer(lua_tothread(L, -1));
}
lua_pop(L, 1);
return status;
......@@ -156,9 +148,8 @@ static int l_ffi_deinit(struct kr_module *module)
static int l_ffi_layer_begin(knot_layer_t *ctx, void *module_param)
{
ctx->data = module_param;
LAYER_FFI_CALL(ctx, begin);
lua_pushlightuserdata(L, module_param);
lua_pushlightuserdata(L, ctx->data);
return l_ffi_call(L, 2);
}
......@@ -175,7 +166,6 @@ static int l_ffi_layer_finish(knot_layer_t *ctx)
LAYER_FFI_CALL(ctx, finish);
lua_pushlightuserdata(L, req);
lua_pushlightuserdata(L, req->answer);
set_metatable(L, META_PKT);
return l_ffi_call(L, 3);
}
......@@ -187,7 +177,6 @@ static int l_ffi_layer_consume(knot_layer_t *ctx, knot_pkt_t *pkt)
LAYER_FFI_CALL(ctx, consume);
lua_pushlightuserdata(L, ctx->data);
lua_pushlightuserdata(L, pkt);
set_metatable(L, META_PKT);
return l_ffi_call(L, 3);
}
......@@ -199,7 +188,6 @@ static int l_ffi_layer_produce(knot_layer_t *ctx, knot_pkt_t *pkt)
LAYER_FFI_CALL(ctx, produce);
lua_pushlightuserdata(L, ctx->data);
lua_pushlightuserdata(L, pkt);
set_metatable(L, META_PKT);
return l_ffi_call(L, 3);
}
#undef LAYER_FFI_CALL
......
-- LuaJIT ffi bindings for libkres, a DNS resolver library.
-- @note Since it's statically compiled, it expects to find the symbols in the C namespace.
local ffi = require('ffi')
local bit = require('bit')
local csym = ffi.C
local knot = ffi.load('knot')
ffi.cdef[[
/*
* Record types and classes.
*/
struct rr_class {
static const int IN = 1;
static const int CH = 3;
static const int NONE = 254;
static const int ANY = 255;
};
struct rr_type {
static const int A = 1;
static const int NS = 2;
static const int CNAME = 5;
static const int SOA = 6;
static const int PTR = 12;
static const int HINFO = 13;
static const int MINFO = 14;
static const int MX = 15;
static const int TXT = 16;
static const int RP = 17;
static const int AFSDB = 18;
static const int RT = 21;
static const int SIG = 24;
static const int KEY = 25;
static const int AAAA = 28;
static const int LOC = 29;
static const int SRV = 33;
static const int NAPTR = 35;
static const int KX = 36;
static const int CERT = 37;
static const int DNAME = 39;
static const int OPT = 41;
static const int APL = 42;
static const int DS = 43;
static const int SSHFP = 44;
static const int IPSECKEY = 45;
static const int RRSIG = 46;
static const int NSEC = 47;
static const int DNSKEY = 48;
static const int DHCID = 49;
static const int NSEC3 = 50;
static const int NSEC3PARAM = 51;
static const int TLSA = 52;
static const int CDS = 59;
static const int CDNSKEY = 60;
static const int SPF = 99;
static const int NID = 104;
static const int L32 = 105;
static const int L64 = 106;
static const int LP = 107;
static const int EUI48 = 108;
static const int EUI64 = 109;
static const int TKEY = 249;
static const int TSIG = 250;
static const int IXFR = 251;
static const int AXFR = 252;
static const int ANY = 255;
};
struct pkt_section {
static const int ANSWER = 0;
static const int AUTHORITY = 1;
static const int ADDITIONAL = 2;
};
struct pkt_rcode {
static const int NOERROR = 0;
static const int FORMERR = 1;
static const int SERVFAIL = 2;
static const int NXDOMAIN = 3;
static const int NOTIMPL = 4;
static const int REFUSED = 5;
static const int YXDOMAIN = 6;
static const int YXRRSET = 7;
static const int NXRRSET = 8;
static const int NOTAUTH = 9;
static const int NOTZONE = 10;
static const int BADVERS = 16;
};
/*
* Data structures
*/
/* libknot */
typedef struct node {
struct node *next, *prev;
} node_t;
typedef uint8_t knot_dname_t;
typedef struct {
uint8_t *wire;
size_t size;
size_t max_size;
size_t parsed;
uint16_t reserved;
uint16_t qname_size;
uint16_t rrset_count;
uint16_t flags;
uint8_t _stub[]; /* Do not touch */
} knot_pkt_t;
/* libkres */
struct kr_query {
node_t _node;
struct kr_query *parent;
knot_dname_t *sname;
uint16_t type;
uint16_t class;
uint16_t id;
uint16_t flags;
unsigned secret;
uint8_t _stub[]; /* Do not touch */
};
struct kr_rplan {
uint8_t _stub[]; /* Do not touch */
};
struct kr_request {
struct kr_context *_ctx;
knot_pkt_t *answer;
uint32_t options;
int state;
uint8_t _stub[]; /* Do not touch */
};
/* libknot API
*/
/* Domain names */
/* Resource records */
/* Packet */
const knot_dname_t *knot_pkt_qname(const knot_pkt_t *pkt);
uint16_t knot_pkt_qtype(const knot_pkt_t *pkt);
uint16_t knot_pkt_qclass(const knot_pkt_t *pkt);
int knot_pkt_begin(knot_pkt_t *pkt, int section_id);
int knot_pkt_put_question(knot_pkt_t *pkt, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype);
/* libkres API
*/
/* Resolution request */
struct kr_rplan *kr_resolve_plan(struct kr_request *request);
/* Resolution plan */
struct kr_query *kr_rplan_current(struct kr_rplan *rplan);
/* Query */
/* Utils */
unsigned kr_rand_uint(unsigned max);
int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl,
uint16_t rclass, uint16_t rtype, const uint8_t *rdata, uint16_t rdlen);
]]
-- Metatype for packet
local knot_pkt_t = ffi.typeof('knot_pkt_t')
ffi.metatype( knot_pkt_t, {
__index = {
qname = function(pkt) return ffi.string(knot.knot_pkt_qname(pkt)) end,
qclass = function(pkt) return knot.knot_pkt_qclass(pkt) end,
qtype = function(pkt) return knot.knot_pkt_qtype(pkt) end,
rcode = function (pkt, val)
if val then
pkt.wire[3] = bit.bor(bit.band(pkt.wire[3], 0xf0), val)
end
return bit.band(pkt.wire[3], 0x0f)
end,
begin = function (pkt, section) return knot.knot_pkt_begin(pkt, section) end,
put = function (pkt, owner, ttl, rclass, rtype, rdata)
return csym.kr_pkt_put(pkt, owner, ttl, rclass, rtype, rdata, string.len(rdata))
end
},
})
-- Metatype for query
local kr_query_t = ffi.typeof('struct kr_query')
ffi.metatype( kr_query_t, {
__index = {
name = function(qry) return ffi.string(qry.sname) end,
},
})
-- Metatype for request
local kr_request_t = ffi.typeof('struct kr_request')
ffi.metatype( kr_request_t, {
__index = {
current = function(req)
assert(req)
return csym.kr_rplan_current(csym.kr_resolve_plan(req))
end,
},
})
-- Module API
local kres = {
-- Constants
class = ffi.new('struct rr_class'),
type = ffi.new('struct rr_type'),
section = ffi.new('struct pkt_section'),
rcode = ffi.new('struct pkt_rcode'),
NOOP = 0, CONSUME = 1, PRODUCE = 2, DONE = 4, FAIL = 8,
-- Metatypes
pkt_t = function (udata) return ffi.cast('knot_pkt_t *', udata) end,
request_t = function (udata) return ffi.cast('struct kr_request *', udata) end,
-- Global API functions
}
return kres
\ No newline at end of file
......@@ -28,7 +28,6 @@
#include "daemon/worker.h"
#include "daemon/engine.h"
#include "daemon/bindings.h"
#include "daemon/bindings/kres.h"
/*
* Globals
......@@ -137,7 +136,6 @@ static struct worker_ctx *init_worker(uv_loop_t *loop, struct engine *engine, mm
engine_lualib(engine, "net", lib_net);
engine_lualib(engine, "cache", lib_cache);
engine_lualib(engine, "event", lib_event);
engine_lualib(engine, "kres", lib_kres);
engine_lualib(engine, "worker", lib_worker);
/* Create main worker. */
......
......@@ -560,3 +560,11 @@ int kr_resolve_finish(struct kr_request *request, int state)
kr_rplan_deinit(&request->rplan);
return KNOT_STATE_DONE;
}
struct kr_rplan *kr_resolve_plan(struct kr_request *request)
{
if (request) {
return &request->rplan;
}
return NULL;
}
......@@ -125,11 +125,11 @@ struct kr_context
*/
struct kr_request {
struct kr_context *ctx;
struct kr_rplan rplan;
knot_pkt_t *answer;
mm_ctx_t pool;
uint32_t options;
int state;
struct kr_rplan rplan;
mm_ctx_t pool;
};
/**
......@@ -207,3 +207,11 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t
* @return DONE
*/
int kr_resolve_finish(struct kr_request *request, int state);
/**
* Return resolution plan.
* @param req request state
* @return pointer to rplan
*/
struct kr_rplan *kr_resolve_plan(struct kr_request *request);
......@@ -55,15 +55,15 @@ extern const lookup_table_t query_flag_names[];
struct kr_query {
node_t node;
struct kr_query *parent;
struct kr_nsrep ns;
struct kr_zonecut zone_cut;
struct timeval timestamp;
knot_dname_t *sname;
uint16_t stype;
uint16_t sclass;
uint16_t id;
uint16_t flags;
unsigned secret;
struct timeval timestamp;
struct kr_nsrep ns;
struct kr_zonecut zone_cut;
};
/**
......
......@@ -156,3 +156,20 @@ int mm_reserve(void *baton, char **mem, size_t elm_size, size_t want, size_t *ha
}
return -1;
}
int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl,
uint16_t rclass, uint16_t rtype, const uint8_t *rdata, uint16_t rdlen)
{
if (!pkt || !name) {
return kr_error(EINVAL);
}
/* Create empty RR */
knot_rrset_t rr;
knot_rrset_init(&rr, knot_dname_copy(name, &pkt->mm), rtype, rclass);
/* Create RDATA */
knot_rdata_t rdata_arr[knot_rdata_array_size(rdlen)];
knot_rdata_init(rdata_arr, rdlen, rdata, ttl);
knot_rdataset_add(&rr.rrs, rdata_arr, &pkt->mm);
/* Append RR */
return knot_pkt_put(pkt, 0, &rr, KNOT_PF_FREE);
}
......@@ -17,6 +17,7 @@
#pragma once
#include <stdio.h>
#include <libknot/packet/pkt.h>
/*
* General-purpose attributes.
......@@ -34,16 +35,6 @@ extern void _cleanup_fclose(FILE **p);
* Defines.
*/
/** @internal Fast packet reset. */
#define KR_PKT_RECYCLE(pkt) do { \
(pkt)->rrset_count = 0; \
(pkt)->size = KNOT_WIRE_HEADER_SIZE; \
(pkt)->current = KNOT_ANSWER; \
memset((pkt)->sections, 0, sizeof((pkt)->sections)); \
knot_pkt_begin((pkt), KNOT_ANSWER); \
knot_pkt_parse_question((pkt)); \
} while (0)
/** @internal Next RDATA shortcut. */
#define kr_rdataset_next(rd) (rd + knot_rdata_array_size(knot_rdata_rdlen(rd)))
......@@ -58,3 +49,17 @@ unsigned kr_rand_uint(unsigned max);
/** Memory reservation routine for mm_ctx_t */
int mm_reserve(void *baton, char **mem, size_t elm_size, size_t want, size_t *have);
/** @internal Fast packet reset. */
#define KR_PKT_RECYCLE(pkt) do { \
(pkt)->rrset_count = 0; \
(pkt)->size = KNOT_WIRE_HEADER_SIZE; \
(pkt)->current = KNOT_ANSWER; \
memset((pkt)->sections, 0, sizeof((pkt)->sections)); \
knot_pkt_begin((pkt), KNOT_ANSWER); \
knot_pkt_parse_question((pkt)); \
} while (0)
/** Construct and put record to packet. */
int kr_pkt_put(knot_pkt_t *pkt, const knot_dname_t *name, uint32_t ttl,
uint16_t rclass, uint16_t rtype, const uint8_t *rdata, uint16_t rdlen);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment