Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-ports-gnome
Path: blob/main/dns/bind916/files/bind-v9.16.0-tcp_quota_fix.patch
16125 views
1
diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h
2
index ae83f943d3..c85065f39d 100644
3
--- a/lib/isc/netmgr/netmgr-int.h
4
+++ b/lib/isc/netmgr/netmgr-int.h
5
@@ -356,7 +356,16 @@ struct isc_nmsocket {
6
*/
7
isc_quota_t *quota;
8
isc_quota_t *pquota;
9
- bool overquota;
10
+
11
+ /*%
12
+ * How many connections we have not accepted due to quota?
13
+ * When we close a connection we need to accept a new one.
14
+ */
15
+ int overquota;
16
+ /*%
17
+ * How many active connections we have?
18
+ */
19
+ int conns;
20
21
/*%
22
* Socket statistics
23
diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c
24
index f4361575cc..26728c1ba6 100644
25
--- a/lib/isc/netmgr/netmgr.c
26
+++ b/lib/isc/netmgr/netmgr.c
27
@@ -727,6 +727,11 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree)
28
for (int i = 0; i < sock->nchildren; i++) {
29
if (!atomic_load(&sock->children[i].destroying)) {
30
nmsocket_cleanup(&sock->children[i], false);
31
+ if (sock->statsindex != NULL) {
32
+ isc__nm_decstats(
33
+ sock->mgr,
34
+ sock->statsindex[STATID_ACTIVE]);
35
+ }
36
}
37
}
38
39
@@ -738,6 +743,9 @@ nmsocket_cleanup(isc_nmsocket_t *sock, bool dofree)
40
sock->children = NULL;
41
sock->nchildren = 0;
42
}
43
+ if (sock->statsindex != NULL) {
44
+ isc__nm_decstats(sock->mgr, sock->statsindex[STATID_ACTIVE]);
45
+ }
46
47
if (sock->tcphandle != NULL) {
48
isc_nmhandle_unref(sock->tcphandle);
49
@@ -854,8 +862,6 @@ isc__nmsocket_prep_destroy(isc_nmsocket_t *sock)
50
if (sock->children != NULL) {
51
for (int i = 0; i < sock->nchildren; i++) {
52
atomic_store(&sock->children[i].active, false);
53
- isc__nm_decstats(sock->mgr,
54
- sock->statsindex[STATID_ACTIVE]);
55
}
56
}
57
58
diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c
59
index a83fede0d2..58ffd3c404 100644
60
--- a/lib/isc/netmgr/tcp.c
61
+++ b/lib/isc/netmgr/tcp.c
62
@@ -26,12 +26,28 @@
63
#include <isc/region.h>
64
#include <isc/result.h>
65
#include <isc/sockaddr.h>
66
+#include <isc/stdtime.h>
67
#include <isc/thread.h>
68
#include <isc/util.h>
69
70
#include "netmgr-int.h"
71
#include "uv-compat.h"
72
73
+static atomic_uint_fast32_t last_tcpquota_log = ATOMIC_VAR_INIT(0);
74
+
75
+static bool
76
+can_log_tcp_quota() {
77
+ isc_stdtime_t now, last;
78
+
79
+ isc_stdtime_get(&now);
80
+ last = atomic_exchange_relaxed(&last_tcpquota_log, now);
81
+ if (now != last) {
82
+ return (true);
83
+ }
84
+
85
+ return (false);
86
+}
87
+
88
static int
89
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
90
91
@@ -668,9 +684,6 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf)
92
}
93
94
isc__nm_free_uvbuf(sock, buf);
95
- if (sock->quota) {
96
- isc_quota_detach(&sock->quota);
97
- }
98
99
/*
100
* This might happen if the inner socket is closing. It means that
101
@@ -699,6 +712,7 @@ accept_connection(isc_nmsocket_t *ssock)
102
struct sockaddr_storage ss;
103
isc_sockaddr_t local;
104
int r;
105
+ bool overquota = false;
106
107
REQUIRE(VALID_NMSOCK(ssock));
108
REQUIRE(ssock->tid == isc_nm_tid());
109
@@ -711,10 +725,25 @@ accept_connection(isc_nmsocket_t *ssock)
110
111
if (ssock->pquota != NULL) {
112
result = isc_quota_attach(ssock->pquota, &quota);
113
+
114
+ /*
115
+ * We share the quota between all TCP sockets. Others
116
+ * may have used up all the quota slots, in which case
117
+ * this socket could starve. So we only fail here if we
118
+ * already had at least one active connection on this
119
+ * socket. This guarantees that we'll maintain some level
120
+ * of service while over quota, and will resume normal
121
+ * service when the quota comes back down.
122
+ */
123
if (result != ISC_R_SUCCESS) {
124
- isc__nm_incstats(ssock->mgr,
125
- ssock->statsindex[STATID_ACCEPTFAIL]);
126
- return (result);
127
+ ssock->overquota++;
128
+ overquota = true;
129
+ if (ssock->conns > 0) {
130
+ isc__nm_incstats(
131
+ ssock->mgr,
132
+ ssock->statsindex[STATID_ACCEPTFAIL]);
133
+ return (result);
134
+ }
135
}
136
}
137
138
@@ -761,6 +790,7 @@ accept_connection(isc_nmsocket_t *ssock)
139
}
140
141
isc_nmsocket_attach(ssock, &csock->server);
142
+ ssock->conns++;
143
144
handle = isc__nmhandle_get(csock, NULL, &local);
145
146
@@ -779,6 +809,9 @@ error:
147
if (csock->quota != NULL) {
148
isc_quota_detach(&csock->quota);
149
}
150
+ if (overquota) {
151
+ ssock->overquota--;
152
+ }
153
/* We need to detach it properly to make sure uv_close is called. */
154
isc_nmsocket_detach(&csock);
155
return (result);
156
@@ -793,14 +826,14 @@ tcp_connection_cb(uv_stream_t *server, int status)
157
UNUSED(status);
158
159
result = accept_connection(ssock);
160
- if (result != ISC_R_SUCCESS) {
161
- if (result == ISC_R_QUOTA || result == ISC_R_SOFTQUOTA) {
162
- ssock->overquota = true;
163
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOCONN) {
164
+ if ((result != ISC_R_QUOTA && result != ISC_R_SOFTQUOTA) ||
165
+ can_log_tcp_quota()) {
166
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
167
+ ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
168
+ "TCP connection failed: %s",
169
+ isc_result_totext(result));
170
}
171
- isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
172
- ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
173
- "TCP connection failed: %s",
174
- isc_result_totext(result));
175
}
176
}
177
178
@@ -936,17 +969,27 @@ tcp_close_direct(isc_nmsocket_t *sock)
179
REQUIRE(VALID_NMSOCK(sock));
180
REQUIRE(sock->tid == isc_nm_tid());
181
REQUIRE(sock->type == isc_nm_tcpsocket);
182
+ isc_nmsocket_t *ssock = sock->server;
183
184
if (sock->quota != NULL) {
185
- isc_nmsocket_t *ssock = sock->server;
186
-
187
isc_quota_detach(&sock->quota);
188
-
189
- if (ssock->overquota) {
190
+ }
191
+ if (ssock != NULL) {
192
+ ssock->conns--;
193
+ while (ssock->conns == 0 && ssock->overquota > 0) {
194
+ ssock->overquota--;
195
isc_result_t result = accept_connection(ssock);
196
- if (result != ISC_R_QUOTA &&
197
- result != ISC_R_SOFTQUOTA) {
198
- ssock->overquota = false;
199
+ if (result == ISC_R_SUCCESS || result == ISC_R_NOCONN) {
200
+ continue;
201
+ }
202
+ if ((result != ISC_R_QUOTA &&
203
+ result != ISC_R_SOFTQUOTA) ||
204
+ can_log_tcp_quota()) {
205
+ isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
206
+ ISC_LOGMODULE_NETMGR,
207
+ ISC_LOG_ERROR,
208
+ "TCP connection failed: %s",
209
+ isc_result_totext(result));
210
}
211
}
212
}
213
diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c
214
index e384b73be9..f89eb359af 100644
215
--- a/lib/isc/netmgr/tcpdns.c
216
+++ b/lib/isc/netmgr/tcpdns.c
217
@@ -43,6 +43,9 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_region_t *region, void *arg);
218
static void
219
resume_processing(void *arg);
220
221
+static void
222
+tcpdns_close_direct(isc_nmsocket_t *sock);
223
+
224
static inline size_t
225
dnslen(unsigned char *base)
226
{
227
@@ -82,7 +85,6 @@ timer_close_cb(uv_handle_t *handle)
228
{
229
isc_nmsocket_t *sock = (isc_nmsocket_t *)uv_handle_get_data(handle);
230
INSIST(VALID_NMSOCK(sock));
231
- atomic_store(&sock->closed, true);
232
isc_nmsocket_detach(&sock);
233
}
234
235
@@ -94,9 +96,7 @@ dnstcp_readtimeout(uv_timer_t *timer)
236
237
REQUIRE(VALID_NMSOCK(sock));
238
REQUIRE(sock->tid == isc_nm_tid());
239
-
240
- isc_nmsocket_detach(&sock->outer);
241
- uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
242
+ tcpdns_close_direct(sock);
243
}
244
245
/*
246
@@ -252,7 +252,9 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_region_t *region, void *arg)
247
* We have a packet: stop timeout timers
248
*/
249
atomic_store(&dnssock->outer->processing, true);
250
- uv_timer_stop(&dnssock->timer);
251
+ if (dnssock->timer_initialized) {
252
+ uv_timer_stop(&dnssock->timer);
253
+ }
254
255
if (atomic_load(&dnssock->sequential)) {
256
/*
257
@@ -399,8 +401,10 @@ resume_processing(void *arg)
258
if (atomic_load(&sock->ah) == 0) {
259
/* Nothing is active; sockets can timeout now */
260
atomic_store(&sock->outer->processing, false);
261
- uv_timer_start(&sock->timer, dnstcp_readtimeout,
262
- sock->read_timeout, 0);
263
+ if (sock->timer_initialized) {
264
+ uv_timer_start(&sock->timer, dnstcp_readtimeout,
265
+ sock->read_timeout, 0);
266
+ }
267
}
268
269
/*
270
@@ -413,7 +417,9 @@ resume_processing(void *arg)
271
result = processbuffer(sock, &handle);
272
if (result == ISC_R_SUCCESS) {
273
atomic_store(&sock->outer->processing, true);
274
- uv_timer_stop(&sock->timer);
275
+ if (sock->timer_initialized) {
276
+ uv_timer_stop(&sock->timer);
277
+ }
278
isc_nmhandle_unref(handle);
279
} else if (sock->outer != NULL) {
280
isc_nm_resumeread(sock->outer);
281
@@ -441,7 +447,9 @@ resume_processing(void *arg)
282
break;
283
}
284
285
- uv_timer_stop(&sock->timer);
286
+ if (sock->timer_initialized) {
287
+ uv_timer_stop(&sock->timer);
288
+ }
289
atomic_store(&sock->outer->processing, true);
290
isc_nmhandle_unref(dnshandle);
291
} while (atomic_load(&sock->ah) < TCPDNS_CLIENTS_PER_CONN);
292
@@ -507,18 +515,29 @@ static void
293
tcpdns_close_direct(isc_nmsocket_t *sock)
294
{
295
REQUIRE(sock->tid == isc_nm_tid());
296
- if (sock->outer != NULL) {
297
- sock->outer->rcb.recv = NULL;
298
- isc_nmsocket_detach(&sock->outer);
299
- }
300
- if (sock->listener != NULL) {
301
- isc_nmsocket_detach(&sock->listener);
302
- }
303
/* We don't need atomics here, it's all in single network thread */
304
if (sock->timer_initialized) {
305
+ /*
306
+ * We need to fire the timer callback to clean it up,
307
+ * it will then call us again (via detach) so that we
308
+ * can finally close the socket.
309
+ */
310
sock->timer_initialized = false;
311
uv_timer_stop(&sock->timer);
312
uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
313
+ } else {
314
+ /*
315
+ * At this point we're certain that there are no external
316
+ * references, we can close everything.
317
+ */
318
+ if (sock->outer != NULL) {
319
+ sock->outer->rcb.recv = NULL;
320
+ isc_nmsocket_detach(&sock->outer);
321
+ }
322
+ if (sock->listener != NULL) {
323
+ isc_nmsocket_detach(&sock->listener);
324
+ }
325
+ atomic_store(&sock->closed, true);
326
}
327
}
328
329
diff --git a/lib/isc/netmgr/uverr2result.c b/lib/isc/netmgr/uverr2result.c
330
index b6a8065e3e..9781454ca6 100644
331
--- a/lib/isc/netmgr/uverr2result.c
332
+++ b/lib/isc/netmgr/uverr2result.c
333
@@ -38,6 +38,8 @@ isc___nm_uverr2result(int uverr, bool dolog, const char *file,
334
return (ISC_R_INVALIDFILE);
335
case UV_ENOENT:
336
return (ISC_R_FILENOTFOUND);
337
+ case UV_EAGAIN:
338
+ return (ISC_R_NOCONN);
339
case UV_EACCES:
340
case UV_EPERM:
341
return (ISC_R_NOPERM);
342
343