Compare commits
30 Commits
wpk-taskmg
...
NG-lowac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b11668ad8 | ||
|
|
f689db69db | ||
|
|
7b276d4062 | ||
|
|
c5949ff9d1 | ||
|
|
57ab5d3a14 | ||
|
|
496923f71f | ||
|
|
32472059d3 | ||
|
|
0dcdbdfbdd | ||
|
|
3b6985b783 | ||
|
|
96ba0486f3 | ||
|
|
7132ffffad | ||
|
|
48853a75ff | ||
|
|
df0c5bc4cf | ||
|
|
cd6f768a16 | ||
|
|
7a6b2ffddd | ||
|
|
758045a2fd | ||
|
|
0e037f8873 | ||
|
|
7c68a70bf9 | ||
|
|
f9d4a96021 | ||
|
|
9b5bdf4e89 | ||
|
|
8c9ae61062 | ||
|
|
f7390b39f8 | ||
|
|
14ec374173 | ||
|
|
1fec6d70e6 | ||
|
|
96b76abece | ||
|
|
0a73f7bb27 | ||
|
|
aaaa727cb3 | ||
|
|
55a435f091 | ||
|
|
609e505bc1 | ||
|
|
8ffd188a26 |
4
configure
vendored
4
configure
vendored
@@ -15115,8 +15115,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS -lck $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS -I/usr/include/ck"
|
||||
CC="$PTHREAD_CC"
|
||||
|
||||
#
|
||||
|
||||
@@ -657,8 +657,8 @@ AC_CHECK_FUNCS(arc4random arc4random_buf arc4random_uniform getrandom)
|
||||
|
||||
AX_PTHREAD
|
||||
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS -lck $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS -I/usr/include/ck"
|
||||
CC="$PTHREAD_CC"
|
||||
|
||||
#
|
||||
|
||||
@@ -37,7 +37,7 @@ ISCLIBS = ../../lib/isc/libisc.@A@ @OPENSSL_LIBS@
|
||||
|
||||
ISCDEPLIBS = ../../lib/isc/libisc.@A@
|
||||
|
||||
LIBS = @LIBS@
|
||||
LIBS = @LIBS@ -lck
|
||||
|
||||
# Alphabetically
|
||||
|
||||
@@ -73,7 +73,7 @@ DNSOBJS = acl.@O@ adb.@O@ badcache.@O@ byaddr.@O@ \
|
||||
stats.@O@ tcpmsg.@O@ time.@O@ timer.@O@ tkey.@O@ \
|
||||
tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@O@ \
|
||||
version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ \
|
||||
zoneverify.@O@ zt.@O@
|
||||
zoneverify.@O@ zt.@O@ lowac.@O@
|
||||
PORTDNSOBJS = client.@O@ ecdb.@O@
|
||||
|
||||
OBJS= @DNSTAPOBJS@ ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} \
|
||||
@@ -108,7 +108,7 @@ DNSSRCS = acl.c adb.c badcache. byaddr.c \
|
||||
stats.c tcpmsg.c time.c timer.c tkey.c \
|
||||
tsec.c tsig.c ttl.c update.c validator.c \
|
||||
version.c view.c xfrin.c zone.c zoneverify.c \
|
||||
zonekey.c zt.c ${OTHERSRCS}
|
||||
zonekey.c zt.c ${OTHERSRCS} lowac.c
|
||||
PORTDNSSRCS = client.c ecdb.c
|
||||
|
||||
SRCS = ${DSTSRCS} ${DNSSRCS} ${PORTDNSSRCS} @DNSTAPSRCS@ @GEOIPLINKSRCS@
|
||||
|
||||
17
lib/dns/include/dns/lowac.h
Normal file
17
lib/dns/include/dns/lowac.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <isc/mem.h>
|
||||
#include <dns/name.h>
|
||||
typedef struct dns_lowac_entry dns_lowac_entry_t;
|
||||
typedef struct dns_lowac dns_lowac_t;
|
||||
|
||||
dns_lowac_t*
|
||||
dns_lowac_create(isc_mem_t *mctx);
|
||||
|
||||
void
|
||||
dns_lowac_destroy(dns_lowac_t *lowac);
|
||||
|
||||
isc_result_t
|
||||
dns_lowac_put(dns_lowac_t *lowac, dns_name_t *name, char* packet, int size);
|
||||
|
||||
isc_result_t
|
||||
dns_lowac_get(dns_lowac_t *lowac, dns_name_t *name, unsigned char* blob, int* blobsize, bool tcp);
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
#include <dns/rpz.h>
|
||||
#include <dns/types.h>
|
||||
#include <dns/zt.h>
|
||||
#include <dns/lowac.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
@@ -238,6 +239,8 @@ struct dns_view {
|
||||
dns_dtenv_t *dtenv; /* Dnstap environment */
|
||||
dns_dtmsgtype_t dttypes; /* Dnstap message types
|
||||
to log */
|
||||
|
||||
dns_lowac_t* lowac;
|
||||
};
|
||||
|
||||
#define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w')
|
||||
|
||||
490
lib/dns/lowac.c
Normal file
490
lib/dns/lowac.c
Normal file
@@ -0,0 +1,490 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <isc/thread.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/time.h>
|
||||
#include <isc/util.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/lowac.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <ck_ht.h>
|
||||
#include <ck_fifo.h>
|
||||
#include <ck_queue.h>
|
||||
#define fprintf(...) {}
|
||||
#define MAXIMUM_PKT_SIZE 1024
|
||||
|
||||
#define LENTRY_MAGIC ISC_MAGIC('L', 'o', 'w', 'E')
|
||||
#define VALID_LENTRY(c) ISC_MAGIC_VALID(c, LENTRY_MAGIC)
|
||||
|
||||
struct dns_lowac_entry {
|
||||
unsigned int magic;
|
||||
dns_name_t name;
|
||||
isc_region_t key;
|
||||
uint16_t flags;
|
||||
int64_t expire;
|
||||
ck_ht_hash_t hash;
|
||||
unsigned char *blob;
|
||||
uint32_t blobsize;
|
||||
isc_refcount_t refcount;
|
||||
/*
|
||||
* Set to 'true' when we enqueue this entry on remq.
|
||||
* Nothing serious will happen if we enqueue the entry
|
||||
* on remq multiple times as we're refcounting.
|
||||
* It's not locked in any way as it can only change
|
||||
* from false to true during runtime.
|
||||
*/
|
||||
bool remq_enqueued;
|
||||
bool inht;
|
||||
isc_refcount_t rqrefcount;
|
||||
|
||||
|
||||
|
||||
atomic_int_fast64_t lastusage;
|
||||
};
|
||||
|
||||
|
||||
struct dns_lowac {
|
||||
isc_mem_t * mctx;
|
||||
isc_thread_t thread;
|
||||
int expiry; /* Time after which records expire */
|
||||
|
||||
bool running; /* We're not shut down */
|
||||
bool accepting; /* We're accepting packets into cache */
|
||||
|
||||
ck_ht_t ht; /* Cache hash table */
|
||||
ck_ht_iterator_t htit; /* Hashtable maintenance iterator */
|
||||
|
||||
ck_fifo_mpmc_t inq; /* Packet input queue */
|
||||
ck_fifo_mpmc_t remq; /* Removal queue */
|
||||
|
||||
atomic_int_fast64_t now; /* Epoch time, updated at every loop */
|
||||
int count;
|
||||
|
||||
};
|
||||
|
||||
static void *
|
||||
rthread(void*d);
|
||||
|
||||
static void *
|
||||
ht_malloc(size_t r)
|
||||
{
|
||||
return(malloc(r));
|
||||
}
|
||||
|
||||
static void
|
||||
ht_free(void *p, size_t b, bool r)
|
||||
{
|
||||
(void)b;
|
||||
(void)r;
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ht_hash_wrapper(struct ck_ht_hash *h, const void *key, size_t length,
|
||||
uint64_t seed)
|
||||
{
|
||||
(void)seed;
|
||||
h->value = isc_hash_function(key, length, false, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct ck_malloc my_allocator = {
|
||||
.malloc = ht_malloc,
|
||||
.free = ht_free
|
||||
};
|
||||
|
||||
static void
|
||||
free_entry(dns_lowac_t *lowac, dns_lowac_entry_t *entry) {
|
||||
entry->magic = 0xffffffff;
|
||||
dns_name_free(&entry->name, lowac->mctx);
|
||||
isc_mem_put(lowac->mctx, entry->blob, entry->blobsize);
|
||||
isc_mem_put(lowac->mctx, entry, sizeof(*entry));
|
||||
}
|
||||
|
||||
static bool
|
||||
dequeue_input_entry(dns_lowac_t*lowac) {
|
||||
dns_lowac_entry_t *entry = NULL;
|
||||
ck_fifo_mpmc_entry_t *garbage = NULL;
|
||||
if (ck_fifo_mpmc_dequeue(&lowac->inq, &entry,
|
||||
&garbage) == true) {
|
||||
REQUIRE(VALID_LENTRY(entry));
|
||||
isc_mem_put(lowac->mctx, garbage,
|
||||
sizeof(*garbage));
|
||||
ck_ht_entry_t htentry;
|
||||
ck_ht_entry_t oldhtentry;
|
||||
|
||||
ck_ht_entry_set(&htentry, entry->hash, entry->key.base,
|
||||
entry->key.length, entry);
|
||||
ck_ht_entry_set(&oldhtentry, entry->hash, entry->key.base,
|
||||
entry->key.length, NULL);
|
||||
|
||||
if (ck_ht_get_spmc(&lowac->ht, entry->hash,
|
||||
&oldhtentry) == false) {
|
||||
/* We don't have this entry in hashtable */
|
||||
entry->inht = true;
|
||||
if (ck_ht_put_spmc(&lowac->ht, entry->hash,
|
||||
&htentry) == false) {
|
||||
abort();
|
||||
printf("oddness but might happen\n");
|
||||
/* We can do it safely as it never was in
|
||||
* hashtable */
|
||||
RUNTIME_CHECK(isc_refcount_decrement(&entry->
|
||||
refcount) ==
|
||||
1);
|
||||
free_entry(lowac, entry);
|
||||
} else {
|
||||
fprintf(stderr, "XXXInsert %p %d\n", entry, lowac->count);
|
||||
lowac->count++;
|
||||
}
|
||||
} else {
|
||||
dns_lowac_entry_t *oldentry =
|
||||
ck_ht_entry_value(&oldhtentry);
|
||||
/* Note: set without remove doesn't seem to work
|
||||
* properly */
|
||||
oldentry->inht = false;
|
||||
RUNTIME_CHECK(ck_ht_remove_spmc(&lowac->ht,
|
||||
entry->hash,
|
||||
&oldhtentry) == true);
|
||||
entry->inht = true;
|
||||
RUNTIME_CHECK(ck_ht_set_spmc(&lowac->ht, entry->hash,
|
||||
&htentry) == true);
|
||||
lowac->count++;
|
||||
|
||||
/*
|
||||
* We don't need to increment refcount since we
|
||||
* have not decremented it
|
||||
* when removing from hashtable
|
||||
*/
|
||||
ck_fifo_mpmc_entry_t *qentry =
|
||||
isc_mem_get(lowac->mctx,
|
||||
(sizeof(
|
||||
ck_fifo_mpmc_entry_t)));
|
||||
oldentry->remq_enqueued = true;
|
||||
isc_refcount_increment(&oldentry->rqrefcount);
|
||||
fprintf(stderr, "XXXenq %p %d\n", oldentry, __LINE__);
|
||||
ck_fifo_mpmc_enqueue(&lowac->remq, qentry,
|
||||
oldentry);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
static int
|
||||
expire_entries(dns_lowac_t *lowac) {
|
||||
int iterated = 0;
|
||||
|
||||
ck_ht_entry_t *htitentry = NULL;
|
||||
bool iterok = ck_ht_next(&lowac->ht, &lowac->htit, &htitentry);
|
||||
if (!iterok) {
|
||||
ck_ht_iterator_init(&lowac->htit);
|
||||
iterok = ck_ht_next(&lowac->ht, &lowac->htit, &htitentry);
|
||||
}
|
||||
while (iterok && htitentry != NULL && iterated < 2048) {
|
||||
dns_lowac_entry_t *entry = ck_ht_entry_value(htitentry);
|
||||
REQUIRE(VALID_LENTRY(entry));
|
||||
if (entry->expire < atomic_load(&lowac->now)) {
|
||||
if (!ck_ht_remove_spmc(&lowac->ht, entry->hash, htitentry)) {
|
||||
abort();
|
||||
/*
|
||||
* Very unlikely, but can happen when we're between generations.
|
||||
* TODO verify that it's ok at all, maybe we're using the iterator wrong?
|
||||
*/
|
||||
isc_refcount_increment(&entry->refcount);
|
||||
fprintf(stderr, "INCREF %d %p\n", __LINE__, entry);
|
||||
} else {
|
||||
dns_lowac_entry_t *ent2 = ck_ht_entry_value(htitentry);
|
||||
RUNTIME_CHECK(ent2 == entry);
|
||||
}
|
||||
entry->inht = false;
|
||||
/*
|
||||
* We don't need to increment refcount since we have
|
||||
* not decremented it when removing from hashtable.
|
||||
*/
|
||||
ck_fifo_mpmc_entry_t *qentry =
|
||||
isc_mem_get(lowac->mctx,
|
||||
(sizeof(
|
||||
ck_fifo_mpmc_entry_t)));
|
||||
entry->remq_enqueued = true;
|
||||
isc_refcount_increment(&entry->rqrefcount);
|
||||
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
|
||||
ck_fifo_mpmc_enqueue(&lowac->remq, qentry, entry);
|
||||
}
|
||||
htitentry = NULL;
|
||||
iterok = ck_ht_next(&lowac->ht, &lowac->htit, &htitentry);
|
||||
iterated++;
|
||||
}
|
||||
|
||||
if (!iterok) {
|
||||
ck_ht_iterator_init(&lowac->htit);
|
||||
}
|
||||
return (iterated);
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over remq.
|
||||
* If the entry is in HT - remove it, requeue.
|
||||
* If the entry is not in HT but it is referenced - requeue.
|
||||
* If the entry is not referenced - free.
|
||||
*/
|
||||
static int
|
||||
cleanup_entries(dns_lowac_t *lowac) {
|
||||
ck_ht_entry_t htentry;
|
||||
dns_lowac_entry_t *entry;
|
||||
ck_fifo_mpmc_entry_t *qentry = NULL;
|
||||
int removed = 0;
|
||||
int max = 100;
|
||||
|
||||
while (--max > 0 &&
|
||||
ck_fifo_mpmc_dequeue(&lowac->remq, &entry, &qentry) == true)
|
||||
{
|
||||
REQUIRE(VALID_LENTRY(entry));
|
||||
int rc = isc_refcount_decrement(&entry->refcount);
|
||||
int rqrc = isc_refcount_decrement(&entry->rqrefcount);
|
||||
fprintf(stderr, "DECREF %d %p %d\n", __LINE__, entry, lowac->count);
|
||||
if (entry->inht) {
|
||||
/*
|
||||
* Remove entry from the hashtable, we'll remove the
|
||||
* entry itself in the next iteration.
|
||||
*/
|
||||
ck_ht_entry_set(&htentry, entry->hash, entry->key.base,
|
||||
entry->key.length, entry);
|
||||
RUNTIME_CHECK(ck_ht_remove_spmc(&lowac->ht,
|
||||
entry->hash,
|
||||
&htentry) == true);
|
||||
entry->inht = false;
|
||||
isc_refcount_increment(&entry->rqrefcount);
|
||||
/* We don't increment refcount - it was at 2 (remq + ht), it stays at 1 (remq) */
|
||||
fprintf(stderr, "INCREF %d %p\n", __LINE__, entry);
|
||||
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
|
||||
ck_fifo_mpmc_enqueue(&lowac->remq, qentry, entry);
|
||||
} else {
|
||||
if (rc > 1) {
|
||||
/* Requeue if still in use and there's no other request in queue */
|
||||
/* TODO that's completely wrong, if we have two instances in the queue they will always have rc > 1 !!! */
|
||||
if (rqrc == 0) {
|
||||
int p1 = isc_refcount_increment(&entry->rqrefcount);
|
||||
int p2 = isc_refcount_increment(&entry->refcount);
|
||||
(void) p1;
|
||||
(void) p2;
|
||||
fprintf(stderr, "INCREF %d %p %d %d\n", __LINE__, entry, p1, p2);
|
||||
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
|
||||
ck_fifo_mpmc_enqueue(&lowac->remq, qentry,
|
||||
entry);
|
||||
} else {
|
||||
isc_mem_put(lowac->mctx, qentry,
|
||||
sizeof(*qentry));
|
||||
}
|
||||
fprintf(stderr, "IGNREF %d %p\n", __LINE__, entry);
|
||||
} else {
|
||||
isc_mem_put(lowac->mctx, qentry,
|
||||
sizeof(*qentry));
|
||||
removed++;
|
||||
free_entry(lowac, entry);
|
||||
fprintf(stderr, "XXXFree %p %d\n", entry, lowac->count);
|
||||
lowac->count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (removed);
|
||||
}
|
||||
|
||||
static void *
|
||||
rthread(void *d) {
|
||||
dns_lowac_t *lowac = (dns_lowac_t*) d;
|
||||
isc_thread_resetaffinity();
|
||||
ck_ht_iterator_init(&lowac->htit);
|
||||
while (lowac->running) {
|
||||
isc_time_t now;
|
||||
isc_time_now(&now);
|
||||
atomic_store(&lowac->now, now.seconds);
|
||||
bool dequeued = dequeue_input_entry(lowac);
|
||||
if (!dequeued) {
|
||||
expire_entries(lowac);
|
||||
int removed = cleanup_entries(lowac);
|
||||
if (removed < 256) {
|
||||
usleep(1000);
|
||||
} else {
|
||||
RUNTIME_CHECK(ck_ht_gc(&lowac->ht, 128,
|
||||
isc_random32()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
dns_lowac_t*
|
||||
dns_lowac_create(isc_mem_t *mctx) {
|
||||
dns_lowac_t *lowac = isc_mem_get(mctx, sizeof(dns_lowac_t));
|
||||
lowac->expiry = 600;
|
||||
lowac->count = 0;
|
||||
lowac->running = true;
|
||||
|
||||
if (ck_ht_init(&lowac->ht,
|
||||
CK_HT_MODE_BYTESTRING | CK_HT_WORKLOAD_DELETE,
|
||||
ht_hash_wrapper,
|
||||
&my_allocator, 32, isc_random32()) == false) {
|
||||
abort();
|
||||
}
|
||||
|
||||
ck_fifo_mpmc_entry_t *inq_stub =
|
||||
isc_mem_get(mctx, sizeof(ck_fifo_mpmc_entry_t));
|
||||
ck_fifo_mpmc_entry_t *remq_stub =
|
||||
isc_mem_get(mctx, sizeof(ck_fifo_mpmc_entry_t));
|
||||
|
||||
ck_fifo_mpmc_init(&lowac->inq, inq_stub);
|
||||
ck_fifo_mpmc_init(&lowac->remq, remq_stub);
|
||||
|
||||
|
||||
lowac->mctx = NULL;
|
||||
isc_mem_attach(mctx, &lowac->mctx);
|
||||
|
||||
isc_thread_create(rthread, lowac, &lowac->thread);
|
||||
isc_thread_setname(lowac->thread, "lowac-worker");
|
||||
return (lowac);
|
||||
}
|
||||
|
||||
void
|
||||
dns_lowac_destroy(dns_lowac_t *lowac) {
|
||||
lowac->running = false;
|
||||
isc_thread_join(lowac->thread, NULL);
|
||||
dns_lowac_entry_t *entry;
|
||||
ck_fifo_mpmc_entry_t *fentry;
|
||||
|
||||
/* Entries in inq can only be in inq, it's safe to free them */
|
||||
while (ck_fifo_mpmc_dequeue(&lowac->inq,
|
||||
&entry,
|
||||
&fentry))
|
||||
{
|
||||
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
|
||||
free_entry(lowac, entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Entries in remq can be freed only if they're no longer referenced
|
||||
* by either multiple occurences in queue or HT
|
||||
*/
|
||||
while (ck_fifo_mpmc_dequeue(&lowac->remq,
|
||||
&entry,
|
||||
&fentry))
|
||||
{
|
||||
if (isc_refcount_decrement(&entry->refcount) == 1) {
|
||||
fprintf(stderr, "DECREF %d %p\n", __LINE__, entry);
|
||||
free_entry(lowac, entry);
|
||||
} else {
|
||||
fprintf(stderr, "Non-unreferenced entry in remq %p\n", entry);
|
||||
}
|
||||
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
|
||||
}
|
||||
|
||||
/* Finally we free rest of entries from HT */
|
||||
while (ck_ht_count(&lowac->ht) > 0) {
|
||||
ck_ht_gc(&lowac->ht, 0, 0);
|
||||
ck_ht_iterator_t htit = CK_HT_ITERATOR_INITIALIZER;
|
||||
ck_ht_entry_t *htitentry = NULL;
|
||||
while (ck_ht_next(&lowac->ht, &htit, &htitentry)) {
|
||||
entry = ck_ht_entry_value(htitentry);
|
||||
ck_ht_remove_spmc(&lowac->ht, entry->hash, htitentry);
|
||||
free_entry(lowac, entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ck_fifo_mpmc_deinit(&lowac->inq, &fentry);
|
||||
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
|
||||
|
||||
ck_fifo_mpmc_deinit(&lowac->remq, &fentry);
|
||||
isc_mem_put(lowac->mctx, fentry, sizeof(*fentry));
|
||||
|
||||
ck_ht_destroy(&lowac->ht);
|
||||
isc_mem_putanddetach(&lowac->mctx, lowac, sizeof(*lowac));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_lowac_put(dns_lowac_t *lowac, dns_name_t *name, char*packet, int size) {
|
||||
if (!lowac->running) {
|
||||
return (ISC_R_SHUTTINGDOWN);
|
||||
}
|
||||
if (size > MAXIMUM_PKT_SIZE) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
dns_lowac_entry_t *entry = isc_mem_get(lowac->mctx, sizeof(*entry));
|
||||
dns_name_init(&entry->name, NULL);
|
||||
dns_name_dup(name, lowac->mctx, &entry->name);
|
||||
entry->blob = isc_mem_get(lowac->mctx, size);
|
||||
memcpy(entry->blob, packet, size);
|
||||
entry->blobsize = size;
|
||||
isc_refcount_init(&entry->refcount, 1);
|
||||
isc_refcount_init(&entry->rqrefcount, 0);
|
||||
entry->expire = atomic_load(&lowac->now) + lowac->expiry;
|
||||
entry->remq_enqueued = false;
|
||||
entry->inht = false;
|
||||
entry->magic = LENTRY_MAGIC;
|
||||
|
||||
dns_name_toregion(&entry->name, &entry->key);
|
||||
|
||||
ck_ht_hash(&entry->hash, &lowac->ht, entry->key.base,
|
||||
entry->key.length);
|
||||
ck_fifo_mpmc_entry_t *qentry =
|
||||
isc_mem_get(lowac->mctx, (sizeof(ck_fifo_mpmc_entry_t)));
|
||||
ck_fifo_mpmc_enqueue(&lowac->inq, qentry, entry);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
isc_result_t
|
||||
dns_lowac_get(dns_lowac_t *lowac, dns_name_t *name, unsigned char *blob,
|
||||
int *blobsize, bool tcp) {
|
||||
ck_ht_entry_t htentry;
|
||||
ck_ht_hash_t h;
|
||||
isc_region_t r;
|
||||
|
||||
dns_name_toregion(name, &r);
|
||||
ck_ht_hash(&h, &lowac->ht, r.base, r.length);
|
||||
ck_ht_entry_key_set(&htentry, r.base, r.length);
|
||||
if (ck_ht_get_spmc(&lowac->ht, h, &htentry) == false) {
|
||||
return (ISC_R_NOTFOUND);
|
||||
} else {
|
||||
dns_lowac_entry_t *entry = ck_ht_entry_value(&htentry);
|
||||
REQUIRE(VALID_LENTRY(entry));
|
||||
int oldrc = isc_refcount_increment(&entry->refcount);
|
||||
fprintf(stderr, "INCREF %d %p\n", __LINE__, entry, oldrc);
|
||||
RUNTIME_CHECK(oldrc > 0);
|
||||
if (entry->remq_enqueued || !entry->inht) {
|
||||
/* This entry is being removed, bail */
|
||||
isc_refcount_decrement(&entry->refcount);
|
||||
fprintf(stderr, "DECREF %d %p\n", __LINE__, entry);
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
if (entry->expire < atomic_load(&lowac->now)) {
|
||||
ck_fifo_mpmc_entry_t *qentry =
|
||||
isc_mem_get(lowac->mctx,
|
||||
(sizeof(ck_fifo_mpmc_entry_t)));
|
||||
entry->remq_enqueued = true;
|
||||
isc_refcount_increment(&entry->rqrefcount);
|
||||
fprintf(stderr, "XXXenq %p %d\n", entry, __LINE__);
|
||||
ck_fifo_mpmc_enqueue(&lowac->remq, qentry, entry);
|
||||
return (ISC_R_NOTFOUND);
|
||||
}
|
||||
if (tcp) {
|
||||
blob[0] = entry->blobsize >> 8;
|
||||
blob[1] = entry->blobsize;
|
||||
memcpy(blob + 2, entry->blob, entry->blobsize);
|
||||
*blobsize = entry->blobsize + 2;
|
||||
} else {
|
||||
memcpy(blob, entry->blob, entry->blobsize);
|
||||
*blobsize = entry->blobsize;
|
||||
}
|
||||
isc_refcount_decrement(&entry->refcount);
|
||||
fprintf(stderr, "DECREF %d %p\n", __LINE__, entry);
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
@@ -1835,7 +1835,21 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
|
||||
if (c == 0)
|
||||
done = true;
|
||||
n = c;
|
||||
state = fw_ordinary;
|
||||
if (downcase) {
|
||||
state = fw_ordinary;
|
||||
} else {
|
||||
current += n;
|
||||
if (current >= source->active) {
|
||||
return (ISC_R_UNEXPECTEDEND);
|
||||
}
|
||||
memcpy(ndata, cdata, n);
|
||||
cdata += n;
|
||||
ndata += n;
|
||||
if (!seen_pointer) {
|
||||
cused+=n;
|
||||
}
|
||||
state = fw_start;
|
||||
}
|
||||
} else if (c >= 128 && c < 192) {
|
||||
/*
|
||||
* 14 bit local compression pointer.
|
||||
|
||||
@@ -288,6 +288,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
||||
view, NULL, NULL, NULL);
|
||||
view->viewlist = NULL;
|
||||
view->magic = DNS_VIEW_MAGIC;
|
||||
/* TODO we might destroy the view (and LOWAC) when we still need it on shutdown! */
|
||||
view->lowac = dns_lowac_create(view->mctx);
|
||||
|
||||
*viewp = view;
|
||||
|
||||
@@ -627,6 +629,9 @@ view_flushanddetach(dns_view_t **viewp, bool flush) {
|
||||
if (view->catzs != NULL) {
|
||||
dns_catz_catzs_detach(&view->catzs);
|
||||
}
|
||||
if (view->lowac != NULL) {
|
||||
dns_lowac_destroy(view->lowac);
|
||||
}
|
||||
done = all_done(view);
|
||||
UNLOCK(&view->lock);
|
||||
|
||||
|
||||
@@ -17,10 +17,47 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/util.h>
|
||||
#include <isc/rwlock.h>
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
typedef atomic_int_fast64_t isc_stat_t;
|
||||
#define ISC_STATS_MAGIC ISC_MAGIC('S', 't', 'a', 't')
|
||||
#define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
|
||||
|
||||
struct isc_stats {
|
||||
/*% Unlocked */
|
||||
unsigned int magic;
|
||||
isc_mem_t *mctx;
|
||||
int ncounters;
|
||||
|
||||
isc_mutex_t lock;
|
||||
unsigned int references; /* locked by lock */
|
||||
|
||||
/*%
|
||||
* Locked by counterlock or unlocked if efficient rwlock is not
|
||||
* available.
|
||||
*/
|
||||
isc_stat_t *counters;
|
||||
|
||||
/*%
|
||||
* We don't want to lock the counters while we are dumping, so we first
|
||||
* copy the current counter values into a local array. This buffer
|
||||
* will be used as the copy destination. It's allocated on creation
|
||||
* of the stats structure so that the dump operation won't fail due
|
||||
* to memory allocation failure.
|
||||
* XXX: this approach is weird for non-threaded build because the
|
||||
* additional memory and the copy overhead could be avoided. We prefer
|
||||
* simplicity here, however, under the assumption that this function
|
||||
* should be only rarely called.
|
||||
*/
|
||||
uint64_t *copiedcounters;
|
||||
};
|
||||
|
||||
/*%<
|
||||
* Flag(s) for isc_stats_dump().
|
||||
*/
|
||||
@@ -78,8 +115,9 @@ isc_stats_ncounters(isc_stats_t *stats);
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter);
|
||||
#define isc_stats_increment(stats, counter) do { \
|
||||
atomic_fetch_add_explicit(&stats->counters[counter], 1, \
|
||||
memory_order_relaxed); } while(0)
|
||||
/*%<
|
||||
* Increment the counter-th counter of stats.
|
||||
*
|
||||
@@ -90,8 +128,10 @@ isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter);
|
||||
* on creation.
|
||||
*/
|
||||
|
||||
void
|
||||
isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter);
|
||||
|
||||
#define isc_stats_decrement(stats, counter) do { \
|
||||
atomic_fetch_sub_explicit(&stats->counters[counter], 1, \
|
||||
memory_order_relaxed); } while(0)
|
||||
/*%<
|
||||
* Decrement the counter-th counter of stats.
|
||||
*
|
||||
|
||||
@@ -134,11 +134,11 @@ typedef uint_fast64_t atomic_uint_fast64_t;
|
||||
|
||||
#define atomic_load(obj) \
|
||||
atomic_load_explicit(obj, memory_order_seq_cst)
|
||||
#define atomic_store(obj) \
|
||||
atomic_store_explicit(obj, memory_order_seq_cst)
|
||||
#define atomic_fetch_add(obj) \
|
||||
#define atomic_store(obj, arg) \
|
||||
atomic_store_explicit(obj, arg, memory_order_seq_cst)
|
||||
#define atomic_fetch_add(obj, arg) \
|
||||
atomic_fetch_add_explicit(obj, arg, memory_order_seq_cst)
|
||||
#define atomic_fetch_sub(obj) \
|
||||
#define atomic_fetch_sub(obj, arg) \
|
||||
atomic_fetch_sub_explicit(obj, arg, memory_order_seq_cst)
|
||||
#define atomic_compare_exchange_strong(obj, expected, desired) \
|
||||
atomic_compare_exchange_strong_explicit(obj, expected, desired, memory_order_seq_cst, memory_order_seq_cst)
|
||||
|
||||
@@ -44,9 +44,13 @@ isc_thread_yield(void);
|
||||
void
|
||||
isc_thread_setname(isc_thread_t thread, const char *name);
|
||||
|
||||
|
||||
isc_result_t
|
||||
isc_thread_setaffinity(int cpu);
|
||||
|
||||
isc_result_t
|
||||
isc_thread_resetaffinity(void);
|
||||
|
||||
/* XXX We could do fancier error handling... */
|
||||
|
||||
#define isc_thread_join(t, rp) \
|
||||
|
||||
@@ -111,6 +111,38 @@ isc_thread_yield(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_thread_resetaffinity() {
|
||||
#if defined(HAVE_CPUSET_SETAFFINITY)
|
||||
cpuset_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
for (int cpu=0; cpu < 32; cpu++) {
|
||||
CPU_SET(cpu, &cpuset);
|
||||
}
|
||||
if (cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1,
|
||||
&cpuset, sizeof(cpuset)) != 0) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
#elif defined(HAVE_PTHREAD_SETAFFINITY_NP)
|
||||
cpu_set_t set;
|
||||
CPU_ZERO(&set);
|
||||
for (int cpu=0; cpu < 32; cpu++) {
|
||||
CPU_SET(cpu, &set);
|
||||
}
|
||||
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t),
|
||||
&set) != 0) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
#elif defined(HAVE_PROCESSOR_BIND)
|
||||
if (processor_bind(P_LWPID, P_MYID, PBIND_NONE, NULL) != 0) {
|
||||
return (ISC_R_FAILURE);
|
||||
}
|
||||
#else
|
||||
UNUSED(cpu);
|
||||
#endif
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_thread_setaffinity(int cpu) {
|
||||
#if defined(HAVE_CPUSET_SETAFFINITY)
|
||||
|
||||
@@ -19,47 +19,10 @@
|
||||
|
||||
#include <isc/atomic.h>
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/platform.h>
|
||||
#include <isc/print.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/stats.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#define ISC_STATS_MAGIC ISC_MAGIC('S', 't', 'a', 't')
|
||||
#define ISC_STATS_VALID(x) ISC_MAGIC_VALID(x, ISC_STATS_MAGIC)
|
||||
|
||||
typedef atomic_int_fast64_t isc_stat_t;
|
||||
|
||||
struct isc_stats {
|
||||
/*% Unlocked */
|
||||
unsigned int magic;
|
||||
isc_mem_t *mctx;
|
||||
int ncounters;
|
||||
|
||||
isc_mutex_t lock;
|
||||
unsigned int references; /* locked by lock */
|
||||
|
||||
/*%
|
||||
* Locked by counterlock or unlocked if efficient rwlock is not
|
||||
* available.
|
||||
*/
|
||||
isc_stat_t *counters;
|
||||
|
||||
/*%
|
||||
* We don't want to lock the counters while we are dumping, so we first
|
||||
* copy the current counter values into a local array. This buffer
|
||||
* will be used as the copy destination. It's allocated on creation
|
||||
* of the stats structure so that the dump operation won't fail due
|
||||
* to memory allocation failure.
|
||||
* XXX: this approach is weird for non-threaded build because the
|
||||
* additional memory and the copy overhead could be avoided. We prefer
|
||||
* simplicity here, however, under the assumption that this function
|
||||
* should be only rarely called.
|
||||
*/
|
||||
uint64_t *copiedcounters;
|
||||
};
|
||||
|
||||
static isc_result_t
|
||||
create_stats(isc_mem_t *mctx, int ncounters, isc_stats_t **statsp) {
|
||||
@@ -159,23 +122,6 @@ isc_stats_create(isc_mem_t *mctx, isc_stats_t **statsp, int ncounters) {
|
||||
return (create_stats(mctx, ncounters, statsp));
|
||||
}
|
||||
|
||||
void
|
||||
isc_stats_increment(isc_stats_t *stats, isc_statscounter_t counter) {
|
||||
REQUIRE(ISC_STATS_VALID(stats));
|
||||
REQUIRE(counter < stats->ncounters);
|
||||
|
||||
atomic_fetch_add_explicit(&stats->counters[counter], 1,
|
||||
memory_order_relaxed);
|
||||
}
|
||||
|
||||
void
|
||||
isc_stats_decrement(isc_stats_t *stats, isc_statscounter_t counter) {
|
||||
REQUIRE(ISC_STATS_VALID(stats));
|
||||
REQUIRE(counter < stats->ncounters);
|
||||
|
||||
atomic_fetch_sub_explicit(&stats->counters[counter], 1,
|
||||
memory_order_relaxed);
|
||||
}
|
||||
|
||||
void
|
||||
isc_stats_dump(isc_stats_t *stats, isc_stats_dumper_t dump_fn,
|
||||
|
||||
@@ -924,7 +924,7 @@ client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer,
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
|
||||
client_sendpkg(ns_client_t *client, isc_buffer_t *buffer, bool lowac) {
|
||||
struct in6_pktinfo *pktinfo;
|
||||
isc_result_t result;
|
||||
isc_region_t r;
|
||||
@@ -989,7 +989,9 @@ client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
|
||||
client->sendevent->attributes |= ISC_SOCKEVENTATTR_USEMINMTU;
|
||||
|
||||
CTRACE("sendto");
|
||||
|
||||
if (lowac && client->view != NULL) {
|
||||
dns_lowac_put(client->view->lowac, ISC_LIST_HEAD(client->message->sections[0]), (char*) r.base, r.length);
|
||||
}
|
||||
result = isc_socket_sendto2(sock, &r, client->task,
|
||||
address, pktinfo,
|
||||
client->sendevent, sockflags);
|
||||
@@ -1037,7 +1039,7 @@ ns_client_sendraw(ns_client_t *client, dns_message_t *message) {
|
||||
r.base[0] = (client->message->id >> 8) & 0xff;
|
||||
r.base[1] = client->message->id & 0xff;
|
||||
|
||||
result = client_sendpkg(client, &buffer);
|
||||
result = client_sendpkg(client, &buffer, true);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
return;
|
||||
|
||||
@@ -1302,7 +1304,7 @@ client_send(ns_client_t *client) {
|
||||
|
||||
/* don't count the 2-octet length header */
|
||||
respsize = isc_buffer_usedlength(&tcpbuffer) - 2;
|
||||
result = client_sendpkg(client, &tcpbuffer);
|
||||
result = client_sendpkg(client, &tcpbuffer, true);
|
||||
|
||||
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
||||
case AF_INET:
|
||||
@@ -1333,7 +1335,7 @@ client_send(ns_client_t *client) {
|
||||
#endif /* HAVE_DNSTAP */
|
||||
|
||||
respsize = isc_buffer_usedlength(&buffer);
|
||||
result = client_sendpkg(client, &buffer);
|
||||
result = client_sendpkg(client, &buffer, true);
|
||||
|
||||
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
||||
case AF_INET:
|
||||
@@ -2271,6 +2273,60 @@ process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
lowac_checksend(ns_client_t *client) {
|
||||
isc_result_t result;
|
||||
unsigned char *data;
|
||||
isc_buffer_t buffer;
|
||||
isc_buffer_t tcpbuffer;
|
||||
isc_region_t r;
|
||||
unsigned char sendbuf[SEND_BUFFER_SIZE];
|
||||
result = client_allocsendbuf(client, &buffer, &tcpbuffer, 0,
|
||||
sendbuf, &data);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
int blen;
|
||||
result = dns_lowac_get(client->view->lowac, ISC_LIST_HEAD(client->message->sections[0]), data, &blen, TCP_CLIENT(client));
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto done;
|
||||
}
|
||||
if (TCP_CLIENT(client)) {
|
||||
data[2] = (client->message->id >> 8) & 0xff;
|
||||
data[3] = client->message->id & 0xff;
|
||||
} else {
|
||||
data[0] = (client->message->id >> 8) & 0xff;
|
||||
data[1] = client->message->id & 0xff;
|
||||
}
|
||||
isc_buffer_add(&buffer, blen);
|
||||
/*
|
||||
isc_buffer_putuint16(&buffer, client->message->id);
|
||||
isc_buffer_putuint8(&buffer, 0x81);
|
||||
isc_buffer_putuint8(&buffer, 0x80);
|
||||
isc_buffer_putuint16(&buffer, 0);
|
||||
isc_buffer_putuint16(&buffer, 0);
|
||||
isc_buffer_putuint16(&buffer, 0);
|
||||
isc_buffer_putuint16(&buffer, 0);
|
||||
*/
|
||||
if (client->sendcb != NULL) {
|
||||
client->sendcb(&buffer);
|
||||
} else if (TCP_CLIENT(client)) {
|
||||
isc_buffer_usedregion(&buffer, &r);
|
||||
isc_buffer_putuint16(&tcpbuffer, (uint16_t) r.length);
|
||||
isc_buffer_add(&tcpbuffer, r.length);
|
||||
result = client_sendpkg(client, &tcpbuffer, false);
|
||||
} else {
|
||||
result = client_sendpkg(client, &buffer, false);
|
||||
}
|
||||
done:
|
||||
if (client->tcpbuf != NULL) {
|
||||
isc_mem_put(client->mctx, client->tcpbuf, TCP_BUFFER_SIZE);
|
||||
client->tcpbuf = NULL;
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle an incoming request event from the socket (UDP case)
|
||||
* or tcpmsg (TCP case).
|
||||
@@ -2733,6 +2789,11 @@ ns__client_request(isc_task_t *task, isc_event_t *event) {
|
||||
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(5),
|
||||
"using view '%s'", client->view->name);
|
||||
|
||||
result = lowac_checksend(client);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for a signature. We log bad signatures regardless of
|
||||
* whether they ultimately cause the request to be rejected or
|
||||
|
||||
Reference in New Issue
Block a user