From 9294cbfefa014dee0ac303cfd13a429e603d6ac2 Mon Sep 17 00:00:00 2001
From: Jan Kadlec <jan.kadlec@nic.cz>
Date: Wed, 2 Apr 2014 16:42:11 +0200
Subject: [PATCH] new_node: Remove more RRSet functions, doxygen.

- knot_rrset_create_rr removed, only way to insert RR into rrset now is
  when you already have RDATA, so that we never create RRSet that is not
sorted.
- rr.h doxygenated, functions moved around a bit.
---
 src/knot/ctl/remote.c           |  16 +-
 src/knot/dnssec/nsec-chain.c    |  12 +-
 src/knot/dnssec/nsec3-chain.c   |  11 +-
 src/knot/nameserver/chaos.c     |  13 +-
 src/knot/nameserver/internet.c  |  11 +-
 src/knot/updates/ddns.c         |   2 +-
 src/knot/zone/node.c            |   2 +-
 src/knot/zone/semantic-check.c  |   8 +-
 src/libknot/dnssec/rrset-sign.c | 143 +++++-------
 src/libknot/dnssec/sig0.c       |  11 +-
 src/libknot/rr.c                | 393 +++++++++++++++-----------------
 src/libknot/rr.h                | 205 +++++++++++++++--
 src/libknot/rrset.c             |  63 ++---
 src/libknot/rrset.h             |  21 --
 src/libknot/tsig.c              |  11 +-
 15 files changed, 498 insertions(+), 424 deletions(-)

diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 0ac9285a2c..00e93783d2 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -797,24 +797,26 @@ int remote_create_txt(knot_rrset_t *rr, const char *v, size_t v_len)
 	/* Number of chunks. */
 	const size_t K = 255;
 	unsigned chunks = v_len / K + 1;
-	uint8_t *raw = knot_rrset_create_rr(rr, v_len + chunks, 0, NULL);
+	uint8_t raw[v_len + chunks];
+	memset(raw, 0, v_len + chunks);
 
 	/* Write TXT item. */
 	unsigned p = 0;
+	size_t off = 0;
 	if (v_len > K) {
 		for (; p + K < v_len; p += K) {
-			*(raw++) = (uint8_t)K;
-			memcpy(raw, v+p, K);
-			raw += K;
+			raw[off++] = (uint8_t)K;
+			memcpy(raw + off, v + p, K);
+			off += K;
 		}
 	}
 	unsigned r = v_len - p;
 	if (r > 0) {
-		*(raw++) = (uint8_t)r;
-		memcpy(raw, v+p, r);
+		raw[off++] = (uint8_t)r;
+		memcpy(raw + off, v + p, r);
 	}
 
-	return KNOT_EOK;
+	return knot_rrset_add_rr(rr, raw, v_len + chunks, 0, NULL);
 }
 
 int remote_create_ns(knot_rrset_t *rr, const char *d)
diff --git a/src/knot/dnssec/nsec-chain.c b/src/knot/dnssec/nsec-chain.c
index 46cdd87fc0..0634abce09 100644
--- a/src/knot/dnssec/nsec-chain.c
+++ b/src/knot/dnssec/nsec-chain.c
@@ -64,16 +64,18 @@ static knot_rrset_t *create_nsec_rrset(const knot_node_t *from,
 	assert(to->owner);
 	size_t next_owner_size = knot_dname_size(to->owner);
 	size_t rdata_size = next_owner_size + bitmap_size(&rr_types);
-	uint8_t *rdata = knot_rrset_create_rr(rrset, rdata_size, ttl, NULL);
-	if (!rdata) {
-		knot_rrset_free(&rrset, NULL);
-		return NULL;
-	}
+	uint8_t rdata[rdata_size];
 
 	// Fill RDATA
 	memcpy(rdata, to->owner, next_owner_size);
 	bitmap_write(&rr_types, rdata + next_owner_size);
 
+	int ret = knot_rrset_add_rr(rrset, rdata, rdata_size, ttl, NULL);
+	if (ret != KNOT_EOK) {
+		knot_rrset_free(&rrset, NULL);
+		return NULL;
+	}
+
 	return rrset;
 }
 
diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c
index 789bf79028..d5ea8f18b6 100644
--- a/src/knot/dnssec/nsec3-chain.c
+++ b/src/knot/dnssec/nsec3-chain.c
@@ -57,7 +57,7 @@ inline static bool valid_nsec3_node(const knot_node_t *node)
 		return false;
 	}
 
-	if (knot_rrs_rr_count(nsec3) != 1) {
+	if (nsec3->rr_count != 1) {
 		return false;
 	}
 
@@ -262,15 +262,10 @@ static int create_nsec3_rrset(knot_rrset_t *rrset,
 	knot_rrset_init(rrset, owner, KNOT_RRTYPE_NSEC3, KNOT_CLASS_IN);
 
 	size_t rdata_size = nsec3_rdata_size(params, rr_types);
-	uint8_t *rdata = knot_rrset_create_rr(rrset, rdata_size, ttl, NULL);
-	if (!rdata) {
-		knot_rrset_clear(rrset, NULL);
-		return KNOT_ENOMEM;
-	}
-
+	uint8_t rdata[rdata_size];
 	nsec3_fill_rdata(rdata, params, rr_types, next_hashed, ttl);
 
-	return KNOT_EOK;
+	return knot_rrset_add_rr(rrset, rdata, rdata_size, ttl, NULL);
 }
 
 /*!
diff --git a/src/knot/nameserver/chaos.c b/src/knot/nameserver/chaos.c
index a550069bff..0a3cd2b526 100644
--- a/src/knot/nameserver/chaos.c
+++ b/src/knot/nameserver/chaos.c
@@ -69,16 +69,17 @@ static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner,
 	}
 
 	knot_rrset_init(rrset, rowner, KNOT_RRTYPE_TXT, KNOT_CLASS_CH);
-	uint8_t *rdata = knot_rrset_create_rr(rrset, response_len + 1, 0, mm);
-	if (!rdata) {
-		knot_dname_free(&rrset->owner, mm);
-		knot_rrs_clear(&rrset->rrs, mm);
-		return KNOT_ENOMEM;
-	}
+	uint8_t rdata[response_len + 1];
 
 	rdata[0] = response_len;
 	memcpy(&rdata[1], response, response_len);
 
+	int ret = knot_rrset_add_rr(rrset, rdata, response_len + 1, 0, mm);
+	if (ret != KNOT_EOK) {
+		knot_dname_free(&rrset->owner, mm);
+		return ret;
+	}
+
 	return KNOT_EOK;
 }
 
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
index 1af5da97b7..157f7e2f45 100644
--- a/src/knot/nameserver/internet.c
+++ b/src/knot/nameserver/internet.c
@@ -81,17 +81,12 @@ static int dname_cname_synth(const knot_rrset_t *dname_rr,
 
 	/* Store DNAME into RDATA. */
 	int cname_size = knot_dname_size(cname);
-	uint8_t *cname_rdata = knot_rrset_create_rr(cname_rrset, cname_size,
-	                                            knot_rrset_rr_ttl(dname_rr, 0),
-	                                            mm);
-	if (cname_rdata == NULL) {
-		knot_dname_free(&cname, NULL);
-		return KNOT_ENOMEM;
-	}
+	uint8_t cname_rdata[cname_size];
 	memcpy(cname_rdata, cname, cname_size);
 	knot_dname_free(&cname, NULL);
 
-	return KNOT_EOK;
+	return knot_rrset_add_rr(cname_rrset, cname_rdata, cname_size,
+	                         knot_rrset_rr_ttl(dname_rr, 0), mm);
 }
 
 /*!
diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
index 83b17264df..dcf3348a00 100644
--- a/src/knot/updates/ddns.c
+++ b/src/knot/updates/ddns.c
@@ -685,7 +685,7 @@ static int process_rem_rr(const knot_rrset_t *rr,
 	                     type == KNOT_RRTYPE_NS;
 	if (apex_ns) {
 		const knot_rrs_t *ns_rrs = knot_node_rrs(node, KNOT_RRTYPE_NS);
-		if (*apex_ns_rem == knot_rrs_rr_count(ns_rrs) - 1) {
+		if (*apex_ns_rem == ns_rrs->rr_count - 1) {
 			// Cannot remove last apex NS RR
 			return KNOT_EOK;
 		}
diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c
index fd669c3ac9..ca91dbcfa6 100644
--- a/src/knot/zone/node.c
+++ b/src/knot/zone/node.c
@@ -656,7 +656,7 @@ bool knot_node_rrtype_is_signed(const knot_node_t *node, uint16_t type)
 		return false;
 	}
 
-	uint16_t rrsigs_rdata_count = knot_rrs_rr_count(rrsigs);
+	uint16_t rrsigs_rdata_count = rrsigs->rr_count;
 	for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) {
 		const uint16_t type_covered =
 			knot_rrs_rrsig_type_covered(rrsigs, i);
diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c
index 79a6c84728..7ecad72b89 100644
--- a/src/knot/zone/semantic-check.c
+++ b/src/knot/zone/semantic-check.c
@@ -511,7 +511,7 @@ static int check_rrsig_in_rrset(err_handler_t *handler,
 		                         info_str);
 	}
 
-	for (uint16_t i = 0; i < knot_rrs_rr_count(&rrsigs); ++i) {
+	for (uint16_t i = 0; i < (&rrsigs)->rr_count; ++i) {
 		int ret = check_rrsig_rdata(handler, node, &rrsigs, i, rrset,
 		                            dnskey_rrset);
 		if (ret != KNOT_EOK) {
@@ -772,7 +772,7 @@ static int sem_check_node_mandatory(const knot_node_t *node,
 			}
 		}
 
-		if (knot_rrs_rr_count(cname_rrs) != 1) {
+		if (cname_rrs->rr_count != 1) {
 			*fatal_error = true;
 			err_handler_handle_error(handler, node,
 			                         ZC_ERR_CNAME_MULTIPLE, NULL);
@@ -822,7 +822,7 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone,
 		return KNOT_EOK;
 	}
 
-	for (int i = 0; i < knot_rrs_rr_count(ns_rrs); ++i) {
+	for (int i = 0; i < ns_rrs->rr_count; ++i) {
 		const knot_dname_t *ns_dname =
 			knot_rrs_ns_name(ns_rrs, i);
 		const knot_node_t *glue_node =
@@ -982,7 +982,7 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone,
 			}
 			free(array);
 			/* Test that only one record is in the NSEC RRSet */
-			if (knot_rrs_rr_count(nsec_rrs) != 1) {
+			if (nsec_rrs->rr_count != 1) {
 				err_handler_handle_error(handler,
 				                         node,
 				                         ZC_ERR_NSEC_RDATA_MULTIPLE,
diff --git a/src/libknot/dnssec/rrset-sign.c b/src/libknot/dnssec/rrset-sign.c
index 4163009ec2..8c0ecc244c 100644
--- a/src/libknot/dnssec/rrset-sign.c
+++ b/src/libknot/dnssec/rrset-sign.c
@@ -100,62 +100,6 @@ int knot_rrsig_write_rdata(uint8_t *rdata, const knot_dnssec_key_t *key,
 	return KNOT_EOK;
 }
 
-/*- Creating of RRSIGs from covered RRs -------------------------------------*/
-
-/*!
- * \brief Create RRSIG RDATA (all fields except signature are filled).
- *
- * \param[in]  rrsigs        RR set with RRSIGS.
- * \param[in]  covered       RR covered by the signature.
- * \param[in]  key           Key used for signing.
- * \param[in]  sig_incepted  Timestamp of signature inception.
- * \param[in]  sig_expires   Timestamp of signature expiration.
- * \param[out] rdata         Created RDATA.
- * \param[out] rdata_size    Size of created RDATA.
- *
- * \return Error code, KNOT_EOK if succesful.
- */
-static int rrsigs_create_rdata(knot_rrset_t *rrsigs,
-                               const knot_rrset_t *covered,
-                               const knot_dnssec_key_t *key,
-                               uint32_t sig_incepted, uint32_t sig_expires,
-                               uint8_t **rdata, size_t *rdata_size)
-{
-	assert(rrsigs);
-	assert(rrsigs->type == KNOT_RRTYPE_RRSIG);
-	assert(!knot_rrset_empty(covered));
-	assert(key);
-	assert(rdata);
-	assert(rdata_size);
-
-	size_t size = knot_rrsig_rdata_size(key);
-	assert(size != 0);
-
-	uint8_t *result = knot_rrset_create_rr(rrsigs, size,
-	                                       knot_rrset_rr_ttl(covered, 0),
-	                                       NULL);
-	if (!result) {
-		return KNOT_ENOMEM;
-	}
-
-	uint8_t owner_labels = knot_dname_labels(covered->owner, NULL);
-	if (knot_dname_is_wildcard(covered->owner)) {
-		owner_labels -= 1;
-	}
-
-	int res = knot_rrsig_write_rdata(result, key, covered->type, owner_labels,
-	                                 knot_rrset_rr_ttl(covered, 0),
-	                                 sig_incepted, sig_expires);
-
-	assert(res == KNOT_EOK);
-	UNUSED(res);
-
-	*rdata = result;
-	*rdata_size = size;
-
-	return KNOT_EOK;
-}
-
 /*- Computation of signatures ------------------------------------------------*/
 
 /*!
@@ -242,6 +186,67 @@ static int sign_ctx_add_data(knot_dnssec_sign_context_t *ctx,
 	return sign_ctx_add_records(ctx, covered);
 }
 
+/*!
+ * \brief Create RRSIG RDATA (all fields except signature are filled).
+ *
+ * \param[in]  rrsigs        RR set with RRSIGS.
+ * \param[in]  rrsigs        DNSSEC signing context.
+ * \param[in]  covered       RR covered by the signature.
+ * \param[in]  key           Key used for signing.
+ * \param[in]  sig_incepted  Timestamp of signature inception.
+ * \param[in]  sig_expires   Timestamp of signature expiration.
+ *
+ * \return Error code, KNOT_EOK if succesful.
+ */
+static int rrsigs_create_rdata(knot_rrset_t *rrsigs,
+                               knot_dnssec_sign_context_t *context,
+                               const knot_rrset_t *covered,
+                               const knot_dnssec_key_t *key,
+                               uint32_t sig_incepted, uint32_t sig_expires)
+{
+	assert(rrsigs);
+	assert(rrsigs->type == KNOT_RRTYPE_RRSIG);
+	assert(!knot_rrset_empty(covered));
+	assert(key);
+
+	size_t size = knot_rrsig_rdata_size(key);
+	assert(size != 0);
+
+	uint8_t owner_labels = knot_dname_labels(covered->owner, NULL);
+	if (knot_dname_is_wildcard(covered->owner)) {
+		owner_labels -= 1;
+	}
+
+	uint8_t result[size];
+	int res = knot_rrsig_write_rdata(result, key, covered->type, owner_labels,
+	                                 knot_rrset_rr_ttl(covered, 0),
+	                                 sig_incepted, sig_expires);
+	assert(res == KNOT_EOK);
+
+	res = knot_dnssec_sign_new(context);
+	if (res != KNOT_EOK) {
+		return res;
+	}
+
+	res = sign_ctx_add_data(context, result, covered);
+	if (res != KNOT_EOK) {
+		return res;
+	}
+
+	const size_t signature_offset = RRSIG_RDATA_SIGNER_OFFSET + knot_dname_size(key->name);
+	uint8_t *signature = result + signature_offset;
+	const size_t signature_size = size - signature_offset;
+
+	res = knot_dnssec_sign_write(context, signature, signature_size);
+	if (res != KNOT_EOK) {
+		return res;
+	}
+
+
+	return knot_rrset_add_rr(rrsigs, result, size,
+	                         knot_rrset_rr_ttl(covered, 0), NULL);
+}
+
 /*!
  * \brief Create RRSIG RR for given RR set.
  */
@@ -260,30 +265,8 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered,
 	uint32_t sig_incept = policy->now;
 	uint32_t sig_expire = sig_incept + policy->sign_lifetime;
 
-	uint8_t *rdata = NULL;
-	size_t rdata_size = 0;
-
-	int result = rrsigs_create_rdata(rrsigs, covered, key, sig_incept,
-	                                 sig_expire, &rdata, &rdata_size);
-	if (result != KNOT_EOK) {
-		return result;
-	}
-
-	result = knot_dnssec_sign_new(sign_ctx);
-	if (result != KNOT_EOK) {
-		return result;
-	}
-
-	result = sign_ctx_add_data(sign_ctx, rdata, covered);
-	if (result != KNOT_EOK) {
-		return result;
-	}
-
-	size_t signature_offset = RRSIG_RDATA_SIGNER_OFFSET + knot_dname_size(key->name);
-	uint8_t *signature = rdata + signature_offset;
-	size_t signature_size = rdata_size - signature_offset;
-
-	return knot_dnssec_sign_write(sign_ctx, signature, signature_size);
+	return rrsigs_create_rdata(rrsigs, sign_ctx, covered, key, sig_incept,
+	                           sig_expire);
 }
 
 /*- Verification of signatures -----------------------------------------------*/
diff --git a/src/libknot/dnssec/sig0.c b/src/libknot/dnssec/sig0.c
index ff4de0d1dc..03b43ced8b 100644
--- a/src/libknot/dnssec/sig0.c
+++ b/src/libknot/dnssec/sig0.c
@@ -71,15 +71,14 @@ static uint8_t *sig0_create_rdata(knot_rrset_t *rrset, knot_dnssec_key_t *key)
 	assert(key);
 
 	size_t rdata_size = knot_rrsig_rdata_size(key);
-	uint32_t ttl = 0;
-	uint8_t *rdata = knot_rrset_create_rr(rrset, rdata_size, ttl, NULL);
-	if (!rdata) {
+	const uint32_t ttl = 0;
+	uint8_t rdata[rdata_size];
+	sig0_write_rdata(rdata, key);
+	if (knot_rrset_add_rr(rrset, rdata, rdata_size, ttl, NULL) != KNOT_EOK) {
 		return NULL;
 	}
 
-	sig0_write_rdata(rdata, key);
-
-	return rdata;
+	return knot_rrset_rr_rdata(rrset, 0);
 }
 
 /*!
diff --git a/src/libknot/rr.c b/src/libknot/rr.c
index aa2f7f3d1e..962e47b74c 100644
--- a/src/libknot/rr.c
+++ b/src/libknot/rr.c
@@ -7,38 +7,9 @@
 #include "libknot/common.h"
 #include "common/errcode.h"
 
+/*!< \brief RR metadata size. */
 static const size_t RR_META_SIZE = sizeof(uint16_t) + sizeof(uint32_t);
 
-uint16_t knot_rr_size(const knot_rr_t *rr)
-{
-	return *((uint16_t *)rr);
-}
-
-uint32_t knot_rr_ttl(const knot_rr_t *rr)
-{
-	return *((uint32_t *)(rr + sizeof(uint16_t)));
-}
-
-const uint8_t *knot_rr_rdata(const knot_rr_t *rr)
-{
-	return (const uint8_t *)(rr + RR_META_SIZE);
-}
-
-uint8_t *knot_rr_get_rdata(knot_rr_t *rr)
-{
-	return rr + RR_META_SIZE;
-}
-
-void knot_rr_set_size(knot_rr_t *rr, uint16_t size)
-{
-	*((uint16_t *)rr) = size;
-}
-
-void knot_rr_set_ttl(knot_rr_t *rr, uint32_t ttl)
-{
-	*((uint32_t *)(rr + sizeof(uint16_t))) = ttl;
-}
-
 static knot_rr_t *rr_seek(knot_rr_t *d, size_t pos)
 {
 	if (d == NULL) {
@@ -54,25 +25,7 @@ static knot_rr_t *rr_seek(knot_rr_t *d, size_t pos)
 	return d + offset;
 }
 
-knot_rr_t *knot_rrs_get_rr(const knot_rrs_t *rrs, size_t pos)
-{
-	if (rrs == NULL || pos >= rrs->rr_count) {
-		return NULL;
-	}
-
-	return rr_seek(rrs->data, pos);
-}
-
-const knot_rr_t *knot_rrs_rr(const knot_rrs_t *rrs, size_t pos)
-{
-	if (rrs == NULL || pos >= rrs->rr_count) {
-		return NULL;
-	}
-
-	return (const knot_rr_t *)rr_seek(rrs->data, pos);
-}
-
-size_t knot_rrs_size(const knot_rrs_t *rrs)
+static size_t knot_rrs_size(const knot_rrs_t *rrs)
 {
 	if (rrs == NULL) {
 		return 0;
@@ -88,99 +41,13 @@ size_t knot_rrs_size(const knot_rrs_t *rrs)
 	return total_size;
 }
 
-uint16_t knot_rrs_rr_count(const knot_rrs_t *rrs)
-{
-	if (rrs == NULL) {
-		return 0;
-	}
-	
-	return rrs->rr_count;
-}
-
-int knot_rrs_remove_rr_at_pos(knot_rrs_t *rrs, size_t pos, mm_ctx_t *mm)
-{
-	if (rrs == NULL || pos >= rrs->rr_count) {
-		return KNOT_EINVAL;
-	}
-
-	knot_rr_t *old_rr = knot_rrs_get_rr(rrs, pos);
-	knot_rr_t *last_rr = knot_rrs_get_rr(rrs, rrs->rr_count - 1);
-	assert(old_rr);
-	assert(last_rr);
-
-	size_t total_size = knot_rrs_size(rrs);
-	uint16_t old_size = knot_rr_size(old_rr);
-
-	void *old_threshold = old_rr + old_size + RR_META_SIZE;
-	void *last_threshold = last_rr + knot_rr_size(last_rr) + RR_META_SIZE;
-	// Move RDATA
-	memmove(old_rr, old_threshold,
-	        last_threshold - old_threshold);
-
-	if (rrs->rr_count > 1) {
-		// Realloc RDATA
-		void *tmp = mm_realloc(mm, rrs->data,
-		                       total_size - (old_size + RR_META_SIZE),
-		                       total_size);
-		if (tmp == NULL) {
-			ERR_ALLOC_FAILED;
-			return KNOT_ENOMEM;
-		} else {
-			rrs->data = tmp;
-		}
-	} else {
-		// Free RDATA
-		mm_free(mm, rrs->data);
-		rrs->data = NULL;
-	}
-	rrs->rr_count--;
-
-	return KNOT_EOK;
-}
-
-const uint8_t *knot_rrs_rr_rdata(const knot_rrs_t *rrs, size_t pos)
-{
-	if (rrs == NULL || pos >= rrs->rr_count) {
-		return NULL;
-	}
-	
-	return knot_rr_rdata(knot_rrs_rr(rrs, pos));
-}
-
-uint8_t *knot_rrs_rr_get_rdata(const knot_rrs_t *rrs, size_t pos)
-{
-	return (uint8_t *)knot_rrs_rr_rdata(rrs, pos);
-}
-
-uint16_t knot_rrs_rr_size(const knot_rrs_t *rrs, size_t pos)
-{
-	if (rrs == NULL || pos >= rrs->rr_count) {
-		return 0;
-	}
-	
-	return knot_rr_size(knot_rrs_rr(rrs, pos));
-}
-
-uint32_t knot_rrs_rr_ttl(const knot_rrs_t *rrs, size_t pos)
-{
-	if (rrs == NULL || pos >= rrs->rr_count) {
-		return 0;
-	}
-	
-	return knot_rr_ttl(knot_rrs_rr(rrs, pos));
-}
-
-uint8_t* knot_rrs_create_rr_at_pos(knot_rrs_t *rrs,
-                                   size_t pos, uint16_t size,
-                                   uint32_t ttl, mm_ctx_t *mm)
+static uint8_t* knot_rrs_create_rr_at_pos(knot_rrs_t *rrs,
+                                          size_t pos, uint16_t size,
+                                          uint32_t ttl, mm_ctx_t *mm)
 {
 	if (rrs == NULL || pos > rrs->rr_count) {
 		return NULL;
 	}
-	if (pos == rrs->rr_count) {
-		// Normal RDATA addition
-		return knot_rrs_create_rr(rrs, size, ttl, mm);
-	}
 
 	size_t total_size = knot_rrs_size(rrs);
 
@@ -195,10 +62,29 @@ uint8_t* knot_rrs_create_rr_at_pos(knot_rrs_t *rrs,
 		return NULL;
 	}
 
-	knot_rr_t *old_rr = knot_rrs_get_rr(rrs, pos);
+	// Solve corner cases: first RR
+	if (rrs->rr_count == 0) {
+		rrs->rr_count++;
+		assert(pos == 0);
+		knot_rr_t *new_rr = knot_rrs_get_rr(rrs, pos);
+		knot_rr_set_size(new_rr, size);
+		knot_rr_set_ttl(new_rr, ttl);
+		return knot_rr_get_rdata(new_rr);
+	}
+
 	knot_rr_t *last_rr = knot_rrs_get_rr(rrs, rrs->rr_count - 1);
-	assert(old_rr);
 	assert(last_rr);
+	// Last RR
+	if (pos == rrs->rr_count) {
+		rrs->rr_count++;
+		knot_rr_t *new_rr = knot_rrs_get_rr(rrs, pos);
+		knot_rr_set_size(new_rr, size);
+		knot_rr_set_ttl(new_rr, ttl);
+		return knot_rr_get_rdata(new_rr);
+	}
+
+	knot_rr_t *old_rr = knot_rrs_get_rr(rrs, pos);
+	assert(old_rr);
 
 	// Make space for new data by moving the array
 	memmove(old_rr + size + RR_META_SIZE, old_rr,
@@ -213,8 +99,8 @@ uint8_t* knot_rrs_create_rr_at_pos(knot_rrs_t *rrs,
 	return knot_rr_get_rdata(old_rr);
 }
 
-int knot_rrs_add_rr_at_pos(knot_rrs_t *rrs, const knot_rr_t *rr,
-                           size_t pos, mm_ctx_t *mm)
+static int knot_rrs_add_rr_at_pos(knot_rrs_t *rrs, const knot_rr_t *rr,
+                                  size_t pos, mm_ctx_t *mm)
 {
 	if (rrs == NULL || pos > rrs->rr_count) {
 		return KNOT_EINVAL;
@@ -232,43 +118,56 @@ int knot_rrs_add_rr_at_pos(knot_rrs_t *rrs, const knot_rr_t *rr,
 	return KNOT_EOK;
 }
 
-uint8_t* knot_rrs_create_rr(knot_rrs_t *rrs, const uint16_t size,
-                            const uint32_t ttl, mm_ctx_t *mm)
+
+uint16_t knot_rr_size(const knot_rr_t *rr)
 {
-	if (rrs == NULL) {
-		return NULL;
-	}
+	return *((uint16_t *)rr);
+}
 
-	size_t total_size = knot_rrs_size(rrs);
-	/* Realloc RRs. */
-	void *tmp = mm_realloc(mm, rrs->data, total_size + size + RR_META_SIZE,
-	                       total_size);
-	if (tmp) {
-		rrs->data = tmp;
-	} else {
-		ERR_ALLOC_FAILED;
-		return NULL;
-	}
+void knot_rr_set_size(knot_rr_t *rr, uint16_t size)
+{
+	*((uint16_t *)rr) = size;
+}
 
-	rrs->rr_count++;
-	knot_rr_t *rr = knot_rrs_get_rr(rrs, rrs->rr_count - 1);
-	assert(rr);
+uint32_t knot_rr_ttl(const knot_rr_t *rr)
+{
+	return *((uint32_t *)(rr + sizeof(uint16_t)));
+}
 
-	knot_rr_set_size(rr, size);
-	knot_rr_set_ttl(rr, ttl);
+void knot_rr_set_ttl(knot_rr_t *rr, uint32_t ttl)
+{
+	*((uint32_t *)(rr + sizeof(uint16_t))) = ttl;
+}
 
-	return knot_rr_get_rdata(rr);
+const uint8_t *knot_rr_rdata(const knot_rr_t *rr)
+{
+	return (const uint8_t *)(rr + RR_META_SIZE);
 }
 
-knot_rrs_t *knot_rrs_new(mm_ctx_t *mm)
+uint8_t *knot_rr_get_rdata(knot_rr_t *rr)
 {
-	knot_rrs_t *rrs = mm_alloc(mm, sizeof(knot_rrs_t));
-	if (rrs == NULL) {
-		ERR_ALLOC_FAILED;
-		return NULL;
+	return rr + RR_META_SIZE;
+}
+
+size_t knot_rr_array_size(uint16_t size)
+{
+	return size + RR_META_SIZE;
+}
+
+int knot_rr_cmp(const knot_rr_t *rr1, const knot_rr_t *rr2)
+{
+	if (rr1 == NULL || rr2 == NULL) {
+		return -1;
+	}
+	const uint8_t *r1 = knot_rr_rdata(rr1);
+	const uint8_t *r2 = knot_rr_rdata(rr2);
+	uint16_t l1 = knot_rr_size(rr1);
+	uint16_t l2 = knot_rr_size(rr2);
+	int cmp = memcmp(r1, r2, MIN(l1, l2));
+	if (cmp == 0 && l1 != l2) {
+		cmp = l1 < l2 ? -1 : 1;
 	}
-	knot_rrs_init(rrs);
-	return rrs;
+	return cmp;
 }
 
 void knot_rrs_init(knot_rrs_t *rrs)
@@ -306,46 +205,117 @@ int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm)
 	return KNOT_EOK;
 }
 
+knot_rr_t *knot_rrs_get_rr(const knot_rrs_t *rrs, size_t pos)
+{
+	if (rrs == NULL || pos >= rrs->rr_count) {
+		return NULL;
+	}
+
+	return rr_seek(rrs->data, pos);
+}
+
+const knot_rr_t *knot_rrs_rr(const knot_rrs_t *rrs, size_t pos)
+{
+	if (rrs == NULL || pos >= rrs->rr_count) {
+		return NULL;
+	}
+
+	return (const knot_rr_t *)rr_seek(rrs->data, pos);
+}
 
-int knot_rrs_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs,
-                         knot_rrs_t *out_sig, mm_ctx_t *mm)
+const uint8_t *knot_rrs_rr_rdata(const knot_rrs_t *rrs, size_t pos)
 {
-	if (rrsig_rrs == NULL) {
-		return KNOT_ENOENT;
+	if (rrs == NULL || pos >= rrs->rr_count) {
+		return NULL;
 	}
 	
-	if (out_sig == NULL || out_sig->rr_count > 0) {
-		return KNOT_EINVAL;
+	return knot_rr_rdata(knot_rrs_rr(rrs, pos));
+}
+
+uint8_t *knot_rrs_rr_get_rdata(const knot_rrs_t *rrs, size_t pos)
+{
+	return (uint8_t *)knot_rrs_rr_rdata(rrs, pos);
+}
+
+uint16_t knot_rrs_rr_size(const knot_rrs_t *rrs, size_t pos)
+{
+	if (rrs == NULL || pos >= rrs->rr_count) {
+		return 0;
 	}
 	
-	for (int i = 0; i < rrsig_rrs->rr_count; ++i) {
-		if (type == knot_rrs_rrsig_type_covered(rrsig_rrs, i)) {
-			const knot_rr_t *rr_to_copy = knot_rrs_rr(rrsig_rrs, i);
-			int ret = knot_rrs_add_rr(out_sig, rr_to_copy, mm);
-			if (ret != KNOT_EOK) {
-				knot_rrs_clear(out_sig, mm);
-				return ret;
-			}
-		}
+	return knot_rr_size(knot_rrs_rr(rrs, pos));
+}
+
+uint32_t knot_rrs_rr_ttl(const knot_rrs_t *rrs, size_t pos)
+{
+	if (rrs == NULL || pos >= rrs->rr_count) {
+		return 0;
 	}
 	
-	return out_sig->rr_count > 0 ? KNOT_EOK : KNOT_ENOENT;
+	return knot_rr_ttl(knot_rrs_rr(rrs, pos));
 }
 
-int knot_rr_cmp(const knot_rr_t *rr1, const knot_rr_t *rr2)
+int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm)
 {
-	if (rr1 == NULL || rr2 == NULL) {
-		return -1;
+	if (rrs == NULL || rr == NULL) {
+		return KNOT_EINVAL;
 	}
-	const uint8_t *r1 = knot_rr_rdata(rr1);
-	const uint8_t *r2 = knot_rr_rdata(rr2);
-	uint16_t l1 = knot_rr_size(rr1);
-	uint16_t l2 = knot_rr_size(rr2);
-	int cmp = memcmp(r1, r2, MIN(l1, l2));
-	if (cmp == 0 && l1 != l2) {
-		cmp = l1 < l2 ? -1 : 1;
+
+	for (uint16_t i = 0; i < rrs->rr_count; ++i) {
+		const knot_rr_t *rrset_rr = knot_rrs_rr(rrs, i);
+		int cmp = knot_rr_cmp(rrset_rr, rr);
+		if (cmp == 0) {
+			// Duplication - no need to add this RR
+			return KNOT_EOK;
+		} else if (cmp > 0) {
+			// Found position to insert
+			return knot_rrs_add_rr_at_pos(rrs, rr, i, mm);
+		}
 	}
-	return cmp;
+
+	// If flow gets here, it means that we should insert at the last position
+	return knot_rrs_add_rr_at_pos(rrs, rr, rrs->rr_count, mm);
+}
+
+int knot_rrs_remove_rr_at_pos(knot_rrs_t *rrs, size_t pos, mm_ctx_t *mm)
+{
+	if (rrs == NULL || pos >= rrs->rr_count) {
+		return KNOT_EINVAL;
+	}
+
+	knot_rr_t *old_rr = knot_rrs_get_rr(rrs, pos);
+	knot_rr_t *last_rr = knot_rrs_get_rr(rrs, rrs->rr_count - 1);
+	assert(old_rr);
+	assert(last_rr);
+
+	size_t total_size = knot_rrs_size(rrs);
+	uint16_t old_size = knot_rr_size(old_rr);
+
+	void *old_threshold = old_rr + old_size + RR_META_SIZE;
+	void *last_threshold = last_rr + knot_rr_size(last_rr) + RR_META_SIZE;
+	// Move RDATA
+	memmove(old_rr, old_threshold,
+	        last_threshold - old_threshold);
+
+	if (rrs->rr_count > 1) {
+		// Realloc RDATA
+		void *tmp = mm_realloc(mm, rrs->data,
+		                       total_size - (old_size + RR_META_SIZE),
+		                       total_size);
+		if (tmp == NULL) {
+			ERR_ALLOC_FAILED;
+			return KNOT_ENOMEM;
+		} else {
+			rrs->data = tmp;
+		}
+	} else {
+		// Free RDATA
+		mm_free(mm, rrs->data);
+		rrs->data = NULL;
+	}
+	rrs->rr_count--;
+
+	return KNOT_EOK;
 }
 
 bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2)
@@ -365,26 +335,29 @@ bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2)
 	return true;
 }
 
-int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm)
+int knot_rrs_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs,
+                         knot_rrs_t *out_sig, mm_ctx_t *mm)
 {
-	if (rrs == NULL || rr == NULL) {
+	if (rrsig_rrs == NULL) {
+		return KNOT_ENOENT;
+	}
+
+	if (out_sig == NULL || out_sig->rr_count > 0) {
 		return KNOT_EINVAL;
 	}
 
-	for (uint16_t i = 0; i < rrs->rr_count; ++i) {
-		const knot_rr_t *rrset_rr = knot_rrs_rr(rrs, i);
-		int cmp = knot_rr_cmp(rrset_rr, rr);
-		if (cmp == 0) {
-			// Duplication - no need to add this RR
-			return KNOT_EOK;
-		} else if (cmp > 0) {
-			// Found position to insert
-			return knot_rrs_add_rr_at_pos(rrs, rr, i, mm);
+	for (int i = 0; i < rrsig_rrs->rr_count; ++i) {
+		if (type == knot_rrs_rrsig_type_covered(rrsig_rrs, i)) {
+			const knot_rr_t *rr_to_copy = knot_rrs_rr(rrsig_rrs, i);
+			int ret = knot_rrs_add_rr(out_sig, rr_to_copy, mm);
+			if (ret != KNOT_EOK) {
+				knot_rrs_clear(out_sig, mm);
+				return ret;
+			}
 		}
 	}
 
-	// If flow gets here, it means that we should insert at the last position
-	return knot_rrs_add_rr_at_pos(rrs, rr, rrs->rr_count, mm);
+	return out_sig->rr_count > 0 ? KNOT_EOK : KNOT_ENOENT;
 }
 
 int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm)
diff --git a/src/libknot/rr.h b/src/libknot/rr.h
index 28a7226903..ab02754a09 100644
--- a/src/libknot/rr.h
+++ b/src/libknot/rr.h
@@ -7,44 +7,205 @@
 
 #include "common/mempattern.h"
 
-typedef uint8_t knot_rr_t;
+/* ---------------------------- Single RR ----------------------------------- */
 
-typedef struct knot_rrs {
-	uint16_t rr_count;
-	knot_rr_t *data;
-} knot_rrs_t;
+typedef uint8_t knot_rr_t;  /*!< \brief Single RR containing size, TTL and RDATA. */
+
+/* ------------------------- RR getters/setters ----------------------------- */
 
+/*!
+ * \brief Returns size of single RR.
+ * \param rr  RR whose size we want.
+ * \return  RR size.
+ */
 uint16_t knot_rr_size(const knot_rr_t *rr);
+
+/*!
+ * \brief Sets size for given RR.
+ * \param rr    RR whose size we want to set.
+ * \param size  Size to be set.
+ */
+void knot_rr_set_size(knot_rr_t *rr, uint16_t size);
+
+/*!
+ * \brief Returns TTL of single RR.
+ * \param rr  RR whose TTL we want.
+ * \return  RR TTL.
+ */
 uint32_t knot_rr_ttl(const knot_rr_t *rr);
+
+/*!
+ * \brief Sets TTL for given RR.
+ * \param rr   RR whose TTL we want to set.
+ * \param ttl  TTL to be set.
+ */
+void knot_rr_set_ttl(knot_rr_t *rr, uint32_t ttl);
+
+/*!
+ * \brief Returns const pointer to RR data.
+ * \param rr  RR whose data we want.
+ * \return RR data const pointer.
+ */
 const uint8_t *knot_rr_rdata(const knot_rr_t *rr);
+
+/*!
+ * \brief Returns pointer to RR data.
+ * \param rr  RR whose data we want.
+ * \return RR data pointer.
+ */
 uint8_t *knot_rr_get_rdata(knot_rr_t *rr);
-void knot_rr_set_size(knot_rr_t *rr, uint16_t size);
-void knot_rr_set_ttl(knot_rr_t *rr, uint32_t ttl);
-int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm);
-knot_rrs_t *knot_rrs_new(mm_ctx_t *mm);
+
+/* ----------------------------- RR misc ------------------------------------ */
+
+/*!
+ * \brief Returns actual size of RR structure for given RDATA size.
+ * \param size  RDATA size.
+ * \return Actual structure size.
+ */
+size_t knot_rr_array_size(uint16_t size);
+
+/*!
+ * \brief Canonical comparison of two RRs.
+ * \param rr1  First RR to compare.
+ * \param rr2  Second RR to compare.
+ * \retval 0 if rr1 == rr2.
+ * \retval < 0 if rr1 < rr2.
+ * \retval > 0 if rr1 > rr2.
+ */
+int knot_rr_cmp(const knot_rr_t *rr1, const knot_rr_t *rr2);
+
+/* --------------------------- Multiple RRs ----------------------------------*/
+
+/*!< \brief Array of RRs */
+typedef struct knot_rrs {
+	uint16_t rr_count;  /*!< \brief Count of RRs stored in the structure. */
+	knot_rr_t *data;    /*!< \brief Actual data, canonically sorted. */
+} knot_rrs_t;
+
+/* -------------------------- RRs init/clear ---------------------------------*/
+
+/*!
+ * \brief Initializes RRS structure.
+ * \param rrs  Structure to be initialized.
+ */
 void knot_rrs_init(knot_rrs_t *rrs);
-size_t knot_rrs_size(const knot_rrs_t *rrs);
-uint16_t knot_rrs_rr_count(const knot_rrs_t *rrs);
+
+/*!
+ * \brief Frees data initialized by RRS structure, but not the structure itself.
+ * \param rrs  Structure to be cleared.
+ * \param mm   Memory context used to create allocations.
+ */
+void knot_rrs_clear(knot_rrs_t *rrs, mm_ctx_t *mm);
+
+/*!
+ * \brief Deep copies RRS structure. All data are duplicated.
+ * \param dst  Copy destination.
+ * \param src  Copy source.
+ * \param mm   Memory context.
+ * \return KNOT_E*
+ */
+int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm);
+
+/* ----------------------- RRs getters/setters ------------------------------ */
+
+/*!
+ * \brief Gets RR from RRS structure, using given position.
+ * \param rrs  RRS structure to get RR from.
+ * \param pos  Position to use.
+ * \return Pointer to RR at \a pos position.
+ */
 knot_rr_t *knot_rrs_get_rr(const knot_rrs_t *rrs, size_t pos);
+
+/*!
+ * \brief Gets RR from RRS structure, using given position.
+ * \param rrs  RRS structure to get RR from.
+ * \param pos  Position to use.
+ * \return Const pointer to RR at \a pos position.
+ */
 const knot_rr_t *knot_rrs_rr(const knot_rrs_t *rrs, size_t pos);
+
+/*!
+ * \brief Gets RDATA from RR at \a pos position.
+ * \param rrs  RRS to get RDATA from.
+ * \param pos  Position to use.
+ * \return Pointer to RDATA of RR at \a pos position.
+ */
 const uint8_t *knot_rrs_rr_rdata(const knot_rrs_t *rrs, size_t pos);
+
+/*!
+ * \brief Gets RDATA from RR at \a pos position.
+ * \param rrs  RRS to get RDATA from.
+ * \param pos  Position to use.
+ * \return Const pointer to RDATA of RR at \a pos position.
+ */
 uint8_t *knot_rrs_rr_get_rdata(const knot_rrs_t *rrs, size_t pos);
+
+/*!
+ * \brief Gets size from RR at \a pos position.
+ * \param rrs  RRS to get size from.
+ * \param pos  Position to use.
+ * \return Size of RR at \a pos position.
+ */
 uint16_t knot_rrs_rr_size(const knot_rrs_t *rrs, size_t pos);
+
+/*!
+ * \brief Gets TTL from RR at \a pos position.
+ * \param rrs  RRS to get TTL from.
+ * \param pos  Position to use.
+ * \return Size of TTL at \a pos position.
+ */
 uint32_t knot_rrs_rr_ttl(const knot_rrs_t *rrs, size_t pos);
-uint8_t* knot_rrs_create_rr(knot_rrs_t *rrs, const uint16_t size,
-                            const uint32_t ttl, mm_ctx_t *mm);
-uint8_t* knot_rrs_create_rr_at_pos(knot_rrs_t *rrs,
-                                   size_t pos, uint16_t size,
-                                   uint32_t ttl, mm_ctx_t *mm);
-int knot_rrs_add_rr_at_pos(knot_rrs_t *rrs, const knot_rr_t *rr,
-                           size_t pos, mm_ctx_t *mm);
+
+/* ----------------------- RRs RR manipulation ------------------------------ */
+
+/*!
+ * \brief Adds single RR into RRS structure. All data are copied.
+ * \param rrs  RRS structure to add RR into.
+ * \param rr   RR to add.
+ * \param mm   Memory context.
+ * \return KNOT_E*
+ */
+int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm);
+
+/*!
+ * \brief Removes RR at a given position from RRS structure. RR is dropped.
+ * \param rrs  RRS structure to remove from.
+ * \param pos  Position to use.
+ * \param mm   Memory context.
+ * \return KNOT_E*
+ */
 int knot_rrs_remove_rr_at_pos(knot_rrs_t *rrs, size_t pos, mm_ctx_t *mm);
-void knot_rrs_clear(knot_rrs_t *rrs, mm_ctx_t *mm);
-int knot_rr_cmp(const knot_rr_t *rr1, const knot_rr_t *rr2);
+
+/* ----------------------------- RRs misc ----------------------------------- */
+
+/*!
+ * \brief RRS equality check.
+ * \param rrs1  First RRS to be compared.
+ * \param rrs2  Second RRS to be compared.
+ * \retval true if rrs1 == rrs2.
+ * \retval false if rrs1 != rrs2.
+ */
 bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2);
-int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm);
+
+/*!
+ * \brief Creates new RRS using \a rrsig_rrs as a source. Only those RRs that
+ *        cover given \a type are copied into \a out_sig
+ * \param type       Covered type.
+ * \param rrsig_rrs  Source RRS.
+ * \param out_sig    Output RRS.
+ * \param mm         Memory context.
+ * \return KNOT_E*
+ */
 int knot_rrs_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs,
                          knot_rrs_t *out_sig, mm_ctx_t *mm);
-int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm);
+
+/*!
+ * \brief Merges two RRS into the first one. Second RRS is left intact.
+ *        Canonical order is preserved.
+ * \param rrs1  Destination RRS (merge here).
+ * \param rrs2  RRS to be merged (merge from).
+ * \param mm    Memory context.
+ * \return KNOT_E*
+ */
 int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm);
 
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index c729e955b5..d42ba6fb43 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -407,15 +407,8 @@ static int rrset_deserialize_rr(knot_rrset_t *rrset,
 {
 	uint32_t ttl;
 	memcpy(&ttl, stream, sizeof(uint32_t));
-	uint8_t *rdata = knot_rrset_create_rr(rrset,
-	                                      rdata_size - sizeof(uint32_t),
-	                                      ttl, NULL);
-	if (rdata == NULL) {
-		return KNOT_ENOMEM;
-	}
-
-	memcpy(rdata, stream + sizeof(uint32_t), rdata_size - sizeof(uint32_t));
-	return KNOT_EOK;
+	return knot_rrset_add_rr(rrset, stream + sizeof(uint32_t),
+	                         rdata_size - sizeof(uint32_t), ttl, NULL);
 }
 
 void knot_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, uint16_t type,
@@ -470,16 +463,13 @@ int knot_rrset_add_rr(knot_rrset_t *rrset,
 		return KNOT_EINVAL;
 	}
 
-	uint8_t *p = knot_rrset_create_rr(rrset, size, ttl, mm);
-	memcpy(p, rdata, size);
-
-	return KNOT_EOK;
-}
+	// Create knot_rr_t from given data
+	knot_rr_t rr[knot_rr_array_size(size)];
+	knot_rr_set_size(rr, size);
+	knot_rr_set_ttl(rr, ttl);
+	memcpy(knot_rr_get_rdata(rr), rdata, size);
 
-uint8_t* knot_rrset_create_rr(knot_rrset_t *rrset, const uint16_t size,
-                              const uint32_t ttl, mm_ctx_t *mm)
-{
-	return knot_rrs_create_rr(&rrset->rrs, size, ttl, mm);
+	return knot_rrs_add_rr(&rrset->rrs, rr, mm);
 }
 
 uint16_t knot_rrset_rr_size(const knot_rrset_t *rrset, size_t pos)
@@ -561,8 +551,13 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
 	}
 
 	if (rdlength == 0) {
-		return knot_rrset_create_rr(rrset, 0, ttl, mm) == NULL ?
-		       KNOT_ENOMEM : KNOT_EOK;
+		uint8_t *empty_rdata = malloc(1);
+		if (empty_rdata == NULL) {
+			return KNOT_ENOMEM;
+		}
+		int ret = knot_rrset_add_rr(rrset, empty_rdata, 0, ttl, mm);
+		free(empty_rdata);
+		return ret;
 	}
 
 	dbg_rrset_detail("rr: parse_rdata_wire: Parsing RDATA of size=%zu,"
@@ -703,14 +698,7 @@ dbg_rrset_exec_detail(
 		}
 	}
 
-	uint8_t *rdata = knot_rrset_create_rr(rrset, offset, ttl, mm);
-	if (rdata == NULL) {
-		return KNOT_ENOMEM;
-	}
-
-	memcpy(rdata, rdata_buffer, offset);
-
-	return KNOT_EOK;
+	return knot_rrset_add_rr(rrset, rdata_buffer, offset, ttl, mm);
 }
 
 bool knot_rrset_equal(const knot_rrset_t *r1,
@@ -996,20 +984,11 @@ int knot_rrset_add_rr_from_rrset(knot_rrset_t *dest, const knot_rrset_t *source,
 		return KNOT_EINVAL;
 	}
 
-	/* Get size and TTL of RR to be copied. */
-	uint16_t size = knot_rrset_rr_size(source, rdata_pos);
-	uint32_t ttl = knot_rrset_rr_ttl(source, rdata_pos);
-	/* Reserve space in dest RRSet. */
-	uint8_t *rdata = knot_rrset_create_rr(dest, size, ttl, mm);
-	if (rdata == NULL) {
-		dbg_rrset("rr: add_rr_from_rrset: Could not create RDATA.\n");
-		return KNOT_ERROR;
-	}
-
-	/* Copy actual data. */
-	memcpy(rdata, knot_rrset_rr_rdata(source, rdata_pos), size);
-
-	return KNOT_EOK;
+	/* Get RDATA, size and TTL of RR to be copied. */
+	const uint8_t *rdata = knot_rrset_rr_rdata(source, rdata_pos);
+	const uint16_t size = knot_rrset_rr_size(source, rdata_pos);
+	const uint32_t ttl = knot_rrset_rr_ttl(source, rdata_pos);
+	return knot_rrset_add_rr(dest, rdata, size, ttl, mm);
 }
 
 int knot_rrset_remove_rr_using_rrset(knot_rrset_t *from,
diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h
index f0baa47abf..92f356354e 100644
--- a/src/libknot/rrset.h
+++ b/src/libknot/rrset.h
@@ -63,12 +63,6 @@ typedef enum {
 	KNOT_RRSET_COMPARE_WHOLE
 } knot_rrset_compare_type_t;
 
-typedef enum  {
-	KNOT_RRSET_DUPL_MERGE,
-	KNOT_RRSET_DUPL_REPLACE,
-	KNOT_RRSET_DUPL_SKIP
-} knot_rrset_dupl_handling_t;
-
 /*----------------------------------------------------------------------------*/
 
 /*!
@@ -116,21 +110,6 @@ int knot_rrset_add_rr(knot_rrset_t *rrset, const uint8_t *rdata,
                       const uint16_t size, const uint32_t ttl,
                       mm_ctx_t *mm);
 
-/*!
- * \brief Creates RDATA memory and returns a pointer to it.
- *        If the RRSet is not empty, function will return a memory
- *        pointing to a beginning of a new RR.
- *
- * \param rrset  RRSet to add the RDATA to.
- * \param size   Size of RR RDATA (Size in internal representation)
- * \param mm     Memory context.
- *
- * \retval  Pointer to memory to be written to.
- * \retval  NULL if arguments are invalid / no memory.
- */
-uint8_t* knot_rrset_create_rr(knot_rrset_t *rrset, const uint16_t size,
-                              const uint32_t ttl, mm_ctx_t *mm);
-
 /*!
  * \brief Returns RDATA of RR on given position.
  *
diff --git a/src/libknot/tsig.c b/src/libknot/tsig.c
index 233814ed97..c527d23f94 100644
--- a/src/libknot/tsig.c
+++ b/src/libknot/tsig.c
@@ -132,15 +132,20 @@ int tsig_create_rdata(knot_rrset_t *rr, const knot_dname_t *alg, uint16_t maclen
 	if (tsig_err != KNOT_RCODE_BADTIME) {
 		rdlen -= TSIG_OTHER_MAXLEN;
 	}
-	uint8_t *rd = knot_rrset_create_rr(rr, rdlen, 0, NULL);
+	uint8_t rd[rdlen];
 	memset(rd, 0, rdlen);
 
 	/* Copy alg name. */
 	knot_dname_to_wire(rd, alg, rdlen);
 
 	/* Set MAC variable length in advance. */
-	rd += alg_len + TSIG_OFF_MACLEN;
-	knot_wire_write_u16(rd, maclen);
+	size_t offset = alg_len + TSIG_OFF_MACLEN;
+	knot_wire_write_u16(rd + offset, maclen);
+
+	int ret = knot_rrset_add_rr(rr, rd, rdlen, 0, NULL);
+	if (ret != KNOT_EOK) {
+		return ret;
+	}
 
 	/* Set error. */
 	tsig_rdata_set_tsig_error(rr, tsig_err);
-- 
GitLab