Browse code

dns cache: dns_cache_rec_pref config var added

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.

Miklos Tirpak authored on 23/06/2010 14:34:56
Showing 4 changed files
... ...
@@ -14,6 +14,7 @@ core:
14 14
     See dst_blacklist_udp_imask a.s.o (dst_blacklist_*_imask).
15 15
   - per message blacklist ignore masks
16 16
   - route() now supports rvalue expressions (e.g. route("test"+$i))
17
+  - support for permanent entries in the DNS cache.
17 18
 
18 19
 new config variables:
19 20
   - dst_blacklist_udp_imask - global blacklist events ignore mask for udp
... ...
@@ -27,6 +28,11 @@ new config variables:
27 27
    - dst_blacklist_tcp_imask - like dst_blacklist_udp_imask, but for tcp.
28 28
    - dst_blacklist_tls_imask - like dst_blacklist_tls_imask, but for tcp.
29 29
    - dst_blacklist_sctp_imask -like dst_blacklist_sctp_imask, but for tcp.
30
+   - dns_cache_rec_pref - DNS cache record preference:
31
+		0 - do not check duplicates (default)
32
+		1 - prefer old records
33
+		2 - prefer new records
34
+		3 - prefer records with longer lifetime
30 35
 
31 36
 modules:
32 37
    - blst: functions for ignoring blacklist events per message:
... ...
@@ -102,6 +102,7 @@ struct cfg_group_core default_core_cfg = {
102 102
 	DEFAULT_DNS_CACHE_MAX_TTL, /*!< maximum ttl */
103 103
 	DEFAULT_DNS_MAX_MEM, /*!< dns_cache_max_mem */
104 104
 	0, /*!< dns_cache_del_nonexp -- delete only expired entries by default */
105
+	0, /*!< dns_cache_rec_pref -- 0 by default, do not check the existing entries. */
105 106
 #endif
106 107
 #ifdef PKG_MALLOC
107 108
 	0, /*!< mem_dump_pkg */
... ...
@@ -206,6 +207,12 @@ cfg_def_t core_cfg_def[] = {
206 206
 	{"dns_cache_del_nonexp",	CFG_VAR_INT,	0, 1, 0, 0,
207 207
 		"allow deletion of non-expired records from the cache when "
208 208
 		"there is no more space left for new ones"},
209
+	{"dns_cache_rec_pref",	CFG_VAR_INT,	0, 3, 0, 0,
210
+		"DNS cache record preference: "
211
+		" 0 - do not check duplicates"
212
+		" 1 - prefer old records"
213
+		" 2 - prefer new records"
214
+		" 3 - prefer records with longer lifetime"},
209 215
 #endif
210 216
 #ifdef PKG_MALLOC
211 217
 	{"mem_dump_pkg",	CFG_VAR_INT,	0, 0, 0, mem_dump_pkg_cb,
... ...
@@ -92,6 +92,7 @@ struct cfg_group_core {
92 92
 	unsigned int dns_cache_max_ttl;
93 93
 	unsigned int dns_cache_max_mem;
94 94
 	int dns_cache_del_nonexp;
95
+	int dns_cache_rec_pref;
95 96
 #endif
96 97
 #ifdef PKG_MALLOC
97 98
 	int mem_dump_pkg;
... ...
@@ -1874,10 +1874,14 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
1874 1874
 	struct ip_addr* ip;
1875 1875
 	str cname_val;
1876 1876
 	char name_buf[MAX_DNS_NAME];
1877
+	struct dns_hash_entry* old;
1878
+	str rec_name;
1879
+	int add_record, h, err;
1877 1880
 
1878 1881
 	e=0;
1879 1882
 	l=0;
1880 1883
 	cname_val.s=0;
1884
+	old = NULL;
1881 1885
 
1882 1886
 #ifdef USE_DNS_CACHE_STATS
1883 1887
 	if (dns_cache_stats)
... ...
@@ -1944,10 +1948,55 @@ inline static struct dns_hash_entry* dns_cache_do_request(str* name, int type)
1944 1944
 			LOCK_DNS_HASH(); /* optimization */
1945 1945
 			for (r=l; r; r=t){
1946 1946
 				t=r->next;
1947
-				dns_cache_add_unsafe(r); /* refcnt++ inside */
1948
-				if (atomic_get(&r->refcnt)==0){
1949
-					/* if cache adding failed and nobody else is interested
1950
-					 * destroy this entry */
1947
+				/* add the new record to the cache by default */
1948
+				add_record = 1;
1949
+				if (cfg_get(core, core_cfg, dns_cache_rec_pref) > 0) {
1950
+					/* check whether there is an old record with the
1951
+					 * same type in the cache */
1952
+					rec_name.s = r->name;
1953
+					rec_name.len = r->name_len;
1954
+					old = _dns_hash_find(&rec_name, r->type, &h, &err);
1955
+					if (old) {
1956
+						if (old->type != r->type) {
1957
+							/* probably CNAME found */
1958
+							old = NULL;
1959
+
1960
+						} else if (old->ent_flags & DNS_FLAG_PERMANENT) {
1961
+							/* never overwrite permanent entries */
1962
+							add_record = 0;
1963
+
1964
+						} else if ((old->ent_flags & DNS_FLAG_BAD_NAME) == 0) {
1965
+							/* Non-negative, non-permanent entry found with
1966
+							 * the same type. */
1967
+							add_record =
1968
+								/* prefer new records */
1969
+								((cfg_get(core, core_cfg, dns_cache_rec_pref) == 2)
1970
+								/* prefer the record with the longer lifetime */
1971
+								|| ((cfg_get(core, core_cfg, dns_cache_rec_pref) == 3)
1972
+									&& TICKS_LT(old->expire, r->expire)));
1973
+						}
1974
+					}
1975
+				}
1976
+				if (add_record) {
1977
+					dns_cache_add_unsafe(r); /* refcnt++ inside */
1978
+					if (atomic_get(&r->refcnt)==0){
1979
+						/* if cache adding failed and nobody else is interested
1980
+						 * destroy this entry */
1981
+						dns_destroy_entry(r);
1982
+					}
1983
+					if (old) {
1984
+						_dns_hash_remove(old);
1985
+						old = NULL;
1986
+					}
1987
+				} else {
1988
+					if (old) {
1989
+						if (r == e) {
1990
+							/* this entry has to be returned */
1991
+							e = old;
1992
+							atomic_inc(&e->refcnt);
1993
+						}
1994
+						old = NULL;
1995
+					}
1951 1996
 					dns_destroy_entry(r);
1952 1997
 				}
1953 1998
 			}