Commit 79a6348e authored by Marek Vavruša's avatar Marek Vavruša

pkt: switched to allocd rr/rrinfo fields to reduce memory footprint

this comes with some extra CPU cost, however:
- parsed packets are prealloc'd based on header information, so no
  reallocs
- constructed packets are alloc'd by steps
- packet construction / copy is  cheaper now
- doesn't matter when the mm backend is mempool anyway

the rationale for this change is the use in resolver and in smaller
installations
parent 48418c8c
......@@ -164,7 +164,7 @@ static int cmd_remote_reply(int c)
switch(ret) {
case KNOT_RCODE_NOERROR:
if (authority->count > 0) {
ret = cmd_remote_print_reply(&authority->rr[0]);
ret = cmd_remote_print_reply(knot_pkt_rr(authority, 0));
}
break;
case KNOT_RCODE_REFUSED:
......
......@@ -701,7 +701,7 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt)
}
const knot_pktsection_t *authority = knot_pkt_section(pkt, KNOT_AUTHORITY);
args.arg = authority->rr;
args.arg = knot_pkt_rr(authority, 0);
args.argc = authority->count;
args.rc = KNOT_RCODE_NOERROR;
......
......@@ -355,13 +355,13 @@ static int axfr_answer_packet(knot_pkt_t *pkt, struct xfr_proc *proc)
zcreator_t zc = {.z = proc->contents, .master = false, .ret = KNOT_EOK };
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
const knot_rrset_t *answer_rr = knot_pkt_rr(answer, 0);
for (uint16_t i = 0; i < answer->count; ++i) {
const knot_rrset_t *rr = &answer->rr[i];
if (rr->type == KNOT_RRTYPE_SOA &&
if (answer_rr[i].type == KNOT_RRTYPE_SOA &&
node_rrtype_exists(zc.z->apex, KNOT_RRTYPE_SOA)) {
return KNOT_NS_PROC_DONE;
} else {
int ret = zcreator_step(&zc, rr);
int ret = zcreator_step(&zc, &answer_rr[i]);
if (ret != KNOT_EOK) {
return KNOT_NS_PROC_FAIL;
}
......
......@@ -866,7 +866,8 @@ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data)
/* Expect SOA in answer section. */
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
if (answer->count < 1 || answer->rr[0].type != KNOT_RRTYPE_SOA) {
const knot_rrset_t *first_rr = knot_pkt_rr(answer, 0);
if (answer->count < 1 || first_rr->type != KNOT_RRTYPE_SOA) {
return KNOT_NS_PROC_FAIL;
}
......@@ -879,7 +880,7 @@ static int process_soa_answer(knot_pkt_t *pkt, struct answer_data *data)
/* Check if master has newer zone and schedule transfer. */
knot_rdataset_t *soa = node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA);
uint32_t our_serial = knot_soa_serial(soa);
uint32_t their_serial = knot_soa_serial(&answer->rr[0].rrs);
uint32_t their_serial = knot_soa_serial(&first_rr->rrs);
if (serial_compare(our_serial, their_serial) >= 0) {
ANSWER_LOG(LOG_INFO, data, "refresh, outgoing", "zone is up-to-date");
zone_events_cancel(zone, ZONE_EVENT_EXPIRE);
......
......@@ -197,7 +197,7 @@ static int ixfr_query_check(struct query_data *qdata)
NS_NEED_QTYPE(qdata, KNOT_RRTYPE_IXFR, KNOT_RCODE_FORMERR);
/* Need SOA authority record. */
const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
const knot_rrset_t *their_soa = &authority->rr[0];
const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
if (authority->count < 1 || their_soa->type != KNOT_RRTYPE_SOA) {
qdata->rcode = KNOT_RCODE_FORMERR;
return KNOT_NS_PROC_FAIL;
......@@ -241,7 +241,8 @@ static int ixfr_answer_init(struct query_data *qdata)
}
/* Compare serials. */
const knot_rrset_t *their_soa = &knot_pkt_section(qdata->query, KNOT_AUTHORITY)->rr[0];
const knot_pktsection_t *authority = knot_pkt_section(qdata->query, KNOT_AUTHORITY);
const knot_rrset_t *their_soa = knot_pkt_rr(authority, 0);
list_t chgsets;
init_list(&chgsets);
int ret = ixfr_load_chsets(&chgsets, (zone_t *)qdata->zone, their_soa);
......@@ -332,8 +333,8 @@ static bool ixfr_is_axfr(const knot_pkt_t *pkt)
{
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
return answer->count >= 2 &&
answer->rr[0].type == KNOT_RRTYPE_SOA &&
answer->rr[1].type != KNOT_RRTYPE_SOA;
knot_pkt_rr(answer, 0)->type == KNOT_RRTYPE_SOA &&
knot_pkt_rr(answer, 1)->type != KNOT_RRTYPE_SOA;
}
/*! \brief Cleans up data allocated by IXFR-in processing. */
......@@ -584,7 +585,7 @@ static int process_ixfrin_packet(knot_pkt_t *pkt, struct answer_data *adata)
return KNOT_NS_PROC_FAIL;
}
const knot_rrset_t *rr = &answer->rr[i];
const knot_rrset_t *rr = knot_pkt_rr(answer, i);
if (out_of_zone(rr, ixfr)) {
continue;
}
......@@ -674,7 +675,7 @@ static int check_format(knot_pkt_t *pkt)
{
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
if (answer->count >= 1 && answer->rr[0].type == KNOT_RRTYPE_SOA) {
if (answer->count >= 1 && knot_pkt_rr(answer, 0)->type == KNOT_RRTYPE_SOA) {
return KNOT_EOK;
} else {
return KNOT_EMALF;
......
......@@ -85,7 +85,7 @@ int notify_process_query(knot_pkt_t *pkt, struct query_data *qdata)
/* SOA RR in answer may be included, recover serial. */
const knot_pktsection_t *answer = knot_pkt_section(qdata->query, KNOT_ANSWER);
if (answer->count > 0) {
const knot_rrset_t *soa = &answer->rr[0];
const knot_rrset_t *soa = knot_pkt_rr(answer, 0);
if (soa->type == KNOT_RRTYPE_SOA) {
uint32_t serial = knot_soa_serial(&soa->rrs);
NOTIFY_QLOG(LOG_INFO, "received serial %u", serial);
......
......@@ -892,9 +892,10 @@ int ddns_process_prereqs(const knot_pkt_t *query, zone_update_t *update,
init_list(&rrset_list);
const knot_pktsection_t *answer = knot_pkt_section(query, KNOT_ANSWER);
const knot_rrset_t *answer_rr = knot_pkt_rr(answer, 0);
for (int i = 0; i < answer->count; ++i) {
// Check what can be checked, store full RRs into list
ret = process_prereq(&answer->rr[i], knot_pkt_qclass(query),
ret = process_prereq(&answer_rr[i], knot_pkt_qclass(query),
update, rcode, &rrset_list);
if (ret != KNOT_EOK) {
rrset_list_clear(&rrset_list);
......@@ -934,10 +935,10 @@ int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
// Process all RRs in the authority section.
int apex_ns_rem = 0;
const knot_pktsection_t *authority =
knot_pkt_section(query, KNOT_AUTHORITY);
const knot_pktsection_t *authority = knot_pkt_section(query, KNOT_AUTHORITY);
const knot_rrset_t *authority_rr = knot_pkt_rr(authority, 0);
for (uint16_t i = 0; i < authority->count; ++i) {
const knot_rrset_t *rr = &authority->rr[i];
const knot_rrset_t *rr = &authority_rr[i];
// Check if RR is correct.
int ret = check_update(rr, query, rcode);
if (ret != KNOT_EOK) {
......
......@@ -314,12 +314,17 @@ bool zone_transfer_needed(const zone_t *zone, const knot_pkt_t *pkt)
}
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
const knot_rrset_t soa = answer->rr[0];
if (soa.type != KNOT_RRTYPE_SOA) {
if (answer->count < 1) {
log_zone_warning(zone->name, "empty SOA response received, ignoring");
return false;
}
const knot_rrset_t *soa = knot_pkt_rr(answer, 0);
if (soa->type != KNOT_RRTYPE_SOA) {
return false;
}
return serial_compare(zone_contents_serial(zone->contents),
knot_soa_serial(&soa.rrs)) < 0;
knot_soa_serial(&soa->rrs)) < 0;
}
......@@ -27,6 +27,10 @@
#include "libknot/packet/rrset-wire.h"
#include "libknot/internal/macros.h"
/*! \brief Packet RR array growth step. */
#define NEXT_RR_ALIGN 16
#define NEXT_RR_COUNT(count) (((count) / NEXT_RR_ALIGN + 1) * NEXT_RR_ALIGN)
/*! \brief Scan packet for RRSet existence. */
static bool pkt_contains(const knot_pkt_t *packet,
const knot_rrset_t *rrset)
......@@ -124,6 +128,41 @@ static void pkt_rr_wirecount_add(knot_pkt_t *pkt, knot_section_t section_id,
}
}
/*! \brief Reserve enough space in the RR arrays. */
static int pkt_rr_array_alloc(knot_pkt_t *pkt, uint16_t count)
{
/* Enough space. */
if (pkt->rrset_allocd >= count) {
return KNOT_EOK;
}
/* Allocate rr_info and rr fields to next size. */
size_t next_size = NEXT_RR_COUNT(count);
knot_rrinfo_t *rr_info = mm_alloc(&pkt->mm, sizeof(knot_rrinfo_t) * next_size);
if (rr_info == NULL) {
return KNOT_ENOMEM;
}
knot_rrset_t *rr = mm_alloc(&pkt->mm, sizeof(knot_rrset_t) * next_size);
if (rr == NULL) {
mm_free(&pkt->mm, rr_info);
return KNOT_ENOMEM;
}
/* Copy the old data. */
memcpy(rr_info, pkt->rr_info, pkt->rrset_allocd * sizeof(knot_rrinfo_t));
memcpy(rr, pkt->rr, pkt->rrset_allocd * sizeof(knot_rrset_t));
/* Reassign and free old data. */
mm_free(&pkt->mm, pkt->rr);
mm_free(&pkt->mm, pkt->rr_info);
pkt->rr = rr;
pkt->rr_info = rr_info;
pkt->rrset_allocd = next_size;
return KNOT_EOK;
}
/*! \brief Clear the packet and switch wireformat pointers (possibly allocate new). */
static int pkt_reset(knot_pkt_t *pkt, void *wire, uint16_t len)
{
......@@ -131,14 +170,12 @@ static int pkt_reset(knot_pkt_t *pkt, void *wire, uint16_t len)
/* Free allocated data. */
pkt_free_data(pkt);
/* NULL everything up to 'sections' (not the large data fields). */
int ret = KNOT_EOK;
mm_ctx_t mm = pkt->mm;
memset(pkt, 0, offsetof(knot_pkt_t, rr_info));
memset(pkt, 0, sizeof(knot_pkt_t));
pkt->mm = mm;
/* Initialize wire. */
int ret = KNOT_EOK;
if (wire == NULL) {
ret = pkt_wire_alloc(pkt, len);
} else {
......@@ -185,9 +222,9 @@ static knot_pkt_t *pkt_new_mm(void *wire, uint16_t len, mm_ctx_t *mm)
if (pkt == NULL) {
return NULL;
}
memset(pkt, 0, sizeof(knot_pkt_t));
/* No data to free, set memory context. */
pkt->rrset_count = 0;
memcpy(&pkt->mm, mm, sizeof(mm_ctx_t));
if (pkt_reset(pkt, wire, len) != KNOT_EOK) {
mm_free(mm, pkt);
......@@ -233,6 +270,12 @@ int knot_pkt_copy(knot_pkt_t *dst, const knot_pkt_t *src)
}
}
/* Invalidate arrays . */
dst->rr = NULL;
dst->rr_info = NULL;
dst->rrset_count = 0;
dst->rrset_allocd = 0;
/* @note This could be done more effectively if needed. */
return knot_pkt_parse(dst, 0);
}
......@@ -291,6 +334,10 @@ void knot_pkt_free(knot_pkt_t **pkt)
/* Free temporary RRSets. */
pkt_free_data(*pkt);
/* Free RR/RR info arrays. */
mm_free(&(*pkt)->mm, (*pkt)->rr);
mm_free(&(*pkt)->mm, (*pkt)->rr_info);
// free the space for wireformat
if ((*pkt)->flags & KNOT_PF_FREE) {
(*pkt)->mm.free((*pkt)->wire);
......@@ -423,8 +470,9 @@ int knot_pkt_begin(knot_pkt_t *pkt, knot_section_t section_id)
pkt->current = section_id;
/* Remember watermark. */
pkt->sections[section_id].rr = pkt->rr + pkt->rrset_count;
pkt->sections[section_id].rrinfo = pkt->rr_info + pkt->rrset_count;
pkt->sections[section_id].pkt = pkt;
pkt->sections[section_id].pos = pkt->rrset_count;
return KNOT_EOK;
}
......@@ -474,12 +522,18 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
return KNOT_EINVAL;
}
/* Reserve memory for RR descriptors. */
int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
if (ret != KNOT_EOK) {
return ret;
}
knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count];
memset(rrinfo, 0, sizeof(knot_rrinfo_t));
rrinfo->pos = pkt->size;
rrinfo->flags = flags;
rrinfo->compress_ptr[0] = compr_hint;
pkt->rr[pkt->rrset_count] = *rr;
memcpy(pkt->rr + pkt->rrset_count, rr, sizeof(knot_rrset_t));
/* Check for double insertion. */
if ((flags & KNOT_PF_CHECKDUP) &&
......@@ -499,7 +553,7 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
compr.wire);
/* Write RRSet to wireformat. */
int ret = knot_rrset_to_wire(rr, pos, maxlen, &compr);
ret = knot_rrset_to_wire(rr, pos, maxlen, &compr);
if (ret < 0) {
/* Truncate packet if required. */
if (ret == KNOT_ESPACE && !(flags & KNOT_PF_NOTRUNC)) {
......@@ -537,6 +591,16 @@ const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
return &pkt->sections[section_id];
}
_public_
const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i)
{
if (section == NULL) {
return NULL;
}
return section->pkt->rr + section->pos + i;
}
_public_
int knot_pkt_parse(knot_pkt_t *pkt, unsigned flags)
{
......@@ -656,8 +720,13 @@ int knot_pkt_parse_rr(knot_pkt_t *pkt, unsigned flags)
return KNOT_EFEWDATA;
}
/* Reserve memory for RR descriptors. */
int ret = pkt_rr_array_alloc(pkt, pkt->rrset_count + 1);
if (ret != KNOT_EOK) {
return ret;
}
/* Initialize RR info. */
int ret = KNOT_EOK;
memset(&pkt->rr_info[pkt->rrset_count], 0, sizeof(knot_rrinfo_t));
pkt->rr_info[pkt->rrset_count].pos = pkt->parsed;
pkt->rr_info[pkt->rrset_count].flags = KNOT_PF_FREE;
......@@ -714,7 +783,14 @@ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags)
assert(pkt->wire != NULL);
assert(pkt->size > 0);
int ret = KNOT_ERROR;
/* Reserve memory in advance to avoid resizing. */
size_t rr_count = knot_wire_get_ancount(pkt->wire) +
knot_wire_get_nscount(pkt->wire) +
knot_wire_get_arcount(pkt->wire);
int ret = pkt_rr_array_alloc(pkt, rr_count);
if (ret != KNOT_EOK) {
return ret;
}
for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) {
ret = knot_pkt_begin(pkt, i);
......@@ -730,7 +806,8 @@ int knot_pkt_parse_payload(knot_pkt_t *pkt, unsigned flags)
/* TSIG must be last record of AR if present. */
const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
if (pkt->tsig_rr != NULL) {
if (ar->count > 0 && pkt->tsig_rr->rrs.data != ar->rr[ar->count - 1].rrs.data) {
const knot_rrset_t *last_rr = knot_pkt_rr(ar, ar->count - 1);
if (ar->count > 0 && pkt->tsig_rr->rrs.data != last_rr->rrs.data) {
return KNOT_EMALF;
}
}
......
......@@ -39,8 +39,8 @@
/* Number of packet sections (ANSWER, AUTHORITY, ADDITIONAL). */
#define KNOT_PKT_SECTIONS 3
/* Number of maximum RRs in packet. */
#define KNOT_PKT_MAX_RRS (KNOT_WIRE_MAX_PAYLOAD / KNOT_WIRE_RR_MIN_SIZE)
/* Forward decls */
struct knot_pkt;
/*!
* \brief DNS query types (internal use only).
......@@ -80,9 +80,9 @@ enum {
* This structure is required for random access to packet sections.
*/
typedef struct {
const knot_rrset_t *rr; /*!< Array of RRSets for this section. */
knot_rrinfo_t *rrinfo; /*!< Compression info for each RRSet. */
uint16_t count; /*!< Number of RRSets in this section. */
struct knot_pkt *pkt; /*!< Owner. */
uint16_t pos; /*!< Position in the rr/rrinfo fields in packet. */
uint16_t count; /*!< Number of RRSets in this section. */
} knot_pktsection_t;
/*!
......@@ -106,11 +106,10 @@ typedef struct knot_pkt {
knot_section_t current;
knot_pktsection_t sections[KNOT_PKT_SECTIONS];
/*! \note <== Memory below this point is not cleared on init for performance reasons. */
/* Packet RRSet (meta)data. */
knot_rrinfo_t rr_info[KNOT_PKT_MAX_RRS];
knot_rrset_t rr[KNOT_PKT_MAX_RRS];
size_t rrset_allocd;
knot_rrinfo_t *rr_info;
knot_rrset_t *rr;
mm_ctx_t mm; /*!< Memory allocation context. */
} knot_pkt_t;
......@@ -244,6 +243,8 @@ int knot_pkt_put(knot_pkt_t *pkt, uint16_t compr_hint, const knot_rrset_t *rr,
const knot_pktsection_t *knot_pkt_section(const knot_pkt_t *pkt,
knot_section_t section_id);
/*! \brief Get RRSet from the packet section. */
const knot_rrset_t *knot_pkt_rr(const knot_pktsection_t *section, uint16_t i);
/*
* Packet parsing API.
*/
......
......@@ -516,13 +516,13 @@ void print_data_xfr(const knot_pkt_t *packet,
switch (style->format) {
case FORMAT_DIG:
print_section_dig(answers->rr, answers->count, style);
print_section_dig(knot_pkt_rr(answers, 0), answers->count, style);
break;
case FORMAT_HOST:
print_section_host(answers->rr, answers->count, style);
print_section_host(knot_pkt_rr(answers, 0), answers->count, style);
break;
case FORMAT_FULL:
print_section_full(answers->rr, answers->count, style, true);
print_section_full(knot_pkt_rr(answers, 0), answers->count, style, true);
// Print TSIG record.
if (style->show_tsig && knot_pkt_has_tsig(packet)) {
......@@ -603,12 +603,12 @@ void print_packet(const knot_pkt_t *packet,
switch (style->format) {
case FORMAT_DIG:
if (ancount > 0) {
print_section_dig(answers->rr, ancount, style);
print_section_dig(knot_pkt_rr(answers, 0), ancount, style);
}
break;
case FORMAT_HOST:
if (ancount > 0) {
print_section_host(answers->rr, ancount, style);
print_section_host(knot_pkt_rr(answers, 0), ancount, style);
} else {
print_error_host(rcode, packet, style);
}
......@@ -624,17 +624,17 @@ void print_packet(const knot_pkt_t *packet,
if (style->show_answer && ancount > 0) {
printf("\n;; PREREQUISITE SECTION:\n");
print_section_full(answers->rr, ancount, style, true);
print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
}
if (style->show_authority && nscount > 0) {
printf("\n;; UPDATE SECTION:\n");
print_section_full(authority->rr, nscount, style, true);
print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
}
if (style->show_additional && arcount > 0) {
printf("\n;; ADDITIONAL DATA:\n");
print_section_full(additional->rr, arcount, style, true);
print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
}
break;
case FORMAT_FULL:
......@@ -648,17 +648,17 @@ void print_packet(const knot_pkt_t *packet,
if (style->show_answer && ancount > 0) {
printf("\n;; ANSWER SECTION:\n");
print_section_full(answers->rr, ancount, style, true);
print_section_full(knot_pkt_rr(answers, 0), ancount, style, true);
}
if (style->show_authority && nscount > 0) {
printf("\n;; AUTHORITY SECTION:\n");
print_section_full(authority->rr, nscount, style, true);
print_section_full(knot_pkt_rr(authority, 0), nscount, style, true);
}
if (style->show_additional && arcount > 0) {
printf("\n;; ADDITIONAL SECTION:\n");
print_section_full(additional->rr, arcount, style, true);
print_section_full(knot_pkt_rr(additional, 0), arcount, style, true);
}
break;
default:
......
......@@ -438,7 +438,7 @@ static int64_t first_serial_check(const knot_pkt_t *reply)
return -1;
}
const knot_rrset_t *first = &answer->rr[0];
const knot_rrset_t *first = knot_pkt_rr(answer, 0);
if (first->type != KNOT_RRTYPE_SOA) {
return -1;
......@@ -454,7 +454,7 @@ static bool last_serial_check(const uint32_t serial, const knot_pkt_t *reply)
return false;
}
const knot_rrset_t *last = &answer->rr[answer->count - 1];
const knot_rrset_t *last = knot_pkt_rr(answer, answer->count - 1);
if (last->type != KNOT_RRTYPE_SOA) {
return false;
......
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