dns cache: dns_cache_rec_pref config var added
authorMiklos Tirpak <miklos@iptel.org>
Wed, 23 Jun 2010 14:34:56 +0000 (16:34 +0200)
committerMiklos Tirpak <miklos@iptel.org>
Wed, 23 Jun 2010 15:31:56 +0000 (17:31 +0200)
The config variable, dns_cache_rec_pref, can be used
to set the DNS cache preference as follows:

0 - do not check duplicates (default)
1 - prefer old records
2 - prefer new records
3 - prefer records with longer lifetime

This variable is checked when a duplicated record is
tried to be inserted into the cache. For instance the
SRV query answer contains also an A record which is
already in the cache.
If the config var is not 0, then permanent entries
are always preferred.

Note: works only with #define CACHE_RELEVANT_RECS_ONLY
at the moment.

NEWS
cfg_core.c
cfg_core.h
dns_cache.c

diff --git a/NEWS b/NEWS
index 0112243..5d691cb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ core:
     See dst_blacklist_udp_imask a.s.o (dst_blacklist_*_imask).
   - per message blacklist ignore masks
   - route() now supports rvalue expressions (e.g. route("test"+$i))
+  - support for permanent entries in the DNS cache.
 
 new config variables:
   - dst_blacklist_udp_imask - global blacklist events ignore mask for udp
@@ -27,6 +28,11 @@ new config variables:
    - dst_blacklist_tcp_imask - like dst_blacklist_udp_imask, but for tcp.
    - dst_blacklist_tls_imask - like dst_blacklist_tls_imask, but for tcp.
    - dst_blacklist_sctp_imask -like dst_blacklist_sctp_imask, but for tcp.
+   - dns_cache_rec_pref - DNS cache record preference:
+               0 - do not check duplicates (default)
+               1 - prefer old records
+               2 - prefer new records
+               3 - prefer records with longer lifetime
 
 modules:
    - blst: functions for ignoring blacklist events per message:
index 101ba9f..d819dee 100644 (file)
@@ -102,6 +102,7 @@ struct cfg_group_core default_core_cfg = {
        DEFAULT_DNS_CACHE_MAX_TTL, /*!< maximum ttl */
        DEFAULT_DNS_MAX_MEM, /*!< dns_cache_max_mem */
        0, /*!< dns_cache_del_nonexp -- delete only expired entries by default */
+       0, /*!< dns_cache_rec_pref -- 0 by default, do not check the existing entries. */
 #endif
 #ifdef PKG_MALLOC
        0, /*!< mem_dump_pkg */
@@ -206,6 +207,12 @@ cfg_def_t core_cfg_def[] = {
        {"dns_cache_del_nonexp",        CFG_VAR_INT,    0, 1, 0, 0,
                "allow deletion of non-expired records from the cache when "
                "there is no more space left for new ones"},
+       {"dns_cache_rec_pref",  CFG_VAR_INT,    0, 3, 0, 0,
+               "DNS cache record preference: "
+               " 0 - do not check duplicates"
+               " 1 - prefer old records"
+               " 2 - prefer new records"
+               " 3 - prefer records with longer lifetime"},
 #endif
 #ifdef PKG_MALLOC
        {"mem_dump_pkg",        CFG_VAR_INT,    0, 0, 0, mem_dump_pkg_cb,
index 1e86692..c0d83c8 100644 (file)
@@ -92,6 +92,7 @@ struct cfg_group_core {
        unsigned int dns_cache_max_ttl;
        unsigned int dns_cache_max_mem;
        int dns_cache_del_nonexp;
+       int dns_cache_rec_pref;
 #endif
 #ifdef PKG_MALLOC
        int mem_dump_pkg;
index 2ec3d3e..adf2940 100644 (file)
@@ -1874,10 +1874,14 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
        struct ip_addr* ip;
        str cname_val;
        char name_buf[MAX_DNS_NAME];
+       struct dns_hash_entry* old;
+       str rec_name;
+       int add_record, h, err;
 
        e=0;
        l=0;
        cname_val.s=0;
+       old = NULL;
 
 #ifdef USE_DNS_CACHE_STATS
        if (dns_cache_stats)
@@ -1944,10 +1948,55 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
                        LOCK_DNS_HASH(); /* optimization */
                        for (r=l; r; r=t){
                                t=r->next;
-                               dns_cache_add_unsafe(r); /* refcnt++ inside */
-                               if (atomic_get(&r->refcnt)==0){
-                                       /* if cache adding failed and nobody else is interested
-                                        * destroy this entry */
+                               /* add the new record to the cache by default */
+                               add_record = 1;
+                               if (cfg_get(core, core_cfg, dns_cache_rec_pref) > 0) {
+                                       /* check whether there is an old record with the
+                                        * same type in the cache */
+                                       rec_name.s = r->name;
+                                       rec_name.len = r->name_len;
+                                       old = _dns_hash_find(&rec_name, r->type, &h, &err);
+                                       if (old) {
+                                               if (old->type != r->type) {
+                                                       /* probably CNAME found */
+                                                       old = NULL;
+
+                                               } else if (old->ent_flags & DNS_FLAG_PERMANENT) {
+                                                       /* never overwrite permanent entries */
+                                                       add_record = 0;
+
+                                               } else if ((old->ent_flags & DNS_FLAG_BAD_NAME) == 0) {
+                                                       /* Non-negative, non-permanent entry found with
+                                                        * the same type. */
+                                                       add_record =
+                                                               /* prefer new records */
+                                                               ((cfg_get(core, core_cfg, dns_cache_rec_pref) == 2)
+                                                               /* prefer the record with the longer lifetime */
+                                                               || ((cfg_get(core, core_cfg, dns_cache_rec_pref) == 3)
+                                                                       && TICKS_LT(old->expire, r->expire)));
+                                               }
+                                       }
+                               }
+                               if (add_record) {
+                                       dns_cache_add_unsafe(r); /* refcnt++ inside */
+                                       if (atomic_get(&r->refcnt)==0){
+                                               /* if cache adding failed and nobody else is interested
+                                                * destroy this entry */
+                                               dns_destroy_entry(r);
+                                       }
+                                       if (old) {
+                                               _dns_hash_remove(old);
+                                               old = NULL;
+                                       }
+                               } else {
+                                       if (old) {
+                                               if (r == e) {
+                                                       /* this entry has to be returned */
+                                                       e = old;
+                                                       atomic_inc(&e->refcnt);
+                                               }
+                                               old = NULL;
+                                       }
                                        dns_destroy_entry(r);
                                }
                        }