Commit acd8d14d authored by Marek Vavruša's avatar Marek Vavruša

processing: split layer/process APIs

layer - implements FSM on prepared packets
process - implements FSM on raw wire (uses layer)
parent 07a07983
......@@ -176,6 +176,8 @@ libknot_la_SOURCES = \
libknot/packet/wire.h \
libknot/processing/process.c \
libknot/processing/process.h \
libknot/processing/layer.c \
libknot/processing/layer.h \
libknot/processing/overlay.c \
libknot/processing/overlay.h \
libknot/processing/requestor.c \
......
......@@ -19,21 +19,27 @@
#include "knot/server/udp-handler.h"
/* State-less packet capture, only incoming data is accepted. */
static int reset(knot_process_t *ctx) { return NS_PROC_MORE; }
static int finish(knot_process_t *ctx) { return NS_PROC_NOOP; }
static int reset(knot_layer_t *ctx) { return NS_PROC_FULL; }
static int finish(knot_layer_t *ctx) { return NS_PROC_NOOP; }
/* Set capture parameters (sink). */
static int begin(knot_process_t *ctx, void *module_param)
static int begin(knot_layer_t *ctx, void *module_param)
{
ctx->data = module_param;
return reset(ctx);
}
static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
{
/* \note Don't touch the query, expect answer. */
return NS_PROC_MORE;
}
/* Forward packet. */
static int capture(knot_pkt_t *pkt, knot_process_t *ctx)
static int capture(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
struct process_capture_param *param = ctx->data;
struct capture_param *param = ctx->data;
/* Copy packet contents and free. */
knot_pkt_copy(param->sink, pkt);
......@@ -43,16 +49,16 @@ static int capture(knot_pkt_t *pkt, knot_process_t *ctx)
}
/*! \brief Module implementation. */
static const knot_process_module_t PROCESS_CAPTURE_MODULE = {
static const knot_layer_api_t CAPTURE_LAYER = {
&begin,
&reset,
&finish,
&capture,
&knot_process_noop, /* No output. */
&knot_process_noop /* No error processing. */
&prepare_query,
NULL
};
const knot_process_module_t *proc_capture_get_module(void)
const knot_layer_api_t *capture_get_module(void)
{
return &PROCESS_CAPTURE_MODULE;
return &CAPTURE_LAYER;
}
......@@ -30,14 +30,14 @@
#include "libknot/packet/pkt.h"
/* Processing module implementation. */
const knot_process_module_t *proc_capture_get_module(void);
#define NS_PROC_CAPTURE proc_capture_get_module()
#define NS_PROC_CAPTURE_ID 3
const knot_layer_api_t *capture_get_module(void);
#define LAYER_CAPTURE capture_get_module()
#define LAYER_CAPTURE_ID 3
/*!
* \brief Processing module parameters.
*/
struct process_capture_param {
struct capture_param {
knot_pkt_t *sink; /*!< Container for captured response. */
};
......
......@@ -23,7 +23,7 @@
/*! \brief Accessor to query-specific data. */
#define ANSWER_DATA(ctx) ((struct answer_data *)(ctx)->data)
static void answer_data_init(knot_process_t *ctx, void *module_param)
static void answer_data_init(knot_layer_t *ctx, void *module_param)
{
/* Initialize persistent data. */
struct answer_data *data = ANSWER_DATA(ctx);
......@@ -42,7 +42,7 @@ static bool is_answer_to_query(const knot_pkt_t *query, knot_pkt_t *answer)
return knot_wire_get_id(query->wire) == knot_wire_get_id(answer->wire);
}
static int process_answer_begin(knot_process_t *ctx, void *module_param)
static int process_answer_begin(knot_layer_t *ctx, void *module_param)
{
/* Initialize context. */
assert(ctx);
......@@ -52,11 +52,11 @@ static int process_answer_begin(knot_process_t *ctx, void *module_param)
/* Initialize persistent data. */
answer_data_init(ctx, module_param);
/* Await packet. */
return NS_PROC_MORE;
/* Issue the query. */
return NS_PROC_FULL;
}
static int process_answer_reset(knot_process_t *ctx)
static int process_answer_reset(knot_layer_t *ctx)
{
assert(ctx);
struct answer_data *data = ANSWER_DATA(ctx);
......@@ -72,11 +72,11 @@ static int process_answer_reset(knot_process_t *ctx)
/* Initialize persistent data. */
answer_data_init(ctx, module_param);
/* Await packet. */
return NS_PROC_MORE;
/* Issue the query. */
return NS_PROC_FULL;
}
static int process_answer_finish(knot_process_t *ctx)
static int process_answer_finish(knot_layer_t *ctx)
{
process_answer_reset(ctx);
mm_free(ctx->mm, ctx->data);
......@@ -92,7 +92,7 @@ static int process_answer_finish(knot_process_t *ctx)
return ret; \
}
static int process_answer(knot_pkt_t *pkt, knot_process_t *ctx)
static int process_answer(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
struct answer_data *data = ANSWER_DATA(ctx);
......@@ -143,19 +143,24 @@ static int process_answer(knot_pkt_t *pkt, knot_process_t *ctx)
return next_state;
}
static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
{
/* \note Don't touch the query, expect answer. */
return NS_PROC_MORE;
}
#undef ANSWER_REQUIRES
/*! \brief Module implementation. */
static const knot_process_module_t PROCESS_ANSWER_MODULE = {
static const knot_layer_api_t PROCESS_ANSWER_MODULE = {
&process_answer_begin,
&process_answer_reset,
&process_answer_finish,
&process_answer,
&knot_process_noop, /* No output. */
&knot_process_noop /* No error processing. */
&prepare_query,
&knot_layer_noop
};
const knot_process_module_t *process_answer_get_module(void)
const knot_layer_api_t *process_answer_get_module(void)
{
return &PROCESS_ANSWER_MODULE;
}
......@@ -30,7 +30,7 @@
#include "knot/nameserver/tsig_ctx.h"
/* Answer processing module implementation. */
const knot_process_module_t *process_answer_get_module(void);
const knot_layer_api_t *process_answer_get_module(void);
#define NS_PROC_ANSWER process_answer_get_module()
#define NS_PROC_ANSWER_ID 2
......
......@@ -21,7 +21,7 @@
#define QUERY_DATA(ctx) ((struct query_data *)(ctx)->data)
/*! \brief Reinitialize query data structure. */
static void query_data_init(knot_process_t *ctx, void *module_param)
static void query_data_init(knot_layer_t *ctx, void *module_param)
{
/* Initialize persistent data. */
struct query_data *data = QUERY_DATA(ctx);
......@@ -34,7 +34,7 @@ static void query_data_init(knot_process_t *ctx, void *module_param)
init_list(&data->rrsigs);
}
static int process_query_begin(knot_process_t *ctx, void *module_param)
static int process_query_begin(knot_layer_t *ctx, void *module_param)
{
/* Initialize context. */
assert(ctx);
......@@ -48,7 +48,7 @@ static int process_query_begin(knot_process_t *ctx, void *module_param)
return NS_PROC_MORE;
}
static int process_query_reset(knot_process_t *ctx)
static int process_query_reset(knot_layer_t *ctx)
{
assert(ctx);
struct query_data *qdata = QUERY_DATA(ctx);
......@@ -72,7 +72,7 @@ static int process_query_reset(knot_process_t *ctx)
return NS_PROC_MORE;
}
static int process_query_finish(knot_process_t *ctx)
static int process_query_finish(knot_layer_t *ctx)
{
process_query_reset(ctx);
mm_free(ctx->mm, ctx->data);
......@@ -81,7 +81,7 @@ static int process_query_finish(knot_process_t *ctx)
return NS_PROC_NOOP;
}
static int process_query_in(knot_pkt_t *pkt, knot_process_t *ctx)
static int process_query_in(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
struct query_data *qdata = QUERY_DATA(ctx);
......@@ -109,7 +109,7 @@ static int process_query_in(knot_pkt_t *pkt, knot_process_t *ctx)
/*!
* \brief Create a response for a given query in the INTERNET class.
*/
static int query_internet(knot_pkt_t *pkt, knot_process_t *ctx)
static int query_internet(knot_pkt_t *pkt, knot_layer_t *ctx)
{
struct query_data *data = QUERY_DATA(ctx);
int next_state = NS_PROC_FAIL;
......@@ -144,7 +144,7 @@ static int query_internet(knot_pkt_t *pkt, knot_process_t *ctx)
/*!
* \brief Create a response for a given query in the CHAOS class.
*/
static int query_chaos(knot_pkt_t *pkt, knot_process_t *ctx)
static int query_chaos(knot_pkt_t *pkt, knot_layer_t *ctx)
{
dbg_ns("%s(%p, %p)\n", __func__, pkt, ctx);
struct query_data *data = QUERY_DATA(ctx);
......@@ -350,7 +350,7 @@ static void qname_case_restore(struct query_data *qdata, knot_pkt_t *pkt)
}
/*! \brief Initialize response, sizes and find zone from which we're going to answer. */
static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, knot_process_t *ctx)
static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, knot_layer_t *ctx)
{
struct query_data *qdata = QUERY_DATA(ctx);
server_t *server = qdata->param->server;
......@@ -405,7 +405,7 @@ static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, knot_proces
return ret;
}
static int process_query_err(knot_pkt_t *pkt, knot_process_t *ctx)
static int process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
struct query_data *qdata = QUERY_DATA(ctx);
......@@ -442,7 +442,7 @@ static int process_query_err(knot_pkt_t *pkt, knot_process_t *ctx)
/*!
* \brief Apply rate limit.
*/
static int ratelimit_apply(int state, knot_pkt_t *pkt, knot_process_t *ctx)
static int ratelimit_apply(int state, knot_pkt_t *pkt, knot_layer_t *ctx)
{
/* Check if rate limiting applies. */
struct query_data *qdata = QUERY_DATA(ctx);
......@@ -466,7 +466,7 @@ static int ratelimit_apply(int state, knot_pkt_t *pkt, knot_process_t *ctx)
/* Now it is slip or drop. */
if (rrl_slip_roll(conf()->rrl_slip)) {
/* Answer slips. */
if (process_query_err(pkt, ctx) != KNOT_EOK) {
if (process_query_err(ctx, pkt) != KNOT_EOK) {
return NS_PROC_FAIL;
}
knot_wire_set_tc(pkt->wire);
......@@ -478,7 +478,7 @@ static int ratelimit_apply(int state, knot_pkt_t *pkt, knot_process_t *ctx)
return NS_PROC_DONE;
}
static int process_query_out(knot_pkt_t *pkt, knot_process_t *ctx)
static int process_query_out(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
struct query_data *qdata = QUERY_DATA(ctx);
......@@ -664,7 +664,7 @@ int process_query_verify(struct query_data *qdata)
}
/*! \brief Module implementation. */
static const knot_process_module_t PROCESS_QUERY_MODULE = {
static const knot_layer_api_t PROCESS_QUERY_MODULE = {
&process_query_begin,
&process_query_reset,
&process_query_finish,
......@@ -673,7 +673,7 @@ static const knot_process_module_t PROCESS_QUERY_MODULE = {
&process_query_err
};
const knot_process_module_t *process_query_get_module(void)
const knot_layer_api_t *process_query_get_module(void)
{
return &PROCESS_QUERY_MODULE;
}
......@@ -31,7 +31,7 @@
#include "knot/updates/acl.h"
/* Query processing module implementation. */
const knot_process_module_t *process_query_get_module(void);
const knot_layer_api_t *process_query_get_module(void);
#define NS_PROC_QUERY process_query_get_module()
#define NS_PROC_QUERY_ID 1
......
......@@ -99,7 +99,7 @@ static int sign_update(zone_t *zone, const zone_contents_t *old_contents,
return KNOT_EOK;
}
static int check_prereqs(struct knot_request_data *request,
static int check_prereqs(struct knot_request *request,
const zone_t *zone, zone_update_t *update,
struct query_data *qdata)
{
......@@ -116,7 +116,7 @@ static int check_prereqs(struct knot_request_data *request,
return KNOT_EOK;
}
static int process_single_update(struct knot_request_data *request,
static int process_single_update(struct knot_request *request,
const zone_t *zone, zone_update_t *update,
struct query_data *qdata)
{
......@@ -137,7 +137,7 @@ static int process_single_update(struct knot_request_data *request,
static void set_rcodes(list_t *requests, const uint16_t rcode)
{
struct knot_request_data *req;
struct knot_request *req;
WALK_LIST(req, *requests) {
if (knot_wire_get_rcode(req->resp->wire) == KNOT_RCODE_NOERROR) {
knot_wire_set_rcode(req->resp->wire, rcode);
......@@ -152,7 +152,7 @@ static int process_bulk(zone_t *zone, list_t *requests, changeset_t *ddns_ch)
zone_update_init(&zone_update, zone->contents, ddns_ch);
// Walk all the requests and process.
struct knot_request_data *req;
struct knot_request *req;
WALK_LIST(req, *requests) {
// Init qdata structure for logging (unique per-request).
struct process_query_param param = { 0 };
......@@ -310,11 +310,11 @@ static int process_requests(zone_t *zone, list_t *requests)
return KNOT_EOK;
}
static int forward_request(zone_t *zone, struct knot_request_data *request)
static int forward_request(zone_t *zone, struct knot_request *request)
{
/* Create requestor instance. */
struct knot_requestor re;
knot_requestor_init(&re, NS_PROC_CAPTURE, NULL);
knot_requestor_init(&re, NULL);
/* Fetch primary master. */
const conf_iface_t *master = zone_master(zone);
......@@ -333,17 +333,19 @@ static int forward_request(zone_t *zone, struct knot_request_data *request)
/* Create a request. */
const struct sockaddr *dst = (const struct sockaddr *)&master->addr;
const struct sockaddr *src = (const struct sockaddr *)&master->via;
struct knot_request *req = knot_requestor_make(&re, dst, src, query, 0);
struct knot_request *req = knot_request_make(re.mm, dst, src, query, 0);
if (req == NULL) {
knot_pkt_free(&query);
return KNOT_ENOMEM;
}
/* Enqueue and execute request. */
struct process_capture_param param;
/* Prepare packet capture layer. */
struct capture_param param;
param.sink = request->resp;
ret = knot_requestor_enqueue(&re, req, &param);
knot_requestor_overlay(&re, LAYER_CAPTURE, &param);
/* Enqueue and execute request. */
ret = knot_requestor_enqueue(&re, req);
if (ret == KNOT_EOK) {
struct timeval tv = { conf()->max_conn_reply, 0 };
ret = knot_requestor_exec(&re, &tv);
......@@ -371,7 +373,7 @@ static int forward_request(zone_t *zone, struct knot_request_data *request)
static void forward_requests(zone_t *zone, list_t *requests)
{
struct knot_request_data *req;
struct knot_request *req;
WALK_LIST(req, *requests) {
forward_request(zone, req);
}
......@@ -379,14 +381,8 @@ static void forward_requests(zone_t *zone, list_t *requests)
static int init_update_respones(list_t *updates)
{
struct knot_request_data *r = NULL;
struct knot_request *r = NULL;
WALK_LIST(r, *updates) {
r->resp = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
if (r->resp == NULL) {
return KNOT_ENOMEM;
}
assert(r->query);
knot_pkt_init_response(r->resp, r->query);
}
......@@ -395,7 +391,7 @@ static int init_update_respones(list_t *updates)
static void send_update_responses(list_t *updates)
{
struct knot_request_data *r, *nxt;
struct knot_request *r, *nxt;
WALK_LIST_DELSAFE(r, nxt, *updates) {
if (r->resp) {
if (net_is_connected(r->fd)) {
......@@ -406,10 +402,7 @@ static void send_update_responses(list_t *updates)
}
}
close(r->fd);
knot_pkt_free(&r->query);
knot_pkt_free(&r->resp);
free(r);
knot_request_free(NULL, r);
}
}
......
......@@ -44,7 +44,7 @@
/*! \brief TCP context data. */
typedef struct tcp_context {
knot_process_t query_ctx; /*!< Query processing context. */
knot_layer_t query_ctx; /*!< Query processing context. */
server_t *server; /*!< Name server structure. */
struct iovec iov[2]; /*!< TX/RX buffers. */
unsigned client_threshold; /*!< Index of first TCP client. */
......@@ -134,7 +134,7 @@ static int tcp_handle(tcp_context_t *tcp, int fd,
}
/* Create query processing context. */
knot_process_begin(&tcp->query_ctx, &param, NS_PROC_QUERY);
knot_process_begin(&tcp->query_ctx, NS_PROC_QUERY, &param);
/* Input packet. */
int state = knot_process_in(&tcp->query_ctx, rx->iov_base, rx->iov_len);
......
......@@ -57,7 +57,7 @@ enum {
/*! \brief UDP context data. */
typedef struct udp_context {
knot_process_t query_ctx; /*!< Query processing context. */
knot_layer_t query_ctx; /*!< Query processing context. */
server_t *server; /*!< Name server structure. */
unsigned thread_id; /*!< Thread identifier. */
} udp_context_t;
......@@ -133,7 +133,7 @@ void udp_handle(udp_context_t *udp, int fd, struct sockaddr_storage *ss,
}
/* Create query processing context. */
knot_process_begin(&udp->query_ctx, &param, NS_PROC_QUERY);
knot_process_begin(&udp->query_ctx, NS_PROC_QUERY, &param);
/* Input packet. */
int state = knot_process_in(&udp->query_ctx, rx->iov_base, rx->iov_len);
......
......@@ -123,15 +123,17 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
return KNOT_ENOMEM;
}
/* Create requestor instance. */
struct knot_requestor re;
knot_requestor_init(&re, NS_PROC_ANSWER, &mm);
/* Answer processing parameters. */
struct process_answer_param param = { 0 };
param.zone = zone;
param.query = query;
param.remote = &remote->addr;
/* Create requestor instance. */
struct knot_requestor re;
knot_requestor_init(&re, &mm);
knot_requestor_overlay(&re, NS_PROC_ANSWER, &param);
tsig_init(&param.tsig_ctx, remote->key);
ret = tsig_sign_packet(&param.tsig_ctx, query);
......@@ -142,14 +144,14 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
/* Create a request. */
const struct sockaddr *dst = (const struct sockaddr *)&remote->addr;
const struct sockaddr *src = (const struct sockaddr *)&remote->via;
struct knot_request *req = knot_requestor_make(&re, dst, src, query, 0);
struct knot_request *req = knot_request_make(re.mm, dst, src, query, 0);
if (req == NULL) {
ret = KNOT_ENOMEM;
goto fail;
}
/* Send the queries and process responses. */
ret = knot_requestor_enqueue(&re, req, &param);
ret = knot_requestor_enqueue(&re, req);
if (ret == KNOT_EOK) {
struct timeval tv = { conf()->max_conn_reply, 0 };
ret = knot_requestor_exec(&re, &tv);
......@@ -630,7 +632,7 @@ static void replan_flush(zone_t *zone, const zone_t *old_zone)
/*!< \brief Creates new DDNS q in the new zone - q contains references from the old zone. */
static void duplicate_ddns_q(zone_t *zone, zone_t *old_zone)
{
struct knot_request_data *d, *nxt;
struct knot_request *d, *nxt;
WALK_LIST_DELSAFE(d, nxt, old_zone->ddns_queue) {
add_tail(&zone->ddns_queue, (node_t *)d);
}
......
/* Copyright (C) 2014 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/>.
*/
#include <assert.h>
#include "libknot/processing/layer.h"
#include "common/debug.h"
/*! \brief Helper for conditional layer call. */
#define LAYER_CALL(layer, func, ...) \
if (layer->api->func) { \
layer->state = layer->api->func(layer, ##__VA_ARGS__); \
}
/* State -> string translation table. */
#ifdef KNOT_NS_DEBUG
#define LAYER_STATE_STR(x) _state_table[x]
static const char* _state_table[] = {
[NS_PROC_NOOP] = "NOOP",
[NS_PROC_MORE] = "MORE",
[NS_PROC_FULL] = "FULL",
[NS_PROC_DONE] = "DONE",
[NS_PROC_FAIL] = "FAIL"
};
#endif /* KNOT_NS_DEBUG */
int knot_layer_begin(knot_layer_t *ctx, const knot_layer_api_t *api, void *param)
{
/* Only in inoperable state. */
if (ctx->state != NS_PROC_NOOP) {
return ctx->state;
}
ctx->api = api;
LAYER_CALL(ctx, begin, param);
dbg_ns("%s -> %s\n", __func__, LAYER_STATE_STR(ctx->state));
return ctx->state;
}
int knot_layer_reset(knot_layer_t *ctx)
{
LAYER_CALL(ctx, reset);
dbg_ns("%s -> %s\n", __func__, LAYER_STATE_STR(ctx->state));
return ctx->state;
}
int knot_layer_finish(knot_layer_t *ctx)
{
/* Only in operable state. */
if (ctx->state == NS_PROC_NOOP) {
return ctx->state;
}
LAYER_CALL(ctx, finish);
dbg_ns("%s -> %s\n", __func__, LAYER_STATE_STR(ctx->state));
return ctx->state;
}
int knot_layer_in(knot_layer_t *ctx, knot_pkt_t *pkt)
{
/* Only if expecting data. */
if (ctx->state != NS_PROC_MORE) {
return ctx->state;
}
LAYER_CALL(ctx, in, pkt);
dbg_ns("%s -> %s\n", __func__, LAYER_STATE_STR(ctx->state));
return ctx->state;
}
int knot_layer_out(knot_layer_t *ctx, knot_pkt_t *pkt)
{
switch (ctx->state) {
case NS_PROC_FULL: LAYER_CALL(ctx, out, pkt); break;
case NS_PROC_FAIL: LAYER_CALL(ctx, err, pkt); break;
default:
break;
}
dbg_ns("%s -> %s\n", __func__, LAYER_STATE_STR(ctx->state));
return ctx->state;
}
#undef LAYER_STATE_STR
/* Copyright (C) 2014 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/>.
*/
/*!
* \file process.h
*
* \author Marek Vavrusa <marek.vavrusa@nic.cz>
*
* \addtogroup query_processing
* @{
*/
#pragma once
#include <stdint.h>
#include "libknot/mempattern.h"
#include "libknot/consts.h"
#include "libknot/rrtype/tsig.h"
#include "libknot/packet/pkt.h"
#include "common/lists.h"
/*! \brief Main packet processing states.
* Each state describes the current machine processing step
* and determines readiness for next action.
*/
enum knot_layer_state {
NS_PROC_NOOP = 0, /* N/A */
NS_PROC_MORE = 1 << 0, /* More input data. */
NS_PROC_FULL = 1 << 1, /* Has output data. */
NS_PROC_DONE = 1 << 2, /* Finished. */
NS_PROC_FAIL = 1 << 3 /* Error. */
};
/* Forward declarations. */
struct knot_layer_api;
/*! \brief Packet processing context. */
typedef struct knot_layer
{
node_t node;
uint16_t state; /* Bitmap of enum knot_layer_state. */
uint16_t type; /* Module identifier. */
mm_ctx_t *mm; /* Processing memory context. */
/* Module specific. */
void *data;
const struct knot_layer_api *api;
} knot_layer_t;
/*! \brief Packet processing module API. */
typedef struct knot_layer_api {
int (*begin)(knot_layer_t *ctx, void *module_param);
int (*reset)(knot_layer_t *ctx);
int (*finish)(knot_layer_t *ctx);
int (*in)(knot_layer_t *ctx, knot_pkt_t *pkt);
int (*out)(knot_layer_t *ctx, knot_pkt_t *pkt);
int (*err)(knot_layer_t *ctx, knot_pkt_t *pkt);
} knot_layer_api_t;
/*!
* \brief Universal noop process function.
*/
inline static int knot_layer_noop(knot_layer_t *ctx, knot_pkt_t *pkt)
{
return NS_PROC_NOOP;
}
/*!
* \brief Initialize packet processing context.
*
* Allowed from states: NOOP
*
* \param ctx Layer context.
* \param param Parameters for given module.
* \param api Layer API.
* \return (module specific state)
*/
int knot_layer_begin(knot_layer_t *ctx, const knot_layer_api_t *api, void *param);
/*!
* \brief Reset current packet processing context.
* \param ctx Layer context.
* \return (module specific state)
*/
int knot_layer_reset(knot_layer_t *ctx);
/*!
* \brief Finish and close packet processing context.
*
* Allowed from states: MORE, FULL, DONE, FAIL
*
* \param ctx Layer context.
* \return (module specific state)
*/
int knot_layer_finish(knot_layer_t *ctx);
/*!
* \brief Add more data to layer processing.
*
* Allowed from states: MORE
*
* \param ctx Layer context.
* \param pkt Data packet.
*
* \return (module specific state)
*/
int knot_layer_in(knot_layer_t *ctx, knot_pkt_t *pkt);