From e6d0a391f5f9b18f5bd497aefff269e474ee560c Mon Sep 17 00:00:00 2001 From: Witold Krecicki Date: Mon, 28 Sep 2015 11:08:50 +0200 Subject: [PATCH] 4223. [func] Add support for setting max-cache-size to percentage of available physical memory, set default to 90%. [RT #38442] --- .gitignore | 1 + CHANGES | 4 + bin/named/builtin.c | 1 + bin/named/config.c | 2 +- bin/named/server.c | 29 ++++++ bin/tests/system/cacheclean/ns2/named.conf | 2 +- .../system/checkconf/max-cache-size-good.conf | 3 + bin/tests/system/checkconf/tests.sh | 7 ++ doc/arm/Bv9ARM-book.xml | 32 ++++++- doc/misc/options | 16 ++-- lib/isc/Makefile.in | 11 ++- lib/isc/include/isc/meminfo.h | 35 +++++++ lib/isc/unix/Makefile.in | 8 +- lib/isc/unix/meminfo.c | 40 ++++++++ lib/isc/win32/Makefile.in | 6 +- lib/isc/win32/meminfo.c | 27 ++++++ lib/isccfg/include/isccfg/cfg.h | 24 +++++ lib/isccfg/include/isccfg/grammar.h | 12 ++- lib/isccfg/namedconf.c | 95 ++++++++++++++++++- lib/isccfg/parser.c | 70 ++++++++++++++ 20 files changed, 396 insertions(+), 29 deletions(-) create mode 100644 bin/tests/system/checkconf/max-cache-size-good.conf create mode 100644 lib/isc/include/isc/meminfo.h create mode 100644 lib/isc/unix/meminfo.c create mode 100644 lib/isc/win32/meminfo.c diff --git a/.gitignore b/.gitignore index 052e7b9636..e8d7aa4873 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ unit/atf-src/test-programs/cpp_helpers unit/atf-src/test-programs/sh_helpers # ccc-analyzer store its results in .plist directories *.plist/ +*~ diff --git a/CHANGES b/CHANGES index 66a58e87c0..82c58c19cc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +4223. [func] Add support for setting max-cache-size to percentage + of available physical memory, set default to 90%. + [RT #38442] + 4222. [func] Bias IPv6 servers when selecting the next server to query. [RT #40836] diff --git a/bin/named/builtin.c b/bin/named/builtin.c index e55e954222..96d624a21b 100644 --- a/bin/named/builtin.c +++ b/bin/named/builtin.c @@ -368,6 +368,7 @@ do_authors_lookup(dns_sdblookup_t *lookup) { "Bob Halley", "Evan Hunt", "JINMEI Tatuya", + "Witold Krecicki", "David Lawrence", "Scott Mann", "Danny Mayer", diff --git a/bin/named/config.c b/bin/named/config.c index fbc6c18acb..aed352316b 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -160,7 +160,7 @@ options {\n\ max-ncache-ttl 10800; /* 3 hours */\n\ max-cache-ttl 604800; /* 1 week */\n\ transfer-format many-answers;\n\ - max-cache-size 0;\n\ + max-cache-size 90%;\n\ check-names master fail;\n\ check-names slave warn;\n\ check-names response ignore;\n\ diff --git a/bin/named/server.c b/bin/named/server.c index 2dbafe8939..4c54419c4b 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,10 @@ #define SIZE_MAX ((size_t)-1) #endif +#ifndef SIZE_AS_PERCENT +#define SIZE_AS_PERCENT ((size_t)-2) +#endif + #ifdef TUNE_LARGE #define RESOLVER_NTASKS 523 #define UDPBUFFERS 32768 @@ -2400,6 +2405,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, isc_result_t result; unsigned int cleaning_interval; size_t max_cache_size; + isc_uint32_t max_cache_size_percent = 0; size_t max_acache_size; size_t max_adb_size; isc_uint32_t lame_ttl, fail_ttl; @@ -2685,6 +2691,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, str = cfg_obj_asstring(obj); INSIST(strcasecmp(str, "unlimited") == 0); max_cache_size = 0; + } else if (cfg_obj_ispercentage(obj)) { + max_cache_size = SIZE_AS_PERCENT; + max_cache_size_percent = cfg_obj_aspercentage(obj); } else { isc_resourcevalue_t value; value = cfg_obj_asuint64(obj); @@ -2701,6 +2710,26 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, max_cache_size = (size_t) value; } + if (max_cache_size == SIZE_AS_PERCENT) { + isc_uint64_t totalphys = isc_meminfo_totalphys(); + max_cache_size = totalphys * max_cache_size_percent/100; + if (totalphys == 0) { + cfg_obj_log(obj, ns_g_lctx, + ISC_LOG_WARNING, + "Unable to determine amount of physical " + "memory, setting 'max-cache-size' to " + "unlimited"); + } else { + cfg_obj_log(obj, ns_g_lctx, + ISC_LOG_INFO, + "'max-cache-size %d%%' " + "- setting to %luMB (out of %luMB)", + max_cache_size_percent, + max_cache_size / (1024*1024), + (unsigned long) totalphys / (1024*1024)); + } + } + /* Check-names. */ obj = NULL; result = ns_checknames_get(maps, "response", &obj); diff --git a/bin/tests/system/cacheclean/ns2/named.conf b/bin/tests/system/cacheclean/ns2/named.conf index f9aab1af39..accfda8558 100644 --- a/bin/tests/system/cacheclean/ns2/named.conf +++ b/bin/tests/system/cacheclean/ns2/named.conf @@ -28,7 +28,7 @@ options { listen-on { 10.53.0.2; }; listen-on-v6 { none; }; notify yes; - max-cache-size 10000; + max-cache-size 80%; disable-empty-zone 127.IN-ADDR.ARPA; }; diff --git a/bin/tests/system/checkconf/max-cache-size-good.conf b/bin/tests/system/checkconf/max-cache-size-good.conf new file mode 100644 index 0000000000..952b0221b2 --- /dev/null +++ b/bin/tests/system/checkconf/max-cache-size-good.conf @@ -0,0 +1,3 @@ +options { + max-cache-size 60%; +}; diff --git a/bin/tests/system/checkconf/tests.sh b/bin/tests/system/checkconf/tests.sh index 031f6fe5de..4324c582c9 100644 --- a/bin/tests/system/checkconf/tests.sh +++ b/bin/tests/system/checkconf/tests.sh @@ -261,5 +261,12 @@ grep "zone shared.example/IN: loaded serial" < checkconf.out7 > /dev/null || ret if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi status=`expr $status + $ret` +echo "I: check that named-checkconf prints max-cache-size correctly" +ret=0 +$CHECKCONF -p max-cache-size-good.conf > checkconf.out8 2>&1 || ret=1 +grep "max-cache-size 60%;" checkconf.out8 > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 393317f75b..651988717a 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -2930,6 +2930,25 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. + + + + size_or_percent + + + + + size_spec or integer value + followed by '%' to represent percents. + + + The behaviour is exactly the same as + size_spec, but + size_or_percent allows also + to specify a positive integer value followed by + '%' sign to represent percents. + + @@ -4959,7 +4978,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] additional-from-auth yes_or_no ; additional-from-cache yes_or_no ; random-device path_name ; - max-cache-size size_spec ; + max-cache-size size_or_percent ; match-mapped-addresses yes_or_no; filter-aaaa-on-v4 ( yes_or_no | break-dnssec ); filter-aaaa-on-v6 ( yes_or_no | break-dnssec ); @@ -8747,7 +8766,7 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; The maximum amount of memory to use for the - server's cache, in bytes. + server's cache, in bytes or % of total physical memory. When the amount of data in the cache reaches this limit, the server will cause records to expire prematurely based on an LRU based strategy so @@ -8760,7 +8779,14 @@ avoid-v6-udp-ports { 40000; range 50000 60000; }; and reset to 2MB. In a server with multiple views, the limit applies separately to the cache of each view. - The default is unlimited. + The default is 90%. + On systems where detection of amount of physical + memory is not supported values represented as % + fall back to unlimited. + Note that the detection of physical memory is done only + once at startup, so named will not + adjust the cache size if the amount of physical memory + is changed during runtime. diff --git a/doc/misc/options b/doc/misc/options index fa5a610a57..d345d8db5d 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -178,12 +178,12 @@ options { masterfile-format ( text | raw | map ); masterfile-style ( full | relative ); match-mapped-addresses ; - max-acache-size ; - max-cache-size ; + max-acache-size ( unlimited | ); + max-cache-size ( unlimited | default | | ); max-cache-ttl ; max-clients-per-query ; max-ixfr-log-size ( unlimited | default | ); // obsolete - max-journal-size ; + max-journal-size ( unlimited | ); max-ncache-ttl ; max-recursion-depth ; max-recursion-queries ; @@ -461,12 +461,12 @@ view [ ] { match-clients { ; ... }; match-destinations { ; ... }; match-recursive-only ; - max-acache-size ; - max-cache-size ; + max-acache-size ( unlimited | ); + max-cache-size ( unlimited | default | | ); max-cache-ttl ; max-clients-per-query ; max-ixfr-log-size ( unlimited | default | ); // obsolete - max-journal-size ; + max-journal-size ( unlimited | ); max-ncache-ttl ; max-recursion-depth ; max-recursion-queries ; @@ -645,7 +645,7 @@ view [ ] { port ] ) [ key ]; ... }; max-ixfr-log-size ( unlimited | default | ); // obsolete - max-journal-size ; + max-journal-size ( unlimited | ); max-refresh-time ; max-retry-time ; max-transfer-idle-in ; @@ -746,7 +746,7 @@ zone [ ] { [ port ] | [ port ] ) [ key ]; ... }; max-ixfr-log-size ( unlimited | default | ); // obsolete - max-journal-size ; + max-journal-size ( unlimited | ); max-refresh-time ; max-retry-time ; max-transfer-idle-in ; diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in index 5d088987e5..9702b8d171 100644 --- a/lib/isc/Makefile.in +++ b/lib/isc/Makefile.in @@ -37,9 +37,10 @@ CWARNINGS = UNIXOBJS = @ISC_ISCIPV6_O@ @ISC_ISCPK11_API_O@ \ unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ \ unix/errno2result.@O@ unix/file.@O@ unix/fsaccess.@O@ \ - unix/interfaceiter.@O@ unix/keyboard.@O@ unix/net.@O@ \ - unix/os.@O@ unix/resource.@O@ unix/socket.@O@ unix/stdio.@O@ \ - unix/stdtime.@O@ unix/strerror.@O@ unix/syslog.@O@ unix/time.@O@ + unix/interfaceiter.@O@ unix/keyboard.@O@ unix/meminfo.@O@ \ + unix/net.@O@ unix/os.@O@ unix/resource.@O@ unix/socket.@O@ \ + unix/stdio.@O@ unix/stdtime.@O@ unix/strerror.@O@ \ + unix/syslog.@O@ unix/time.@O@ NLSOBJS = nls/msgcat.@O@ @@ -48,8 +49,8 @@ THREADOPTOBJS = @ISC_THREAD_DIR@/condition.@O@ @ISC_THREAD_DIR@/mutex.@O@ THREADOBJS = @THREADOPTOBJS@ @ISC_THREAD_DIR@/thread.@O@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ - win32/fsaccess.@O@ win32/once.@O@ win32/stdtime.@O@ \ - win32/thread.@O@ win32/time.@O@ + win32/fsaccess.@O@ win32/meminfo.@O@ win32/once.@O@ \ + win32/stdtime.@O@ win32/thread.@O@ win32/time.@O@ # Alphabetically OBJS = @ISC_EXTRA_OBJS@ @ISC_PK11_O@ @ISC_PK11_RESULT_O@ \ diff --git a/lib/isc/include/isc/meminfo.h b/lib/isc/include/isc/meminfo.h new file mode 100644 index 0000000000..3291a1724e --- /dev/null +++ b/lib/isc/include/isc/meminfo.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ISC_MEMINFO_H +#define ISC_MEMINFO_H 1 + +#include + +#include + +ISC_LANG_BEGINDECLS + +isc_uint64_t +isc_meminfo_totalphys(void); +/*%< + * Return total available physical memory in bytes, or 0 if this cannot + * be determined +*/ + +ISC_LANG_ENDDECLS + +#endif /* ISC_MEMINFO_H */ diff --git a/lib/isc/unix/Makefile.in b/lib/isc/unix/Makefile.in index 5a63cfe5d3..71150ae0a5 100644 --- a/lib/isc/unix/Makefile.in +++ b/lib/isc/unix/Makefile.in @@ -31,15 +31,15 @@ CWARNINGS = # Alphabetically OBJS = @ISC_IPV6_O@ @ISC_PK11_API_O@ \ app.@O@ dir.@O@ entropy.@O@ errno2result.@O@ file.@O@ \ - fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ net.@O@ \ - os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \ + fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ meminfo.@O@ \ + net.@O@ os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \ strerror.@O@ syslog.@O@ time.@O@ # Alphabetically SRCS = @ISC_IPV6_C@ @ISC_PK11_API_C@ \ app.c dir.c entropy.c errno2result.c file.c \ - fsaccess.c interfaceiter.c keyboard.c net.c \ - os.c resource.c socket.c stdio.c stdtime.c \ + fsaccess.c interfaceiter.c keyboard.c meminfo.c \ + net.c os.c resource.c socket.c stdio.c stdtime.c \ strerror.c syslog.c time.c SUBDIRS = include diff --git a/lib/isc/unix/meminfo.c b/lib/isc/unix/meminfo.c new file mode 100644 index 0000000000..07f0f7221b --- /dev/null +++ b/lib/isc/unix/meminfo.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +isc_uint64_t +isc_meminfo_totalphys(void) { +#if defined(CTL_HW) && (defined(HW_PHYSMEM64) || defined(HW_MEMSIZE)) + int mib[2]; + mib[0] = CTL_HW; +#if defined(HW_MEMSIZE) + mib[1] = HW_MEMSIZE; +#elif defined(HW_PHYSMEM64) + mib[1] = HW_PHYSMEM64; +#endif + isc_uint64_t size = 0; + size_t len = sizeof(size); + if (sysctl(mib, 2, &size, &len, NULL, 0) == 0) + return (size); +#endif +#if defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE) + return ((size_t) (sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE))); +#endif + return (0); +} diff --git a/lib/isc/win32/Makefile.in b/lib/isc/win32/Makefile.in index 97439a44a4..9e2934467e 100644 --- a/lib/isc/win32/Makefile.in +++ b/lib/isc/win32/Makefile.in @@ -27,11 +27,11 @@ CDEFINES = CWARNINGS = # Alphabetically -OBJS = condition.@O@ dir.@O@ file.@O@ fsaccess.@O@ once.@O@ \ - stdtime.@O@ thread.@O@ time.@O@ @ISC_PK11_API_O@ +OBJS = condition.@O@ dir.@O@ file.@O@ meminfo.@O@ fsaccess.@O@ \ + once.@O@ stdtime.@O@ thread.@O@ time.@O@ @ISC_PK11_API_O@ # Alphabetically -SRCS = condition.c dir.c file.c once.c fsaccess.c \ +SRCS = condition.c dir.c file.c meminfo.c once.c fsaccess.c \ stdtime.c thread.c time.c @ISC_PK11_API_C@ SUBDIRS = include diff --git a/lib/isc/win32/meminfo.c b/lib/isc/win32/meminfo.c new file mode 100644 index 0000000000..aa259f228a --- /dev/null +++ b/lib/isc/win32/meminfo.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +isc_uint64_t +isc_meminfo_totalphys(void) { + MEMORYSTATUSEX statex; + status.dwLength = sizeof(statex); + GlobalMemoryStatusEx(&statex); + return ((size_t)statex.ullTotalPhys); +} \ No newline at end of file diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h index 57b04f7a7a..c52a41f28f 100644 --- a/lib/isccfg/include/isccfg/cfg.h +++ b/lib/isccfg/include/isccfg/cfg.h @@ -190,6 +190,18 @@ cfg_obj_ismap(const cfg_obj_t *obj); * Return true iff 'obj' is of a map type. */ +isc_boolean_t +cfg_obj_isfixedpoint(const cfg_obj_t *obj); +/*%< + * Return true iff 'obj' is of a fixedpoint type. + */ + +isc_boolean_t +cfg_obj_ispercentage(const cfg_obj_t *obj); +/*%< + * Return true iff 'obj' is of a percentage type. + */ + isc_result_t cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj); /*%< @@ -297,6 +309,18 @@ cfg_obj_asfixedpoint(const cfg_obj_t *obj); * \li A 32-bit unsigned integer. */ +isc_uint32_t +cfg_obj_aspercentage(const cfg_obj_t *obj); +/*%< + * Returns the value of a configuration object of percentage + * + * Requires: + * \li 'obj' points to a valid configuration object of percentage type. + * + * Returns: + * \li A 32-bit unsigned integer. + */ + isc_boolean_t cfg_obj_isstring(const cfg_obj_t *obj); /*%< diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h index cc54fcc386..2546a6ca03 100644 --- a/lib/isccfg/include/isccfg/grammar.h +++ b/lib/isccfg/include/isccfg/grammar.h @@ -267,6 +267,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_sockaddr; LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_netprefix; LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_void; LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_fixedpoint; +LIBISCCFG_EXTERNAL_DATA extern cfg_rep_t cfg_rep_percentage; /*@}*/ /*@{*/ @@ -292,6 +293,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_void; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_token; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_unsupported; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_fixedpoint; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_percentage; /*@}*/ isc_result_t @@ -455,11 +457,19 @@ void cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type); isc_result_t -cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); +cfg_parse_fixedpoint(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret); void cfg_print_fixedpoint(cfg_printer_t *pctx, const cfg_obj_t *obj); +isc_result_t +cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret); + +void +cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj); + isc_result_t cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index ce2db8c5ac..7569bada16 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -133,6 +133,7 @@ static cfg_type_t cfg_type_server; static cfg_type_t cfg_type_server_key_kludge; static cfg_type_t cfg_type_size; static cfg_type_t cfg_type_sizenodefault; +static cfg_type_t cfg_type_sizeorpercent; static cfg_type_t cfg_type_sockaddr4wild; static cfg_type_t cfg_type_sockaddr6wild; static cfg_type_t cfg_type_statschannels; @@ -1595,7 +1596,7 @@ view_clauses[] = { { "nocookie-udp-size", &cfg_type_uint32, 0 }, { "nosit-udp-size", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE }, { "max-acache-size", &cfg_type_sizenodefault, 0 }, - { "max-cache-size", &cfg_type_sizenodefault, 0 }, + { "max-cache-size", &cfg_type_sizeorpercent, 0 }, { "max-cache-ttl", &cfg_type_uint32, 0 }, { "max-clients-per-query", &cfg_type_uint32, 0 }, { "max-ncache-ttl", &cfg_type_uint32, 0 }, @@ -2065,6 +2066,56 @@ parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (result); } +static isc_result_t +parse_sizeval_percent(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + char *endp; + isc_result_t result; + cfg_obj_t *obj = NULL; + isc_uint64_t val; + isc_uint32_t percent; + + UNUSED(type); + + CHECK(cfg_gettoken(pctx, 0)); + if (pctx->token.type != isc_tokentype_string) { + result = ISC_R_UNEXPECTEDTOKEN; + goto cleanup; + } + + percent = isc_string_touint64(TOKEN_STRING(pctx), &endp, 10); + + if (*endp == '%' && *(endp+1) == 0) { + CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj)); + obj->value.uint32 = percent; + *ret = obj; + return (ISC_R_SUCCESS); + } else { + CHECK(parse_unitstring(TOKEN_STRING(pctx), &val)); + CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj)); + obj->value.uint64 = val; + *ret = obj; + return (ISC_R_SUCCESS); + } + + cleanup: + cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit or percent"); + return (result); +} + +static void +doc_sizeval_percent(cfg_printer_t *pctx, const cfg_type_t *type) { + + UNUSED(type); + + cfg_print_cstr(pctx, "( "); + cfg_doc_terminal(pctx, &cfg_type_size); + cfg_print_cstr(pctx, " | "); + cfg_doc_terminal(pctx, &cfg_type_percentage); + cfg_print_cstr(pctx, " )"); +} + /*% * A size value (number + optional unit). */ @@ -2097,10 +2148,42 @@ static cfg_type_t cfg_type_size = { */ static const char *sizenodefault_enums[] = { "unlimited", NULL }; static cfg_type_t cfg_type_sizenodefault = { - "size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal, + "size_no_default", parse_size, cfg_print_ustring, doc_size, &cfg_rep_string, sizenodefault_enums }; +/*% + * A size in absolute values or percents. + */ + +static cfg_type_t cfg_type_sizeval_percent = { + "sizeval_percent", parse_sizeval_percent, cfg_print_ustring, + doc_sizeval_percent, &cfg_rep_string, NULL +}; + +/*% + * A size in absolute values or percents, or "unlimited", or "default" + */ + +static isc_result_t +parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + return (parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent, + ret)); +} + +static void +doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) { + doc_enum_or_other(pctx, type, &cfg_type_sizeval_percent); +} + +static const char *sizeorpercent_enums[] = { "unlimited", "default", NULL }; +static cfg_type_t cfg_type_sizeorpercent = { + "size_or_percent", parse_size_or_percent, cfg_print_ustring, + doc_parse_size_or_percent, &cfg_rep_string, sizeorpercent_enums +}; + /*% * optional_keyvalue */ @@ -2170,7 +2253,13 @@ doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype, first = ISC_FALSE; cfg_print_cstr(pctx, *p); } - if (othertype != &cfg_type_void) { + if (othertype == &cfg_type_sizeval_percent) { + if (!first) + cfg_print_cstr(pctx, " | "); + cfg_doc_terminal(pctx, &cfg_type_sizeval); + cfg_print_cstr(pctx, " | "); + cfg_doc_terminal(pctx, &cfg_type_percentage); + } else if (othertype != &cfg_type_void) { if (!first) cfg_print_cstr(pctx, " | "); cfg_doc_terminal(pctx, othertype); diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 17b5c628c3..4e1eb477ce 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -123,6 +123,7 @@ cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop }; cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop }; cfg_rep_t cfg_rep_void = { "void", free_noop }; cfg_rep_t cfg_rep_fixedpoint = { "fixedpoint", free_noop }; +cfg_rep_t cfg_rep_percentage = { "percentage", free_noop }; /* * Configuration type definitions. @@ -650,6 +651,69 @@ cfg_type_t cfg_type_void = { "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void, NULL }; +/* + * percentage + */ +isc_result_t +cfg_parse_percentage(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + char *endp; + isc_result_t result; + cfg_obj_t *obj = NULL; + isc_uint32_t percent; + + UNUSED(type); + + CHECK(cfg_gettoken(pctx, 0)); + if (pctx->token.type != isc_tokentype_string) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected percentage"); + return (ISC_R_UNEXPECTEDTOKEN); + } + + percent = isc_string_touint64(TOKEN_STRING(pctx), &endp, 10); + if (*endp != '%' || *(endp+1) != 0) { + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected percentage"); + return (ISC_R_UNEXPECTEDTOKEN); + } + + CHECK(cfg_create_obj(pctx, &cfg_type_percentage, &obj)); + obj->value.uint32 = percent; + *ret = obj; + + cleanup: + return (result); +} + +void +cfg_print_percentage(cfg_printer_t *pctx, const cfg_obj_t *obj) { + char buf[64]; + int n; + + n = snprintf(buf, sizeof(buf), "%u%%", obj->value.uint32); + INSIST(n > 0 && (size_t)n < sizeof(buf)); + cfg_print_chars(pctx, buf, strlen(buf)); +} + +isc_uint32_t +cfg_obj_aspercentage(const cfg_obj_t *obj) { + REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_percentage); + return (obj->value.uint32); +} + +cfg_type_t cfg_type_percentage = { + "percentage", cfg_parse_percentage, cfg_print_percentage, + cfg_doc_terminal, &cfg_rep_percentage, NULL +}; + +isc_boolean_t +cfg_obj_ispercentage(const cfg_obj_t *obj) { + REQUIRE(obj != NULL); + return (ISC_TF(obj->type->rep == &cfg_rep_percentage)); +} + /* * Fixed point */ @@ -724,6 +788,12 @@ cfg_type_t cfg_type_fixedpoint = { cfg_doc_terminal, &cfg_rep_fixedpoint, NULL }; +isc_boolean_t +cfg_obj_isfixedpoint(const cfg_obj_t *obj) { + REQUIRE(obj != NULL); + return (ISC_TF(obj->type->rep == &cfg_rep_fixedpoint)); +} + /* * uint32 */ -- GitLab