Skip to content
Snippets Groups Projects
Commit 6632cf95 authored by Marek Vavrusa's avatar Marek Vavrusa
Browse files

UDP handler uses separate buffers for RX/TX, ported to new pkt API.

parent 222b2ff6
No related branches found
No related tags found
No related merge requests found
......@@ -45,13 +45,20 @@
#include "libknot/nameserver/name-server.h"
#include "knot/stat/stat.h"
#include "knot/server/server.h"
#include "libknot/util/wire.h"
#include "libknot/packet/wire.h"
#include "libknot/consts.h"
#include "libknot/packet/packet.h"
#include "libknot/packet/pkt.h"
#include "knot/server/zones.h"
#include "knot/server/notify.h"
#include "libknot/dnssec/cleanup.h"
/* Buffer identifiers. */
enum {
RX = 0,
TX = 1,
NBUFS = 2
};
/* FD_COPY macro compat. */
#ifndef FD_COPY
#define FD_COPY(src, dest) memcpy((dest), (src), sizeof(fd_set))
......@@ -103,7 +110,7 @@ struct answer_ctx
/*! \brief RRL reject procedure. */
static size_t udp_rrl_reject(const knot_nameserver_t *ns,
const knot_packet_t *packet,
const knot_pkt_t *packet,
uint8_t* resp, size_t rlen,
uint8_t rcode, unsigned *slip)
{
......@@ -128,15 +135,14 @@ static size_t udp_rrl_reject(const knot_nameserver_t *ns,
return 0; /* Discard response. */
}
int udp_handle(struct answer_ctx *ans, int fd,
uint8_t *qbuf, size_t qbuflen, size_t *resp_len,
sockaddr_t* addr)
int udp_handle(struct answer_ctx *ans, int fd, sockaddr_t *addr,
struct iovec *rx, struct iovec *tx)
{
#ifdef DEBUG_ENABLE_BRIEF
char strfrom[SOCKADDR_STRLEN];
memset(strfrom, 0, sizeof(strfrom));
sockaddr_tostr(addr, strfrom, sizeof(strfrom));
dbg_net("udp: received %zd bytes from '%s@%d'.\n", qbuflen,
dbg_net("udp: received %zd bytes from '%s@%d'.\n", rx->iov_len,
strfrom, sockaddr_portnum(addr));
#endif
......@@ -145,32 +151,32 @@ int udp_handle(struct answer_ctx *ans, int fd,
knot_nameserver_t *ns = ans->srv->nameserver;
rrl_table_t *rrl = ans->srv->rrl;
knot_packet_type_t qtype = KNOT_QUERY_INVALID;
*resp_len = SOCKET_MTU_SZ;
/* The packet MUST contain at least DNS header.
* If it doesn't, it's not a DNS packet and we should discard it.
*/
if (qbuflen < KNOT_WIRE_HEADER_SIZE) {
if (rx->iov_len < KNOT_WIRE_HEADER_SIZE) {
return KNOT_EFEWDATA;
}
#ifdef MIRROR_MODE
knot_wire_set_qr(qbuf);
*resp_len = qbuflen;
memcpy(tx->iov_base, rx->iov_base, rx->iov_len);
knot_wire_set_qr(tx->iov_base);
tx->iov_len = rx->iov_len;
return KNOT_EOK;
#endif
knot_packet_t *packet = knot_packet_new_mm(ans->mm);
if (packet == NULL) {
knot_pkt_t *query = knot_pkt_new(rx->iov_base, rx->iov_len, ans->mm);
if (query == NULL) {
dbg_net("udp: failed to create packet\n");
int ret = knot_ns_error_response_from_query_wire(ns, qbuf, qbuflen,
int ret = knot_ns_error_response_from_query_wire(ns, rx->iov_base, rx->iov_len,
KNOT_RCODE_SERVFAIL,
qbuf, resp_len);
tx->iov_base, &tx->iov_len);
return ret;
}
/* Parse query. */
rcode = knot_ns_parse_packet(qbuf, qbuflen, packet, &qtype);
rcode = knot_ns_parse_packet(query, &qtype);
if (rcode < KNOT_RCODE_NOERROR) {
dbg_net("udp: failed to parse packet\n");
rcode = KNOT_RCODE_SERVFAIL;
......@@ -179,30 +185,30 @@ int udp_handle(struct answer_ctx *ans, int fd,
/* Handle query. */
switch(qtype) {
case KNOT_QUERY_NORMAL:
res = zones_normal_query_answer(ns, packet, addr, qbuf,
resp_len, NS_TRANSPORT_UDP);
res = zones_normal_query_answer(ns, query, addr, tx->iov_base,
&tx->iov_len, NS_TRANSPORT_UDP);
break;
case KNOT_QUERY_AXFR:
/* RFC1034, p.28 requires reliable transfer protocol.
* Bind responds with FORMERR.
*/
res = knot_ns_error_response_from_query(ns, packet,
KNOT_RCODE_FORMERR, qbuf,
resp_len);
res = knot_ns_error_response_from_query(ns, query,
KNOT_RCODE_FORMERR, tx->iov_base,
&tx->iov_len);
break;
case KNOT_QUERY_IXFR:
/* According to RFC1035, respond with SOA. */
res = zones_normal_query_answer(ns, packet, addr,
qbuf, resp_len,
res = zones_normal_query_answer(ns, query, addr,
tx->iov_base, &tx->iov_len,
NS_TRANSPORT_UDP);
break;
case KNOT_QUERY_NOTIFY:
res = notify_process_request(ns, packet, addr,
qbuf, resp_len);
res = notify_process_request(ns, query, addr,
tx->iov_base, &tx->iov_len);
break;
case KNOT_QUERY_UPDATE:
res = zones_process_update(ns, packet, addr, qbuf, resp_len,
res = zones_process_update(ns, query, addr, tx->iov_base, &tx->iov_len,
fd, NS_TRANSPORT_UDP);
break;
......@@ -213,13 +219,13 @@ int udp_handle(struct answer_ctx *ans, int fd,
case KNOT_RESPONSE_NOTIFY:
case KNOT_RESPONSE_UPDATE:
res = KNOT_EOK;
*resp_len = 0;
tx->iov_len = 0;
break;
/* Unknown opcodes */
default:
res = knot_ns_error_response_from_query(ns, packet,
rcode, qbuf,
resp_len);
res = knot_ns_error_response_from_query(ns, query,
rcode, tx->iov_base,
&tx->iov_len);
break;
}
......@@ -227,22 +233,22 @@ int udp_handle(struct answer_ctx *ans, int fd,
if (knot_unlikely(rrl != NULL) && rrl->rate > 0) {
rrl_req_t rrl_rq;
memset(&rrl_rq, 0, sizeof(rrl_req_t));
rrl_rq.w = qbuf; /* Wire */
rrl_rq.query = packet;
rrl_rq.w = tx->iov_base; /* Wire */
rrl_rq.query = query;
rcu_read_lock();
rrl_rq.flags = packet->flags;
if (rrl_query(rrl, addr, &rrl_rq, packet->zone) != KNOT_EOK) {
*resp_len = udp_rrl_reject(ns, packet, qbuf,
SOCKET_MTU_SZ,
knot_wire_get_rcode(qbuf),
&ans->slip);
rrl_rq.flags = query->flags;
if (rrl_query(rrl, addr, &rrl_rq, query->zone) != KNOT_EOK) {
tx->iov_len = udp_rrl_reject(ns, query, tx->iov_base,
KNOT_WIRE_MAX_PKTSIZE,
knot_wire_get_rcode(query->wire),
&ans->slip);
}
rcu_read_unlock();
}
knot_packet_free(&packet);
knot_pkt_free(&query);
return res;
}
......@@ -267,26 +273,30 @@ static int (*_udp_send)(void *) = 0;
struct udp_recvfrom {
int fd;
sockaddr_t addr;
struct msghdr msg;
struct iovec iov;
uint8_t buf[SOCKET_MTU_SZ];
size_t buflen;
struct msghdr msg[NBUFS];
struct iovec iov[NBUFS];
uint8_t buf[NBUFS][KNOT_WIRE_MAX_PKTSIZE];
};
static void *udp_recvfrom_init(void)
{
struct udp_recvfrom *rq = malloc(sizeof(struct udp_recvfrom));
if (rq) {
sockaddr_prep(&rq->addr);
rq->buflen = SOCKET_MTU_SZ;
rq->iov.iov_base = rq->buf;
rq->iov.iov_len = rq->buflen;
rq->msg.msg_name = &rq->addr;
rq->msg.msg_namelen = rq->addr.len;
rq->msg.msg_iov = &rq->iov;
rq->msg.msg_iovlen = 1;
rq->msg.msg_control = NULL;
rq->msg.msg_controllen = 0;
if (rq == NULL) {
return NULL;
}
memset(rq->msg, 0, NBUFS * sizeof(struct msghdr));
memset(rq->iov, 0, NBUFS * sizeof(struct iovec));
sockaddr_prep(&rq->addr);
for (unsigned i = 0; i < NBUFS; ++i) {
rq->iov[i].iov_base = rq->buf + i;
rq->iov[i].iov_len = KNOT_WIRE_MAX_PKTSIZE;
rq->msg[i].msg_name = &rq->addr;
rq->msg[i].msg_namelen = rq->addr.len;
rq->msg[i].msg_iov = &rq->iov[i];
rq->msg[i].msg_iovlen = 1;
rq->msg[i].msg_control = NULL;
rq->msg[i].msg_controllen = 0;
}
return rq;
}
......@@ -301,10 +311,10 @@ static int udp_recvfrom_deinit(void *d)
static int udp_recvfrom_recv(int fd, void *d)
{
struct udp_recvfrom *rq = (struct udp_recvfrom *)d;
int ret = recvmsg(fd, &rq->msg, MSG_DONTWAIT);
int ret = recvmsg(fd, &rq->msg[RX], MSG_DONTWAIT);
if (ret > 0) {
rq->fd = fd;
rq->buflen = ret;
rq->iov[RX].iov_len = ret;
return 1;
}
......@@ -315,15 +325,20 @@ static int udp_recvfrom_handle(struct answer_ctx *ans, void *d)
{
struct udp_recvfrom *rq = (struct udp_recvfrom *)d;
/* Prepare TX address. */
rq->addr.len = rq->msg[RX].msg_namelen;
rq->msg[TX].msg_namelen = rq->addr.len;
rq->iov[TX].iov_len = KNOT_WIRE_MAX_PKTSIZE;
/* Process received pkt. */
rq->addr.len = rq->msg.msg_namelen;
int ret = udp_handle(ans, rq->fd,
rq->buf, rq->buflen, &rq->iov.iov_len,
&rq->addr);
int ret = udp_handle(ans, rq->fd, &rq->addr, &rq->iov[RX], &rq->iov[TX]);
if (ret != KNOT_EOK) {
rq->iov.iov_len = 0;
rq->iov[TX].iov_len = 0;
}
/* Reset RX buflen. */
rq->iov[RX].iov_len = KNOT_WIRE_MAX_PKTSIZE;
return ret;
}
......@@ -331,14 +346,14 @@ static int udp_recvfrom_send(void *d)
{
struct udp_recvfrom *rq = (struct udp_recvfrom *)d;
int rc = 0;
if (rq->iov.iov_len > 0) {
rc = sendmsg(rq->fd, &rq->msg, 0);
if (rq->iov[TX].iov_len > 0) {
rc = sendmsg(rq->fd, &rq->msg[TX], 0);
}
/* Reset buffer size and address len. */
rq->iov.iov_len = SOCKET_MTU_SZ;
/* Reset address lengths. */
sockaddr_prep(&rq->addr);
rq->msg.msg_namelen = rq->addr.len;
rq->msg[RX].msg_namelen = rq->addr.len;
rq->msg[TX].msg_namelen = rq->addr.len;
/* Return number of packets sent. */
if (rc > 1) {
......@@ -395,40 +410,44 @@ int udp_sendmmsg(int sock, sockaddr_t *_, struct mmsghdr *msgs, size_t count)
/* UDP recvmmsg() request struct. */
struct udp_recvmmsg {
int fd;
char *iobuf;
sockaddr_t *addrs;
struct iovec *iov;
struct mmsghdr *msgs;
char *iobuf[NBUFS];
struct iovec *iov[NBUFS];
struct mmsghdr *msgs[NBUFS];
unsigned rcvd;
mm_ctx_t mm;
};
static void *udp_recvmmsg_init(void)
{
struct udp_recvmmsg *rq = malloc(sizeof(struct udp_recvmmsg));
if (rq) {
rq->iobuf = malloc(SOCKET_MTU_SZ * RECVMMSG_BATCHLEN);
rq->addrs = malloc(sizeof(sockaddr_t) * RECVMMSG_BATCHLEN);
rq->iov = malloc(sizeof(struct iovec) * RECVMMSG_BATCHLEN);
rq->msgs = malloc(sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
if (!rq->iobuf || !rq->addrs || !rq->iov || !rq->msgs) {
free(rq->iobuf);
free(rq->addrs);
free(rq->iov);
free(rq->msgs);
free(rq);
return NULL;
}
memset(rq->msgs, 0, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
for (unsigned i = 0; i < RECVMMSG_BATCHLEN; ++i) {
sockaddr_prep(rq->addrs + i);
rq->iov[i].iov_base = rq->iobuf + i * SOCKET_MTU_SZ;
rq->iov[i].iov_len = SOCKET_MTU_SZ;
rq->msgs[i].msg_hdr.msg_iov = rq->iov + i;
rq->msgs[i].msg_hdr.msg_iovlen = 1;
rq->msgs[i].msg_hdr.msg_name = rq->addrs + i;
rq->msgs[i].msg_hdr.msg_namelen = rq->addrs[i].len;
mm_ctx_t mm;
mm_ctx_mempool(&mm, sizeof(struct udp_recvmmsg));
struct udp_recvmmsg *rq = mm.alloc(mm.ctx, sizeof(struct udp_recvmmsg));
memcpy(&rq->mm, &mm, sizeof(mm_ctx_t));
/* Initialize addresses. */
rq->addrs = mm.alloc(mm.ctx, sizeof(sockaddr_t) * RECVMMSG_BATCHLEN);
for (unsigned i = 0; i < RECVMMSG_BATCHLEN; ++i) {
sockaddr_prep(rq->addrs + i);
}
/* Initialize buffers. */
for (unsigned i = 0; i < NBUFS; ++i) {
rq->iobuf[i] = mm.alloc(mm.ctx, KNOT_WIRE_MAX_PKTSIZE * RECVMMSG_BATCHLEN);
rq->iov[i] = mm.alloc(mm.ctx, sizeof(struct iovec) * RECVMMSG_BATCHLEN);
rq->msgs[i] = mm.alloc(mm.ctx, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
memset(rq->msgs[i], 0, sizeof(struct mmsghdr) * RECVMMSG_BATCHLEN);
for (unsigned k = 0; k < RECVMMSG_BATCHLEN; ++k) {
rq->iov[i][k].iov_base = rq->iobuf[i] + k * KNOT_WIRE_MAX_PKTSIZE;
rq->iov[i][k].iov_len = KNOT_WIRE_MAX_PKTSIZE;
rq->msgs[i][k].msg_hdr.msg_iov = rq->iov[i] + k;
rq->msgs[i][k].msg_hdr.msg_iovlen = 1;
rq->msgs[i][k].msg_hdr.msg_name = rq->addrs + k;
rq->msgs[i][k].msg_hdr.msg_namelen = rq->addrs[k].len;
}
}
return rq;
}
......@@ -436,19 +455,16 @@ static int udp_recvmmsg_deinit(void *d)
{
struct udp_recvmmsg *rq = (struct udp_recvmmsg *)d;
if (rq) {
free(rq->iobuf);
free(rq->addrs);
free(rq->iov);
free(rq->msgs);
free(rq);
mp_delete(rq->mm.ctx);
}
return 0;
}
static int udp_recvmmsg_recv(int fd, void *d)
{
struct udp_recvmmsg *rq = (struct udp_recvmmsg *)d;
int n = recvmmsg(fd, rq->msgs, RECVMMSG_BATCHLEN, MSG_DONTWAIT, NULL);
int n = recvmmsg(fd, rq->msgs[RX], RECVMMSG_BATCHLEN, MSG_DONTWAIT, NULL);
if (n > 0) {
rq->fd = fd;
rq->rcvd = n;
......@@ -463,31 +479,37 @@ static int udp_recvmmsg_handle(struct answer_ctx *st, void *d)
/* Handle each received msg. */
int ret = 0;
for (unsigned i = 0; i < rq->rcvd; ++i) {
struct iovec *cvec = rq->msgs[i].msg_hdr.msg_iov;
size_t rlen = 0;
rq->addrs[i].len = rq->msgs[i].msg_hdr.msg_namelen;
ret = udp_handle(st, rq->fd, cvec->iov_base,
rq->msgs[i].msg_len, &rlen,
rq->addrs + i);
struct iovec *rx = rq->msgs[RX][i].msg_hdr.msg_iov;
struct iovec *tx = rq->msgs[TX][i].msg_hdr.msg_iov;
rx->iov_len = rq->msgs[RX][i].msg_len; /* Received bytes. */
rq->addrs[i].len = rq->msgs[RX][i].msg_hdr.msg_namelen;
ret = udp_handle(st, rq->fd, rq->addrs + i, rx, tx);
if (ret != KNOT_EOK) { /* Do not send. */
rlen = 0;
tx->iov_len = 0;
}
cvec->iov_len = rlen;
rq->msgs[TX][i].msg_len = tx->iov_len;
rq->msgs[TX][i].msg_hdr.msg_namelen = rq->addrs[i].len;
}
return KNOT_EOK;
}
static int udp_recvmmsg_send(void *d)
{
struct udp_recvmmsg *rq = (struct udp_recvmmsg *)d;
int rc = _send_mmsg(rq->fd, rq->addrs, rq->msgs, rq->rcvd);
int rc = _send_mmsg(rq->fd, rq->addrs, rq->msgs[TX], rq->rcvd);
for (unsigned i = 0; i < rq->rcvd; ++i) {
/* Reset buffer size and address len. */
struct iovec *cvec = rq->msgs[i].msg_hdr.msg_iov;
cvec->iov_len = SOCKET_MTU_SZ;
struct iovec *rx = rq->msgs[RX][i].msg_hdr.msg_iov;
struct iovec *tx = rq->msgs[TX][i].msg_hdr.msg_iov;
rx->iov_len = KNOT_WIRE_MAX_PKTSIZE; /* Reset RX buflen */
tx->iov_len = KNOT_WIRE_MAX_PKTSIZE;
sockaddr_prep(rq->addrs + i);
rq->msgs[i].msg_hdr.msg_namelen = rq->addrs[i].len;
rq->msgs[RX][i].msg_hdr.msg_namelen = rq->addrs[i].len;
rq->msgs[TX][i].msg_hdr.msg_namelen = rq->addrs[i].len;
}
return rc;
}
......@@ -539,11 +561,8 @@ int udp_reader(iohandler_t *h, dthread_t *thread)
ifacelist_t *ref = NULL;
/* Create memory pool context. */
struct mempool *pool = mp_new(64 * 1024);
mm_ctx_t mm;
mm.ctx = pool;
mm.alloc = (mm_alloc_t)mp_alloc;
mm.free = mm_nofree;
mm_ctx_mempool(&mm, 2 * sizeof(knot_pkt_t));
/* Create UDP answering context. */
struct answer_ctx ans_ctx;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment