shm_main.c revision 1.1.1.3
138494Sobrien/* 251292Sobrien * util/shm_side/shm_main.c - SHM for statistics transport 338494Sobrien * 438494Sobrien * Copyright (c) 2017, NLnet Labs. All rights reserved. 538494Sobrien * 638494Sobrien * This software is open source. 738494Sobrien * 838494Sobrien * Redistribution and use in source and binary forms, with or without 938494Sobrien * modification, are permitted provided that the following conditions 1038494Sobrien * are met: 1138494Sobrien * 1238494Sobrien * Redistributions of source code must retain the above copyright notice, 1338494Sobrien * this list of conditions and the following disclaimer. 1438494Sobrien * 1538494Sobrien * Redistributions in binary form must reproduce the above copyright notice, 1638494Sobrien * this list of conditions and the following disclaimer in the documentation 1738494Sobrien * and/or other materials provided with the distribution. 1838494Sobrien * 1938494Sobrien * Neither the name of the NLNET LABS nor the names of its contributors may 2042629Sobrien * be used to endorse or promote products derived from this software without 2138494Sobrien * specific prior written permission. 2238494Sobrien * 2338494Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2438494Sobrien * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2538494Sobrien * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2638494Sobrien * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2738494Sobrien * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2838494Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2938494Sobrien * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3038494Sobrien * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3138494Sobrien * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3238494Sobrien * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3338494Sobrien * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3438494Sobrien */ 3538494Sobrien 3638494Sobrien/** 3738494Sobrien * \file 3838494Sobrien * 3938494Sobrien * This file contains functions for the SHM implementation. 4038494Sobrien */ 4151292Sobrien 4238494Sobrien#include "config.h" 4338494Sobrien#include <ctype.h> 4438494Sobrien#include <stdarg.h> 4538494Sobrien#ifdef HAVE_SYS_IPC_H 4638494Sobrien#include <sys/ipc.h> 4738494Sobrien#endif 4838494Sobrien#ifdef HAVE_SYS_SHM_H 4938494Sobrien#include <sys/shm.h> 5038494Sobrien#endif 5138494Sobrien#include <sys/time.h> 5238494Sobrien#include <errno.h> 5338494Sobrien#include "shm_main.h" 5438494Sobrien#include "daemon/daemon.h" 5538494Sobrien#include "daemon/worker.h" 5638494Sobrien#include "daemon/stats.h" 5738494Sobrien#include "services/mesh.h" 5838494Sobrien#include "services/cache/rrset.h" 5938494Sobrien#include "services/cache/infra.h" 6038494Sobrien#include "validator/validator.h" 6138494Sobrien#include "util/config_file.h" 6238494Sobrien#include "util/fptr_wlist.h" 6338494Sobrien#include "util/log.h" 6438494Sobrien 6538494Sobrien#ifdef HAVE_SHMGET 6638494Sobrien/** subtract timers and the values do not overflow or become negative */ 6738494Sobrienstatic void 6838494Sobrienstat_timeval_subtract(long long *d_sec, long long *d_usec, const struct timeval* end, 6938494Sobrien const struct timeval* start) 7038494Sobrien{ 7138494Sobrien#ifndef S_SPLINT_S 7238494Sobrien time_t end_usec = end->tv_usec; 7338494Sobrien *d_sec = end->tv_sec - start->tv_sec; 7438494Sobrien if(end_usec < start->tv_usec) { 7538494Sobrien end_usec += 1000000; 7638494Sobrien (*d_sec)--; 7738494Sobrien } 7838494Sobrien *d_usec = end_usec - start->tv_usec; 7938494Sobrien#endif 8038494Sobrien} 8138494Sobrien#endif /* HAVE_SHMGET */ 8238494Sobrien 8338494Sobrienint shm_main_init(struct daemon* daemon) 8438494Sobrien{ 8538494Sobrien#ifdef HAVE_SHMGET 8638494Sobrien struct ub_shm_stat_info *shm_stat; 8738494Sobrien size_t shm_size; 8838494Sobrien 8938494Sobrien /* sanitize */ 9038494Sobrien if(!daemon) 9138494Sobrien return 0; 9238494Sobrien if(!daemon->cfg->shm_enable) 9338494Sobrien return 1; 9438494Sobrien if(daemon->cfg->stat_interval == 0) 9538494Sobrien log_warn("shm-enable is yes but statistics-interval is 0"); 9638494Sobrien 9738494Sobrien /* Statistics to maintain the number of thread + total */ 9838494Sobrien shm_size = (sizeof(struct ub_stats_info) * (daemon->num + 1)); 9938494Sobrien 10038494Sobrien /* Allocation of needed memory */ 10138494Sobrien daemon->shm_info = (struct shm_main_info*)calloc(1, shm_size); 10238494Sobrien 10338494Sobrien /* Sanitize */ 10438494Sobrien if(!daemon->shm_info) { 10538494Sobrien log_err("shm fail: malloc failure"); 10638494Sobrien return 0; 10738494Sobrien } 10838494Sobrien 10938494Sobrien daemon->shm_info->key = daemon->cfg->shm_key; 11038494Sobrien 11138494Sobrien /* Check for previous create SHM */ 11238494Sobrien daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(int), SHM_R); 11338494Sobrien daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, sizeof(int), SHM_R); 11438494Sobrien 11538494Sobrien /* Destroy previous SHM */ 11638494Sobrien if (daemon->shm_info->id_ctl >= 0) 11738494Sobrien shmctl(daemon->shm_info->id_ctl, IPC_RMID, NULL); 11838494Sobrien 11938494Sobrien /* Destroy previous SHM */ 12038494Sobrien if (daemon->shm_info->id_arr >= 0) 12138494Sobrien shmctl(daemon->shm_info->id_arr, IPC_RMID, NULL); 12238494Sobrien 12338494Sobrien /* SHM: Create the segment */ 12438494Sobrien daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(struct ub_shm_stat_info), IPC_CREAT | 0644); 12538494Sobrien 12638494Sobrien if (daemon->shm_info->id_ctl < 0) 12738494Sobrien { 12838494Sobrien log_err("SHM failed(id_ctl) cannot shmget(key %d) %s", 12938494Sobrien daemon->shm_info->key, strerror(errno)); 13038494Sobrien 13138494Sobrien /* Just release memory unused */ 13238494Sobrien free(daemon->shm_info); 13338494Sobrien 13438494Sobrien return 0; 13538494Sobrien } 13638494Sobrien 13738494Sobrien daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, shm_size, IPC_CREAT | 0644); 13838494Sobrien 13938494Sobrien if (daemon->shm_info->id_arr < 0) 14038494Sobrien { 14138494Sobrien log_err("SHM failed(id_arr) cannot shmget(key %d + 1) %s", 14238494Sobrien daemon->shm_info->key, strerror(errno)); 14338494Sobrien 14438494Sobrien /* Just release memory unused */ 14538494Sobrien free(daemon->shm_info); 14638494Sobrien 14738494Sobrien return 0; 14838494Sobrien } 14938494Sobrien 15038494Sobrien /* SHM: attach the segment */ 15151292Sobrien daemon->shm_info->ptr_ctl = (struct ub_shm_stat_info*) 15238494Sobrien shmat(daemon->shm_info->id_ctl, NULL, 0); 15338494Sobrien if(daemon->shm_info->ptr_ctl == (void *) -1) { 15438494Sobrien log_err("SHM failed(ctl) cannot shmat(%d) %s", 15538494Sobrien daemon->shm_info->id_ctl, strerror(errno)); 15638494Sobrien 15738494Sobrien /* Just release memory unused */ 15838494Sobrien free(daemon->shm_info); 15938494Sobrien 16038494Sobrien return 0; 16138494Sobrien } 16238494Sobrien 16338494Sobrien daemon->shm_info->ptr_arr = (struct ub_stats_info*) 16438494Sobrien shmat(daemon->shm_info->id_arr, NULL, 0); 16538494Sobrien 16638494Sobrien if (daemon->shm_info->ptr_arr == (void *) -1) 16738494Sobrien { 16838494Sobrien log_err("SHM failed(arr) cannot shmat(%d) %s", 16938494Sobrien daemon->shm_info->id_arr, strerror(errno)); 17038494Sobrien 17138494Sobrien /* Just release memory unused */ 17238494Sobrien free(daemon->shm_info); 17338494Sobrien 17438494Sobrien return 0; 17538494Sobrien } 17638494Sobrien 17738494Sobrien /* Zero fill SHM to stand clean while is not filled by other events */ 17838494Sobrien memset(daemon->shm_info->ptr_ctl, 0, sizeof(struct ub_shm_stat_info)); 17938494Sobrien memset(daemon->shm_info->ptr_arr, 0, shm_size); 18038494Sobrien 18138494Sobrien shm_stat = daemon->shm_info->ptr_ctl; 18238494Sobrien shm_stat->num_threads = daemon->num; 18338494Sobrien 18438494Sobrien#else 18538494Sobrien (void)daemon; 18638494Sobrien#endif /* HAVE_SHMGET */ 18738494Sobrien return 1; 18838494Sobrien} 18938494Sobrien 19038494Sobrienvoid shm_main_shutdown(struct daemon* daemon) 19138494Sobrien{ 19238494Sobrien#ifdef HAVE_SHMGET 19338494Sobrien /* web are OK, just disabled */ 19438494Sobrien if(!daemon->cfg->shm_enable) 19538494Sobrien return; 19638494Sobrien 19738494Sobrien verbose(VERB_DETAIL, "SHM shutdown - KEY [%d] - ID CTL [%d] ARR [%d] - PTR CTL [%p] ARR [%p]", 19838494Sobrien daemon->shm_info->key, daemon->shm_info->id_ctl, daemon->shm_info->id_arr, daemon->shm_info->ptr_ctl, daemon->shm_info->ptr_arr); 19938494Sobrien 20038494Sobrien /* Destroy previous SHM */ 20151292Sobrien if (daemon->shm_info->id_ctl >= 0) 20238494Sobrien shmctl(daemon->shm_info->id_ctl, IPC_RMID, NULL); 20338494Sobrien 20438494Sobrien if (daemon->shm_info->id_arr >= 0) 20538494Sobrien shmctl(daemon->shm_info->id_arr, IPC_RMID, NULL); 20638494Sobrien 20738494Sobrien if (daemon->shm_info->ptr_ctl) 20838494Sobrien shmdt(daemon->shm_info->ptr_ctl); 20938494Sobrien 21038494Sobrien if (daemon->shm_info->ptr_arr) 21138494Sobrien shmdt(daemon->shm_info->ptr_arr); 21238494Sobrien 21338494Sobrien#else 21438494Sobrien (void)daemon; 21538494Sobrien#endif /* HAVE_SHMGET */ 21638494Sobrien} 21738494Sobrien 21838494Sobrienvoid shm_main_run(struct worker *worker) 21938494Sobrien{ 22038494Sobrien#ifdef HAVE_SHMGET 22138494Sobrien struct ub_shm_stat_info *shm_stat; 22238494Sobrien struct ub_stats_info *stat_total; 22338494Sobrien struct ub_stats_info *stat_info; 22438494Sobrien int offset; 22538494Sobrien 22638494Sobrien#ifndef S_SPLINT_S 22738494Sobrien verbose(VERB_DETAIL, "SHM run - worker [%d] - daemon [%p] - timenow(%u) - timeboot(%u)", 22838494Sobrien worker->thread_num, worker->daemon, (unsigned)worker->env.now_tv->tv_sec, (unsigned)worker->daemon->time_boot.tv_sec); 22938494Sobrien#endif 23038494Sobrien 23138494Sobrien offset = worker->thread_num + 1; 23238494Sobrien stat_total = worker->daemon->shm_info->ptr_arr; 23338494Sobrien stat_info = worker->daemon->shm_info->ptr_arr + offset; 23438494Sobrien 23538494Sobrien /* Copy data to the current position */ 23638494Sobrien server_stats_compile(worker, stat_info, 0); 23738494Sobrien 23838494Sobrien /* First thread, zero fill total, and copy general info */ 23938494Sobrien if (worker->thread_num == 0) { 24038494Sobrien 24138494Sobrien /* Copy data to the current position */ 24238494Sobrien memset(stat_total, 0, sizeof(struct ub_stats_info)); 24338494Sobrien 24438494Sobrien /* Point to data into SHM */ 24538494Sobrien#ifndef S_SPLINT_S 24638494Sobrien shm_stat = worker->daemon->shm_info->ptr_ctl; 24738494Sobrien shm_stat->time.now_sec = (long long)worker->env.now_tv->tv_sec; 24838494Sobrien shm_stat->time.now_usec = (long long)worker->env.now_tv->tv_usec; 24938494Sobrien#endif 25038494Sobrien 25138494Sobrien stat_timeval_subtract(&shm_stat->time.up_sec, &shm_stat->time.up_usec, worker->env.now_tv, &worker->daemon->time_boot); 25238494Sobrien stat_timeval_subtract(&shm_stat->time.elapsed_sec, &shm_stat->time.elapsed_usec, worker->env.now_tv, &worker->daemon->time_last_stat); 25338494Sobrien 25438494Sobrien shm_stat->mem.msg = (long long)slabhash_get_mem(worker->env.msg_cache); 25538494Sobrien shm_stat->mem.rrset = (long long)slabhash_get_mem(&worker->env.rrset_cache->table); 25638494Sobrien shm_stat->mem.dnscrypt_shared_secret = 0; 25738494Sobrien#ifdef USE_DNSCRYPT 25838494Sobrien if(worker->daemon->dnscenv) { 25938494Sobrien shm_stat->mem.dnscrypt_shared_secret = (long long)slabhash_get_mem( 26038494Sobrien worker->daemon->dnscenv->shared_secrets_cache); 26138494Sobrien shm_stat->mem.dnscrypt_nonce = (long long)slabhash_get_mem( 26251292Sobrien worker->daemon->dnscenv->nonces_cache); 26338494Sobrien } 26438494Sobrien#endif 26538494Sobrien shm_stat->mem.val = (long long)mod_get_mem(&worker->env, 26638494Sobrien "validator"); 26738494Sobrien shm_stat->mem.iter = (long long)mod_get_mem(&worker->env, 26838494Sobrien "iterator"); 26938494Sobrien shm_stat->mem.respip = (long long)mod_get_mem(&worker->env, 27038494Sobrien "respip"); 27138494Sobrien 27238494Sobrien /* subnet mem value is available in shm, also when not enabled, 27338494Sobrien * to make the struct easier to memmap by other applications, 27438494Sobrien * independent of the configuration of unbound */ 27538494Sobrien shm_stat->mem.subnet = 0; 27638494Sobrien#ifdef CLIENT_SUBNET 27738494Sobrien shm_stat->mem.subnet = (long long)mod_get_mem(&worker->env, 27838494Sobrien "subnet"); 27938494Sobrien#endif 28038494Sobrien /* ipsecmod mem value is available in shm, also when not enabled, 28138494Sobrien * to make the struct easier to memmap by other applications, 28238494Sobrien * independent of the configuration of unbound */ 28338494Sobrien shm_stat->mem.ipsecmod = 0; 28438494Sobrien#ifdef USE_IPSECMOD 28538494Sobrien shm_stat->mem.ipsecmod = (long long)mod_get_mem(&worker->env, 28638494Sobrien "ipsecmod"); 28738494Sobrien#endif 28838494Sobrien#ifdef WITH_DYNLIBMODULE 28938494Sobrien shm_stat->mem.dynlib = (long long)mod_get_mem(&worker->env, 29038494Sobrien "dynlib"); 29138494Sobrien#endif 29238494Sobrien } 29338494Sobrien 29438494Sobrien server_stats_add(stat_total, stat_info); 29538494Sobrien 29638494Sobrien /* print the thread statistics */ 29738494Sobrien stat_total->mesh_time_median /= (double)worker->daemon->num; 29838494Sobrien 29938494Sobrien#else 30038494Sobrien (void)worker; 30138494Sobrien#endif /* HAVE_SHMGET */ 30238494Sobrien} 30338494Sobrien