1 /* $NetBSD: quota.h,v 1.11 2025/01/26 16:25:42 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #pragma once 17 18 /***** 19 ***** Module Info 20 *****/ 21 22 /*! \file isc/quota.h 23 * 24 * \brief The isc_quota_t object is a simple helper object for implementing 25 * quotas on things like the number of simultaneous connections to 26 * a server. It keeps track of the amount of quota in use, and 27 * encapsulates the locking necessary to allow multiple tasks to 28 * share a quota. 29 */ 30 31 /*** 32 *** Imports. 33 ***/ 34 35 #include <isc/atomic.h> 36 #include <isc/job.h> 37 #include <isc/lang.h> 38 #include <isc/magic.h> 39 #include <isc/mutex.h> 40 #include <isc/os.h> 41 #include <isc/refcount.h> 42 #include <isc/types.h> 43 #include <isc/urcu.h> 44 45 /***** 46 ***** Types. 47 *****/ 48 49 /* Add -DISC_QUOTA_TRACE=1 to CFLAGS for detailed reference tracing */ 50 51 ISC_LANG_BEGINDECLS 52 53 /*% 54 * isc_quota structure 55 * 56 * NOTE: We are using struct cds_wfcq_head which has an internal 57 * mutex, because we are using enqueue and dequeue, and dequeues need 58 * synchronization between multiple threads (see urcu/wfcqueue.h for 59 * detailed description). 60 */ 61 STATIC_ASSERT(ISC_OS_CACHELINE_SIZE >= sizeof(struct __cds_wfcq_head), 62 "ISC_OS_CACHELINE_SIZE smaller than " 63 "sizeof(struct __cds_wfcq_head)"); 64 struct isc_quota { 65 int magic; 66 atomic_uint_fast32_t max; 67 atomic_uint_fast32_t used; 68 atomic_uint_fast32_t soft; 69 struct { 70 struct cds_wfcq_head head; 71 uint8_t __padding[ISC_OS_CACHELINE_SIZE - 72 sizeof(struct __cds_wfcq_head)]; 73 struct cds_wfcq_tail tail; 74 } jobs; 75 ISC_LINK(isc_quota_t) link; 76 }; 77 78 void 79 isc_quota_init(isc_quota_t *quota, unsigned int max); 80 /*%< 81 * Initialize a quota object. 82 */ 83 84 void 85 isc_quota_destroy(isc_quota_t *quota); 86 /*%< 87 * Destroy a quota object. 88 */ 89 90 void 91 isc_quota_soft(isc_quota_t *quota, unsigned int soft); 92 /*%< 93 * Set a soft quota. 94 */ 95 96 void 97 isc_quota_max(isc_quota_t *quota, unsigned int max); 98 /*%< 99 * Re-set a maximum quota. 100 */ 101 102 unsigned int 103 isc_quota_getmax(isc_quota_t *quota); 104 /*%< 105 * Get the maximum quota. 106 */ 107 108 unsigned int 109 isc_quota_getsoft(isc_quota_t *quota); 110 /*%< 111 * Get the soft quota. 112 */ 113 114 unsigned int 115 isc_quota_getused(isc_quota_t *quota); 116 /*%< 117 * Get the current usage of quota. 118 */ 119 120 #define isc_quota_acquire(quota) isc_quota_acquire_cb(quota, NULL, NULL, NULL) 121 isc_result_t 122 isc_quota_acquire_cb(isc_quota_t *quota, isc_job_t *job, isc_job_cb cb, 123 void *cbarg); 124 /*%< 125 * 126 * Attempt to reserve one unit of 'quota', if there's no quota left then 127 * cb->cb(cb->cbarg) will be called when there's quota again. 128 * 129 * Note: It's the caller's responsibility to make sure that we don't end up 130 * with a huge number of callbacks waiting, making it easy to create a 131 * resource exhaustion attack. For example, in the case of TCP listening, 132 * we simply don't accept new connections when the quota is exceeded, so 133 * the number of callbacks waiting in the queue will be limited by the 134 * listen() backlog. 135 * 136 * Returns: 137 * \li #ISC_R_SUCCESS Success 138 * \li #ISC_R_SOFTQUOTA Success soft quota reached 139 * \li #ISC_R_QUOTA Quota is full 140 */ 141 142 void 143 isc_quota_release(isc_quota_t *quota); 144 /*%< 145 * Release one unit of quota. 146 */ 147 148 ISC_LANG_ENDDECLS 149