Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: quota.h,v 1.12 2026/04/08 00:16:16 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