diff --git a/Knot.files b/Knot.files
index 4a28db2c2f879e382c2f90c1307171d3e85d446c..4c8794faf4b71e5ea5da602286a17bea4babc47a 100644
--- a/Knot.files
+++ b/Knot.files
@@ -134,6 +134,8 @@ src/knot/server/notify.c
 src/knot/server/notify.h
 src/knot/server/rrl.c
 src/knot/server/rrl.h
+src/knot/server/serialization.c
+src/knot/server/serialization.h
 src/knot/server/server.c
 src/knot/server/server.h
 src/knot/server/tcp-handler.c
@@ -187,8 +189,6 @@ src/libknot/dnssec/crypto.c
 src/libknot/dnssec/crypto.h
 src/libknot/dnssec/key.c
 src/libknot/dnssec/key.h
-src/libknot/dnssec/nsec3.c
-src/libknot/dnssec/nsec3.h
 src/libknot/dnssec/policy.c
 src/libknot/dnssec/policy.h
 src/libknot/dnssec/random.h
@@ -208,17 +208,27 @@ src/libknot/packet/pkt.h
 src/libknot/packet/wire.h
 src/libknot/processing/process.c
 src/libknot/processing/process.h
+src/libknot/rdata.c
 src/libknot/rdata.h
-src/libknot/rr.c
-src/libknot/rr.h
+src/libknot/rdata/dnskey.h
+src/libknot/rdata/nsec.h
+src/libknot/rdata/nsec3.c
+src/libknot/rdata/nsec3.h
+src/libknot/rdata/nsec3param.c
+src/libknot/rdata/nsec3param.h
+src/libknot/rdata/rdname.h
+src/libknot/rdata/rrsig.h
+src/libknot/rdata/soa.h
+src/libknot/rdata/tsig.c
+src/libknot/rdata/tsig.h
+src/libknot/rdataset.c
+src/libknot/rdataset.h
 src/libknot/rrset-dump.c
 src/libknot/rrset-dump.h
 src/libknot/rrset.c
 src/libknot/rrset.h
 src/libknot/tsig-op.c
 src/libknot/tsig-op.h
-src/libknot/tsig.c
-src/libknot/tsig.h
 src/libknot/util/endian.h
 src/libknot/util/tolower.c
 src/libknot/util/tolower.h
@@ -293,5 +303,3 @@ tests/slab.c
 tests/wire.c
 tests/zonedb.c
 tests/ztree.c
-src/knot/server/serialization.c
-src/knot/server/serialization.h
diff --git a/src/Makefile.am b/src/Makefile.am
index cc67ce21a9516bb6c3319dac05cf4e3746611aa0..19b7a2197e3b30554a9c58a7df96f8d0f2863ac5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -148,8 +148,6 @@ libknot_la_SOURCES =				\
 	libknot/dnssec/key.c			\
 	libknot/dnssec/key.h			\
 	libknot/dnssec/bitmap.h			\
-	libknot/dnssec/nsec3.c			\
-	libknot/dnssec/nsec3.h			\
 	libknot/dnssec/policy.c			\
 	libknot/dnssec/policy.h			\
 	libknot/dnssec/random.h			\
@@ -169,17 +167,28 @@ libknot_la_SOURCES =				\
 	libknot/packet/wire.h			\
 	libknot/processing/process.c		\
 	libknot/processing/process.h		\
-	libknot/rdata.h				\
+	libknot/rdata/rdname.h			\
+	libknot/rdata/dnskey.h			\
+	libknot/rdata/nsec.h			\
+	libknot/rdata/nsec3.c			\
+	libknot/rdata/nsec3.h			\
+	libknot/rdata/nsec3param.h			\
+	libknot/rdata/nsec3param.c			\
+	libknot/rdata/nsec.h			\
+	libknot/rdata/rrsig.h			\
+	libknot/rdata/soa.h			\
+	libknot/rdata/tsig.c				\
+	libknot/rdata/tsig.h				\
 	libknot/rrset-dump.c			\
 	libknot/rrset-dump.h			\
-	libknot/rr.c				\
-	libknot/rr.h				\
+	libknot/rdata.c				\
+	libknot/rdata.h				\
+	libknot/rdataset.c				\
+	libknot/rdataset.h				\
 	libknot/rrset.c				\
 	libknot/rrset.h				\
 	libknot/tsig-op.c			\
 	libknot/tsig-op.h			\
-	libknot/tsig.c				\
-	libknot/tsig.h				\
 	libknot/util/endian.h			\
 	libknot/util/tolower.c			\
 	libknot/util/tolower.h			\
diff --git a/src/knot/conf/conf.h b/src/knot/conf/conf.h
index 381ef32afb15e16c2c8ca3241b037cbf498718e9..217fa1a6a195acae60cca5d15474c0c99288d6cf 100644
--- a/src/knot/conf/conf.h
+++ b/src/knot/conf/conf.h
@@ -35,7 +35,7 @@
 #include <urcu.h>
 
 #include "libknot/dname.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "libknot/dnssec/key.h"
 #include "libknot/dnssec/policy.h"
 #include "common/lists.h"
diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c
index 68e5ea20cf460f7eb6b5648b5f5d12e0e2a751f3..9a1142dca6e5bd166b69fb23b69d4ec522addaec 100644
--- a/src/knot/ctl/remote.c
+++ b/src/knot/ctl/remote.c
@@ -26,7 +26,8 @@
 #include "libknot/packet/wire.h"
 #include "common/descriptor.h"
 #include "libknot/tsig-op.h"
-#include "libknot/rdata.h"
+#include "libknot/rdata/rdname.h"
+#include "libknot/rdata/soa.h"
 #include "libknot/dnssec/random.h"
 #include "knot/dnssec/zone-sign.h"
 #include "knot/dnssec/zone-nsec.h"
@@ -100,7 +101,7 @@ static int remote_rdata_apply(server_t *s, remote_cmdargs_t* a, remote_zonef_t *
 
 		uint16_t rr_count = knot_rrset_rr_count(rr);
 		for (uint16_t i = 0; i < rr_count; i++) {
-			const knot_dname_t *dn = knot_rrs_ns_name(&rr->rrs, i);
+			const knot_dname_t *dn = knot_ns_name(&rr->rrs, i);
 			rcu_read_lock();
 			zone = knot_zonedb_find(s->zone_db, dn);
 			if (cb(s, zone) != KNOT_EOK) {
@@ -235,13 +236,13 @@ static int remote_c_zonestatus(server_t *s, remote_cmdargs_t* a)
 		const zone_t *zone = knot_zonedb_iter_val(&it);
 
 		/* Fetch latest serial. */
-		const knot_rrs_t *soa_rrs = NULL;
+		const knot_rdataset_t *soa_rrs = NULL;
 		uint32_t serial = 0;
 		if (zone->contents) {
-			soa_rrs = knot_node_rrs(zone->contents->apex,
+			soa_rrs = knot_node_rdataset(zone->contents->apex,
 			                        KNOT_RRTYPE_SOA);
 			assert(soa_rrs != NULL);
-			serial = knot_rrs_soa_serial(soa_rrs);
+			serial = knot_soa_serial(soa_rrs);
 		}
 
 		/* Evalute zone type. */
@@ -538,7 +539,7 @@ static void log_command(const char *cmd, const remote_cmdargs_t* args)
 
 		uint16_t rr_count = knot_rrset_rr_count(rr);
 		for (uint16_t j = 0; j < rr_count; j++) {
-			const knot_dname_t *dn = knot_rrs_ns_name(&rr->rrs, j);
+			const knot_dname_t *dn = knot_ns_name(&rr->rrs, j);
 			char *name = knot_dname_to_str(dn);
 
 			int ret = snprintf(params, rest, " %s", name);
@@ -816,7 +817,7 @@ int remote_create_txt(knot_rrset_t *rr, const char *v, size_t v_len)
 		memcpy(raw + off, v + p, r);
 	}
 
-	return knot_rrset_add_rr(rr, raw, v_len + chunks, 0, NULL);
+	return knot_rrset_add_rdata(rr, raw, v_len + chunks, 0, NULL);
 }
 
 int remote_create_ns(knot_rrset_t *rr, const char *d)
@@ -833,7 +834,7 @@ int remote_create_ns(knot_rrset_t *rr, const char *d)
 
 	/* Build RDATA. */
 	int dn_size = knot_dname_size(dn);
-	int result = knot_rrset_add_rr(rr, dn, dn_size, 0, NULL);
+	int result = knot_rrset_add_rdata(rr, dn, dn_size, 0, NULL);
 	knot_dname_free(&dn, NULL);
 
 	return result;
diff --git a/src/knot/dnssec/nsec-chain.c b/src/knot/dnssec/nsec-chain.c
index f2547054b0f462b06ef9856a6cfdd454f25c99a3..b21f10e48963d6efd5776f32091e7f2461814e48 100644
--- a/src/knot/dnssec/nsec-chain.c
+++ b/src/knot/dnssec/nsec-chain.c
@@ -17,7 +17,6 @@
 #include <assert.h>
 #include <stdint.h>
 
-#include "libknot/rdata.h"
 #include "common/debug.h"
 #include "knot/dnssec/nsec-chain.h"
 #include "knot/dnssec/zone-sign.h"
@@ -66,7 +65,7 @@ static knot_rrset_t *create_nsec_rrset(const knot_node_t *from,
 	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);
+	int ret = knot_rrset_add_rdata(rrset, rdata, rdata_size, ttl, NULL);
 	if (ret != KNOT_EOK) {
 		knot_rrset_free(&rrset, NULL);
 		return NULL;
diff --git a/src/knot/dnssec/nsec3-chain.c b/src/knot/dnssec/nsec3-chain.c
index 23b90d70c806aac096dfdfa060c23cad37aed017..e06c3e19500c289e768c06814b0c39e00e8f429d 100644
--- a/src/knot/dnssec/nsec3-chain.c
+++ b/src/knot/dnssec/nsec3-chain.c
@@ -19,7 +19,6 @@
 #include "common/base32hex.h"
 #include "knot/dnssec/nsec3-chain.h"
 #include "libknot/dname.h"
-#include "libknot/rdata.h"
 #include "libknot/packet/wire.h"
 #include "knot/zone/zone-contents.h"
 #include "knot/zone/zone-diff.h"
@@ -27,6 +26,7 @@
 #include "knot/dnssec/zone-sign.h"
 #include "knot/dnssec/zone-nsec.h"
 #include "libknot/dnssec/bitmap.h"
+#include "libknot/rdata/nsec3.h"
 
 /* - Forward declarations --------------------------------------------------- */
 
@@ -52,7 +52,7 @@ inline static bool valid_nsec3_node(const knot_node_t *node)
 		return false;
 	}
 
-	const knot_rrs_t *nsec3 = knot_node_rrs(node, KNOT_RRTYPE_NSEC3);
+	const knot_rdataset_t *nsec3 = knot_node_rdataset(node, KNOT_RRTYPE_NSEC3);
 	if (nsec3 == NULL) {
 		return false;
 	}
@@ -175,10 +175,10 @@ static void free_nsec3_tree(knot_zone_tree_t *nodes)
 	for (/* NOP */; !hattrie_iter_finished(it); hattrie_iter_next(it)) {
 		knot_node_t *node = (knot_node_t *)*hattrie_iter_val(it);
 		// newly allocated NSEC3 nodes
-		knot_rrs_t *nsec3 = knot_node_get_rrs(node, KNOT_RRTYPE_NSEC3);
-		knot_rrs_t *rrsig = knot_node_get_rrs(node, KNOT_RRTYPE_RRSIG);
-		knot_rrs_clear(nsec3, NULL);
-		knot_rrs_clear(rrsig, NULL);
+		knot_rdataset_t *nsec3 = knot_node_get_rdataset(node, KNOT_RRTYPE_NSEC3);
+		knot_rdataset_t *rrsig = knot_node_get_rdataset(node, KNOT_RRTYPE_RRSIG);
+		knot_rdataset_clear(nsec3, NULL);
+		knot_rdataset_clear(rrsig, NULL);
 		knot_node_free(&node);
 	}
 
@@ -266,7 +266,7 @@ static int create_nsec3_rrset(knot_rrset_t *rrset,
 	uint8_t rdata[rdata_size];
 	nsec3_fill_rdata(rdata, params, rr_types, next_hashed, ttl);
 
-	return knot_rrset_add_rr(rrset, rdata, rdata_size, ttl, NULL);
+	return knot_rrset_add_rdata(rrset, rdata, rdata_size, ttl, NULL);
 }
 
 /*!
@@ -367,16 +367,16 @@ static int connect_nsec3_nodes(knot_node_t *a, knot_node_t *b,
 
 	assert(a->rrset_count == 1);
 
-	knot_rrs_t *a_rrs = knot_node_get_rrs(a, KNOT_RRTYPE_NSEC3);
+	knot_rdataset_t *a_rrs = knot_node_get_rdataset(a, KNOT_RRTYPE_NSEC3);
 	assert(a_rrs);
-	uint8_t algorithm = knot_rrs_nsec3_algorithm(a_rrs, 0);
+	uint8_t algorithm = knot_nsec3_algorithm(a_rrs, 0);
 	if (algorithm == 0) {
 		return KNOT_EINVAL;
 	}
 
 	uint8_t *raw_hash = NULL;
 	uint8_t raw_length = 0;
-	knot_rrs_nsec3_next_hashed(a_rrs, 0, &raw_hash, &raw_length);
+	knot_nsec3_next_hashed(a_rrs, 0, &raw_hash, &raw_length);
 	if (raw_hash == NULL) {
 		return KNOT_EINVAL;
 	}
diff --git a/src/knot/dnssec/zone-keys.c b/src/knot/dnssec/zone-keys.c
index 2ec945f0112b52842cb1146728a77dbe0927c2b5..5946e18bae6f620c698f43b5bfb3d1a256fdbfe4 100644
--- a/src/knot/dnssec/zone-keys.c
+++ b/src/knot/dnssec/zone-keys.c
@@ -18,16 +18,16 @@
 #include <dirent.h>
 #include <stdbool.h>
 #include <inttypes.h>
+
+#include "common/debug.h"
 #include "common/errcode.h"
 #include "common/mempattern.h"
 #include "libknot/common.h"
 #include "libknot/dname.h"
 #include "libknot/consts.h"
-#include "libknot/dnssec/nsec3.h"
+#include "libknot/rdata/dnskey.h"
 #include "libknot/dnssec/sign.h"
 #include "knot/dnssec/zone-keys.h"
-#include "libknot/rdata.h"
-#include "common/debug.h"
 
 /*!
  * \brief Free DNSSEC signing context for each key.
diff --git a/src/knot/dnssec/zone-nsec.c b/src/knot/dnssec/zone-nsec.c
index ade08a681ea6ab621417c9c05e6ba36480caa8cd..54358e12edc9ed495824c68a5f6f4eab67479f5b 100644
--- a/src/knot/dnssec/zone-nsec.c
+++ b/src/knot/dnssec/zone-nsec.c
@@ -21,18 +21,18 @@
 #include <limits.h>
 
 #include "common/base32hex.h"
+#include "common/debug.h"
 #include "common/descriptor.h"
 #include "common/hhash.h"
+#include "libknot/dnssec/bitmap.h"
+#include "libknot/util/utils.h"
+#include "libknot/packet/wire.h"
+#include "libknot/rdata/soa.h"
+#include "libknot/rdata/nsec3.h"
 #include "knot/dnssec/nsec-chain.h"
 #include "knot/dnssec/nsec3-chain.h"
-#include "libknot/dnssec/bitmap.h"
-#include "libknot/dnssec/nsec3.h"
 #include "knot/dnssec/zone-nsec.h"
 #include "knot/dnssec/zone-sign.h"
-#include "libknot/rdata.h"
-#include "common/debug.h"
-#include "libknot/util/utils.h"
-#include "libknot/packet/wire.h"
 #include "knot/zone/zone-contents.h"
 #include "knot/zone/zone-diff.h"
 
@@ -93,12 +93,12 @@ static bool get_zone_soa_min_ttl(const knot_zone_contents_t *zone,
 	assert(ttl);
 
 	knot_node_t *apex = zone->apex;
-	const knot_rrs_t *soa = knot_node_rrs(apex, KNOT_RRTYPE_SOA);
+	const knot_rdataset_t *soa = knot_node_rdataset(apex, KNOT_RRTYPE_SOA);
 	if (!soa) {
 		return false;
 	}
 
-	uint32_t result =  knot_rrs_soa_minimum(soa);
+	uint32_t result =  knot_soa_minimum(soa);
 	if (result == 0) {
 		return false;
 	}
diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c
index 177c4594c4f1bc5d5d08fba54aa8f4e45626a97e..45e918e7efd308bb8e9fac26b4946b1a7565490a 100644
--- a/src/knot/dnssec/zone-sign.c
+++ b/src/knot/dnssec/zone-sign.c
@@ -19,21 +19,24 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <time.h>
+
+#include "common/debug.h"
 #include "common/descriptor.h"
 #include "common/errcode.h"
 #include "common/hattrie/hat-trie.h"
 #include "libknot/common.h"
 #include "libknot/dname.h"
+#include "libknot/rrset.h"
 #include "libknot/dnssec/key.h"
 #include "libknot/dnssec/policy.h"
 #include "libknot/dnssec/rrset-sign.h"
 #include "libknot/dnssec/sign.h"
+#include "libknot/rdata/rdname.h"
+#include "libknot/rdata/rrsig.h"
+#include "libknot/rdata/soa.h"
 #include "knot/dnssec/zone-keys.h"
 #include "knot/dnssec/zone-sign.h"
-#include "libknot/rdata.h"
-#include "libknot/rrset.h"
 #include "knot/updates/changesets.h"
-#include "common/debug.h"
 #include "knot/zone/node.h"
 #include "knot/zone/zone-contents.h"
 
@@ -77,8 +80,8 @@ static bool valid_signature_exists(const knot_rrset_t *covered,
 
 	uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs);
 	for (uint16_t i = 0; i < rrsigs_rdata_count; i++) {
-		uint16_t keytag = knot_rrs_rrsig_key_tag(&rrsigs->rrs, i);
-		uint16_t type_covered = knot_rrs_rrsig_type_covered(&rrsigs->rrs, i);
+		uint16_t keytag = knot_rrsig_key_tag(&rrsigs->rrs, i);
+		uint16_t type_covered = knot_rrsig_type_covered(&rrsigs->rrs, i);
 		if (keytag != key->keytag || type_covered != covered->type) {
 			continue;
 		}
@@ -169,7 +172,7 @@ static const knot_zone_key_t *get_matching_zone_key(const knot_rrset_t *rrsigs,
 	assert(rrsigs && rrsigs->type == KNOT_RRTYPE_RRSIG);
 	assert(keys);
 
-	uint16_t keytag = knot_rrs_rrsig_key_tag(&rrsigs->rrs, pos);
+	uint16_t keytag = knot_rrsig_key_tag(&rrsigs->rrs, pos);
 
 	return knot_get_zone_key(keys, keytag);
 }
@@ -187,7 +190,7 @@ static void note_earliest_expiration(const knot_rrset_t *rrsigs, size_t pos,
 	assert(rrsigs);
 	assert(expires_at);
 
-	const uint32_t current = knot_rrs_rrsig_sig_expiration(&rrsigs->rrs, pos);
+	const uint32_t current = knot_rrsig_sig_expiration(&rrsigs->rrs, pos);
 	if (current < *expires_at) {
 		*expires_at = current;
 	}
@@ -263,8 +266,8 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered,
 			}
 		}
 
-		knot_rr_t *rr_rem = knot_rrs_rr(&synth_rrsig.rrs, i);
-		result = knot_rrs_add_rr(&to_remove->rrs, rr_rem, NULL);
+		knot_rdata_t *rr_rem = knot_rdataset_at(&synth_rrsig.rrs, i);
+		result = knot_rdataset_add(&to_remove->rrs, rr_rem, NULL);
 		if (result != KNOT_EOK) {
 			break;
 		}
@@ -279,7 +282,7 @@ static int remove_expired_rrsigs(const knot_rrset_t *covered,
 		knot_rrset_free(&to_remove, NULL);
 	}
 
-	knot_rrs_clear(&synth_rrsig.rrs, NULL);
+	knot_rdataset_clear(&synth_rrsig.rrs, NULL);
 
 	return result;
 }
@@ -458,7 +461,7 @@ static int remove_standalone_rrsigs(const knot_node_t *node,
 
 	uint16_t rrsigs_rdata_count = knot_rrset_rr_count(rrsigs);
 	for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) {
-		uint16_t type_covered = knot_rrs_rrsig_type_covered(&rrsigs->rrs, i);
+		uint16_t type_covered = knot_rrsig_type_covered(&rrsigs->rrs, i);
 		if (!knot_node_rrtype_exists(node, type_covered)) {
 			knot_rrset_t *to_remove = knot_rrset_new(rrsigs->owner,
 			                                         rrsigs->type,
@@ -467,8 +470,8 @@ static int remove_standalone_rrsigs(const knot_node_t *node,
 			if (to_remove == NULL) {
 				return KNOT_ENOMEM;
 			}
-			knot_rr_t *rr_rem = knot_rrs_rr(&rrsigs->rrs, i);
-			int ret = knot_rrs_add_rr(&to_remove->rrs, rr_rem, NULL);
+			knot_rdata_t *rr_rem = knot_rdataset_at(&rrsigs->rrs, i);
+			int ret = knot_rdataset_add(&to_remove->rrs, rr_rem, NULL);
 			if (ret != KNOT_EOK) {
 				knot_rrset_free(&to_remove, NULL);
 				return ret;
@@ -714,7 +717,7 @@ static int rrset_add_zone_key(knot_rrset_t *rrset,
 
 	const knot_binary_t *key_rdata = &zone_key->dnssec_key.dnskey_rdata;
 
-	return knot_rrset_add_rr(rrset, key_rdata->data, key_rdata->size, ttl,
+	return knot_rrset_add_rdata(rrset, key_rdata->data, key_rdata->size, ttl,
 	                         NULL);
 }
 
@@ -785,8 +788,8 @@ static int remove_invalid_dnskeys(const knot_rrset_t *soa,
 			}
 		}
 
-		knot_rr_t *to_rem = knot_rrs_rr(&dnskeys->rrs, i);
-		result = knot_rrs_add_rr(&to_remove->rrs, to_rem, NULL);
+		knot_rdata_t *to_rem = knot_rdataset_at(&dnskeys->rrs, i);
+		result = knot_rdataset_add(&to_remove->rrs, to_rem, NULL);
 		if (result != KNOT_EOK) {
 			break;
 		}
@@ -927,8 +930,8 @@ static int update_dnskeys_rrsigs(const knot_rrset_t *dnskeys,
 			continue;
 		}
 
-		knot_rr_t *to_add = knot_rrs_rr(&dnskeys->rrs, i);
-		result = knot_rrs_add_rr(&new_dnskeys->rrs, to_add, NULL);
+		knot_rdata_t *to_add = knot_rdataset_at(&dnskeys->rrs, i);
+		result = knot_rdataset_add(&new_dnskeys->rrs, to_add, NULL);
 		if (result != KNOT_EOK) {
 			goto fail;
 		}
@@ -1019,7 +1022,7 @@ static int update_dnskeys(const knot_zone_contents_t *zone,
 	bool signatures_exist = (!knot_rrset_empty(&dnskeys) &&
 	                        all_signatures_exist(&dnskeys, &dnskey_rrsig,
 	                                             zone_keys, policy));
-	knot_rrs_clear(&dnskey_rrsig.rrs, NULL);
+	knot_rdataset_clear(&dnskey_rrsig.rrs, NULL);
 	if (!modified && signatures_exist) {
 		return KNOT_EOK;
 	}
@@ -1325,7 +1328,7 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa,
 
 	dbg_dnssec_verb("Updating SOA...\n");
 
-	uint32_t serial = knot_rrs_soa_serial(&soa->rrs);
+	uint32_t serial = knot_soa_serial(&soa->rrs);
 	if (serial == UINT32_MAX && policy->soa_up == KNOT_SOA_SERIAL_UPDATE) {
 		// TODO: this is wrong, the value should be 'rewound' to 0 in this case
 		return KNOT_EINVAL;
@@ -1366,7 +1369,7 @@ int knot_zone_sign_update_soa(const knot_rrset_t *soa,
 		return KNOT_ENOMEM;
 	}
 
-	knot_rrs_soa_serial_set(&soa_to->rrs, new_serial);
+	knot_soa_serial_set(&soa_to->rrs, new_serial);
 
 	// add signatures for new SOA
 
diff --git a/src/knot/modules/synth_record.c b/src/knot/modules/synth_record.c
index b7ce6241a2b33990585acf4e11feba687eef2ea6..53fc4382fe6d62da283a77c32bc5e4cf62dd11fa 100644
--- a/src/knot/modules/synth_record.c
+++ b/src/knot/modules/synth_record.c
@@ -196,7 +196,7 @@ static int reverse_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, kn
 	}
 
 	rr->type = KNOT_RRTYPE_PTR;
-	knot_rrset_add_rr(rr, ptrname, knot_dname_size(ptrname), tpl->ttl, &pkt->mm);
+	knot_rrset_add_rdata(rr, ptrname, knot_dname_size(ptrname), tpl->ttl, &pkt->mm);
 	knot_dname_free(&ptrname, NULL);
 
 	return KNOT_EOK;
@@ -211,12 +211,12 @@ static int forward_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, kn
 	if (tpl->subnet.ss.ss_family == AF_INET6) {
 		rr->type = KNOT_RRTYPE_AAAA;
 		const struct sockaddr_in6* ip = (const struct sockaddr_in6*)&query_addr;
-		knot_rrset_add_rr(rr, (const uint8_t *)&ip->sin6_addr, sizeof(struct in6_addr),
+		knot_rrset_add_rdata(rr, (const uint8_t *)&ip->sin6_addr, sizeof(struct in6_addr),
 		                  tpl->ttl, &pkt->mm);
 	} else if (tpl->subnet.ss.ss_family == AF_INET) {
 		rr->type = KNOT_RRTYPE_A;
 		const struct sockaddr_in* ip = (const struct sockaddr_in*)&query_addr;
-		knot_rrset_add_rr(rr, (const uint8_t *)&ip->sin_addr, sizeof(struct in_addr),
+		knot_rrset_add_rdata(rr, (const uint8_t *)&ip->sin_addr, sizeof(struct in_addr),
 		                  tpl->ttl, &pkt->mm);
 	} else {
 		return KNOT_EINVAL;
diff --git a/src/knot/nameserver/chaos.c b/src/knot/nameserver/chaos.c
index 0a3cd2b526e1025e55dfe5b760086aed4ce77cb9..85bdcdd4e22d79b244dd34d9e532a29db2b486aa 100644
--- a/src/knot/nameserver/chaos.c
+++ b/src/knot/nameserver/chaos.c
@@ -74,7 +74,7 @@ static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner,
 	rdata[0] = response_len;
 	memcpy(&rdata[1], response, response_len);
 
-	int ret = knot_rrset_add_rr(rrset, rdata, response_len + 1, 0, mm);
+	int ret = knot_rrset_add_rdata(rrset, rdata, response_len + 1, 0, mm);
 	if (ret != KNOT_EOK) {
 		knot_dname_free(&rrset->owner, mm);
 		return ret;
diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c
index 9101641ba4f9822213d41d636e8bdac4d6d81b15..18f85a38e820092cd766c67fa77b6ef54c810953 100644
--- a/src/knot/nameserver/internet.c
+++ b/src/knot/nameserver/internet.c
@@ -1,13 +1,30 @@
+/*  Copyright (C) 2013 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 "common/debug.h"
+#include "common/descriptor.h"
+#include "libknot/common.h"
+#include "libknot/rdata/rdname.h"
+#include "libknot/rdata/soa.h"
+#include "libknot/dnssec/rrset-sign.h"
 #include "knot/nameserver/internet.h"
 #include "knot/nameserver/nsec_proofs.h"
 #include "knot/nameserver/process_query.h"
 #include "knot/zone/zonedb.h"
-#include "libknot/common.h"
-#include "libknot/rdata.h"
-#include "common/debug.h"
-#include "common/descriptor.h"
 #include "knot/server/zones.h"
-#include "libknot/dnssec/rrset-sign.h"
 
 /*! \brief Check if given node was already visited. */
 static int wildcard_has_visited(struct query_data *qdata, const knot_node_t *node)
@@ -59,7 +76,7 @@ static int dname_cname_synth(const knot_rrset_t *dname_rr,
 
 	/* Replace last labels of qname with DNAME. */
 	const knot_dname_t *dname_wire = dname_rr->owner;
-	const knot_dname_t *dname_tgt = knot_rrs_dname_target(&dname_rr->rrs);
+	const knot_dname_t *dname_tgt = knot_dname_target(&dname_rr->rrs);
 	int labels = knot_dname_labels(dname_wire, NULL);
 	knot_dname_t *cname = knot_dname_replace_suffix(qname, labels, dname_tgt);
 	if (cname == NULL) {
@@ -73,7 +90,7 @@ static int dname_cname_synth(const knot_rrset_t *dname_rr,
 	memcpy(cname_rdata, cname, cname_size);
 	knot_dname_free(&cname, NULL);
 
-	int ret = knot_rrset_add_rr(cname_rrset, cname_rdata, cname_size,
+	int ret = knot_rrset_add_rdata(cname_rrset, cname_rdata, cname_size,
 	                            knot_rrset_rr_ttl(dname_rr, 0), mm);
 	if (ret != KNOT_EOK) {
 		knot_dname_free(&owner_copy, mm);
@@ -91,7 +108,7 @@ static bool dname_cname_cannot_synth(const knot_rrset_t *rrset, const knot_dname
 {
 	if (knot_dname_labels(qname, NULL)
 		- knot_dname_labels(rrset->owner, NULL)
-		+ knot_dname_labels(knot_rrs_dname_target(&rrset->rrs), NULL)
+		+ knot_dname_labels(knot_dname_target(&rrset->rrs), NULL)
 		> KNOT_DNAME_MAXLABELS) {
 		return true;
 	} else {
@@ -112,8 +129,8 @@ static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type,
                      knot_rrinfo_t *rrinfo,
                      struct query_data *qdata)
 {
-	knot_rrs_t synth_rrs;
-	knot_rrs_init(&synth_rrs);
+	knot_rdataset_t synth_rrs;
+	knot_rdataset_init(&synth_rrs);
 	int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrs, qdata->mm);
 	if (ret == KNOT_ENOENT) {
 		// No signature
@@ -126,7 +143,7 @@ static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type,
 	/* Create rrsig info structure. */
 	struct rrsig_info *info = mm_alloc(qdata->mm, sizeof(struct rrsig_info));
 	if (info == NULL) {
-		knot_rrs_clear(&synth_rrs, qdata->mm);
+		knot_rdataset_clear(&synth_rrs, qdata->mm);
 		return KNOT_ENOMEM;
 	}
 
@@ -134,7 +151,7 @@ static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type,
 	knot_dname_t *owner_copy = knot_dname_copy(sig_owner, qdata->mm);
 	if (owner_copy == NULL) {
 		mm_free(qdata->mm, info);
-		knot_rrs_clear(&synth_rrs, qdata->mm);
+		knot_rdataset_clear(&synth_rrs, qdata->mm);
 		return KNOT_ENOMEM;
 	}
 	knot_rrset_init(&info->synth_rrsig, owner_copy, rrsigs->type, rrsigs->rclass);
@@ -237,7 +254,7 @@ static int put_authority_soa(knot_pkt_t *pkt, struct query_data *qdata,
 	// MINIMUM as TTL
 	int ret = KNOT_EOK;
 	uint32_t flags = KNOT_PF_NOTRUNC;
-	uint32_t min = knot_rrs_soa_minimum(&soa_rrset.rrs);
+	uint32_t min = knot_soa_minimum(&soa_rrset.rrs);
 	if (min < knot_rrset_rr_ttl(&soa_rrset, 0)) {
 		knot_rrset_t copy;
 		knot_dname_t *dname_cpy = knot_dname_copy(soa_rrset.owner, &pkt->mm);
@@ -245,7 +262,7 @@ static int put_authority_soa(knot_pkt_t *pkt, struct query_data *qdata,
 			return KNOT_ENOMEM;
 		}
 		knot_rrset_init(&copy, dname_cpy, soa_rrset.type, soa_rrset.rclass);
-		int ret = knot_rrs_copy(&copy.rrs, &soa_rrset.rrs, &pkt->mm);
+		int ret = knot_rdataset_copy(&copy.rrs, &soa_rrset.rrs, &pkt->mm);
 		if (ret != KNOT_EOK) {
 			knot_dname_free(&dname_cpy, &pkt->mm);
 			return ret;
@@ -392,7 +409,7 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda
 	}
 
 	/* Now follow the next CNAME TARGET. */
-	qdata->name = knot_rrs_cname_name(&cname_rr.rrs);
+	qdata->name = knot_cname_name(&cname_rr.rrs);
 
 #ifdef KNOT_NS_DEBUG
 	char *cname_str = knot_dname_to_str(cname_node->owner);
@@ -699,7 +716,7 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr,
 			return KNOT_ENOMEM;
 		}
 		knot_rrset_init(&to_add, qname_cpy, rr->type, rr->rclass);
-		int ret = knot_rrs_copy(&to_add.rrs, &rr->rrs, &pkt->mm);
+		int ret = knot_rdataset_copy(&to_add.rrs, &rr->rrs, &pkt->mm);
 		if (ret != KNOT_EOK) {
 			knot_dname_free(&qname_cpy, &pkt->mm);
 		}
diff --git a/src/knot/nameserver/ixfr.c b/src/knot/nameserver/ixfr.c
index 422d7aab0e758a2193d31a5888c9ecf1a03b73ca..57f18f5bd759b8f029630d27f89fe39050389c9b 100644
--- a/src/knot/nameserver/ixfr.c
+++ b/src/knot/nameserver/ixfr.c
@@ -3,10 +3,10 @@
 #include "knot/nameserver/internet.h"
 #include "knot/nameserver/process_query.h"
 #include "common/debug.h"
-#include "libknot/rdata.h"
 #include "knot/server/zones.h"
 #include "common/descriptor.h"
 #include "libknot/util/utils.h"
+#include "libknot/rdata/soa.h"
 
 /*! \brief Current IXFR answer sections. */
 enum {
@@ -130,7 +130,7 @@ static int ixfr_load_chsets(knot_changesets_t **chgsets, const zone_t *zone,
 
 	/* Compare serials. */
 	uint32_t serial_to = knot_zone_serial(zone->contents);
-	uint32_t serial_from = knot_rrs_soa_serial(&their_soa->rrs);
+	uint32_t serial_from = knot_soa_serial(&their_soa->rrs);
 	int ret = knot_serial_compare(serial_to, serial_from);
 	if (ret <= 0) { /* We have older/same age zone. */
 		return KNOT_EUPTODATE;
@@ -297,8 +297,8 @@ int ixfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
 		case KNOT_EOK:      /* OK */
 			ixfr = (struct ixfr_proc*)qdata->ext;
 			IXFR_LOG(LOG_INFO, "Started (serial %u -> %u).",
-			         knot_rrs_soa_serial(&ixfr->soa_from->rrs),
-			         knot_rrs_soa_serial(&ixfr->soa_to->rrs));
+			         knot_soa_serial(&ixfr->soa_from->rrs),
+			         knot_soa_serial(&ixfr->soa_to->rrs));
 			break;
 		case KNOT_EUPTODATE: /* Our zone is same age/older, send SOA. */
 			IXFR_LOG(LOG_INFO, "Zone is up-to-date.");
@@ -387,7 +387,7 @@ int ixfr_process_answer(knot_pkt_t *pkt, knot_ns_xfr_t *xfr)
 			// serial
 			uint32_t zone_serial = knot_zone_serial(zone->contents);
 			if (knot_serial_compare(
-			      knot_rrs_soa_serial(&chgsets->first_soa->rrs),
+			      knot_soa_serial(&chgsets->first_soa->rrs),
 			      zone_serial)
 			    > 0) {
 				if ((xfr->flags & XFR_FLAG_UDP) != 0) {
diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c
index 1fa9e4cd71ad0e0539e94ba0d95c29469c002b1b..b0fd02da4a66c3775f57b5068c5d83f070e74ff8 100644
--- a/src/knot/nameserver/nsec_proofs.c
+++ b/src/knot/nameserver/nsec_proofs.c
@@ -4,7 +4,6 @@
 #include "knot/dnssec/zone-nsec.h"
 
 #include "libknot/common.h"
-#include "libknot/rdata.h"
 #include "common/debug.h"
 
 #define DNSSEC_ENABLED 1
@@ -790,7 +789,7 @@ int nsec_append_rrsigs(knot_pkt_t *pkt, struct query_data *qdata, bool optional)
 			break;
 		}
 		/* RRSIG is owned by packet now. */
-		knot_rrs_init(&info->synth_rrsig.rrs);
+		knot_rdataset_init(&info->synth_rrsig.rrs);
 	};
 
 	/* Clear the list. */
diff --git a/src/knot/server/notify.c b/src/knot/server/notify.c
index 5efc59c9debc5c48b7c06102cc3e217733d103ef..ef5e434cf3b52f6e8ba7cba62cb48c3c14ac6eb8 100644
--- a/src/knot/server/notify.c
+++ b/src/knot/server/notify.c
@@ -31,11 +31,11 @@
 #include "common/evsched.h"
 #include "knot/other/debug.h"
 #include "knot/server/server.h"
-#include "libknot/rdata.h"
 #include "knot/nameserver/internet.h"
 #include "common/debug.h"
 #include "knot/nameserver/process_query.h"
 #include "libknot/dnssec/random.h"
+#include "libknot/rdata/soa.h"
 
 /*----------------------------------------------------------------------------*/
 /* API functions                                                              */
@@ -96,7 +96,7 @@ int internet_notify(knot_pkt_t *pkt, struct query_data *qdata)
 	if (answer->count > 0) {
 		const knot_rrset_t *soa = &answer->rr[0];
 		if (soa->type == KNOT_RRTYPE_SOA) {
-			serial = knot_rrs_soa_serial(&soa->rrs);
+			serial = knot_soa_serial(&soa->rrs);
 			dbg_ns("%s: received serial %u\n", __func__, serial);
 		} else { /* Ignore */
 			dbg_ns("%s: NOTIFY answer != SOA_RR\n", __func__);
diff --git a/src/knot/server/serialization.c b/src/knot/server/serialization.c
index 097b0eff07176d07a72b22f0c04c64b2b9d14908..c036f221cd5c51fb5f203a4096d8f060f2e99520 100644
--- a/src/knot/server/serialization.c
+++ b/src/knot/server/serialization.c
@@ -21,10 +21,10 @@
 
 static size_t rr_binary_size(const knot_rrset_t *rrset, size_t rdata_pos)
 {
-	const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, rdata_pos);
+	const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, rdata_pos);
 	if (rr) {
 		// RR size + TTL
-		return knot_rr_rdata_size(rr) + sizeof(uint32_t);
+		return knot_rdata_rdlen(rr) + sizeof(uint32_t);
 	} else {
 		return 0;
 	}
@@ -54,18 +54,18 @@ static uint64_t rrset_binary_size(const knot_rrset_t *rrset)
 static void serialize_rr(const knot_rrset_t *rrset, size_t rdata_pos,
                          uint8_t *stream)
 {
-	const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, rdata_pos);
+	const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, rdata_pos);
 	assert(rr);
-	uint32_t ttl = knot_rr_ttl(rr);
+	uint32_t ttl = knot_rdata_ttl(rr);
 	memcpy(stream, &ttl, sizeof(uint32_t));
-	memcpy(stream + sizeof(uint32_t), knot_rr_rdata(rr), knot_rr_rdata_size(rr));
+	memcpy(stream + sizeof(uint32_t), knot_rdata_data(rr), knot_rdata_rdlen(rr));
 }
 
 static int deserialize_rr(knot_rrset_t *rrset, const uint8_t *stream, uint32_t rdata_size)
 {
 	uint32_t ttl;
 	memcpy(&ttl, stream, sizeof(uint32_t));
-	return knot_rrset_add_rr(rrset, stream + sizeof(uint32_t),
+	return knot_rrset_add_rdata(rrset, stream + sizeof(uint32_t),
 	                         rdata_size - sizeof(uint32_t), ttl, NULL);
 }
 
diff --git a/src/knot/server/serialization.h b/src/knot/server/serialization.h
index 4627d60697e27876abd691a9876d24b25412f86e..cd0f9aa139f7b22bacddc08a90679c625a7f1e3c 100644
--- a/src/knot/server/serialization.h
+++ b/src/knot/server/serialization.h
@@ -1,5 +1,5 @@
 /*!
- * \file rr.h
+ * \file serialization.h
  *
  * \author Jan Kadlec <jan.kadlec@nic.cz>
  *
diff --git a/src/knot/server/zone-load.c b/src/knot/server/zone-load.c
index 6edf5f32284f91277a78b74131e93665f0979521..2be811f1210a29804c9f6b2c4556164e28cf2e33 100644
--- a/src/knot/server/zone-load.c
+++ b/src/knot/server/zone-load.c
@@ -26,7 +26,7 @@
 #include "libknot/dname.h"
 #include "libknot/dnssec/crypto.h"
 #include "libknot/dnssec/random.h"
-#include "libknot/rdata.h"
+#include "libknot/rdata/soa.h"
 #include "knot/zone/zone.h"
 #include "knot/zone/zone.h"
 #include "knot/zone/zonedb.h"
@@ -203,9 +203,9 @@ static void log_zone_load_info(const zone_t *zone, const char *zone_name,
 
 	int64_t serial = 0;
 	if (zone->contents && zone->contents->apex) {
-		const knot_rrs_t *soa = knot_node_rrs(zone->contents->apex,
+		const knot_rdataset_t *soa = knot_node_rdataset(zone->contents->apex,
 		                                      KNOT_RRTYPE_SOA);
-		serial = knot_rrs_soa_serial(soa);
+		serial = knot_soa_serial(soa);
 	}
 
 	log_zone_info("Zone '%s' %s (serial %" PRId64 ")\n", zone_name, action, serial);
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index bd3538966f09d52ebc93d33ab19b62c1add7ea1f..9852b8e47fd2497118f83fbb0de61b57e85ed477 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -31,10 +31,10 @@
 #include "knot/zone/zone-dump.h"
 #include "libknot/dname.h"
 #include "libknot/dnssec/random.h"
+#include "libknot/rdata/soa.h"
 #include "knot/dnssec/zone-events.h"
 #include "knot/dnssec/zone-sign.h"
 #include "knot/nameserver/chaos.h"
-#include "libknot/rdata.h"
 #include "libknot/tsig-op.h"
 #include "knot/updates/changesets.h"
 #include "knot/updates/ddns.h"
@@ -65,7 +65,7 @@ static uint32_t zones_jitter(uint32_t interval)
  * \param rr_func RDATA specificator.
  * \return Timer in miliseconds.
  */
-static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs_t*))
+static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rdataset_t*))
 {
 	if (!zone) {
 		dbg_zones_verb("zones: zones_soa_timer() called "
@@ -76,7 +76,7 @@ static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs
 	uint32_t ret = 0;
 
 	/* Retrieve SOA RDATA. */
-	const knot_rrs_t *soa_rrs = NULL;
+	const knot_rdataset_t *soa_rrs = NULL;
 
 	rcu_read_lock();
 
@@ -86,7 +86,7 @@ static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs
 		return 0;
 	}
 
-	soa_rrs = knot_node_rrs(zc->apex, KNOT_RRTYPE_SOA);
+	soa_rrs = knot_node_rdataset(zc->apex, KNOT_RRTYPE_SOA);
 	assert(soa_rrs != NULL);
 	ret = rr_func(soa_rrs);
 
@@ -104,7 +104,7 @@ static uint32_t zones_soa_timer(zone_t *zone, uint32_t (*rr_func)(const knot_rrs
  */
 static uint32_t zones_soa_refresh(zone_t *zone)
 {
-	return zones_soa_timer(zone, knot_rrs_soa_refresh);
+	return zones_soa_timer(zone, knot_soa_refresh);
 }
 
 /*!
@@ -115,7 +115,7 @@ static uint32_t zones_soa_refresh(zone_t *zone)
  */
 static uint32_t zones_soa_retry(zone_t *zone)
 {
-	return zones_soa_timer(zone, knot_rrs_soa_retry);
+	return zones_soa_timer(zone, knot_soa_retry);
 }
 
 /*!
@@ -126,7 +126,7 @@ static uint32_t zones_soa_retry(zone_t *zone)
  */
 static uint32_t zones_soa_expire(zone_t *zone)
 {
-	return zones_soa_timer(zone, knot_rrs_soa_expire);
+	return zones_soa_timer(zone, knot_soa_expire);
 }
 
 /*!
@@ -509,7 +509,7 @@ int zones_changesets_from_binary(knot_changesets_t *chgsets)
 		dbg_xfr_verb("xfr: reading RRSets to REMOVE, first RR is %hu\n",
 		             rrset->type);
 		assert(rrset->type == KNOT_RRTYPE_SOA);
-		assert(chs->serial_from == knot_rrs_soa_serial(&rrset->rrs));
+		assert(chs->serial_from == knot_soa_serial(&rrset->rrs));
 		knot_changeset_add_soa(chs, rrset, KNOT_CHANGESET_REMOVE);
 
 		/* Read remaining RRSets */
@@ -951,11 +951,11 @@ int zones_zonefile_sync(zone_t *zone, journal_t *journal)
 	}
 
 	/* Latest zone serial. */
-	const knot_rrs_t *soa_rrs = knot_node_rrs(contents->apex,
+	const knot_rdataset_t *soa_rrs = knot_node_rdataset(contents->apex,
 	                                          KNOT_RRTYPE_SOA);
 	assert(soa_rrs != NULL);
 
-	int64_t serial_ret = knot_rrs_soa_serial(soa_rrs);
+	int64_t serial_ret = knot_soa_serial(soa_rrs);
 	if (serial_ret < 0) {
 		rcu_read_unlock();
 		pthread_mutex_unlock(&zone->lock);
@@ -1836,10 +1836,10 @@ int zones_journal_apply(zone_t *zone)
 	}
 
 	/* Fetch SOA serial. */
-	const knot_rrs_t *soa_rrs = 0;
-	soa_rrs = knot_node_rrs(contents->apex, KNOT_RRTYPE_SOA);
+	const knot_rdataset_t *soa_rrs = 0;
+	soa_rrs = knot_node_rdataset(contents->apex, KNOT_RRTYPE_SOA);
 	assert(soa_rrs != NULL);
-	int64_t serial_ret = knot_rrs_soa_serial(soa_rrs);
+	int64_t serial_ret = knot_soa_serial(soa_rrs);
 	if (serial_ret < 0) {
 		rcu_read_unlock();
 		return KNOT_EINVAL;
diff --git a/src/knot/updates/acl.c b/src/knot/updates/acl.c
index 595915e700093028898c83e837f6ad74f2e5cf5f..3be5a74e0dfa5ba662bac5a79b1fa33c741a9ca1 100644
--- a/src/knot/updates/acl.c
+++ b/src/knot/updates/acl.c
@@ -25,7 +25,7 @@
 #include "common/errcode.h"
 #include "knot/updates/acl.h"
 #include "libknot/util/endian.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 
 static inline uint32_t ipv4_chunk(const struct sockaddr_in *ipv4)
 {
diff --git a/src/knot/updates/acl.h b/src/knot/updates/acl.h
index 64fa3b63c21cc2b0f2e743a3d48fb6dca2a66216..21219030cba24a3d35853a58546603dc4a35c897 100644
--- a/src/knot/updates/acl.h
+++ b/src/knot/updates/acl.h
@@ -33,7 +33,7 @@
 #include "common/lists.h"
 #include "common/sockaddr.h"
 #include "common/mempattern.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 
 struct knot_tsig_key;
 
diff --git a/src/knot/updates/changesets.c b/src/knot/updates/changesets.c
index 0acb99476a8b1e9062ee1b2e537f8cb4e5af75a8..cf197a5dc9e526f97507c07072c7812d34ad8a9c 100644
--- a/src/knot/updates/changesets.c
+++ b/src/knot/updates/changesets.c
@@ -24,8 +24,8 @@
 #include "common/mempattern.h"
 #include "common/mempool.h"
 #include "libknot/rrset.h"
+#include "libknot/rdata/soa.h"
 #include "common/debug.h"
-#include "libknot/rdata.h"
 
 int knot_changesets_init(knot_changesets_t **changesets)
 {
@@ -131,7 +131,7 @@ static void knot_changeset_store_soa(knot_rrset_t **chg_soa,
                                      uint32_t *chg_serial, knot_rrset_t *soa)
 {
 	*chg_soa = soa;
-	*chg_serial = knot_rrs_soa_serial(&soa->rrs);
+	*chg_serial = knot_soa_serial(&soa->rrs);
 }
 
 void knot_changeset_add_soa(knot_changeset_t *changeset, knot_rrset_t *soa,
diff --git a/src/knot/updates/ddns.c b/src/knot/updates/ddns.c
index f8637a7f36d7863f1e38bc0eb2d2de9ce6c52579..b3ffdd71733c444c1e82bb45ac928a2bb98917fc 100644
--- a/src/knot/updates/ddns.c
+++ b/src/knot/updates/ddns.c
@@ -22,11 +22,11 @@
 #include "knot/updates/changesets.h"
 #include "knot/updates/xfr-in.h"
 #include "knot/zone/semantic-check.h"
-#include "libknot/rdata.h"
 #include "common/debug.h"
 #include "libknot/packet/pkt.h"
 #include "libknot/common.h"
 #include "libknot/consts.h"
+#include "libknot/rdata/soa.h"
 #include "common/mempattern.h"
 #include "common/descriptor.h"
 #include "common/lists.h"
@@ -53,7 +53,7 @@ static int add_rr_to_list(list_t *l, const knot_rrset_t *rr)
 		ptrnode_t *ptr_n = (ptrnode_t *)n;
 		knot_rrset_t *rrset = (knot_rrset_t *)ptr_n->d;
 		if (knot_rrset_equal(rr, rrset, KNOT_RRSET_COMPARE_HEADER)) {
-			return knot_rrs_merge(&rrset->rrs, &rr->rrs, NULL);
+			return knot_rdataset_merge(&rrset->rrs, &rr->rrs, NULL);
 		}
 	};
 
@@ -372,14 +372,14 @@ static bool node_empty(const knot_node_t *node, knot_dname_t *owner,
 		knot_rrset_t node_rr;
 		knot_rrset_init(&node_rr, node->owner, node_rrset.type, KNOT_CLASS_IN);
 		for (uint16_t j = 0; j < node_rrset.rrs.rr_count; ++j) {
-			knot_rr_t *add_rr = knot_rrs_rr(&node_rrset.rrs, j);
-			knot_rrs_add_rr(&node_rr.rrs, add_rr, NULL);
+			knot_rdata_t *add_rr = knot_rdataset_at(&node_rrset.rrs, j);
+			knot_rdataset_add(&node_rr.rrs, add_rr, NULL);
 			if (!removed_rr(changeset, &node_rr)) {
 				// One of the RRs from node was not removed.
-				knot_rrs_clear(&node_rr.rrs, NULL);
+				knot_rdataset_clear(&node_rr.rrs, NULL);
 				return false;
 			}
-			knot_rrs_clear(&node_rr.rrs, NULL);
+			knot_rdataset_clear(&node_rr.rrs, NULL);
 		}
 	}
 
@@ -390,11 +390,11 @@ static bool node_empty(const knot_node_t *node, knot_dname_t *owner,
 static bool node_contains_rr(const knot_node_t *node,
                              const knot_rrset_t *rr)
 {
-	const knot_rrs_t *zone_rrs = knot_node_rrs(node, rr->type);
+	const knot_rdataset_t *zone_rrs = knot_node_rdataset(node, rr->type);
 	if (zone_rrs) {
 		assert(rr->rrs.rr_count == 1);
 		const bool compare_ttls = false;
-		return knot_rrs_member(zone_rrs, knot_rrs_rr(&rr->rrs, 0),
+		return knot_rdataset_member(zone_rrs, knot_rdataset_at(&rr->rrs, 0),
 		                       compare_ttls);
 	} else {
 		return false;
@@ -437,7 +437,7 @@ static bool skip_soa(const knot_rrset_t *rr, int64_t sn)
 	if (rr->type == KNOT_RRTYPE_SOA
 	    && (rr->rclass == KNOT_CLASS_NONE
 	        || rr->rclass == KNOT_CLASS_ANY
-	        || knot_serial_compare(knot_rrs_soa_serial(&rr->rrs),
+	        || knot_serial_compare(knot_soa_serial(&rr->rrs),
 	                               sn) <= 0)) {
 		return true;
 	}
@@ -539,13 +539,13 @@ static int rem_rrset_to_chgset(const knot_rrset_t *rrset,
 	knot_rrset_t rr;
 	knot_rrset_init(&rr, rrset->owner, rrset->type, rrset->rclass);
 	for (uint16_t i = 0; i < rrset->rrs.rr_count; ++i) {
-		knot_rr_t *rr_add = knot_rrs_rr(&rrset->rrs, i);
-		int ret = knot_rrs_add_rr(&rr.rrs, rr_add, NULL);
+		knot_rdata_t *rr_add = knot_rdataset_at(&rrset->rrs, i);
+		int ret = knot_rdataset_add(&rr.rrs, rr_add, NULL);
 		if (ret != KNOT_EOK) {
 			return ret;
 		}
 		ret = rem_rr_to_chgset(&rr, changeset, apex_ns_rem);
-		knot_rrs_clear(&rr.rrs, NULL);
+		knot_rdataset_clear(&rr.rrs, NULL);
 		if (ret != KNOT_EOK) {
 			return ret;
 		}
@@ -707,7 +707,7 @@ static int process_rem_rr(const knot_rrset_t *rr,
 	const bool apex_ns = knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA) &&
 	                     rr->type == KNOT_RRTYPE_NS;
 	if (apex_ns) {
-		const knot_rrs_t *ns_rrs = knot_node_rrs(node, KNOT_RRTYPE_NS);
+		const knot_rdataset_t *ns_rrs = knot_node_rdataset(node, KNOT_RRTYPE_NS);
 		if (*apex_ns_rem == ns_rrs->rr_count - 1) {
 			// Cannot remove last apex NS RR
 			return KNOT_EOK;
@@ -729,7 +729,7 @@ static int process_rem_rr(const knot_rrset_t *rr,
 
 	knot_rrset_t intersection;
 	knot_rrset_init(&intersection, to_modify.owner, to_modify.type, KNOT_CLASS_IN);
-	int ret = knot_rrs_intersect(&to_modify.rrs, &rr->rrs, &intersection.rrs,
+	int ret = knot_rdataset_intersect(&to_modify.rrs, &rr->rrs, &intersection.rrs,
 	                             NULL);
 	if (ret != KNOT_EOK) {
 		return ret;
@@ -742,7 +742,7 @@ static int process_rem_rr(const knot_rrset_t *rr,
 	assert(intersection.rrs.rr_count == 1);
 	ret = rem_rr_to_chgset(&intersection, changeset,
 	                       apex_ns ? apex_ns_rem : NULL);
-	knot_rrs_clear(&intersection.rrs, NULL);
+	knot_rdataset_clear(&intersection.rrs, NULL);
 	return ret;
 }
 
@@ -1014,7 +1014,7 @@ int knot_ddns_process_update(const knot_zone_contents_t *zone,
 			*rcode = KNOT_RCODE_SERVFAIL;
 			return KNOT_ENOMEM;
 		}
-		knot_rrs_soa_serial_set(&soa_cpy->rrs, new_serial);
+		knot_soa_serial_set(&soa_cpy->rrs, new_serial);
 		knot_changeset_add_soa(changeset, soa_cpy, KNOT_CHANGESET_ADD);
 	}
 
diff --git a/src/knot/updates/xfr-in.c b/src/knot/updates/xfr-in.c
index c29b4aaeb99193cd501623c4d00cb7309dc01f38..973271410946880cce0ffb02ca70c3265a72510e 100644
--- a/src/knot/updates/xfr-in.c
+++ b/src/knot/updates/xfr-in.c
@@ -32,13 +32,13 @@
 #include "libknot/dnssec/random.h"
 #include "libknot/common.h"
 #include "knot/updates/changesets.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "libknot/tsig-op.h"
 #include "knot/zone/semantic-check.h"
 #include "common/lists.h"
 #include "common/descriptor.h"
-#include "libknot/rdata.h"
 #include "libknot/util/utils.h"
+#include "libknot/rdata/soa.h"
 
 #define KNOT_NS_TSIG_FREQ 100
 
@@ -80,8 +80,8 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone,
 	/*
 	 * Retrieve the local Serial
 	 */
-	const knot_rrs_t *soa_rrs =
-		knot_node_rrs(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
+	const knot_rdataset_t *soa_rrs =
+		knot_node_rdataset(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
 	if (soa_rrs == NULL) {
 		char *name = knot_dname_to_str(knot_node_owner(
 				knot_zone_contents_apex(zone)));
@@ -90,7 +90,7 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone,
 		return KNOT_ERROR;
 	}
 
-	uint32_t local_serial = knot_rrs_soa_serial(soa_rrs);
+	uint32_t local_serial = knot_soa_serial(soa_rrs);
 	/*
 	 * Retrieve the remote Serial
 	 */
@@ -104,7 +104,7 @@ int xfrin_transfer_needed(const knot_zone_contents_t *zone,
 		return KNOT_EMALF;
 	}
 
-	uint32_t remote_serial = knot_rrs_soa_serial(&soa_rr.rrs);
+	uint32_t remote_serial = knot_soa_serial(&soa_rr.rrs);
 	return (knot_serial_compare(local_serial, remote_serial) < 0);
 }
 
@@ -457,8 +457,8 @@ int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr)
 				goto cleanup;
 			}
 
-			if (knot_rrs_soa_serial(&rr->rrs)
-			    == knot_rrs_soa_serial(&(*chs)->first_soa->rrs)) {
+			if (knot_soa_serial(&rr->rrs)
+			    == knot_soa_serial(&(*chs)->first_soa->rrs)) {
 
 				/*! \note [TSIG] Check TSIG, we're at the end of
 				 *               transfer.
@@ -534,8 +534,8 @@ int xfrin_process_ixfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr)
 			if (rr->type == KNOT_RRTYPE_SOA) {
 				log_zone_info("%s Serial %u -> %u.\n",
 					      xfr->msg,
-					      knot_rrs_soa_serial(&chset->soa_from->rrs),
-					      knot_rrs_soa_serial(&chset->soa_to->rrs));
+					      knot_soa_serial(&chset->soa_from->rrs),
+					      knot_soa_serial(&chset->soa_to->rrs));
 				state = -1;
 				continue;
 			} else {
@@ -617,7 +617,7 @@ static void xfrin_zone_contents_free(knot_zone_contents_t **contents)
 	dbg_zone("Destroying NSEC3 zone tree.\n");
 	knot_zone_tree_deep_free(&(*contents)->nsec3_nodes);
 
-	knot_nsec3_params_free(&(*contents)->nsec3_params);
+	knot_nsec3param_free(&(*contents)->nsec3_params);
 
 	free(*contents);
 	*contents = NULL;
@@ -673,13 +673,13 @@ static int xfrin_replace_rrs_with_copy(knot_node_t *node,
 	assert(data);
 
 	// Create new data.
-	knot_rrs_t *rrs = &data->rrs;
-	void *copy = malloc(knot_rrs_size(rrs));
+	knot_rdataset_t *rrs = &data->rrs;
+	void *copy = malloc(knot_rdataset_size(rrs));
 	if (copy == NULL) {
 		return KNOT_ENOMEM;
 	}
 
-	memcpy(copy, rrs->data, knot_rrs_size(rrs));
+	memcpy(copy, rrs->data, knot_rdataset_size(rrs));
 
 	/*
 	 * Clear additional array from node in new tree. It's callers
@@ -694,9 +694,9 @@ static int xfrin_replace_rrs_with_copy(knot_node_t *node,
 
 static void clear_new_rrs(knot_node_t *node, uint16_t type)
 {
-	knot_rrs_t *new_rrs = knot_node_get_rrs(node, type);
+	knot_rdataset_t *new_rrs = knot_node_get_rdataset(node, type);
 	if (new_rrs) {
-		knot_rrs_clear(new_rrs, NULL);
+		knot_rdataset_clear(new_rrs, NULL);
 	}
 }
 
@@ -706,7 +706,7 @@ static bool can_remove(const knot_node_t *node, const knot_rrset_t *rr)
 		// Node does not exist, cannot remove anything.
 		return false;
 	}
-	const knot_rrs_t *node_rrs = knot_node_rrs(node, rr->type);
+	const knot_rdataset_t *node_rrs = knot_node_rdataset(node, rr->type);
 	if (node_rrs == NULL) {
 		// Node does not have this type at all.
 		return false;
@@ -714,8 +714,8 @@ static bool can_remove(const knot_node_t *node, const knot_rrset_t *rr)
 
 	const bool compare_ttls = false;
 	for (uint16_t i = 0; i < rr->rrs.rr_count; ++i) {
-		knot_rr_t *rr_cmp = knot_rrs_rr(&rr->rrs, i);
-		if (knot_rrs_member(node_rrs, rr_cmp, compare_ttls)) {
+		knot_rdata_t *rr_cmp = knot_rdataset_at(&rr->rrs, i);
+		if (knot_rdataset_member(node_rrs, rr_cmp, compare_ttls)) {
 			// At least one RR matches.
 			return true;
 		}
@@ -725,7 +725,7 @@ static bool can_remove(const knot_node_t *node, const knot_rrset_t *rr)
 	return false;
 }
 
-static int add_old_data(knot_changeset_t *chset, knot_rr_t *old_data,
+static int add_old_data(knot_changeset_t *chset, knot_rdata_t *old_data,
                         knot_node_t **old_additional)
 {
 	if (ptrlist_add(&chset->old_data, old_data, NULL) == NULL) {
@@ -743,7 +743,7 @@ static int add_old_data(knot_changeset_t *chset, knot_rr_t *old_data,
 	return KNOT_EOK;
 }
 
-static int add_new_data(knot_changeset_t *chset, knot_rr_t *new_data)
+static int add_new_data(knot_changeset_t *chset, knot_rdata_t *new_data)
 {
 	if (ptrlist_add(&chset->new_data, new_data, NULL) == NULL) {
 		return KNOT_ENOMEM;
@@ -756,7 +756,7 @@ static int remove_rr(knot_node_t *node, const knot_rrset_t *rr,
                      knot_changeset_t *chset)
 {
 	knot_rrset_t removed_rrset = knot_node_rrset(node, rr->type);
-	knot_rr_t *old_data = removed_rrset.rrs.data;
+	knot_rdata_t *old_data = removed_rrset.rrs.data;
 	knot_node_t **old_additional = removed_rrset.additional;
 	int ret = xfrin_replace_rrs_with_copy(node, rr->type);
 	if (ret != KNOT_EOK) {
@@ -770,9 +770,9 @@ static int remove_rr(knot_node_t *node, const knot_rrset_t *rr,
 		return ret;
 	}
 
-	knot_rrs_t *changed_rrs = knot_node_get_rrs(node, rr->type);
+	knot_rdataset_t *changed_rrs = knot_node_get_rdataset(node, rr->type);
 	// Subtract changeset RRS from node RRS.
-	ret = knot_rrs_subtract(changed_rrs, &rr->rrs, NULL);
+	ret = knot_rdataset_subtract(changed_rrs, &rr->rrs, NULL);
 	if (ret != KNOT_EOK) {
 		clear_new_rrs(node, rr->type);
 		return ret;
@@ -782,7 +782,7 @@ static int remove_rr(knot_node_t *node, const knot_rrset_t *rr,
 		// Subtraction left some data in RRSet, store it for rollback.
 		ret = add_new_data(chset, changed_rrs->data);
 		if (ret != KNOT_EOK) {
-			knot_rrs_clear(changed_rrs, NULL);
+			knot_rdataset_clear(changed_rrs, NULL);
 			return ret;
 		}
 	} else {
@@ -823,7 +823,7 @@ static int add_rr(knot_node_t *node, const knot_rrset_t *rr,
 	knot_rrset_t changed_rrset = knot_node_rrset(node, rr->type);
 	if (!knot_rrset_empty(&changed_rrset)) {
 		// Modifying existing RRSet.
-		knot_rr_t *old_data = changed_rrset.rrs.data;
+		knot_rdata_t *old_data = changed_rrset.rrs.data;
 		knot_node_t **old_additional = changed_rrset.additional;
 		int ret = xfrin_replace_rrs_with_copy(node, rr->type);
 		if (ret != KNOT_EOK) {
@@ -838,8 +838,8 @@ static int add_rr(knot_node_t *node, const knot_rrset_t *rr,
 		}
 
 		// Extract copy, merge into it
-		knot_rrs_t *changed_rrs = knot_node_get_rrs(node, rr->type);
-		ret = knot_rrs_merge(changed_rrs, &rr->rrs, NULL);
+		knot_rdataset_t *changed_rrs = knot_node_get_rdataset(node, rr->type);
+		ret = knot_rdataset_merge(changed_rrs, &rr->rrs, NULL);
 		if (ret != KNOT_EOK) {
 			clear_new_rrs(node, rr->type);
 			return ret;
@@ -865,10 +865,10 @@ static int add_rr(knot_node_t *node, const knot_rrset_t *rr,
 	}
 
 	// Get changed RRS and store for possible rollback.
-	knot_rrs_t *rrs = knot_node_get_rrs(node, rr->type);
+	knot_rdataset_t *rrs = knot_node_get_rdataset(node, rr->type);
 	int ret = add_new_data(chset, rrs->data);
 	if (ret != KNOT_EOK) {
-		knot_rrs_clear(rrs, NULL);
+		knot_rdataset_clear(rrs, NULL);
 		return ret;
 	}
 
@@ -929,8 +929,8 @@ static int xfrin_apply_changeset(list_t *old_rrs, list_t *new_rrs,
 		  chset->serial_from, chset->serial_to);
 
 	// check if serial matches
-	const knot_rrs_t *soa = knot_node_rrs(contents->apex, KNOT_RRTYPE_SOA);
-	if (soa == NULL || knot_rrs_soa_serial(soa)
+	const knot_rdataset_t *soa = knot_node_rdataset(contents->apex, KNOT_RRTYPE_SOA);
+	if (soa == NULL || knot_soa_serial(soa)
 			   != chset->serial_from) {
 		dbg_xfrin("SOA serials do not match!!\n");
 		return KNOT_EINVAL;
diff --git a/src/knot/zone/node.c b/src/knot/zone/node.c
index fd2dd524ea35faed2b9bdbdb3948d83ced5531a6..dbbfa62b9a5dc9d66b96f8809629b9850bf344f8 100644
--- a/src/knot/zone/node.c
+++ b/src/knot/zone/node.c
@@ -23,8 +23,8 @@
 #include "libknot/common.h"
 #include "knot/zone/node.h"
 #include "libknot/rrset.h"
-#include "libknot/rr.h"
-#include "libknot/rdata.h"
+#include "libknot/rdataset.h"
+#include "libknot/rdata/rrsig.h"
 #include "common/descriptor.h"
 #include "common/debug.h"
 #include "common/mempattern.h"
@@ -71,13 +71,13 @@ static inline void knot_node_flags_clear(knot_node_t *node, uint8_t flag)
 
 static void rr_data_clear(struct rr_data *data, mm_ctx_t *mm)
 {
-	knot_rrs_clear(&data->rrs, mm);
+	knot_rdataset_clear(&data->rrs, mm);
 	free(data->additional);
 }
 
 static int rr_data_from(const knot_rrset_t *rrset, struct rr_data *data, mm_ctx_t *mm)
 {
-	int ret = knot_rrs_copy(&data->rrs, &rrset->rrs, mm);
+	int ret = knot_rdataset_copy(&data->rrs, &rrset->rrs, mm);
 	if (ret != KNOT_EOK) {
 		return ret;
 	}
@@ -152,14 +152,14 @@ int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset,  bool *ttl
 			/* Check if the added RR has the same TTL as the first
 			 * RR in the RRSet.
 			 */
-			knot_rr_t *first = knot_rrs_rr(&node_data->rrs, 0);
+			knot_rdata_t *first = knot_rdataset_at(&node_data->rrs, 0);
 			uint32_t inserted_ttl = knot_rrset_rr_ttl(rrset, 0);
 			if (ttl_err && rrset->type != KNOT_RRTYPE_RRSIG &&
-			    inserted_ttl != knot_rr_ttl(first)) {
+			    inserted_ttl != knot_rdata_ttl(first)) {
 				*ttl_err = true;
 			}
 
-			return knot_rrs_merge(&node_data->rrs, &rrset->rrs, NULL);
+			return knot_rdataset_merge(&node_data->rrs, &rrset->rrs, NULL);
 		}
 	}
 
@@ -169,12 +169,12 @@ int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset,  bool *ttl
 
 /*----------------------------------------------------------------------------*/
 
-const knot_rrs_t *knot_node_rrs(const knot_node_t *node, uint16_t type)
+const knot_rdataset_t *knot_node_rdataset(const knot_node_t *node, uint16_t type)
 {
-	return (const knot_rrs_t *)knot_node_get_rrs(node, type);
+	return (const knot_rdataset_t *)knot_node_get_rdataset(node, type);
 }
 
-knot_rrs_t *knot_node_get_rrs(const knot_node_t *node, uint16_t type)
+knot_rdataset_t *knot_node_get_rdataset(const knot_node_t *node, uint16_t type)
 {
 	if (node == NULL) {
 		return NULL;
@@ -610,7 +610,7 @@ bool knot_node_rrtype_is_signed(const knot_node_t *node, uint16_t type)
 		return false;
 	}
 
-	const knot_rrs_t *rrsigs = knot_node_rrs(node, KNOT_RRTYPE_RRSIG);
+	const knot_rdataset_t *rrsigs = knot_node_rdataset(node, KNOT_RRTYPE_RRSIG);
 	if (rrsigs == NULL) {
 		return false;
 	}
@@ -618,7 +618,7 @@ bool knot_node_rrtype_is_signed(const knot_node_t *node, uint16_t type)
 	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);
+			knot_rrsig_type_covered(rrsigs, i);
 		if (type_covered == type) {
 			return true;
 		}
@@ -629,5 +629,5 @@ bool knot_node_rrtype_is_signed(const knot_node_t *node, uint16_t type)
 
 bool knot_node_rrtype_exists(const knot_node_t *node, uint16_t type)
 {
-	return knot_node_rrs(node, type) != NULL;
+	return knot_node_rdataset(node, type) != NULL;
 }
diff --git a/src/knot/zone/node.h b/src/knot/zone/node.h
index 51dbf2d3e4a4a3ffcaca7e003fdb52818c332cfe..c6abc10be3c3ce2111c395d443e899a2813a1fd6 100644
--- a/src/knot/zone/node.h
+++ b/src/knot/zone/node.h
@@ -31,7 +31,7 @@
 #include "common/descriptor.h"
 #include "libknot/dname.h"
 #include "libknot/rrset.h"
-#include "libknot/rr.h"
+#include "libknot/rdataset.h"
 
 struct rr_data;
 
@@ -82,7 +82,7 @@ typedef struct knot_node knot_node_t;
 /*!< \brief Structure storing RR data. */
 struct rr_data {
 	uint16_t type; /*!< \brief RR type of data. */
-	knot_rrs_t rrs; /*!< \brief Data of given type. */
+	knot_rdataset_t rrs; /*!< \brief Data of given type. */
 	knot_node_t **additional; /*!< \brief Additional nodes with glues. */
 };
 
@@ -132,8 +132,8 @@ knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent,
  */
 int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset, bool *ttl_err);
 
-const knot_rrs_t *knot_node_rrs(const knot_node_t *node, uint16_t type);
-knot_rrs_t *knot_node_get_rrs(const knot_node_t *node, uint16_t type);
+const knot_rdataset_t *knot_node_rdataset(const knot_node_t *node, uint16_t type);
+knot_rdataset_t *knot_node_get_rdataset(const knot_node_t *node, uint16_t type);
 
 /*!
  * \brief Returns the RRSet of the given type from the node (non-const version).
diff --git a/src/knot/zone/semantic-check.c b/src/knot/zone/semantic-check.c
index ffa7f4f16706e8cca7d326c5447b18f809b833ca..ae0c40f317b0ed26cfc610cc3ccb3bb59c1212bf 100644
--- a/src/knot/zone/semantic-check.c
+++ b/src/knot/zone/semantic-check.c
@@ -26,11 +26,14 @@
 #include "libknot/libknot.h"
 #include "libknot/dnssec/key.h"
 #include "libknot/dnssec/rrset-sign.h"
+#include "libknot/rdata/rrsig.h"
+#include "libknot/rdata/soa.h"
+#include "libknot/rdata/nsec.h"
+#include "libknot/rdata/nsec3.h"
 #include "common/base32hex.h"
 #include "common/crc.h"
 #include "common/descriptor.h"
 #include "common/mempattern.h"
-#include "libknot/rdata.h"
 #include "knot/dnssec/zone-nsec.h"
 
 #include "knot/zone/semantic-check.h"
@@ -286,7 +289,7 @@ static int check_dnskey_rdata(const knot_rrset_t *rrset, size_t rdata_pos)
  */
 static int check_rrsig_rdata(err_handler_t *handler,
                              const knot_node_t *node,
-                             const knot_rrs_t *rrsig,
+                             const knot_rdataset_t *rrsig,
                              size_t rr_pos,
                              const knot_rrset_t *rrset,
                              const knot_rrset_t *dnskey_rrset)
@@ -300,14 +303,14 @@ static int check_rrsig_rdata(err_handler_t *handler,
 		return KNOT_ENOMEM;
 	}
 
-	if (knot_rrs_rrsig_type_covered(rrsig, 0) != rrset->type) {
+	if (knot_rrsig_type_covered(rrsig, 0) != rrset->type) {
 		err_handler_handle_error(handler, node,
 		                         ZC_ERR_RRSIG_RDATA_TYPE_COVERED,
 		                         info_str);
 	}
 
 	/* label number at the 2nd index should be same as owner's */
-	uint8_t labels_rdata = knot_rrs_rrsig_labels(rrsig, rr_pos);
+	uint8_t labels_rdata = knot_rrsig_labels(rrsig, rr_pos);
 
 	int tmp = knot_dname_labels(rrset->owner, NULL) - labels_rdata;
 
@@ -327,7 +330,7 @@ static int check_rrsig_rdata(err_handler_t *handler,
 	}
 
 	/* check original TTL */
-	uint32_t original_ttl = knot_rrs_rrsig_original_ttl(rrsig, rr_pos);
+	uint32_t original_ttl = knot_rrsig_original_ttl(rrsig, rr_pos);
 
 	uint16_t rr_count = knot_rrset_rr_count(rrset);
 	for (uint16_t i = 0; i < rr_count; ++i) {
@@ -339,7 +342,7 @@ static int check_rrsig_rdata(err_handler_t *handler,
 	}
 
 	/* Check for expired signature. */
-	if (knot_rrs_rrsig_sig_expiration(rrsig, rr_pos) < time(NULL)) {
+	if (knot_rrsig_sig_expiration(rrsig, rr_pos) < time(NULL)) {
 		err_handler_handle_error(handler, node,
 		                         ZC_ERR_RRSIG_RDATA_EXPIRATION,
 		                         info_str);
@@ -353,7 +356,7 @@ static int check_rrsig_rdata(err_handler_t *handler,
 
 	/* signer's name is same as in the zone apex */
 	const knot_dname_t *signer_name =
-		knot_rrs_rrsig_signer_name(rrsig, rr_pos);
+		knot_rrsig_signer_name(rrsig, rr_pos);
 
 	/* dnskey is in the apex node */
 	if (!knot_rrset_empty(dnskey_rrset) &&
@@ -368,12 +371,12 @@ static int check_rrsig_rdata(err_handler_t *handler,
 	 * before */
 
 	int match = 0;
-	uint8_t rrsig_alg = knot_rrs_rrsig_algorithm(rrsig, rr_pos);
-	uint16_t key_tag_rrsig = knot_rrs_rrsig_key_tag(rrsig, rr_pos);
+	uint8_t rrsig_alg = knot_rrsig_algorithm(rrsig, rr_pos);
+	uint16_t key_tag_rrsig = knot_rrsig_key_tag(rrsig, rr_pos);
 	for (uint16_t i = 0; i < knot_rrset_rr_count(dnskey_rrset) &&
 	     !match; ++i) {
 		uint8_t dnskey_alg =
-			knot_rrs_dnskey_alg(&dnskey_rrset->rrs, i);
+			knot_dnskey_alg(&dnskey_rrset->rrs, i);
 		if (rrsig_alg != dnskey_alg) {
 			continue;
 		}
@@ -432,10 +435,10 @@ static int check_rrsig_in_rrset(err_handler_t *handler,
 	if (ret < 0 || ret >= sizeof(info_str)) {
 		return KNOT_ENOMEM;
 	}
-	knot_rrs_t rrsigs;
-	knot_rrs_init(&rrsigs);
+	knot_rdataset_t rrsigs;
+	knot_rdataset_init(&rrsigs);
 	ret = knot_synth_rrsig(rrset->type,
-	                           knot_node_rrs(node, KNOT_RRTYPE_RRSIG),
+	                           knot_node_rdataset(node, KNOT_RRTYPE_RRSIG),
 	                           &rrsigs, NULL);
 	if (ret != KNOT_EOK) {
 		if (ret != KNOT_ENOENT) {
@@ -458,8 +461,8 @@ static int check_rrsig_in_rrset(err_handler_t *handler,
 		/* Safe to continue, nothing is malformed. */
 	}
 
-	const knot_rr_t *sig_rr = knot_rrs_rr(&rrsigs, 0);
-	if (knot_rrset_rr_ttl(rrset, 0) != knot_rr_ttl(sig_rr)) {
+	const knot_rdata_t *sig_rr = knot_rdataset_at(&rrsigs, 0);
+	if (knot_rrset_rr_ttl(rrset, 0) != knot_rdata_ttl(sig_rr)) {
 		err_handler_handle_error(handler, node,
 		                         ZC_ERR_RRSIG_TTL,
 		                         info_str);
@@ -475,7 +478,7 @@ static int check_rrsig_in_rrset(err_handler_t *handler,
 		}
 	}
 
-	knot_rrs_clear(&rrsigs, NULL);
+	knot_rdataset_clear(&rrsigs, NULL);
 	return ret;
 }
 
@@ -506,7 +509,7 @@ static int get_bit(uint8_t *bits, size_t index)
  * \retval KNOT_OK on success.
  * \retval KNOT_NOMEM on memory error.
  */
-static int rdata_nsec_to_type_array(const knot_rrs_t *rrs, uint16_t type,
+static int rdata_nsec_to_type_array(const knot_rdataset_t *rrs, uint16_t type,
                                     size_t pos, uint16_t **array, size_t *count)
 {
 	assert(*array == NULL);
@@ -514,9 +517,9 @@ static int rdata_nsec_to_type_array(const knot_rrs_t *rrs, uint16_t type,
 	uint8_t *data = NULL;
 	uint16_t rr_bitmap_size = 0;
 	if (type == KNOT_RRTYPE_NSEC) {
-		knot_rrs_nsec_bitmap(rrs, &data, &rr_bitmap_size);
+		knot_nsec_bitmap(rrs, &data, &rr_bitmap_size);
 	} else {
-		knot_rrs_nsec3_bitmap(rrs, pos, &data, &rr_bitmap_size);
+		knot_nsec3_bitmap(rrs, pos, &data, &rr_bitmap_size);
 	}
 	if (data == NULL) {
 		return KNOT_EMALF;
@@ -614,14 +617,14 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 
 			assert(nsec3_previous);
 
-			const knot_rrs_t *previous_rrs =
-				knot_node_rrs(nsec3_previous, KNOT_RRTYPE_NSEC3);
+			const knot_rdataset_t *previous_rrs =
+				knot_node_rdataset(nsec3_previous, KNOT_RRTYPE_NSEC3);
 
 			assert(previous_rrs);
 
 			/* check for Opt-Out flag */
 			uint8_t flags =
-				knot_rrs_nsec3_flags(previous_rrs, 0);
+				knot_nsec3_flags(previous_rrs, 0);
 			uint8_t opt_out_mask = 1;
 
 			if (!(flags & opt_out_mask)) {
@@ -634,7 +637,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 		}
 	}
 
-	const knot_rrs_t *nsec3_rrs = knot_node_rrs(nsec3_node,
+	const knot_rdataset_t *nsec3_rrs = knot_node_rdataset(nsec3_node,
 	                                            KNOT_RRTYPE_NSEC3);
 	if (nsec3_rrs == NULL) {
 		err_handler_handle_error(handler, node,
@@ -642,11 +645,11 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 		return KNOT_EOK;
 	}
 
-	const knot_rr_t *nsec3_rr = knot_rrs_rr(nsec3_rrs, 0);
-	const knot_rrs_t *soa_rrs = knot_node_rrs(zone->apex, KNOT_RRTYPE_SOA);
+	const knot_rdata_t *nsec3_rr = knot_rdataset_at(nsec3_rrs, 0);
+	const knot_rdataset_t *soa_rrs = knot_node_rdataset(zone->apex, KNOT_RRTYPE_SOA);
 	assert(soa_rrs);
-	uint32_t minimum_ttl = knot_rrs_soa_minimum(soa_rrs);
-	if (knot_rr_ttl(nsec3_rr) != minimum_ttl) {
+	uint32_t minimum_ttl = knot_soa_minimum(soa_rrs);
+	if (knot_rdata_ttl(nsec3_rr) != minimum_ttl) {
 		err_handler_handle_error(handler, node,
 		                         ZC_ERR_NSEC3_RDATA_TTL, NULL);
 	}
@@ -655,7 +658,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 	const knot_node_t *apex = knot_zone_contents_apex(zone);
 	uint8_t *next_dname_str = NULL;
 	uint8_t next_dname_size = 0;
-	knot_rrs_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str,
+	knot_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str,
 	                           &next_dname_size);
 	knot_dname_t *next_dname = knot_nsec3_hash_to_dname(next_dname_str,
 	                                                    next_dname_size,
@@ -715,7 +718,7 @@ static int check_nsec3_node_in_zone(knot_zone_contents_t *zone,
 static int sem_check_node_mandatory(const knot_node_t *node,
                                     err_handler_t *handler, bool *fatal_error)
 {
-	const knot_rrs_t *cname_rrs = knot_node_rrs(node, KNOT_RRTYPE_CNAME);
+	const knot_rdataset_t *cname_rrs = knot_node_rdataset(node, KNOT_RRTYPE_CNAME);
 	if (cname_rrs) {
 		if (knot_node_rrset_count(node) != 1) {
 			/* With DNSSEC node can contain RRSIGs or NSEC */
@@ -735,7 +738,7 @@ static int sem_check_node_mandatory(const knot_node_t *node,
 		}
 	}
 
-	const knot_rrs_t *dname_rrs = knot_node_rrs(node, KNOT_RRTYPE_DNAME);
+	const knot_rdataset_t *dname_rrs = knot_node_rdataset(node, KNOT_RRTYPE_DNAME);
 	if (dname_rrs) {
 		if (cname_rrs) {
 			*fatal_error = true;
@@ -770,7 +773,7 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone,
 	                node)) {
 		return KNOT_EOK;
 	}
-	const knot_rrs_t *ns_rrs = knot_node_rrs(node, KNOT_RRTYPE_NS);
+	const knot_rdataset_t *ns_rrs = knot_node_rdataset(node, KNOT_RRTYPE_NS);
 	if (ns_rrs == NULL) {
 		err_handler_handle_error(handler, node,
 		                         ZC_ERR_MISSING_NS_DEL_POINT,
@@ -780,7 +783,7 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone,
 
 	for (int i = 0; i < ns_rrs->rr_count; ++i) {
 		const knot_dname_t *ns_dname =
-			knot_rrs_ns_name(ns_rrs, i);
+			knot_ns_name(ns_rrs, i);
 		const knot_node_t *glue_node =
 			knot_zone_contents_find_node(zone, ns_dname);
 
@@ -792,7 +795,7 @@ static int sem_check_node_optional(const knot_zone_contents_t *zone,
 				memcpy(wildcard, "\x1""*", 2);
 				knot_dname_to_wire(wildcard + 2,
 				                   knot_wire_next_label(ns_dname, NULL),
-				                   sizeof(wildcard));
+				                   sizeof(wildcard) - 2);
 				const knot_node_t *wildcard_node =
 					knot_zone_contents_find_node(zone,
 				                                     wildcard);
@@ -889,8 +892,8 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone,
 
 		if (!nsec3 && auth) {
 			/* check for NSEC record */
-			const knot_rrs_t *nsec_rrs =
-				knot_node_rrs(node, KNOT_RRTYPE_NSEC);
+			const knot_rdataset_t *nsec_rrs =
+				knot_node_rdataset(node, KNOT_RRTYPE_NSEC);
 			if (nsec_rrs == NULL) {
 				err_handler_handle_error(handler, node,
 				                         ZC_ERR_NO_NSEC, NULL);
@@ -940,7 +943,7 @@ static int semantic_checks_dnssec(knot_zone_contents_t *zone,
 			 * the next link in each node.
 			 */
 			const knot_dname_t *next_domain =
-				knot_rrs_nsec_next(nsec_rrs);
+				knot_nsec_next(nsec_rrs);
 			// Convert name to lowercase for trie lookup
 			knot_dname_t *lowercase = knot_dname_copy(next_domain, NULL);
 			if (lowercase == NULL) {
@@ -1062,8 +1065,8 @@ void log_cyclic_errors_in_zone(err_handler_t *handler,
 		if (last_nsec3_node == NULL || first_nsec3_node == NULL) {
 			return;
 		}
-		const knot_rrs_t *nsec3_rrs =
-			knot_node_rrs(last_nsec3_node, KNOT_RRTYPE_NSEC3);
+		const knot_rdataset_t *nsec3_rrs =
+			knot_node_rdataset(last_nsec3_node, KNOT_RRTYPE_NSEC3);
 		if (nsec3_rrs == NULL) {
 			err_handler_handle_error(handler, last_nsec3_node,
 						 ZC_ERR_NSEC3_RDATA_CHAIN, NULL);
@@ -1074,7 +1077,7 @@ void log_cyclic_errors_in_zone(err_handler_t *handler,
 		const knot_node_t *apex = knot_zone_contents_apex(zone);
 		uint8_t *next_dname_str = NULL;
 		uint8_t next_dname_size = 0;
-		knot_rrs_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str,
+		knot_nsec3_next_hashed(nsec3_rrs, 0, &next_dname_str,
 		                           &next_dname_size);
 		knot_dname_t *next_dname = knot_nsec3_hash_to_dname(next_dname_str,
 		                                                    next_dname_size,
@@ -1105,8 +1108,8 @@ void log_cyclic_errors_in_zone(err_handler_t *handler,
 				ZC_ERR_NSEC_RDATA_CHAIN_NOT_CYCLIC, NULL);
 				return;
 		} else {
-			const knot_rrs_t *nsec_rrs =
-				knot_node_rrs(last_node, KNOT_RRTYPE_NSEC);
+			const knot_rdataset_t *nsec_rrs =
+				knot_node_rdataset(last_node, KNOT_RRTYPE_NSEC);
 
 			if (nsec_rrs == NULL) {
 				err_handler_handle_error(handler, last_node,
@@ -1114,7 +1117,7 @@ void log_cyclic_errors_in_zone(err_handler_t *handler,
 				return;
 			}
 
-			const knot_dname_t *next_dname = knot_rrs_nsec_next(nsec_rrs);
+			const knot_dname_t *next_dname = knot_nsec_next(nsec_rrs);
 			assert(next_dname);
 
 			const knot_dname_t *apex_dname =
diff --git a/src/knot/zone/zone-contents.c b/src/knot/zone/zone-contents.c
index 00227537f37e90a1b0fb8c6c8af5b928583fbdb3..bb3097f8452e1feaacb7fe19d3a358240f5a1e5e 100644
--- a/src/knot/zone/zone-contents.c
+++ b/src/knot/zone/zone-contents.c
@@ -27,7 +27,10 @@
 #include "knot/zone/zone-tree.h"
 #include "libknot/packet/wire.h"
 #include "libknot/consts.h"
-#include "libknot/rdata.h"
+#include "libknot/rdata/rrsig.h"
+#include "libknot/rdata/nsec3.h"
+#include "libknot/rdata/soa.h"
+#include "libknot/rdata/rdname.h"
 
 /*----------------------------------------------------------------------------*/
 /* Non-API functions                                                          */
@@ -157,7 +160,7 @@ static int discover_additionals(struct rr_data *rr_data,
 {
 	const knot_node_t *node = NULL, *encloser = NULL, *prev = NULL;
 	const knot_dname_t *dname = NULL;
-	const knot_rrs_t *rrs = &rr_data->rrs;
+	const knot_rdataset_t *rrs = &rr_data->rrs;
 
 	/* Create new additional nodes. */
 	uint16_t rdcount = rrs->rr_count;
@@ -173,7 +176,7 @@ static int discover_additionals(struct rr_data *rr_data,
 	for (uint16_t i = 0; i < rdcount; i++) {
 
 		/* Try to find node for the dname in the RDATA. */
-		dname = knot_rrs_name(rrs, i, rr_data->type);
+		dname = knot_rdata_name(rrs, i, rr_data->type);
 		knot_zone_contents_find_dname(zone, dname, &node, &encloser, &prev);
 		if (node == NULL && encloser
 		    && knot_node_has_wildcard_child(encloser)) {
@@ -393,7 +396,7 @@ static int knot_zone_contents_find_in_tree(knot_zone_tree_t *tree,
 
 /*----------------------------------------------------------------------------*/
 
-static int knot_zc_nsec3_parameters_match(const knot_rrs_t *rrs,
+static int knot_zc_nsec3_parameters_match(const knot_rdataset_t *rrs,
                                           const knot_nsec3_params_t *params,
                                           size_t rdata_pos)
 {
@@ -401,19 +404,19 @@ static int knot_zc_nsec3_parameters_match(const knot_rrs_t *rrs,
 
 	dbg_zone_detail("RDATA algo: %u, iterations: %u, salt length: %u, salt:"
 			" %.*s\n",
-			knot_rrs_nsec3_algorithm(rrs, rdata_pos),
-			knot_rrs_nsec3_iterations(rrs, rdata_pos),
-			knot_rrs_nsec3_salt_length(rrs, rdata_pos),
-			knot_rrs_nsec3_salt_length(rrs, rdata_pos),
-			knot_rrs_nsec3_salt(rrs, rdata_pos));
+			knot_nsec3_algorithm(rrs, rdata_pos),
+			knot_nsec3_iterations(rrs, rdata_pos),
+			knot_nsec3_salt_length(rrs, rdata_pos),
+			knot_nsec3_salt_length(rrs, rdata_pos),
+			knot_nsec3_salt(rrs, rdata_pos));
 	dbg_zone_detail("NSEC3PARAM algo: %u, iterations: %u, salt length: %u, "
 			"salt: %.*s\n",  params->algorithm, params->iterations,
 			params->salt_length, params->salt_length, params->salt);
 
-	return (knot_rrs_nsec3_algorithm(rrs, rdata_pos) == params->algorithm
-		&& knot_rrs_nsec3_iterations(rrs, rdata_pos) == params->iterations
-		&& knot_rrs_nsec3_salt_length(rrs, rdata_pos) == params->salt_length
-		&& strncmp((const char *)knot_rrs_nsec3_salt(rrs, rdata_pos),
+	return (knot_nsec3_algorithm(rrs, rdata_pos) == params->algorithm
+		&& knot_nsec3_iterations(rrs, rdata_pos) == params->iterations
+		&& knot_nsec3_salt_length(rrs, rdata_pos) == params->salt_length
+		&& strncmp((const char *)knot_nsec3_salt(rrs, rdata_pos),
 			   (const char *)params->salt, params->salt_length)
 		   == 0);
 }
@@ -797,7 +800,7 @@ static bool rrset_is_nsec3rel(const knot_rrset_t *rr)
 	/* Is NSEC3 or non-empty RRSIG covering NSEC3. */
 	return ((rr->type == KNOT_RRTYPE_NSEC3)
 	        || (rr->type == KNOT_RRTYPE_RRSIG
-	            && knot_rrs_rrsig_type_covered(&rr->rrs, 0)
+	            && knot_rrsig_type_covered(&rr->rrs, 0)
 	            == KNOT_RRTYPE_NSEC3));
 }
 
@@ -1063,8 +1066,8 @@ dbg_zone_exec_detail(
 	 * from the right chain. Check iterations, hash algorithm and salt
 	 * values and compare them to the ones from NSEC3PARAM.
 	 */
-	const knot_rrs_t *nsec3_rrs =
-		knot_node_rrs(*nsec3_previous, KNOT_RRTYPE_NSEC3);
+	const knot_rdataset_t *nsec3_rrs =
+		knot_node_rdataset(*nsec3_previous, KNOT_RRTYPE_NSEC3);
 	assert(nsec3_rrs);
 	const knot_node_t *original_prev = *nsec3_previous;
 
@@ -1088,7 +1091,7 @@ dbg_zone_exec_detail(
 
 		/* This RRSET was not a match, try the one from previous node. */
 		*nsec3_previous = knot_node_previous(*nsec3_previous);
-		nsec3_rrs = knot_node_rrs(*nsec3_previous, KNOT_RRTYPE_NSEC3);
+		nsec3_rrs = knot_node_rdataset(*nsec3_previous, KNOT_RRTYPE_NSEC3);
 		dbg_zone_exec_detail(
 		char *name = (*nsec3_previous)
 				? knot_dname_to_str(
@@ -1289,9 +1292,9 @@ int knot_zone_contents_load_nsec3param(knot_zone_contents_t *zone)
 		return KNOT_EINVAL;
 	}
 
-	const knot_rrs_t *rrs = knot_node_rrs(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
+	const knot_rdataset_t *rrs = knot_node_rdataset(zone->apex, KNOT_RRTYPE_NSEC3PARAM);
 	if (rrs!= NULL) {
-		int r = knot_nsec3_params_from_wire(&zone->nsec3_params, rrs);
+		int r = knot_nsec3param_from_wire(&zone->nsec3_params, rrs);
 		if (r != KNOT_EOK) {
 			dbg_zone("Failed to load NSEC3PARAM (%s).\n",
 			         knot_strerror(r));
@@ -1415,7 +1418,7 @@ void knot_zone_contents_free(knot_zone_contents_t **contents)
 	dbg_zone("Destroying NSEC3 zone tree.\n");
 	knot_zone_tree_free(&(*contents)->nsec3_nodes);
 
-	knot_nsec3_params_free(&(*contents)->nsec3_params);
+	knot_nsec3param_free(&(*contents)->nsec3_params);
 
 	free(*contents);
 	*contents = NULL;
@@ -1451,9 +1454,9 @@ void knot_zone_contents_deep_free(knot_zone_contents_t **contents)
 uint32_t knot_zone_serial(const knot_zone_contents_t *zone)
 {
 	if (!zone) return 0;
-	const knot_rrs_t *soa = NULL;
-	soa = knot_node_rrs(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
-	uint32_t serial = knot_rrs_soa_serial(soa);
+	const knot_rdataset_t *soa = NULL;
+	soa = knot_node_rdataset(knot_zone_contents_apex(zone), KNOT_RRTYPE_SOA);
+	uint32_t serial = knot_soa_serial(soa);
 	return serial;
 }
 
diff --git a/src/knot/zone/zone-contents.h b/src/knot/zone/zone-contents.h
index 0233e4b778949b98cf92aaa8e83f9f862dbc8477..f25c8c3e3b2801a9e22a63b2cb2bb16ba668377b 100644
--- a/src/knot/zone/zone-contents.h
+++ b/src/knot/zone/zone-contents.h
@@ -27,10 +27,9 @@
 #ifndef _KNOT_ZONE_CONTENTS_H_
 #define _KNOT_ZONE_CONTENTS_H_
 
-#include "knot/zone/node.h"
-#include "libknot/dnssec/nsec3.h"
 #include "common/lists.h"
-
+#include "libknot/rdata/nsec3param.h"
+#include "knot/zone/node.h"
 #include "knot/zone/zone-tree.h"
 
 struct zone_t;
diff --git a/src/knot/zone/zone-create.c b/src/knot/zone/zone-create.c
index 0fd0301b631ea355acb4b9bc6afa94e3816b04e6..938e5da0d4f5028f1d6b5122d232081581202f3d 100644
--- a/src/knot/zone/zone-create.c
+++ b/src/knot/zone/zone-create.c
@@ -34,7 +34,6 @@
 #include "knot/other/debug.h"
 #include "knot/zone/zone-create.h"
 #include "zscanner/zscanner.h"
-#include "libknot/rdata.h"
 
 void process_error(const zs_scanner_t *s)
 {
@@ -52,7 +51,7 @@ void process_error(const zs_scanner_t *s)
 
 static int add_rdata_to_rr(knot_rrset_t *rrset, const zs_scanner_t *scanner)
 {
-	return knot_rrset_add_rr(rrset, scanner->r_data, scanner->r_data_length,
+	return knot_rrset_add_rdata(rrset, scanner->r_data, scanner->r_data_length,
 	                         scanner->r_ttl, NULL);
 }
 
@@ -170,7 +169,7 @@ static void loader_process(const zs_scanner_t *scanner)
 
 	ret = zcreator_step(zc, &rr);
 	knot_dname_free(&owner, NULL);
-	knot_rrs_clear(&rr.rrs, NULL);
+	knot_rdataset_clear(&rr.rrs, NULL);
 	if (ret != KNOT_EOK) {
 		zc->ret = ret;
 		return;
diff --git a/src/knot/zone/zone-diff.c b/src/knot/zone/zone-diff.c
index 43cd8bb545e00dfe7098bd7fa3b0726260b49973..93411c70c9e3fa6be5cffb1a24a060eea9ee56bc 100644
--- a/src/knot/zone/zone-diff.c
+++ b/src/knot/zone/zone-diff.c
@@ -22,8 +22,8 @@
 #include "common/errcode.h"
 #include "knot/zone/zone-diff.h"
 #include "common/descriptor.h"
-#include "libknot/rdata.h"
 #include "libknot/util/utils.h"
+#include "libknot/rdata/soa.h"
 
 struct zone_diff_param {
 	knot_zone_tree_t *nodes;
@@ -60,8 +60,8 @@ static int knot_zone_diff_load_soas(const knot_zone_contents_t *zone1,
 		return KNOT_EINVAL;
 	}
 
-	int64_t soa_serial1 = knot_rrs_soa_serial(&soa_rrset1.rrs);
-	int64_t soa_serial2 = knot_rrs_soa_serial(&soa_rrset2.rrs);
+	int64_t soa_serial1 = knot_soa_serial(&soa_rrset1.rrs);
+	int64_t soa_serial2 = knot_soa_serial(&soa_rrset2.rrs);
 
 	if (knot_serial_compare(soa_serial1, soa_serial2) == 0) {
 		return KNOT_ENODIFF;
@@ -205,9 +205,9 @@ static int knot_zone_diff_remove_node(knot_changeset_t *changeset,
 static bool rr_exists(const knot_rrset_t *in, const knot_rrset_t *ref,
                       size_t ref_pos)
 {
-	knot_rr_t *to_check = knot_rrs_rr(&ref->rrs, ref_pos);
+	knot_rdata_t *to_check = knot_rdataset_at(&ref->rrs, ref_pos);
 	const bool compare_ttls = true;
-	return knot_rrs_member(&in->rrs, to_check, compare_ttls);
+	return knot_rdataset_member(&in->rrs, to_check, compare_ttls);
 }
 
 static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1,
@@ -248,8 +248,8 @@ static int knot_zone_diff_rdata_return_changes(const knot_rrset_t *rrset1,
 			 * No such RR is present in 'rrset2'. We'll copy
 			 * index 'i' into 'changes' RRSet.
 			 */
-			knot_rr_t *add_rr = knot_rrs_rr(&rrset1->rrs, i);
-			int ret = knot_rrs_add_rr(&(*changes)->rrs, add_rr, NULL);
+			knot_rdata_t *add_rr = knot_rdataset_at(&rrset1->rrs, i);
+			int ret = knot_rdataset_add(&(*changes)->rrs, add_rr, NULL);
 			if (ret != KNOT_EOK) {
 				knot_rrset_free(changes, NULL);
 				return ret;
diff --git a/src/knot/zone/zone.c b/src/knot/zone/zone.c
index 09f6ffa3363a77178e1635dc4e337b37da361192..fb74707730ef67d8102f11e950fa9435a63f31c2 100644
--- a/src/knot/zone/zone.c
+++ b/src/knot/zone/zone.c
@@ -27,7 +27,6 @@
 #include "libknot/common.h"
 #include "libknot/dname.h"
 #include "libknot/dnssec/random.h"
-#include "libknot/rdata.h"
 #include "libknot/util/utils.h"
 
 /*!
diff --git a/src/libknot/dnssec/key.c b/src/libknot/dnssec/key.c
index 45edbefe34f52b6744e117ece6093f92ceb4b1be..ce0438e431d201800342992d224062c13bf56c31 100644
--- a/src/libknot/dnssec/key.c
+++ b/src/libknot/dnssec/key.c
@@ -32,7 +32,7 @@
 #include "libknot/dname.h"
 #include "libknot/dnssec/key.h"
 #include "libknot/dnssec/sig0.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "zscanner/zscanner.h"
 
 /*!
diff --git a/src/libknot/dnssec/key.h b/src/libknot/dnssec/key.h
index 789e3ad9a15cf41ef8acd9db0cf4a377d5aabf24..6294b6a34399c088021da735d989be84d6d0f11d 100644
--- a/src/libknot/dnssec/key.h
+++ b/src/libknot/dnssec/key.h
@@ -31,7 +31,7 @@
 #include <time.h>
 #include "libknot/dname.h"
 #include "libknot/binary.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 
 /*----------------------------------------------------------------------------*/
 
diff --git a/src/libknot/dnssec/rrset-sign.c b/src/libknot/dnssec/rrset-sign.c
index 737cfdf1b808c1cf38c2f9740a4313b7943d54d9..eaa98a4565ff0353abca1df37eac0fc5644e6ee7 100644
--- a/src/libknot/dnssec/rrset-sign.c
+++ b/src/libknot/dnssec/rrset-sign.c
@@ -24,8 +24,8 @@
 #include "libknot/dnssec/policy.h"
 #include "libknot/dnssec/rrset-sign.h"
 #include "libknot/dnssec/sign.h"
-#include "libknot/rdata.h"
 #include "libknot/rrset.h"
+#include "libknot/rdata/rrsig.h"
 
 #define MAX_RR_WIREFORMAT_SIZE (64 * 1024)
 #define RRSIG_RDATA_SIGNER_OFFSET 18
@@ -242,7 +242,7 @@ static int rrsigs_create_rdata(knot_rrset_t *rrsigs,
 		return res;
 	}
 
-	return knot_rrset_add_rr(rrsigs, result, size,
+	return knot_rrset_add_rdata(rrsigs, result, size,
 	                         knot_rrset_rr_ttl(covered, 0), NULL);
 }
 
@@ -268,8 +268,8 @@ int knot_sign_rrset(knot_rrset_t *rrsigs, const knot_rrset_t *covered,
 	                           sig_expire);
 }
 
-int knot_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs,
-                     knot_rrs_t *out_sig, mm_ctx_t *mm)
+int knot_synth_rrsig(uint16_t type, const knot_rdataset_t *rrsig_rrs,
+                     knot_rdataset_t *out_sig, mm_ctx_t *mm)
 {
 	if (rrsig_rrs == NULL) {
 		return KNOT_ENOENT;
@@ -280,11 +280,11 @@ int knot_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs,
 	}
 
 	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 (type == knot_rrsig_type_covered(rrsig_rrs, i)) {
+			const knot_rdata_t *rr_to_copy = knot_rdataset_at(rrsig_rrs, i);
+			int ret = knot_rdataset_add(out_sig, rr_to_copy, mm);
 			if (ret != KNOT_EOK) {
-				knot_rrs_clear(out_sig, mm);
+				knot_rdataset_clear(out_sig, mm);
 				return ret;
 			}
 		}
@@ -311,7 +311,7 @@ static bool is_expired_signature(const knot_rrset_t *rrsigs, size_t pos,
 	assert(rrsigs->type == KNOT_RRTYPE_RRSIG);
 	assert(policy);
 
-	uint32_t expiration = knot_rrs_rrsig_sig_expiration(&rrsigs->rrs, pos);
+	uint32_t expiration = knot_rrsig_sig_expiration(&rrsigs->rrs, pos);
 
 	return (expiration <= policy->refresh_before);
 }
@@ -343,7 +343,7 @@ int knot_is_valid_signature(const knot_rrset_t *covered,
 
 	uint8_t *signature = NULL;
 	size_t signature_size = 0;
-	knot_rrs_rrsig_signature(&rrsigs->rrs, pos, &signature, &signature_size);
+	knot_rrsig_signature(&rrsigs->rrs, pos, &signature, &signature_size);
 	if (!signature) {
 		return KNOT_EINVAL;
 	}
diff --git a/src/libknot/dnssec/rrset-sign.h b/src/libknot/dnssec/rrset-sign.h
index 585883d0fd4e9c214b1692d6a6bdbfea44759d53..22f43b29ffcfed485bf8dc99c55a06331bbec2e8 100644
--- a/src/libknot/dnssec/rrset-sign.h
+++ b/src/libknot/dnssec/rrset-sign.h
@@ -90,8 +90,8 @@ int knot_sign_rrset(knot_rrset_t *rrsigs,
  * \retval KNOT_EINVAL if no RRSIGs were found.
  * \retval Error code other than EINVAL on error.
  */
-int knot_synth_rrsig(uint16_t type, const knot_rrs_t *rrsig_rrs,
-                     knot_rrs_t *out_sig, mm_ctx_t *mm);
+int knot_synth_rrsig(uint16_t type, const knot_rdataset_t *rrsig_rrs,
+                     knot_rdataset_t *out_sig, mm_ctx_t *mm);
 
 /*!
  * \brief Check if RRSIG signature is valid.
diff --git a/src/libknot/dnssec/sig0.c b/src/libknot/dnssec/sig0.c
index 48ba754f408c9eca193e3d6b79a760929555bcb7..c16cc6a73c94cc5806d0fcbdb1fb162375279470 100644
--- a/src/libknot/dnssec/sig0.c
+++ b/src/libknot/dnssec/sig0.c
@@ -70,7 +70,7 @@ static uint8_t *sig0_create_rdata(knot_rrset_t *rrset, knot_dnssec_key_t *key)
 	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) {
+	if (knot_rrset_add_rdata(rrset, rdata, rdata_size, ttl, NULL) != KNOT_EOK) {
 		return NULL;
 	}
 
diff --git a/src/libknot/libknot.h b/src/libknot/libknot.h
index cdb6215346660d4fd1fd402aa05a4d2d40dc88aa..4ea9342b73d2d039be9b8a83565c1f4ade900fee 100644
--- a/src/libknot/libknot.h
+++ b/src/libknot/libknot.h
@@ -33,13 +33,20 @@
 #include "libknot/packet/wire.h"
 #include "libknot/packet/compr.h"
 #include "libknot/packet/pkt.h"
+#include "libknot/rdataset.h"
 #include "libknot/rrset.h"
 #include "libknot/rrset-dump.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/rdname.h"
+#include "libknot/rdata/dnskey.h"
+#include "libknot/rdata/nsec3.h"
+#include "libknot/rdata/nsec3param.h"
+#include "libknot/rdata/nsec.h"
+#include "libknot/rdata/rrsig.h"
+#include "libknot/rdata/soa.h"
+#include "libknot/rdata/tsig.h"
 #include "libknot/tsig-op.h"
 #include "libknot/util/tolower.h"
 #include "libknot/util/utils.h"
-#include "libknot/rdata.h"
 
 #endif
 
diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c
index 82bb1905995e277d5d4453555aefa9b8e8149631..929e22c114a5d1be54fcbaeb47c0cb675e890596 100644
--- a/src/libknot/packet/pkt.c
+++ b/src/libknot/packet/pkt.c
@@ -23,7 +23,7 @@
 #include "libknot/common.h"
 #include "common/descriptor.h"
 #include "libknot/packet/wire.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "libknot/tsig-op.h"
 
 /*! \brief Scan packet for RRSet existence. */
diff --git a/src/libknot/processing/process.h b/src/libknot/processing/process.h
index a6bc1060ea087a4885b9140e8a05251310f4fe37..5977cd556ea4dea34133eb8f234b9318c2d1b6e0 100644
--- a/src/libknot/processing/process.h
+++ b/src/libknot/processing/process.h
@@ -29,7 +29,7 @@
 
 #include "common/mempattern.h"
 #include "libknot/consts.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "libknot/packet/pkt.h"
 
 /*! \brief Main packet processing states.
diff --git a/src/libknot/rdata.c b/src/libknot/rdata.c
new file mode 100644
index 0000000000000000000000000000000000000000..6a4c554d16944d8f7354f4f5e3621d7f6077072b
--- /dev/null
+++ b/src/libknot/rdata.c
@@ -0,0 +1,83 @@
+/*  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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libknot/rdata.h"
+#include "libknot/common.h"
+#include "common/errcode.h"
+
+#ifndef STRICT_ALIGNMENT
+#pragma pack(push, 1)
+#endif
+
+/*!< \brief Helper structure - offsets in RR array. */
+struct rr_offsets {
+	uint32_t ttl;
+	uint16_t size;
+	uint8_t rdata[];
+};
+
+#ifndef STRICT_ALIGNMENT
+#pragma pack(pop)
+#endif
+
+uint16_t knot_rdata_rdlen(const knot_rdata_t *rr)
+{
+	return ((struct rr_offsets *)rr)->size;
+}
+
+void knot_rdata_set_rdlen(knot_rdata_t *rr, uint16_t size)
+{
+	((struct rr_offsets *)rr)->size = size;
+}
+
+uint32_t knot_rdata_ttl(const knot_rdata_t *rr)
+{
+	return ((struct rr_offsets *)rr)->ttl;
+}
+
+void knot_rdata_set_ttl(knot_rdata_t *rr, uint32_t ttl)
+{
+	((struct rr_offsets *)rr)->ttl = ttl;
+}
+
+uint8_t *knot_rdata_data(const knot_rdata_t *rr)
+{
+	return ((struct rr_offsets *)rr)->rdata;
+}
+
+size_t knot_rdata_array_size(uint16_t size)
+{
+	return size + sizeof(struct rr_offsets);
+}
+
+int knot_rdata_cmp(const knot_rdata_t *rr1, const knot_rdata_t *rr2)
+{
+	assert(rr1 && rr2);
+	const uint8_t *r1 = knot_rdata_data(rr1);
+	const uint8_t *r2 = knot_rdata_data(rr2);
+	uint16_t l1 = knot_rdata_rdlen(rr1);
+	uint16_t l2 = knot_rdata_rdlen(rr2);
+	int cmp = memcmp(r1, r2, MIN(l1, l2));
+	if (cmp == 0 && l1 != l2) {
+		cmp = l1 < l2 ? -1 : 1;
+	}
+	return cmp;
+}
diff --git a/src/libknot/rdata.h b/src/libknot/rdata.h
index fc7f9a0431568330984fb9ac3013b594f66db9c2..10427e01157b7c5a4c9d8db500925b06b1f3e3cf 100644
--- a/src/libknot/rdata.h
+++ b/src/libknot/rdata.h
@@ -1,14 +1,14 @@
 /*!
  * \file rdata.h
  *
- * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
  *
- * \brief API for manipulating RDATA contents.
+ * \brief API for manipulating RRs and RR arrays.
  *
  * \addtogroup libknot
  * @{
  */
-/*  Copyright (C) 2013 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  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
@@ -24,383 +24,73 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _KNOT_RDATA_H_
-#define _KNOT_RDATA_H_
+#pragma once
 
-#include "common/descriptor.h"
-#include "libknot/dname.h"
-#include "libknot/rr.h"
-#include "libknot/util/utils.h"
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 
-#define KNOT_RDATA_DNSKEY_FLAG_KSK 1
+#include "common/mempattern.h"
 
-#define RRS_CHECK(rrs, pos, code) \
-	if (rrs == NULL || rrs->data == NULL || rrs->rr_count == 0 || \
-	    pos >= rrs->rr_count) { \
-		code; \
-	}
+/* ---------------------------- Single RR ----------------------------------- */
 
-static inline uint8_t *data_offset(const knot_rrs_t *rrs, size_t pos,
-                                   size_t offset) {
-	knot_rr_t *rr = knot_rrs_rr(rrs, pos);
-	return knot_rr_rdata(rr) + offset;
-}
-
-static inline
-const knot_dname_t *knot_rrs_cname_name(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return NULL);
-	return data_offset(rrs, 0, 0);
-}
-
-static inline
-const knot_dname_t *knot_rrs_dname_target(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return NULL);
-	return data_offset(rrs, 0, 0);
-}
-
-static inline
-const knot_dname_t *knot_rrs_soa_primary_ns(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return NULL);
-	return data_offset(rrs, 0, 0);
-}
-
-static inline
-const knot_dname_t *knot_rrs_soa_mailbox(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return NULL);
-	return data_offset(rrs, 0, knot_dname_size(knot_rrs_soa_primary_ns(rrs)));
-}
-
-static inline
-size_t knot_rrs_soa_names_len(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return 0);
-	return knot_dname_size(knot_rrs_soa_primary_ns(rrs))
-	       + knot_dname_size(knot_rrs_soa_mailbox(rrs));
-}
-
-static inline
-uint32_t knot_rrs_soa_serial(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return 0);
-	return knot_wire_read_u32(data_offset(rrs, 0,
-	                                      knot_rrs_soa_names_len(rrs)));
-}
-
-static inline
-void knot_rrs_soa_serial_set(knot_rrs_t *rrs, uint32_t serial)
-{
-	RRS_CHECK(rrs, 0, return);
-	// the number is in network byte order, transform it
-	knot_wire_write_u32(data_offset(rrs, 0, knot_rrs_soa_names_len(rrs)),
-	                    serial);
-}
-
-static inline
-uint32_t knot_rrs_soa_refresh(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return 0);
-	return knot_wire_read_u32(data_offset(rrs, 0,
-	                                      knot_rrs_soa_names_len(rrs) + 4));
-}
-
-static inline
-uint32_t knot_rrs_soa_retry(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return 0);
-	return knot_wire_read_u32(data_offset(rrs, 0,
-	                                      knot_rrs_soa_names_len(rrs) + 8));
-}
-
-static inline
-uint32_t knot_rrs_soa_expire(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return 0);
-	return knot_wire_read_u32(data_offset(rrs, 0,
-	                                      knot_rrs_soa_names_len(rrs) + 12));
-}
-
-static inline
-uint32_t knot_rrs_soa_minimum(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return 0);
-	return knot_wire_read_u32(data_offset(rrs, 0,
-	                                      knot_rrs_soa_names_len(rrs) + 16));
-}
-
-static inline
-uint16_t knot_rrs_rrsig_type_covered(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u16(data_offset(rrs, pos, 0));
-}
-
-static inline
-uint8_t knot_rrs_rrsig_algorithm(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 2);
-}
-
-static inline
-uint8_t knot_rrs_rrsig_labels(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 3);
-}
-
-static inline
-uint32_t knot_rrs_rrsig_original_ttl(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u32(data_offset(rrs, pos, 4));
-}
-
-static inline
-uint32_t knot_rrs_rrsig_sig_expiration(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u32(data_offset(rrs, pos, 8));
-}
-
-static inline
-uint32_t knot_rrs_rrsig_sig_inception(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u32(data_offset(rrs, pos, 12));
-}
-
-static inline
-uint16_t knot_rrs_rrsig_key_tag(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u16(data_offset(rrs, pos, 16));
-}
-
-static inline
-const knot_dname_t *knot_rrs_rrsig_signer_name(const knot_rrs_t *rrs,
-                                                 size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return data_offset(rrs, pos, 18);
-}
-
-static inline
-void knot_rrs_rrsig_signature(const knot_rrs_t *rrs, size_t pos,
-                                uint8_t **signature, size_t *signature_size)
-{
-	if (!signature || !signature_size) {
-		return;
-	}
-
-	if (rrs == NULL || pos >= rrs->rr_count) {
-		*signature = NULL;
-		*signature_size = 0;
-		return;
-	}
-
-	uint8_t *rdata = data_offset(rrs, pos, 0);
-	uint8_t *signer = rdata + 18;
-	const knot_rr_t *rr = knot_rrs_rr(rrs, pos);
-	size_t total_size = knot_rr_rdata_size(rr);
-	size_t header_size = 18 + knot_dname_size(signer);
-
-	*signature = rdata + header_size;
-	*signature_size = total_size - header_size;
-}
-
-static inline
-uint16_t knot_rrs_dnskey_flags(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u16(data_offset(rrs, pos, 0));
-}
-
-static inline
-uint8_t knot_rrs_dnskey_proto(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-
-	return *data_offset(rrs, pos, 2);
-}
-
-static inline
-uint8_t knot_rrs_dnskey_alg(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 3);
-}
-
-static inline
-void knot_rrs_dnskey_key(const knot_rrs_t *rrs, size_t pos, uint8_t **key,
-                           uint16_t *key_size)
-{
-	RRS_CHECK(rrs, pos, return);
-	*key = data_offset(rrs, pos, 4);
-	const knot_rr_t *rr = knot_rrs_rr(rrs, pos);
-	*key_size = knot_rr_rdata_size(rr) - 4;
-}
-
-static inline
-const knot_dname_t *knot_rrs_nsec_next(const knot_rrs_t *rrs)
-{
-	RRS_CHECK(rrs, 0, return NULL);
-	return data_offset(rrs, 0, 0);
-}
-
-static inline
-void knot_rrs_nsec_bitmap(const knot_rrs_t *rrs,
-                            uint8_t **bitmap, uint16_t *size)
-{
-	RRS_CHECK(rrs, 0, return);
-	knot_rr_t *rr = knot_rrs_rr(rrs, 0);
-	int next_size = knot_dname_size(knot_rrs_nsec_next(rrs));
-
-	*bitmap = knot_rr_rdata(rr) + next_size;
-	*size = knot_rr_rdata_size(rr) - next_size;
-}
-
-static inline
-uint8_t knot_rrs_nsec3_algorithm(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 0);
-}
-
-static inline
-uint8_t knot_rrs_nsec3_flags(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 1);
-}
-
-static inline
-uint16_t knot_rrs_nsec3_iterations(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u16(data_offset(rrs, pos, 2));
-}
-
-static inline
-uint8_t knot_rrs_nsec3_salt_length(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *(data_offset(rrs, pos, 0) + 4);
-}
-
-static inline
-const uint8_t *knot_rrs_nsec3_salt(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return NULL);
-	return data_offset(rrs, pos, 5);
-}
-
-static inline
-void knot_rrs_nsec3_next_hashed(const knot_rrs_t *rrs, size_t pos,
-                                  uint8_t **name, uint8_t *name_size)
-{
-	RRS_CHECK(rrs, pos, return);
-	uint8_t salt_size = knot_rrs_nsec3_salt_length(rrs, pos);
-	*name_size = *data_offset(rrs, pos, 4 + salt_size + 1);
-	*name = data_offset(rrs, pos, 4 + salt_size + 2);
-}
-
-static inline
-void knot_rrs_nsec3_bitmap(const knot_rrs_t *rrs, size_t pos,
-                             uint8_t **bitmap, uint16_t *size)
-{
-	RRS_CHECK(rrs, pos, return);
-
-	/* Bitmap is last, skip all the items. */
-	size_t offset = 6; //hash alg., flags, iterations, salt len., hash len.
-	offset += knot_rrs_nsec3_salt_length(rrs, pos); //salt
-
-	uint8_t *next_hashed = NULL;
-	uint8_t next_hashed_size = 0;
-	knot_rrs_nsec3_next_hashed(rrs, pos, &next_hashed, &next_hashed_size);
-	offset += next_hashed_size; //hash
-
-	*bitmap = data_offset(rrs, pos, offset);
-	const knot_rr_t *rr = knot_rrs_rr(rrs, pos);
-	*size = knot_rr_rdata_size(rr) - offset;
-}
-
-static inline
-uint8_t knot_rrs_nsec3param_algorithm(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 0);
-}
-
-static inline
-uint8_t knot_rrs_nsec3param_flags(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 1);
-}
+/*!
+ * \brief knot_rdata_t Array holding single RR payload, i.e. TTL, RDLENGTH and RDATA.
+ */
+typedef uint8_t knot_rdata_t;
 
-static inline
-uint16_t knot_rrs_nsec3param_iterations(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return knot_wire_read_u16(data_offset(rrs, pos, 2));
-}
+/* ------------------------- RR getters/setters ----------------------------- */
 
-static inline
-uint8_t knot_rrs_nsec3param_salt_length(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return *data_offset(rrs, pos, 4);
-}
+/*!
+ * \brief Returns RDATA size of single RR.
+ * \param rr  RR whose size we want.
+ * \return  RR size.
+ */
+uint16_t knot_rdata_rdlen(const knot_rdata_t *rr);
 
-static inline
-const uint8_t *knot_rrs_nsec3param_salt(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return data_offset(rrs, pos, 5);
-}
+/*!
+ * \brief Sets size for given RR.
+ * \param rr    RR whose size we want to set.
+ * \param size  Size to be set.
+ */
+void knot_rdata_set_rdlen(knot_rdata_t *rr, uint16_t size);
 
-static inline
-const knot_dname_t *knot_rrs_ns_name(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return data_offset(rrs, pos, 0);
-}
+/*!
+ * \brief Returns TTL of single RR.
+ * \param rr  RR whose TTL we want.
+ * \return  RR TTL.
+ */
+uint32_t knot_rdata_ttl(const knot_rdata_t *rr);
 
-static inline
-const knot_dname_t *knot_rrs_mx_name(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return data_offset(rrs, pos, 2);
-}
+/*!
+ * \brief Sets TTL for given RR.
+ * \param rr   RR whose TTL we want to set.
+ * \param ttl  TTL to be set.
+ */
+void knot_rdata_set_ttl(knot_rdata_t *rr, uint32_t ttl);
 
-static inline
-const knot_dname_t *knot_rrs_srv_name(const knot_rrs_t *rrs, size_t pos)
-{
-	RRS_CHECK(rrs, pos, return 0);
-	return data_offset(rrs, pos, 6);
-}
+/*!
+ * \brief Returns pointer to RR data.
+ * \param rr  RR whose data we want.
+ * \return RR data pointer.
+ */
+uint8_t *knot_rdata_data(const knot_rdata_t *rr);
 
-static inline
-const knot_dname_t *knot_rrs_name(const knot_rrs_t *rrs, size_t pos,
-                                  uint16_t type)
-{
-	switch (type) {
-		case KNOT_RRTYPE_NS:
-			return knot_rrs_ns_name(rrs, pos);
-		case KNOT_RRTYPE_MX:
-			return knot_rrs_mx_name(rrs, pos);
-		case KNOT_RRTYPE_SRV:
-			return knot_rrs_srv_name(rrs, pos);
-		case KNOT_RRTYPE_CNAME:
-			return knot_rrs_cname_name(rrs);
-	}
+/* ----------------------------- RR misc ------------------------------------ */
 
-	return NULL;
-}
+/*!
+ * \brief Returns actual size of RR structure for given RDATA size.
+ * \param size  RDATA size.
+ * \return Actual structure size.
+ */
+size_t knot_rdata_array_size(uint16_t size);
 
-#endif /* _KNOT_RDATA_H_ */
-/*! @} */
+/*!
+ * \brief Canonical comparison of two RRs. Both RRs *must* exist.
+ * \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_rdata_cmp(const knot_rdata_t *rr1, const knot_rdata_t *rr2);
diff --git a/src/libknot/rdata/dnskey.h b/src/libknot/rdata/dnskey.h
new file mode 100644
index 0000000000000000000000000000000000000000..e8f64843b5d8c344ab2514a8e60bb32012a96b7b
--- /dev/null
+++ b/src/libknot/rdata/dnskey.h
@@ -0,0 +1,53 @@
+/*  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/>.
+ */
+
+#pragma once
+
+#include "libknot/rdataset.h"
+
+#define KNOT_RDATA_DNSKEY_FLAG_KSK 1
+
+static inline
+uint16_t knot_dnskey_flags(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u16(knot_rdata_offset(rrs, pos, 0));
+}
+
+static inline
+uint8_t knot_dnskey_proto(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+
+	return *knot_rdata_offset(rrs, pos, 2);
+}
+
+static inline
+uint8_t knot_dnskey_alg(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 3);
+}
+
+static inline
+void knot_dnskey_key(const knot_rdataset_t *rrs, size_t pos, uint8_t **key,
+                           uint16_t *key_size)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return);
+	*key = knot_rdata_offset(rrs, pos, 4);
+	const knot_rdata_t *rr = knot_rdataset_at(rrs, pos);
+	*key_size = knot_rdata_rdlen(rr) - 4;
+}
\ No newline at end of file
diff --git a/src/libknot/rdata/nsec.h b/src/libknot/rdata/nsec.h
new file mode 100644
index 0000000000000000000000000000000000000000..56b23bff2cecd27759a05ec2470b6e3759528ff2
--- /dev/null
+++ b/src/libknot/rdata/nsec.h
@@ -0,0 +1,38 @@
+/*  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/>.
+ */
+
+#pragma once
+
+#include "libknot/rdataset.h"
+
+static inline
+const knot_dname_t *knot_nsec_next(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return NULL);
+	return knot_rdata_offset(rrs, 0, 0);
+}
+
+static inline
+void knot_nsec_bitmap(const knot_rdataset_t *rrs,
+                            uint8_t **bitmap, uint16_t *size)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return);
+	knot_rdata_t *rr = knot_rdataset_at(rrs, 0);
+	int next_size = knot_dname_size(knot_nsec_next(rrs));
+
+	*bitmap = knot_rdata_data(rr) + next_size;
+	*size = knot_rdata_rdlen(rr) - next_size;
+}
\ No newline at end of file
diff --git a/src/libknot/dnssec/nsec3.c b/src/libknot/rdata/nsec3.c
similarity index 69%
rename from src/libknot/dnssec/nsec3.c
rename to src/libknot/rdata/nsec3.c
index f5c152ee0924513ec6812bda090a05b29042f7ab..f8e2691825b6132d2fc55ed8d21a469e09b8571d 100644
--- a/src/libknot/dnssec/nsec3.c
+++ b/src/libknot/rdata/nsec3.c
@@ -17,17 +17,10 @@
 #include <assert.h>
 #include <openssl/evp.h>
 #include <openssl/sha.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "common/descriptor.h"
-#include "common/memdup.h"
-#include "libknot/common.h"
-#include "libknot/consts.h"
-#include "libknot/dnssec/nsec3.h"
-#include "libknot/rdata.h"
+
+#include "libknot/rdata/nsec3.h"
 #include "libknot/util/tolower.h"
+#include "common/errcode.h"
 
 /*!
  * \brief Compute NSEC3 SHA1 hash.
@@ -102,49 +95,6 @@ static int nsec3_sha1(const uint8_t *salt, uint8_t salt_length,
 	return KNOT_EOK;
 }
 
-/* - public API -------------------------------------------------------------*/
-
-/*!
- * \brief Initialize the structure with NSEC3 params from NSEC3PARAM RR set.
- */
-int knot_nsec3_params_from_wire(knot_nsec3_params_t *params,
-                                const knot_rrs_t *rrs)
-{
-	if (params == NULL || rrs == NULL || rrs->rr_count == 0) {
-		return KNOT_EINVAL;
-	}
-
-	knot_nsec3_params_t result = { 0 };
-
-	result.algorithm   = knot_rrs_nsec3param_algorithm(rrs, 0);
-	result.iterations  = knot_rrs_nsec3param_iterations(rrs, 0);
-	result.flags       = knot_rrs_nsec3param_flags(rrs, 0);
-	result.salt_length = knot_rrs_nsec3param_salt_length(rrs, 0);
-
-	if (result.salt_length > 0) {
-		result.salt = knot_memdup(knot_rrs_nsec3param_salt(rrs, 0),
-		                          result.salt_length);
-		if (!result.salt) {
-			return KNOT_ENOMEM;
-		}
-	} else {
-		result.salt = NULL;
-	}
-
-	knot_nsec3_params_free(params);
-	*params = result;
-
-	return KNOT_EOK;
-}
-
-/*!
- * \brief Clean up structure with NSEC3 params (do not deallocate).
- */
-void knot_nsec3_params_free(knot_nsec3_params_t *params)
-{
-	free(params->salt);
-}
-
 /*!
  * \brief Compute NSEC3 hash for given data.
  */
diff --git a/src/libknot/dnssec/nsec3.h b/src/libknot/rdata/nsec3.h
similarity index 52%
rename from src/libknot/dnssec/nsec3.h
rename to src/libknot/rdata/nsec3.h
index 533adee112747aad5da053ab7b2b23145b60836c..f0e01313cdbeebb52b95f56d2573eff14e4f7fc1 100644
--- a/src/libknot/dnssec/nsec3.h
+++ b/src/libknot/rdata/nsec3.h
@@ -25,17 +25,80 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _KNOT_DNSSEC_NSEC3_H_
-#define _KNOT_DNSSEC_NSEC3_H_
+#pragma once
 
 #include <stdbool.h>
 #include <stdint.h>
 #include <string.h>
 
 #include "libknot/consts.h"
-#include "libknot/rrset.h"
+#include "libknot/rdataset.h"
+#include "libknot/rdata/nsec3param.h"
 
-/*---------------------------------------------------------------------------*/
+static inline
+uint8_t knot_nsec3_algorithm(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 0);
+}
+
+static inline
+uint8_t knot_nsec3_flags(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 1);
+}
+
+static inline
+uint16_t knot_nsec3_iterations(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u16(knot_rdata_offset(rrs, pos, 2));
+}
+
+static inline
+uint8_t knot_nsec3_salt_length(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *(knot_rdata_offset(rrs, pos, 0) + 4);
+}
+
+static inline
+const uint8_t *knot_nsec3_salt(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return NULL);
+	return knot_rdata_offset(rrs, pos, 5);
+}
+
+static inline
+void knot_nsec3_next_hashed(const knot_rdataset_t *rrs, size_t pos,
+                                  uint8_t **name, uint8_t *name_size)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return);
+	uint8_t salt_size = knot_nsec3_salt_length(rrs, pos);
+	*name_size = *knot_rdata_offset(rrs, pos, 4 + salt_size + 1);
+	*name = knot_rdata_offset(rrs, pos, 4 + salt_size + 2);
+}
+
+static inline
+void knot_nsec3_bitmap(const knot_rdataset_t *rrs, size_t pos,
+                             uint8_t **bitmap, uint16_t *size)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return);
+
+	/* Bitmap is last, skip all the items. */
+	size_t offset = 6; //hash alg., flags, iterations, salt len., hash len.
+	offset += knot_nsec3_salt_length(rrs, pos); //salt
+
+	uint8_t *next_hashed = NULL;
+	uint8_t next_hashed_size = 0;
+	knot_nsec3_next_hashed(rrs, pos, &next_hashed, &next_hashed_size);
+	offset += next_hashed_size; //hash
+
+	*bitmap = knot_rdata_offset(rrs, pos, offset);
+	const knot_rdata_t *rr = knot_rdataset_at(rrs, pos);
+	*size = knot_rdata_rdlen(rr) - offset;
+}
 
 /*!
  * \brief Get length of the raw NSEC3 hash.
@@ -69,38 +132,6 @@ inline static size_t knot_nsec3_hash_b32_length(uint8_t algorithm)
 	}
 }
 
-/*---------------------------------------------------------------------------*/
-
-/*!
- * \brief Structure representing the NSEC3PARAM resource record.
- */
-typedef struct {
-	uint8_t algorithm;    //!< Hash algorithm.
-	uint8_t flags;        //!< Flags.
-	uint16_t iterations;  //!< Additional iterations of the hash function.
-	uint8_t salt_length;  //!< Length of the salt field in bytes.
-	uint8_t *salt;        //!< Salt used in hashing.
-} knot_nsec3_params_t;
-
-/*---------------------------------------------------------------------------*/
-
-/*!
- * \brief Initialize the structure with NSEC3 params from NSEC3PARAM RR set.
- *
- * \param params      Structure to initialize.
- * \param nsec3param  The NSEC3PARAM RRs.
- *
- * \return Error code, KNOT_EOK on success.
- */
-int knot_nsec3_params_from_wire(knot_nsec3_params_t *params,
-                                const knot_rrs_t *rrs);
-/*!
- * \brief Clean up structure with NSEC3 params (do not deallocate).
- *
- * \param params Structure with NSEC3 params.
- */
-void knot_nsec3_params_free(knot_nsec3_params_t *params);
-
 /*!
  * \brief Compute NSEC3 hash for given data.
  *
@@ -115,6 +146,4 @@ void knot_nsec3_params_free(knot_nsec3_params_t *params);
 int knot_nsec3_hash(const knot_nsec3_params_t *params, const uint8_t *data,
                     size_t size, uint8_t **digest, size_t *digest_size);
 
-#endif // _KNOT_DNSSEC_NSEC3_H_
-
 /*! @} */
diff --git a/src/libknot/rdata/nsec3param.c b/src/libknot/rdata/nsec3param.c
new file mode 100644
index 0000000000000000000000000000000000000000..212d894b7438c614772d1e46d69e292e5970feb7
--- /dev/null
+++ b/src/libknot/rdata/nsec3param.c
@@ -0,0 +1,60 @@
+/*  Copyright (C) 2011 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 "common/memdup.h"
+#include "common/errcode.h"
+#include "libknot/rdata/nsec3param.h"
+
+/*!
+ * \brief Initialize the structure with NSEC3 params from NSEC3PARAM RR set.
+ */
+int knot_nsec3param_from_wire(knot_nsec3_params_t *params,
+                                const knot_rdataset_t *rrs)
+{
+	if (params == NULL || rrs == NULL || rrs->rr_count == 0) {
+		return KNOT_EINVAL;
+	}
+
+	knot_nsec3_params_t result = { 0 };
+
+	result.algorithm   = knot_nsec3param_algorithm(rrs, 0);
+	result.iterations  = knot_nsec3param_iterations(rrs, 0);
+	result.flags       = knot_nsec3param_flags(rrs, 0);
+	result.salt_length = knot_nsec3param_salt_length(rrs, 0);
+
+	if (result.salt_length > 0) {
+		result.salt = knot_memdup(knot_nsec3param_salt(rrs, 0),
+		                          result.salt_length);
+		if (!result.salt) {
+			return KNOT_ENOMEM;
+		}
+	} else {
+		result.salt = NULL;
+	}
+
+	knot_nsec3param_free(params);
+	*params = result;
+
+	return KNOT_EOK;
+}
+
+/*!
+ * \brief Clean up structure with NSEC3 params (do not deallocate).
+ */
+void knot_nsec3param_free(knot_nsec3_params_t *params)
+{
+	free(params->salt);
+}
diff --git a/src/libknot/rdata/nsec3param.h b/src/libknot/rdata/nsec3param.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bdc9d50a3bebe1d77b472915ff278575e3f511d
--- /dev/null
+++ b/src/libknot/rdata/nsec3param.h
@@ -0,0 +1,89 @@
+/*  Copyright (C) 2011 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/>.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libknot/consts.h"
+#include "libknot/rdataset.h"
+
+/*!
+ * \brief Structure representing the NSEC3PARAM resource record.
+ */
+typedef struct {
+	uint8_t algorithm;    //!< Hash algorithm.
+	uint8_t flags;        //!< Flags.
+	uint16_t iterations;  //!< Additional iterations of the hash function.
+	uint8_t salt_length;  //!< Length of the salt field in bytes.
+	uint8_t *salt;        //!< Salt used in hashing.
+} knot_nsec3_params_t;
+
+/*---------------------------------------------------------------------------*/
+
+static inline
+uint8_t knot_nsec3param_algorithm(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 0);
+}
+
+static inline
+uint8_t knot_nsec3param_flags(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 1);
+}
+
+static inline
+uint16_t knot_nsec3param_iterations(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u16(knot_rdata_offset(rrs, pos, 2));
+}
+
+static inline
+uint8_t knot_nsec3param_salt_length(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 4);
+}
+
+static inline
+const uint8_t *knot_nsec3param_salt(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_rdata_offset(rrs, pos, 5);
+}
+
+/*!
+ * \brief Initialize the structure with NSEC3 params from NSEC3PARAM RR set.
+ *
+ * \param params      Structure to initialize.
+ * \param nsec3param  The NSEC3PARAM RRs.
+ *
+ * \return Error code, KNOT_EOK on success.
+ */
+int knot_nsec3param_from_wire(knot_nsec3_params_t *params,
+                                const knot_rdataset_t *rrs);
+/*!
+ * \brief Clean up structure with NSEC3 params (do not deallocate).
+ *
+ * \param params Structure with NSEC3 params.
+ */
+void knot_nsec3param_free(knot_nsec3_params_t *params);
diff --git a/src/libknot/rdata/rdname.h b/src/libknot/rdata/rdname.h
new file mode 100644
index 0000000000000000000000000000000000000000..0177d1050a36840e506cda00a7662728c91cbf76
--- /dev/null
+++ b/src/libknot/rdata/rdname.h
@@ -0,0 +1,73 @@
+/*  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/>.
+ */
+
+#pragma once
+
+#include "common/descriptor.h"
+#include "libknot/rdataset.h"
+#include "libknot/dname.h"
+
+static inline
+const knot_dname_t *knot_cname_name(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return NULL);
+	return knot_rdata_offset(rrs, 0, 0);
+}
+
+static inline
+const knot_dname_t *knot_dname_target(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return NULL);
+	return knot_rdata_offset(rrs, 0, 0);
+}
+
+static inline
+const knot_dname_t *knot_ns_name(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_rdata_offset(rrs, pos, 0);
+}
+
+static inline
+const knot_dname_t *knot_mx_name(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_rdata_offset(rrs, pos, 2);
+}
+
+static inline
+const knot_dname_t *knot_srv_name(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_rdata_offset(rrs, pos, 6);
+}
+
+static inline
+const knot_dname_t *knot_rdata_name(const knot_rdataset_t *rrs, size_t pos, uint16_t type)
+{
+	switch (type) {
+		case KNOT_RRTYPE_NS:
+			return knot_ns_name(rrs, pos);
+		case KNOT_RRTYPE_MX:
+			return knot_mx_name(rrs, pos);
+		case KNOT_RRTYPE_SRV:
+			return knot_srv_name(rrs, pos);
+		case KNOT_RRTYPE_CNAME:
+			return knot_cname_name(rrs);
+	}
+
+	return NULL;
+}
\ No newline at end of file
diff --git a/src/libknot/rdata/rrsig.h b/src/libknot/rdata/rrsig.h
new file mode 100644
index 0000000000000000000000000000000000000000..f4225585f7604317606884cafe2d213830b60d95
--- /dev/null
+++ b/src/libknot/rdata/rrsig.h
@@ -0,0 +1,100 @@
+/*  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/>.
+ */
+
+#pragma once
+
+#include "libknot/rdataset.h"
+
+static inline
+uint16_t knot_rrsig_type_covered(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u16(knot_rdata_offset(rrs, pos, 0));
+}
+
+static inline
+uint8_t knot_rrsig_algorithm(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 2);
+}
+
+static inline
+uint8_t knot_rrsig_labels(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return *knot_rdata_offset(rrs, pos, 3);
+}
+
+static inline
+uint32_t knot_rrsig_original_ttl(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, pos, 4));
+}
+
+static inline
+uint32_t knot_rrsig_sig_expiration(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, pos, 8));
+}
+
+static inline
+uint32_t knot_rrsig_sig_inception(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, pos, 12));
+}
+
+static inline
+uint16_t knot_rrsig_key_tag(const knot_rdataset_t *rrs, size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_wire_read_u16(knot_rdata_offset(rrs, pos, 16));
+}
+
+static inline
+const knot_dname_t *knot_rrsig_signer_name(const knot_rdataset_t *rrs,
+                                                 size_t pos)
+{
+	KNOT_RDATASET_CHECK(rrs, pos, return 0);
+	return knot_rdata_offset(rrs, pos, 18);
+}
+
+static inline
+void knot_rrsig_signature(const knot_rdataset_t *rrs, size_t pos,
+                                uint8_t **signature, size_t *signature_size)
+{
+	if (!signature || !signature_size) {
+		return;
+	}
+
+	if (rrs == NULL || pos >= rrs->rr_count) {
+		*signature = NULL;
+		*signature_size = 0;
+		return;
+	}
+
+	uint8_t *rdata = knot_rdata_offset(rrs, pos, 0);
+	uint8_t *signer = rdata + 18;
+	const knot_rdata_t *rr = knot_rdataset_at(rrs, pos);
+	size_t total_size = knot_rdata_rdlen(rr);
+	size_t header_size = 18 + knot_dname_size(signer);
+
+	*signature = rdata + header_size;
+	*signature_size = total_size - header_size;
+}
\ No newline at end of file
diff --git a/src/libknot/rdata/soa.h b/src/libknot/rdata/soa.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b8f809395494f3b57f880b5533456b48672b24a
--- /dev/null
+++ b/src/libknot/rdata/soa.h
@@ -0,0 +1,91 @@
+/*  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/>.
+ */
+
+#pragma once
+
+#include "libknot/rdataset.h"
+#include "libknot/dname.h"
+
+static inline
+const knot_dname_t *knot_soa_primary_ns(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return NULL);
+	return knot_rdata_offset(rrs, 0, 0);
+}
+
+static inline
+const knot_dname_t *knot_soa_mailbox(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return NULL);
+	return knot_rdata_offset(rrs, 0, knot_dname_size(knot_soa_primary_ns(rrs)));
+}
+
+static inline
+size_t knot_soa_names_len(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return 0);
+	return knot_dname_size(knot_soa_primary_ns(rrs))
+	       + knot_dname_size(knot_soa_mailbox(rrs));
+}
+
+static inline
+uint32_t knot_soa_serial(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, 0,
+	                                      knot_soa_names_len(rrs)));
+}
+
+static inline
+void knot_soa_serial_set(knot_rdataset_t *rrs, uint32_t serial)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return);
+	// the number is in network byte order, transform it
+	knot_wire_write_u32(knot_rdata_offset(rrs, 0, knot_soa_names_len(rrs)),
+	                    serial);
+}
+
+static inline
+uint32_t knot_soa_refresh(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, 0,
+	                                      knot_soa_names_len(rrs) + 4));
+}
+
+static inline
+uint32_t knot_soa_retry(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, 0,
+	                                      knot_soa_names_len(rrs) + 8));
+}
+
+static inline
+uint32_t knot_soa_expire(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, 0,
+	                                      knot_soa_names_len(rrs) + 12));
+}
+
+static inline
+uint32_t knot_soa_minimum(const knot_rdataset_t *rrs)
+{
+	KNOT_RDATASET_CHECK(rrs, 0, return 0);
+	return knot_wire_read_u32(knot_rdata_offset(rrs, 0,
+	                                      knot_soa_names_len(rrs) + 16));
+}
\ No newline at end of file
diff --git a/src/libknot/tsig.c b/src/libknot/rdata/tsig.c
similarity index 99%
rename from src/libknot/tsig.c
rename to src/libknot/rdata/tsig.c
index c7c8ae75162a676f9198bfab2da6be7828edda64..0f8832ccd88c7d1886f070ad4d6076e2aeac31dc 100644
--- a/src/libknot/tsig.c
+++ b/src/libknot/rdata/tsig.c
@@ -21,7 +21,7 @@
 #include <assert.h>
 #include <time.h>
 
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "common/debug.h"
 #include "libknot/common.h"
 #include "libknot/util/utils.h"
@@ -142,7 +142,7 @@ int tsig_create_rdata(knot_rrset_t *rr, const knot_dname_t *alg, uint16_t 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);
+	int ret = knot_rrset_add_rdata(rr, rd, rdlen, 0, NULL);
 	if (ret != KNOT_EOK) {
 		return ret;
 	}
diff --git a/src/libknot/tsig.h b/src/libknot/rdata/tsig.h
similarity index 96%
rename from src/libknot/tsig.h
rename to src/libknot/rdata/tsig.h
index bd9d364bb818b859b63f67cf88d00093c65d027b..cfbb7dead0679a832c577836ac354a3a440535f2 100644
--- a/src/libknot/tsig.h
+++ b/src/libknot/rdata/tsig.h
@@ -15,7 +15,7 @@
     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,
+    This program is distributed in the hope tha t 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.
@@ -24,8 +24,7 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _KNOT_TSIG_H_
-#define _KNOT_TSIG_H_
+#pragma once
 
 #include <stdint.h>
 
@@ -139,6 +138,4 @@ size_t tsig_wire_actsize(const knot_rrset_t *tsig);
 
 int tsig_rdata_is_ok(const knot_rrset_t *tsig);
 
-#endif /* _KNOT_TSIG_H_ */
-
 /*! @} */
diff --git a/src/libknot/rr.c b/src/libknot/rdataset.c
similarity index 52%
rename from src/libknot/rr.c
rename to src/libknot/rdataset.c
index ddf1df7ed3bba174bebae3e8ad2e0f9c5193b748..4df1127420ea6536b0abc87cd177f4c8718ebde5 100644
--- a/src/libknot/rr.c
+++ b/src/libknot/rdataset.c
@@ -19,25 +19,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "libknot/rr.h"
-#include "libknot/rdata.h"
+#include "libknot/rdataset.h"
 #include "libknot/common.h"
-#include "common/errcode.h"
-
-#ifndef STRICT_ALIGNMENT
-#pragma pack(push, 1)
-#endif
-
-/*!< \brief Helper structure - offsets in RR array. */
-struct rr_offsets {
-	uint32_t ttl;
-	uint16_t size;
-	uint8_t rdata[];
-};
-
-#ifndef STRICT_ALIGNMENT
-#pragma pack(pop)
-#endif
 
 static void *mm_realloc(mm_ctx_t *mm, void *what, size_t size, size_t prev_size)
 {
@@ -60,7 +43,8 @@ static void *mm_realloc(mm_ctx_t *mm, void *what, size_t size, size_t prev_size)
 	}
 }
 
-static knot_rr_t *rr_seek(knot_rr_t *d, size_t pos)
+
+static knot_rdata_t *rr_seek(knot_rdata_t *d, size_t pos)
 {
 	if (d == NULL) {
 		return NULL;
@@ -68,19 +52,19 @@ static knot_rr_t *rr_seek(knot_rr_t *d, size_t pos)
 
 	size_t offset = 0;
 	for (size_t i = 0; i < pos; i++) {
-		knot_rr_t *rr = d + offset;
-		offset += knot_rr_array_size(knot_rr_rdata_size(rr));
+		knot_rdata_t *rr = d + offset;
+		offset += knot_rdata_array_size(knot_rdata_rdlen(rr));
 	}
 
 	return d + offset;
 }
 
-static int find_rr_pos(const knot_rrs_t *search_in,
-                       const knot_rr_t *rr)
+static int find_rr_pos(const knot_rdataset_t *search_in,
+                       const knot_rdata_t *rr)
 {
 	for (uint16_t i = 0; i < search_in->rr_count; ++i) {
-		const knot_rr_t *search_rr = knot_rrs_rr(search_in, i);
-		if (knot_rr_cmp(rr, search_rr) == 0) {
+		const knot_rdata_t *search_rr = knot_rdataset_at(search_in, i);
+		if (knot_rdata_cmp(rr, search_rr) == 0) {
 			return i;
 		}
 	}
@@ -88,21 +72,21 @@ static int find_rr_pos(const knot_rrs_t *search_in,
 	return KNOT_ENOENT;
 }
 
-static int add_rr_at(knot_rrs_t *rrs, const knot_rr_t *rr, size_t pos,
+static int add_rr_at(knot_rdataset_t *rrs, const knot_rdata_t *rr, size_t pos,
                      mm_ctx_t *mm)
 {
 	if (rrs == NULL || pos > rrs->rr_count) {
 		return KNOT_EINVAL;
 	}
-	const uint16_t size = knot_rr_rdata_size(rr);
-	const uint32_t ttl = knot_rr_ttl(rr);
-	const uint8_t *rdata = knot_rr_rdata(rr);
+	const uint16_t size = knot_rdata_rdlen(rr);
+	const uint32_t ttl = knot_rdata_ttl(rr);
+	const uint8_t *rdata = knot_rdata_data(rr);
 
-	size_t total_size = knot_rrs_size(rrs);
+	size_t total_size = knot_rdataset_size(rrs);
 
 	// Realloc data.
 	void *tmp = mm_realloc(mm, rrs->data,
-	                       total_size + knot_rr_array_size(size),
+	                       total_size + knot_rdata_array_size(size),
 	                       total_size);
 	if (tmp) {
 		rrs->data = tmp;
@@ -114,48 +98,48 @@ static int add_rr_at(knot_rrs_t *rrs, const knot_rr_t *rr, size_t pos,
 	if (rrs->rr_count == 0 || pos == rrs->rr_count) {
 		// No need to rearange RDATA
 		rrs->rr_count++;
-		knot_rr_t *new_rr = knot_rrs_rr(rrs, pos);
-		knot_rr_set_size(new_rr, size);
-		knot_rr_set_ttl(new_rr, ttl);
-		memcpy(knot_rr_rdata(new_rr), rdata, size);
+		knot_rdata_t *new_rr = knot_rdataset_at(rrs, pos);
+		knot_rdata_set_rdlen(new_rr, size);
+		knot_rdata_set_ttl(new_rr, ttl);
+		memcpy(knot_rdata_data(new_rr), rdata, size);
 		return KNOT_EOK;
 	}
 
 	// RDATA have to be rearanged.
-	knot_rr_t *last_rr = knot_rrs_rr(rrs, rrs->rr_count - 1);
-	knot_rr_t *old_rr = knot_rrs_rr(rrs, pos);
+	knot_rdata_t *last_rr = knot_rdataset_at(rrs, rrs->rr_count - 1);
+	knot_rdata_t *old_rr = knot_rdataset_at(rrs, pos);
 	assert(last_rr);
 	assert(old_rr);
 
 	// Make space for new data by moving the array
-	memmove(old_rr + knot_rr_array_size(size), old_rr,
-	        (last_rr + knot_rr_array_size(knot_rr_rdata_size(last_rr))) - old_rr);
+	memmove(old_rr + knot_rdata_array_size(size), old_rr,
+	        (last_rr + knot_rdata_array_size(knot_rdata_rdlen(last_rr))) - old_rr);
 
 	// Set new RR
-	knot_rr_set_size(old_rr, size);
-	knot_rr_set_ttl(old_rr, ttl);
-	memcpy(knot_rr_rdata(old_rr), rdata, size);
+	knot_rdata_set_rdlen(old_rr, size);
+	knot_rdata_set_ttl(old_rr, ttl);
+	memcpy(knot_rdata_data(old_rr), rdata, size);
 
 	rrs->rr_count++;
 	return KNOT_EOK;
 }
 
-static int remove_rr_at(knot_rrs_t *rrs, size_t pos, mm_ctx_t *mm)
+static int remove_rr_at(knot_rdataset_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_rr(rrs, pos);
-	knot_rr_t *last_rr = knot_rrs_rr(rrs, rrs->rr_count - 1);
+	knot_rdata_t *old_rr = knot_rdataset_at(rrs, pos);
+	knot_rdata_t *last_rr = knot_rdataset_at(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_rdata_size(old_rr);
+	size_t total_size = knot_rdataset_size(rrs);
+	uint16_t old_size = knot_rdata_rdlen(old_rr);
 
-	void *old_threshold = old_rr + knot_rr_array_size(old_size);
-	void *last_threshold = last_rr + knot_rr_array_size(knot_rr_rdata_size(last_rr));
+	void *old_threshold = old_rr + knot_rdata_array_size(old_size);
+	void *last_threshold = last_rr + knot_rdata_array_size(knot_rdata_rdlen(last_rr));
 	// Move RDATA
 	memmove(old_rr, old_threshold,
 	        last_threshold - old_threshold);
@@ -163,7 +147,7 @@ static int remove_rr_at(knot_rrs_t *rrs, size_t pos, mm_ctx_t *mm)
 	if (rrs->rr_count > 1) {
 		// Realloc RDATA
 		void *tmp = mm_realloc(mm, rrs->data,
-		                       total_size - (knot_rr_array_size(old_size)),
+		                       total_size - (knot_rdata_array_size(old_size)),
 		                       total_size);
 		if (tmp == NULL) {
 			ERR_ALLOC_FAILED;
@@ -181,51 +165,7 @@ static int remove_rr_at(knot_rrs_t *rrs, size_t pos, mm_ctx_t *mm)
 	return KNOT_EOK;
 }
 
-uint16_t knot_rr_rdata_size(const knot_rr_t *rr)
-{
-	return ((struct rr_offsets *)rr)->size;
-}
-
-void knot_rr_set_size(knot_rr_t *rr, uint16_t size)
-{
-	((struct rr_offsets *)rr)->size = size;
-}
-
-uint32_t knot_rr_ttl(const knot_rr_t *rr)
-{
-	return ((struct rr_offsets *)rr)->ttl;
-}
-
-void knot_rr_set_ttl(knot_rr_t *rr, uint32_t ttl)
-{
-	((struct rr_offsets *)rr)->ttl = ttl;
-}
-
-uint8_t *knot_rr_rdata(const knot_rr_t *rr)
-{
-	return ((struct rr_offsets *)rr)->rdata;
-}
-
-size_t knot_rr_array_size(uint16_t size)
-{
-	return size + sizeof(struct rr_offsets);
-}
-
-int knot_rr_cmp(const knot_rr_t *rr1, const knot_rr_t *rr2)
-{
-	assert(rr1 && rr2);
-	const uint8_t *r1 = knot_rr_rdata(rr1);
-	const uint8_t *r2 = knot_rr_rdata(rr2);
-	uint16_t l1 = knot_rr_rdata_size(rr1);
-	uint16_t l2 = knot_rr_rdata_size(rr2);
-	int cmp = memcmp(r1, r2, MIN(l1, l2));
-	if (cmp == 0 && l1 != l2) {
-		cmp = l1 < l2 ? -1 : 1;
-	}
-	return cmp;
-}
-
-void knot_rrs_init(knot_rrs_t *rrs)
+void knot_rdataset_init(knot_rdataset_t *rrs)
 {
 	if (rrs) {
 		rrs->rr_count = 0;
@@ -233,7 +173,7 @@ void knot_rrs_init(knot_rrs_t *rrs)
 	}
 }
 
-void knot_rrs_clear(knot_rrs_t *rrs, mm_ctx_t *mm)
+void knot_rdataset_clear(knot_rdataset_t *rrs, mm_ctx_t *mm)
 {
 	if (rrs) {
 		mm_free(mm, rrs->data);
@@ -242,14 +182,14 @@ void knot_rrs_clear(knot_rrs_t *rrs, mm_ctx_t *mm)
 	}
 }
 
-int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm)
+int knot_rdataset_copy(knot_rdataset_t *dst, const knot_rdataset_t *src, mm_ctx_t *mm)
 {
 	if (dst == NULL || src == NULL) {
 		return KNOT_EINVAL;
 	}
 
 	dst->rr_count = src->rr_count;
-	size_t src_size = knot_rrs_size(src);
+	size_t src_size = knot_rdataset_size(src);
 	dst->data = mm_alloc(mm, src_size);
 	if (dst->data == NULL) {
 		ERR_ALLOC_FAILED;
@@ -260,7 +200,7 @@ 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_rr(const knot_rrs_t *rrs, size_t pos)
+knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *rrs, size_t pos)
 {
 	if (rrs == NULL || pos >= rrs->rr_count) {
 		return NULL;
@@ -269,7 +209,7 @@ knot_rr_t *knot_rrs_rr(const knot_rrs_t *rrs, size_t pos)
 	return rr_seek(rrs->data, pos);
 }
 
-size_t knot_rrs_size(const knot_rrs_t *rrs)
+size_t knot_rdataset_size(const knot_rdataset_t *rrs)
 {
 	if (rrs == NULL) {
 		return 0;
@@ -277,23 +217,23 @@ size_t knot_rrs_size(const knot_rrs_t *rrs)
 
 	size_t total_size = 0;
 	for (size_t i = 0; i < rrs->rr_count; ++i) {
-		const knot_rr_t *rr = knot_rrs_rr(rrs, i);
+		const knot_rdata_t *rr = knot_rdataset_at(rrs, i);
 		assert(rr);
-		total_size += knot_rr_array_size(knot_rr_rdata_size(rr));
+		total_size += knot_rdata_array_size(knot_rdata_rdlen(rr));
 	}
 
 	return total_size;
 }
 
-int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm)
+int knot_rdataset_add(knot_rdataset_t *rrs, const knot_rdata_t *rr, mm_ctx_t *mm)
 {
 	if (rrs == NULL || rr == NULL) {
 		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);
+		const knot_rdata_t *rrset_rr = knot_rdataset_at(rrs, i);
+		int cmp = knot_rdata_cmp(rrset_rr, rr);
 		if (cmp == 0) {
 			// Duplication - no need to add this RR
 			return KNOT_EOK;
@@ -307,16 +247,16 @@ int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm)
 	return add_rr_at(rrs, rr, rrs->rr_count, mm);
 }
 
-bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2)
+bool knot_rdataset_eq(const knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2)
 {
 	if (rrs1->rr_count != rrs2->rr_count) {
 		return false;
 	}
 
 	for (uint16_t i = 0; i < rrs1->rr_count; ++i) {
-		const knot_rr_t *rr1 = knot_rrs_rr(rrs1, i);
-		const knot_rr_t *rr2 = knot_rrs_rr(rrs2, i);
-		if (knot_rr_cmp(rr1, rr2) != 0) {
+		const knot_rdata_t *rr1 = knot_rdataset_at(rrs1, i);
+		const knot_rdata_t *rr2 = knot_rdataset_at(rrs2, i);
+		if (knot_rdata_cmp(rr1, rr2) != 0) {
 			return false;
 		}
 	}
@@ -324,16 +264,16 @@ bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2)
 	return true;
 }
 
-bool knot_rrs_member(const knot_rrs_t *rrs, const knot_rr_t *rr, bool cmp_ttl)
+bool knot_rdataset_member(const knot_rdataset_t *rrs, const knot_rdata_t *rr, bool cmp_ttl)
 {
 	for (uint16_t i = 0; i < rrs->rr_count; ++i) {
-		const knot_rr_t *cmp_rr = knot_rrs_rr(rrs, i);
+		const knot_rdata_t *cmp_rr = knot_rdataset_at(rrs, i);
 		if (cmp_ttl) {
-			if (knot_rr_ttl(rr) != knot_rr_ttl(cmp_rr)) {
+			if (knot_rdata_ttl(rr) != knot_rdata_ttl(cmp_rr)) {
 				continue;
 			}
 		}
-		int cmp = knot_rr_cmp(cmp_rr, rr);
+		int cmp = knot_rdata_cmp(cmp_rr, rr);
 		if (cmp == 0) {
 			// Match.
 			return true;
@@ -346,15 +286,15 @@ bool knot_rrs_member(const knot_rrs_t *rrs, const knot_rr_t *rr, bool cmp_ttl)
 	return false;
 }
 
-int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm)
+int knot_rdataset_merge(knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2, mm_ctx_t *mm)
 {
 	if (rrs1 == NULL || rrs2 == NULL) {
 		return KNOT_EINVAL;
 	}
 
 	for (uint16_t i = 0; i < rrs2->rr_count; ++i) {
-		const knot_rr_t *rr = knot_rrs_rr(rrs2, i);
-		int ret = knot_rrs_add_rr(rrs1, rr, mm);
+		const knot_rdata_t *rr = knot_rdataset_at(rrs2, i);
+		int ret = knot_rdataset_add(rrs1, rr, mm);
 		if (ret != KNOT_EOK) {
 			return ret;
 		}
@@ -363,22 +303,22 @@ int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm)
 	return KNOT_EOK;
 }
 
-int knot_rrs_intersect(const knot_rrs_t *a, const knot_rrs_t *b,
-                       knot_rrs_t *out, mm_ctx_t *mm)
+int knot_rdataset_intersect(const knot_rdataset_t *a, const knot_rdataset_t *b,
+                       knot_rdataset_t *out, mm_ctx_t *mm)
 {
 	if (a == NULL || b == NULL || out == NULL) {
 		return KNOT_EINVAL;
 	}
 
-	knot_rrs_init(out);
+	knot_rdataset_init(out);
 	const bool compare_ttls = false;
 	for (uint16_t i = 0; i < a->rr_count; ++i) {
-		const knot_rr_t *rr = knot_rrs_rr(a, i);
-		if (knot_rrs_member(b, rr, compare_ttls)) {
+		const knot_rdata_t *rr = knot_rdataset_at(a, i);
+		if (knot_rdataset_member(b, rr, compare_ttls)) {
 			// Add RR into output intersection RRSet.
-			int ret = knot_rrs_add_rr(out, rr, mm);
+			int ret = knot_rdataset_add(out, rr, mm);
 			if (ret != KNOT_EOK) {
-				knot_rrs_clear(out, mm);
+				knot_rdataset_clear(out, mm);
 				return ret;
 			}
 		}
@@ -387,14 +327,14 @@ int knot_rrs_intersect(const knot_rrs_t *a, const knot_rrs_t *b,
 	return KNOT_EOK;
 }
 
-int knot_rrs_subtract(knot_rrs_t *from, const knot_rrs_t *what, mm_ctx_t *mm)
+int knot_rdataset_subtract(knot_rdataset_t *from, const knot_rdataset_t *what, mm_ctx_t *mm)
 {
 	if (from == NULL || what == NULL) {
 		return KNOT_EINVAL;
 	}
 
 	for (uint16_t i = 0; i < what->rr_count; ++i) {
-		const knot_rr_t *to_remove = knot_rrs_rr(what, i);
+		const knot_rdata_t *to_remove = knot_rdataset_at(what, i);
 		int pos_to_remove = find_rr_pos(from, to_remove);
 		if (pos_to_remove >= 0) {
 			int ret = remove_rr_at(from, pos_to_remove, mm);
@@ -405,5 +345,4 @@ int knot_rrs_subtract(knot_rrs_t *from, const knot_rrs_t *what, mm_ctx_t *mm)
 	}
 
 	return KNOT_EOK;
-}
-
+}
\ No newline at end of file
diff --git a/src/libknot/rr.h b/src/libknot/rdataset.h
similarity index 58%
rename from src/libknot/rr.h
rename to src/libknot/rdataset.h
index 4fd46b85a6fcb4877447132bd89a6b14ebf5868b..af52126d5514108771f2b2983e79258e2765f20e 100644
--- a/src/libknot/rr.h
+++ b/src/libknot/rdataset.h
@@ -1,5 +1,5 @@
 /*!
- * \file rr.h
+ * \file rdataset.h
  *
  * \author Jan Kadlec <jan.kadlec@nic.cz>
  *
@@ -31,77 +31,15 @@
 #include <stdbool.h>
 
 #include "common/mempattern.h"
-
-/* ---------------------------- Single RR ----------------------------------- */
-
-/*!
- * \brief knot_rr_t Array holding single RR payload, i.e. ttl, size and RDATA.
- */
-typedef uint8_t knot_rr_t;
-
-/* ------------------------- RR getters/setters ----------------------------- */
-
-/*!
- * \brief Returns RDATA size of single RR.
- * \param rr  RR whose size we want.
- * \return  RR size.
- */
-uint16_t knot_rr_rdata_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 pointer to RR data.
- * \param rr  RR whose data we want.
- * \return RR data pointer.
- */
-uint8_t *knot_rr_rdata(const knot_rr_t *rr);
-
-/* ----------------------------- 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. Both RRs *must* exist.
- * \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);
+#include "libknot/rdata.h"
 
 /* --------------------------- Multiple RRs ----------------------------------*/
 
-/*!< \brief Array of RRs. */
-typedef struct knot_rrs {
+/*!< \brief Set of RRs. */
+typedef struct knot_rdataset {
 	uint16_t rr_count;  /*!< \brief Count of RRs stored in the structure. */
-	knot_rr_t *data;    /*!< \brief Actual data, canonically sorted. */
-} knot_rrs_t;
+	knot_rdata_t *data; /*!< \brief Actual data, canonically sorted. */
+} knot_rdataset_t;
 
 /* -------------------------- RRs init/clear ---------------------------------*/
 
@@ -109,14 +47,14 @@ typedef struct knot_rrs {
  * \brief Initializes RRS structure.
  * \param rrs  Structure to be initialized.
  */
-void knot_rrs_init(knot_rrs_t *rrs);
+void knot_rdataset_init(knot_rdataset_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);
+void knot_rdataset_clear(knot_rdataset_t *rrs, mm_ctx_t *mm);
 
 /*!
  * \brief Deep copies RRS structure. All data are duplicated.
@@ -125,7 +63,7 @@ void knot_rrs_clear(knot_rrs_t *rrs, mm_ctx_t *mm);
  * \param mm   Memory context.
  * \return KNOT_E*
  */
-int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm);
+int knot_rdataset_copy(knot_rdataset_t *dst, const knot_rdataset_t *src, mm_ctx_t *mm);
 
 /* ----------------------- RRs getters/setters ------------------------------ */
 
@@ -135,14 +73,14 @@ int knot_rrs_copy(knot_rrs_t *dst, const knot_rrs_t *src, mm_ctx_t *mm);
  * \param pos  Position to use.
  * \return Pointer to RR at \a pos position.
  */
-knot_rr_t *knot_rrs_rr(const knot_rrs_t *rrs, size_t pos);
+knot_rdata_t *knot_rdataset_at(const knot_rdataset_t *rrs, size_t pos);
 
 /*!
- * \brief Returns size of array with RRs.
+ * \brief Returns size of the RR set.
  * \param rrs  RR array.
  * \return Array size.
  */
-size_t knot_rrs_size(const knot_rrs_t *rrs);
+size_t knot_rdataset_size(const knot_rdataset_t *rrs);
 
 /* ----------------------- RRs RR manipulation ------------------------------ */
 
@@ -153,7 +91,7 @@ size_t knot_rrs_size(const knot_rrs_t *rrs);
  * \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);
+int knot_rdataset_add(knot_rdataset_t *rrs, const knot_rdata_t *rr, mm_ctx_t *mm);
 
 /* ---------------------- RRs set-like operations --------------------------- */
 
@@ -164,7 +102,7 @@ int knot_rrs_add_rr(knot_rrs_t *rrs, const knot_rr_t *rr, mm_ctx_t *mm);
  * \retval true if rrs1 == rrs2.
  * \retval false if rrs1 != rrs2.
  */
-bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2);
+bool knot_rdataset_eq(const knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2);
 
 /*!
  * \brief Returns true if \a rr is present in \a rrs, false otherwise.
@@ -174,7 +112,7 @@ bool knot_rrs_eq(const knot_rrs_t *rrs1, const knot_rrs_t *rrs2);
  * \retval true if \a rr is present in \a rrs.
  * \retval false if \a rr is not present in \a rrs.
  */
-bool knot_rrs_member(const knot_rrs_t *rrs, const knot_rr_t *rr, bool cmp_ttl);
+bool knot_rdataset_member(const knot_rdataset_t *rrs, const knot_rdata_t *rr, bool cmp_ttl);
 
 /*!
  * \brief Merges two RRS into the first one. Second RRS is left intact.
@@ -184,7 +122,7 @@ bool knot_rrs_member(const knot_rrs_t *rrs, const knot_rr_t *rr, bool cmp_ttl);
  * \param mm    Memory context.
  * \return KNOT_E*
  */
-int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm);
+int knot_rdataset_merge(knot_rdataset_t *rrs1, const knot_rdataset_t *rrs2, mm_ctx_t *mm);
 
 /*!
  * \brief RRS set-like intersection. Full compare is done.
@@ -194,8 +132,8 @@ int knot_rrs_merge(knot_rrs_t *rrs1, const knot_rrs_t *rrs2, mm_ctx_t *mm);
  * \param mm       Memory context. Will be used to create new RDATA.
  * \return KNOT_E*
  */
-int knot_rrs_intersect(const knot_rrs_t *a, const knot_rrs_t *b,
-                       knot_rrs_t *out, mm_ctx_t *mm);
+int knot_rdataset_intersect(const knot_rdataset_t *a, const knot_rdataset_t *b,
+                            knot_rdataset_t *out, mm_ctx_t *mm);
 
 /*!
  * \brief Does set-like RRS subtraction. \a from RRS is changed.
@@ -204,5 +142,18 @@ int knot_rrs_intersect(const knot_rrs_t *a, const knot_rrs_t *b,
  * \param mm    Memory context use to reallocated \a from data.
  * \return KNOT_E*
  */
-int knot_rrs_subtract(knot_rrs_t *from, const knot_rrs_t *what,
-                      mm_ctx_t *mm);
+int knot_rdataset_subtract(knot_rdataset_t *from, const knot_rdataset_t *what,
+                           mm_ctx_t *mm);
+
+/*! \brief Accession helpers. */
+#define KNOT_RDATASET_CHECK(rrs, pos, code) \
+	if (rrs == NULL || rrs->data == NULL || rrs->rr_count == 0 || \
+	    pos >= rrs->rr_count) { \
+		code; \
+	}
+
+static inline
+uint8_t *knot_rdata_offset(const knot_rdataset_t *rrs, size_t pos, size_t offset) {
+	knot_rdata_t *rr = knot_rdataset_at(rrs, pos);
+	return knot_rdata_data(rr) + offset;
+}
\ No newline at end of file
diff --git a/src/libknot/rrset.c b/src/libknot/rrset.c
index 5b79af261db38bf67cd35ae63f0545ac3f4a729e..421afcda94af4a35812006e66d371bb206b1c3f6 100644
--- a/src/libknot/rrset.c
+++ b/src/libknot/rrset.c
@@ -32,7 +32,6 @@
 #include "libknot/packet/wire.h"
 #include "libknot/packet/pkt.h"
 #include "libknot/dname.h"
-#include "libknot/rdata.h"
 
 static uint16_t rrset_rdata_naptr_bin_chunk_size(const knot_rrset_t *rrset,
                                                size_t pos)
@@ -367,7 +366,7 @@ void knot_rrset_init(knot_rrset_t *rrset, knot_dname_t *owner, uint16_t type,
 	rrset->owner = owner;
 	rrset->type = type;
 	rrset->rclass = rclass;
-	knot_rrs_init(&rrset->rrs);
+	knot_rdataset_init(&rrset->rrs);
 	rrset->additional = NULL;
 }
 
@@ -388,7 +387,7 @@ knot_rrset_t *knot_rrset_copy(const knot_rrset_t *src, mm_ctx_t *mm)
 		return NULL;
 	}
 
-	int ret = knot_rrs_copy(&rrset->rrs, &src->rrs, mm);
+	int ret = knot_rdataset_copy(&rrset->rrs, &src->rrs, mm);
 	if (ret != KNOT_EOK) {
 		knot_rrset_free(&rrset, mm);
 		return NULL;
@@ -412,16 +411,16 @@ void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm)
 void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm)
 {
 	if (rrset) {
-		knot_rrs_clear(&rrset->rrs, mm);
+		knot_rdataset_clear(&rrset->rrs, mm);
 		knot_dname_free(&rrset->owner, mm);
 	}
 }
 
 uint8_t *knot_rrset_rr_rdata(const knot_rrset_t *rrset, size_t pos)
 {
-	knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos);
+	knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
 	if (rr) {
-		return knot_rr_rdata(rr);
+		return knot_rdata_data(rr);
 	} else {
 		return NULL;
 	}
@@ -429,9 +428,9 @@ uint8_t *knot_rrset_rr_rdata(const knot_rrset_t *rrset, size_t pos)
 
 uint16_t knot_rrset_rr_size(const knot_rrset_t *rrset, size_t pos)
 {
-	const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos);
+	const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
 	if (rr) {
-		return knot_rr_rdata_size(rr);
+		return knot_rdata_rdlen(rr);
 	} else {
 		return 0;
 	}
@@ -439,9 +438,9 @@ uint16_t knot_rrset_rr_size(const knot_rrset_t *rrset, size_t pos)
 
 uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos)
 {
-	const knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos);
+	const knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
 	if (rr) {
-		return knot_rr_ttl(rr);
+		return knot_rdata_ttl(rr);
 	} else {
 		return 0;
 	}
@@ -449,9 +448,9 @@ uint32_t knot_rrset_rr_ttl(const knot_rrset_t *rrset, size_t pos)
 
 void knot_rrset_rr_set_ttl(const knot_rrset_t *rrset, size_t pos, uint32_t ttl)
 {
-	knot_rr_t *rr = knot_rrs_rr(&rrset->rrs, pos);
+	knot_rdata_t *rr = knot_rdataset_at(&rrset->rrs, pos);
 	if (rr) {
-		knot_rr_set_ttl(rr, ttl);
+		knot_rdata_set_ttl(rr, ttl);
 	}
 }
 
@@ -510,7 +509,7 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
 		if (empty_rdata == NULL) {
 			return KNOT_ENOMEM;
 		}
-		int ret = knot_rrset_add_rr(rrset, empty_rdata, 0, ttl, mm);
+		int ret = knot_rrset_add_rdata(rrset, empty_rdata, 0, ttl, mm);
 		free(empty_rdata);
 		return ret;
 	}
@@ -589,10 +588,10 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
 		}
 	}
 
-	return knot_rrset_add_rr(rrset, rdata_buffer, offset, ttl, mm);
+	return knot_rrset_add_rdata(rrset, rdata_buffer, offset, ttl, mm);
 }
 
-int knot_rrset_add_rr(knot_rrset_t *rrset,
+int knot_rrset_add_rdata(knot_rrset_t *rrset,
                       const uint8_t *rdata, const uint16_t size,
                       const uint32_t ttl, mm_ctx_t *mm)
 {
@@ -600,13 +599,12 @@ int knot_rrset_add_rr(knot_rrset_t *rrset,
 		return KNOT_EINVAL;
 	}
 
-	// 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_rdata(rr), rdata, size);
+	knot_rdata_t rr[knot_rdata_array_size(size)];
+	knot_rdata_set_rdlen(rr, size);
+	knot_rdata_set_ttl(rr, ttl);
+	memcpy(knot_rdata_data(rr), rdata, size);
 
-	return knot_rrs_add_rr(&rrset->rrs, rr, mm);
+	return knot_rdataset_add(&rrset->rrs, rr, mm);
 }
 
 bool knot_rrset_equal(const knot_rrset_t *r1,
@@ -626,7 +624,7 @@ bool knot_rrset_equal(const knot_rrset_t *r1,
 	}
 
 	if (cmp == KNOT_RRSET_COMPARE_WHOLE) {
-		return knot_rrs_eq(&r1->rrs, &r2->rrs);
+		return knot_rdataset_eq(&r1->rrs, &r2->rrs);
 	}
 
 	return true;
diff --git a/src/libknot/rrset.h b/src/libknot/rrset.h
index 706bc298819e9c7e3eb6a5f9ef3ee324d73129fe..4cc4f77bc35edec876e7263cf87a2d463c03d903 100644
--- a/src/libknot/rrset.h
+++ b/src/libknot/rrset.h
@@ -33,7 +33,7 @@
 #include "common/mempattern.h"
 
 #include "libknot/dname.h"
-#include "libknot/rr.h"
+#include "libknot/rdataset.h"
 
 struct knot_compr;
 struct knot_node;
@@ -47,7 +47,7 @@ struct knot_rrset {
 	knot_dname_t *owner;  /*!< Domain name being the owner of the RRSet. */
 	uint16_t type;        /*!< TYPE of the RRset. */
 	uint16_t rclass;      /*!< CLASS of the RRSet. */
-	knot_rrs_t rrs;       /*!< RRSet's RRs */
+	knot_rdataset_t rrs;  /*!< RRSet's RRs */
 	/* Optional fields. */
 	struct knot_node **additional; /*!< Additional records. */
 };
@@ -125,7 +125,7 @@ void knot_rrset_free(knot_rrset_t **rrset, mm_ctx_t *mm);
  */
 void knot_rrset_clear(knot_rrset_t *rrset, mm_ctx_t *mm);
 
-/* ----------- Getters / Setters (legacy, functionality in rr_t) ------------ */
+/* ----------- Getters / Setters (legacy, functionality in rdata_t) ------------ */
 
 /*!
  * \brief Returns RDATA of RR on given position.
@@ -211,7 +211,7 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
                                    size_t total_size, uint32_t ttl, size_t rdlength,
                                    mm_ctx_t *mm);
 
-/* ---------- RR addition. (legacy, functionality in knot_rrs_t) ------------ */
+/* ---------- RR addition. (legacy, functionality in knot_rdataset_t) ------- */
 
 /*!
  * \brief Adds the given RDATA to the RRSet.
@@ -224,9 +224,9 @@ int knot_rrset_rdata_from_wire_one(knot_rrset_t *rrset,
  *
  * \return KNOT_E*
  */
-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);
+int knot_rrset_add_rdata(knot_rrset_t *rrset, const uint8_t *rdata,
+                         const uint16_t size, const uint32_t ttl,
+                         mm_ctx_t *mm);
 
 /* ------------------ Equality / emptines bool checks ----------------------- */
 
diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c
index 6ff78c9eb86d5dbd4911b568207942a5143368eb..a340f5a9224e2188ca83e163ebe0dd50a07db786 100644
--- a/src/libknot/tsig-op.c
+++ b/src/libknot/tsig-op.c
@@ -23,7 +23,7 @@
 
 #include "libknot/common.h"
 #include "common/descriptor.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "libknot/tsig-op.h"
 #include "libknot/packet/wire.h"
 #include "common/debug.h"
diff --git a/src/libknot/tsig-op.h b/src/libknot/tsig-op.h
index ce627b5c94f11f17b8f3fc54119108b411896906..535d4e325de7144fb4757567401fcc0adcc70874 100644
--- a/src/libknot/tsig-op.h
+++ b/src/libknot/tsig-op.h
@@ -29,7 +29,7 @@
 
 #include <stdint.h>
 
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 #include "libknot/rrset.h"
 #include "libknot/dnssec/key.h"
 
diff --git a/src/utils/dig/dig_exec.c b/src/utils/dig/dig_exec.c
index 4244c80b11c147c85d934a18ebb68e68ba1b05b3..e634cfbf3de17f411e88123879c5a71891364fd4 100644
--- a/src/utils/dig/dig_exec.c
+++ b/src/utils/dig/dig_exec.c
@@ -125,7 +125,7 @@ static knot_pkt_t* create_query_packet(const query_t *query)
 		}
 
 		// Set SOA serial.
-		knot_rrs_soa_serial_set(&soa->rrs, query->xfr_serial);
+		knot_soa_serial_set(&soa->rrs, query->xfr_serial);
 
 		// Add authority section.
 		knot_pkt_begin(packet, KNOT_AUTHORITY);
@@ -232,7 +232,7 @@ static int64_t first_serial_check(const knot_pkt_t *reply)
 	if (first->type != KNOT_RRTYPE_SOA) {
 		return -1;
 	} else {
-		return knot_rrs_soa_serial(&first->rrs);
+		return knot_soa_serial(&first->rrs);
 	}
 }
 
@@ -248,7 +248,7 @@ static bool last_serial_check(const uint32_t serial, const knot_pkt_t *reply)
 	if (last->type != KNOT_RRTYPE_SOA) {
 		return false;
 	} else {
-		int64_t last_serial = knot_rrs_soa_serial(&last->rrs);
+		int64_t last_serial = knot_soa_serial(&last->rrs);
 		if (last_serial == serial) {
 			return true;
 		} else {
diff --git a/src/utils/nsec3hash/nsec3hash_main.c b/src/utils/nsec3hash/nsec3hash_main.c
index f7d33d7d61a9cfb4e5d6c7f15ef83d5fcf33bbee..eaff2315b0bf75fc136e0f8b77618df9344ef7b6 100644
--- a/src/utils/nsec3hash/nsec3hash_main.c
+++ b/src/utils/nsec3hash/nsec3hash_main.c
@@ -27,7 +27,6 @@
 #include "common/hex.h"
 #include "common/strtonum.h"
 #include "libknot/dnssec/crypto.h"
-#include "libknot/dnssec/nsec3.h"
 
 #define PROGRAM_NAME "knsec3hash"
 
@@ -183,7 +182,7 @@ int main(int argc, char *argv[])
 	       nsec3_params.iterations);
 
 fail:
-	knot_nsec3_params_free(&nsec3_params);
+	knot_nsec3param_free(&nsec3_params);
 	knot_dname_free(&dname, NULL);
 	free(digest);
 	free(b32_digest);
diff --git a/tests/dnssec_nsec3.c b/tests/dnssec_nsec3.c
index 8db2af9f3ce581343330c766089aeac946b3f685..37e75dda5716b3dde0f3c146a2403eddb88751b8 100644
--- a/tests/dnssec_nsec3.c
+++ b/tests/dnssec_nsec3.c
@@ -23,8 +23,8 @@
 #include "common/errcode.h"
 #include "libknot/dname.h"
 #include "libknot/consts.h"
-#include "libknot/dnssec/nsec3.h"
 #include "libknot/rrset.h"
+#include "libknot/rdata/nsec3.h"
 
 int main(int argc, char *argv[])
 {
@@ -59,9 +59,9 @@ int main(int argc, char *argv[])
 	rrset = knot_rrset_new(owner, KNOT_RRTYPE_NSEC3PARAM, KNOT_CLASS_IN, NULL);
 	knot_dname_free(&owner, NULL);
 
-	result = knot_rrset_add_rr(rrset, rdata, sizeof(rdata), 0, NULL);
+	result = knot_rrset_add_rdata(rrset, rdata, sizeof(rdata), 0, NULL);
 	if (result == KNOT_EOK) {
-		result = knot_nsec3_params_from_wire(&params, &rrset->rrs);
+		result = knot_nsec3param_from_wire(&params, &rrset->rrs);
 	}
 
 	is_int(1, params.algorithm, "parse algorithm from wire");
@@ -71,7 +71,7 @@ int main(int argc, char *argv[])
 	is_int(0, memcmp(params.salt, "abcd", 4), "parse salt from wire");
 
 	knot_rrset_free(&rrset, NULL);
-	knot_nsec3_params_free(&params);
+	knot_nsec3param_free(&params);
 
 	// hash computation
 
diff --git a/tests/pkt.c b/tests/pkt.c
index 7f6857174a53ef359187cc7e67c79dace26e0b6c..ab9787cc4fa7bef089d96ce64b1b0a3d3edf465a 100644
--- a/tests/pkt.c
+++ b/tests/pkt.c
@@ -19,9 +19,9 @@
 
 #include "common/errcode.h"
 #include "common/mempool.h"
-#include "libknot/rdata.h"
+#include "common/descriptor.h"
 #include "libknot/packet/pkt.h"
-#include "libknot/tsig.h"
+#include "libknot/rdata/tsig.h"
 
 #define TTL 7200
 #define NAMECOUNT 3
@@ -104,7 +104,7 @@ int main(int argc, char *argv[])
 	/* Write ANSWER section. */
 	rrsets[0] = knot_rrset_new(dnames[0], KNOT_RRTYPE_A, KNOT_CLASS_IN, NULL);
 	knot_dname_free(&dnames[0], NULL);
-	knot_rrset_add_rr(rrsets[0], RDVAL(0), RDLEN(0), TTL, NULL);
+	knot_rrset_add_rdata(rrsets[0], RDVAL(0), RDLEN(0), TTL, NULL);
 	ret = knot_pkt_put(out, COMPR_HINT_QNAME, rrsets[0], 0);
 	ok(ret == KNOT_EOK, "pkt: write ANSWER");
 
@@ -117,7 +117,7 @@ int main(int argc, char *argv[])
 	for (unsigned i = 1; i < NAMECOUNT; ++i) {
 		rrsets[i] = knot_rrset_new(dnames[i], KNOT_RRTYPE_NS, KNOT_CLASS_IN, NULL);
 		knot_dname_free(&dnames[i], NULL);
-		knot_rrset_add_rr(rrsets[i], RDVAL(i), RDLEN(i), TTL, NULL);
+		knot_rrset_add_rdata(rrsets[i], RDVAL(i), RDLEN(i), TTL, NULL);
 		ret |= knot_pkt_put(out, COMPR_HINT_NONE, rrsets[i], 0);
 	}
 	ok(ret == KNOT_EOK, "pkt: write AUTHORITY(%u)", NAMECOUNT - 1);
diff --git a/tests/process_query.c b/tests/process_query.c
index 2e2ea6049e6b262b65f4eb5a4bb348e228d1a371..1f4ee62eeaf0fb3defcdf43a071ea8cbcdbef1c7 100644
--- a/tests/process_query.c
+++ b/tests/process_query.c
@@ -51,7 +51,7 @@ void create_root_zone(server_t *server, mm_ctx_t *mm)
 	knot_rrset_t *soa_rrset = knot_rrset_new(root->name,
 	                                         KNOT_RRTYPE_SOA, KNOT_CLASS_IN,
 	                                         NULL);
-	knot_rrset_add_rr(soa_rrset, SOA_RDATA, SOA_RDLEN, 7200, NULL);
+	knot_rrset_add_rdata(soa_rrset, SOA_RDATA, SOA_RDLEN, 7200, NULL);
 	knot_node_add_rrset(root->contents->apex, soa_rrset, NULL);
 
 	/* Bake the zone. */